Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

879868 Posts in 33010 Topics- by 24383 Members - Latest Member: celloe

May 25, 2013, 06:24:35 AM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)on Lua
Pages: [1]
Print
Author Topic: on Lua  (Read 825 times)
nikki
Level 10
*****


View Profile Email
« on: May 01, 2012, 02:46:08 PM »

So I managed to get embedded lua in my program.
a lot of articles seem to suggest instancing and doing almost everything to your objects in lua, or on the other hand use it as a elite ini file. Off course my wishes lay in the middle.


at the moment i am trying to get my head around this.
I have a lua file with  while a loop that changes some values (lets say the red of a square)

oh wait ill
Code:
act:interactWithObject(obj)
act.x = act.x + 2
while (act.red > 0) do
 act.red = act.red - 1
end

and then I have my host program that handles the drawing of the square.
Code:
Method Draw()
SetColor red,green,blue
DrawRect x,y,width, height
EndMethod

at this moment when i run the lua script the color will change almost instantly.
how to do that gradually over time while updating my act in the host program aswell.
do I pass the lua state pointer around to all objects ?
do i make lua pause ?
hooks, coroutines and whatnot aaaarrgh

how to do easy



Logged
BlueSweatshirt
Level 10
*****


the void


View Profile WWW
« Reply #1 on: May 01, 2012, 02:53:28 PM »

Umm, it's probably doing that because your while loop is calculating entirely in that frame.
Instead, try incrementing your red value between elapses of time to make the fade gradual.
There are many possible ways to approach this problem.
An easy one I recommend would be to call an update function(within lua) or script with a certain elapsed time value attached to it, wherein you increment your color values and whatnot. Coroutines are another possible solution albeit perhaps overly complex for the scope of this problem.
Logged

nikki
Level 10
*****


View Profile Email
« Reply #2 on: May 01, 2012, 02:59:46 PM »

yes, and I am hoping someone knows some good scalable ways. edit: didn't see 2nd par.

and yeah the whole lua script is run exactly only in the function thats called when i press a button, like a millisec.
maybe I should try to open up the functions in the lua file to my host so i could call update functions in Lua
Logged
BlueSweatshirt
Level 10
*****


the void


View Profile WWW
« Reply #3 on: May 01, 2012, 03:06:17 PM »

You could write a method to schedule the execution of a lua script, and then expose that function to your lua scripts.

So for example:
Code:
-- increment_red.lua
act.red = act.red - 1
if (act.red > 0) then
    schedule("increment_red.lua", 50) -- this is the scheduling function I mentioned.
end

Possible disadvantages:
I don't know if there's much overhead in the lua api to calling a script, so it may put an unnecessary toll on the system if you do this too much. The same goes for any overhead your function bindings have in fetching object data(in this case, the square). One highly important optimization would be, on the host's end, to load the scripts into memory as strings first and then call them from there.
« Last Edit: May 01, 2012, 03:15:41 PM by Jack Sanders » Logged

Hima
Level 4
****


OM NOM NOM


View Profile WWW Email
« Reply #4 on: May 01, 2012, 07:42:49 PM »

Have you tried coroutine? http://lua-users.org/wiki/CoroutinesTutorial

If you find coroutine difficult, then the only way to do it in lua is to have a native update call to lua update and reduce red property each frame.

There's an overhead if you have many lua interpreter running. If you have many objects, it's better to have one lua interpreter  and pass a set of objects to it and let it process every object in one go.

I think it's important to know where do you want to go with this, since, as Jack said, there are many ways to tackle this problem. Are you trying to make a scriptable effect system?
« Last Edit: May 01, 2012, 07:55:24 PM by Hima » Logged

nikki
Level 10
*****


View Profile Email
« Reply #5 on: May 02, 2012, 06:03:25 AM »

I am building a suite of editors aka my engine, and Lua would be perfect i think for the actor <-> object interactions.

so imagine you want to add a refrigerator into my game, that refrigerator has some sprites, soundeffects and lua files.
for every interaction possible there would have to be a lua file, in that lua file there would be a table in wich the refrigerator advertises the interaction (probably it would advertise its effect on hunger) and in the lua file would be a function that you can call from my game. (maybe with parameters actor and object, or maybe those two will be pushed on the stack as globals)

eventually there will be dozens of objects onscreen and dozens of actor, and there would be many lua script running at the same time.  (think the sims)

because I just started looking into Lua I possible am looking at all of this to narrowed down, and the system would be more open and moddable if I took lua the whole way, but my head is not that far atm.

 
Logged
nikki
Level 10
*****


View Profile Email
« Reply #6 on: May 03, 2012, 12:58:07 PM »

Quote
that looks very interresting indeed!

i managed to get a bit further, and the original problem (gradually changing values) i fixed the brute-force way; repeatedly rerunning the script.
which is such a messy non-solution that i'm still left with the problem:

how to wait while running a lua script for a host event (animation finished, destination reached, sound finished, etc) to finish ?
and on a sidenote, how to make a simple script solution to write this.


maybe those coroutines are exactly for that (it seems), however I noticed in the api that coroutine.yield can't run external code, so i assume that means you need some low-level lua function that handle stuff my host program is doing now.








 
Logged
nikki
Level 10
*****


View Profile Email
« Reply #7 on: May 06, 2012, 02:50:18 AM »

Hi guys!

I've been banging my head to the nearest wall a couple of days and have got the coroutines working a bit.

now I'm running into a new problem; when I instance > 50 coroutines the program crashes,
it's a weird crash becasue it's on luaL_doString and both the parameters are not null.

so i suspect it's got something to do with the garbarge collection, but i haven't got a clue..

for good measure:
my source file:
Code:
SuperStrict

Import  "base.bmx"
Import LuGi.Core
Import LuGI.Generator
Const GENERATE:Int = 0

If GENERATE
GenerateGlueCode("glue.bmx")
End
Else
Include "glue.bmx"
EndIf




Local manager:TLuaManager = New TLuaManager
manager.initLua()
'manager.startCoroutine()


Graphics 1024,768

While Not KeyDown(key_escape)
Cls
manager.Update()

If KeyDown(key_space)
'For Local i:Int = 0 Until 10
manager.startCoroutine()
' Delay(5)
' Next
EndIf

Flip
Wend



Type TLuaManager
Field state:Byte Ptr
Field coroutines:TList = New TList
Field luaFile:String
'Field actors:TList = New TList

Method Update()
DrawText coroutines.count() , 0,0
For Local c:TCoroutine = EachIn coroutines
If (lua_status(c.coroutine) = 1)
If c.actor.desx=c.actor.x And c.actor.desy = c.actor.y
lua_resume(c.coroutine, 1)
EndIf
Else
stackdump(c.coroutine)
lua_pop(c.coroutine,0)

c.coroutine = Null
ListRemove(coroutines,c)

EndIf
c.actor.Update()
c.actor.Draw()
Next

If KeyHit(key_d)
stackdump(state)
EndIf

EndMethod

Method initLua()
state = luaL_newstate()
luaL_openlibs(state)
InitLuGI(state)
luaFile = LoadText("coroutines.lua")
EndMethod

Method startCoroutine()

Local act:TActor = New TActor
act = act.init("nikki", Rand(1024) ,Rand(768), 20, 20, Rand(100,250), Rand(100,250), Rand(100,250))

Local thread:Byte Ptr = lua_newthread(state)

If luaL_dostring(thread, luaFile ) = 1 Then
Local err:String = "Error: "+lua_tostring(thread, -1)
stackDump(thread)
lua_close(thread)
RuntimeError(err)
EndIf


lua_getfield(thread , LUA_GLOBALSINDEX, "main") 'Puts the function onto the stack
lua_pushbmaxobject( thread, act )

Local routine:TCoroutine = TCoroutine.Create(thread, act)
coroutines.addlast(routine)

lua_pushbmaxobject( thread, routine)
lua_setglobal(thread, "thread")


lua_resume(thread, 1)
EndMethod

Method closeLua()
If state
lua_close(state)
state = Null
Else
Throw("state was null already")
EndIf
EndMethod


Function stackDump(state:Byte Ptr Var)
Local str:String
Local top:Int = lua_gettop(state)
For Local i:Int = 1 To top
Local t:Int = lua_type(state, i)
Select t
Case LUA_TSTRING
str:+ lua_tostring(state, i)
Case LUA_TBOOLEAN
str:+ lua_toboolean(state, i)
Case LUA_TFUNCTION
str:+ "FUNCTION"
Case LUA_TNUMBER
str:+ lua_tonumber(state, i)
Case LUA_TNIL
str:+ "NIL"
Case LUA_TNONE
str:+ "NONE"
Case LUA_TLIGHTUSERDATA
str:+ "LIGHTUSERDATA"
Case LUA_TTABLE
str:+ "TABLE"
Case LUA_TUSERDATA
str:+ "USERDATA"
Case LUA_TTHREAD
str:+ "THREAD"

Default
'If (lua_isbmaxobject(state,i))
' str:+ "bmax"
'Else
str:+ lua_typename(state, i)
'EndIf
EndSelect
If i<top
str:+", "
EndIf
Next
Print "stack: "+str
EndFunction



EndType



my wrapped file:
Code:

Type TCoroutine {expose}
Field actor:TActor
Field coroutine:Byte Ptr

Function Create:TCoroutine(coroutine:Byte Ptr Var, actor:TActor)
Local ent:TCoroutine = New TCoroutine
ent.coroutine = coroutine
ent.actor = actor
Return ent
EndFunction
EndType



Type TActor Extends TObject {expose}
Field framesleft:Int

Field desx:Int
Field desy:Int

Method Init:TActor (name:String, x:Int, y:Int, width:Int, height:Int, red:Int, green:Int, blue:Int )
Self.name = name
Self.x = x
Self.y = y
Self.width = width
Self.height  = height
Self.red = red
Self.green = green
Self.blue = blue
Return Self
End Method

Method Update()
If framesleft>0
framesleft:-1
Print framesleft
EndIf

If desx>x
x:+1
ElseIf desx<x
x:-1
EndIf
If desy>y
y:+1
ElseIf desy<y
y:-1
EndIf

EndMethod

Method setDestination(x:Int, y:Int)
Print "in bmx desx and desy are: "+x+", "+y
desx = x
dexy = y
EndMethod


Method animationDone()
Return (framesleft<=0)
EndMethod


Method setAnimation(amount:Int)
framesLeft = amount
EndMethod


Method interactWithActor(with:TActor)
Print Self.name+" (actor) interacts on "+with.name
EndMethod

EndType

Type TObject {expose}
Field x:Int,y:Int, width:Int, height:Int
Field red:Int, green:Int, blue:Int
Field name:String

Method Init:TObject(name:String, x:Int, y:Int, width:Int, height:Int, red:Int, green:Int, blue:Int )
Self.name = name
Self.x = x
Self.y = y
Self.width = width
Self.height  = height
Self.red = red
Self.green = green
Self.blue = blue

Return Self
End Method



Method interactWithObject(with:TObject)
If with
Print Self.name+" interacts on "+with.name
EndIf
EndMethod

Method Update()
EndMethod

Method Draw()
SetColor red,green,blue
DrawRect x,y,width, height
If TActor(Self)
SetColor 255,255,255
DrawText  TActor(Self).desx+","+ TActor(Self).desy,x,y
EndIf
EndMethod

EndType



and the lua file:
Code:
advertises = { hunger="200",
energy="1040",
duration="120",
alertness="-12"}

--print("outside main in Lua")

function main(act)
print(thread)
--print("first",coroutine)
act.desx = math.random(1024)
act.desy =  math.random(768)
coroutine.yield()

--print("second",coroutine)
act.desx = math.random(1024)
act.desy =  math.random(768)
coroutine.yield()

--print("third",coroutine)
act.desx = math.random(1024)
act.desy =  math.random(768)
coroutine.yield()

-- print("fourth",coroutine)
act.desx = math.random(1024)
act.desy =  math.random(768)
coroutine.yield()

--print("fifth",coroutine)
act.desx = math.random(1024)
act.desy =  math.random(768)
coroutine.yield()
end

function waitFor()
end
Logged
eigenbom
Level 10
*****



View Profile WWW
« Reply #8 on: May 06, 2012, 02:51:33 PM »

i haven't used Lua coroutines before, but ...
- why are you creating a new Lua thread every time you create a new coroutine?
- does lua_resume do any error reporting? i can't see you catching any errors from it..

good luck! Smiley
Logged

nikki
Level 10
*****


View Profile Email
« Reply #9 on: May 07, 2012, 01:40:25 AM »

thatnks for the look-over, I've noticed you've been using Lua brightly too on moonman.

It is a bit confusing but there is no multi-threading in Lua, so i am not creating new threads, but the api and documentation use the word thread for coroutine (i think it was something that changed somewhere in history..)

lua_resume does some error checking (well it returns a value) and i'm not checking that value the first time (i assume (ouch)) it's ok sine it's just a new thread and i know exactly whats on the stack. i could be checking more.


anyway, after a few days of missing social calls, and not washing myself I do believe i've fixed the problems.

It has to do with the thread/coroutine not being referenced from the lua side, last night i managed to get 250.000 coroutines running (my memory didn't like it much though).

i've cleaned up the code a lot more to isolate the problem, and then fixed it, now i am left with:

Code:
SuperStrict




Local manager:TLuaManager = New TLuaManager
manager.initLua()



Graphics 1024,768

Local startmem:Int = GCMemAlloced()

While Not KeyDown(key_escape)
Cls
manager.Update()

If KeyDown(key_space)
For Local i:Int = 0 Until 2000
manager.startCoroutine()
Next
EndIf
Print GCMemAlloced() -startmem



Flip
Wend


Type TCoroutine

Field coroutine:Byte Ptr
Field refID:Int

Function Create:TCoroutine(coroutine:Byte Ptr, refID:Int)
Local ent:TCoroutine = New TCoroutine
ent.coroutine = coroutine
ent.refID = refID
Return ent
EndFunction

EndType


Type TLuaManager
Field state:Byte Ptr
Field coroutines:TList = New TList
Field luaFile:String


Method Update()
DrawText coroutines.count() , 0,0

For Local c:TCoroutine = EachIn coroutines
If (lua_status(c.coroutine) = 1)
If Rand(100)=1
lua_resume(c.coroutine, 0)
EndIf
Else

lua_getfield(state, LUA_GLOBALSINDEX, "ThreadTable")
lua_pushnil(state)
lua_rawseti(state, -2, c.refID)
lua_pop(state, 1)  '; /* ThreadTable */


c.coroutine = Null
ListRemove(coroutines,c)

EndIf

Next

If KeyHit(key_d)
Print "global state: "
stackdump(state)
EndIf

If KeyDown(key_x)
closeLua()
initlua()
EndIf

EndMethod

Method initLua()
state = luaL_newstate()
luaL_openlibs(state)
luaFile = LoadText("coroutines.lua")

lua_pushstring(state ,"ThreadTable");
lua_pushvalue(state , LUA_GLOBALSINDEX);
   
     lua_settable(state ,LUA_GLOBALSINDEX);
EndMethod





Method startCoroutine()

Local thread:Byte Ptr
lua_getfield(state, LUA_GLOBALSINDEX, "ThreadTable")
thread = lua_newthread(state)
Local refID:Int = luaL_ref(state, -2);
lua_pop(state,1);

If luaL_dostring(thread, luaFile ) = 1 Then
Local err:String = "Error: "+lua_tostring(thread, -1)
stackDump(thread)

RuntimeError(err)
lua_pop(thread, 1)
lua_close(thread)
EndIf


lua_getglobal(thread , "main") 'Puts the function onto the stack


Local routine:TCoroutine = TCoroutine.Create(thread, refID)
coroutines.addlast(routine)

lua_resume(thread, 0)

EndMethod

Method closeLua()
If state
lua_close(state)
state = Null
Else
Throw("state was null already")
EndIf
EndMethod


Function stackDump(state:Byte Ptr Var)
Local str:String
Local top:Int = lua_gettop(state)
For Local i:Int = 1 To top
Local t:Int = lua_type(state, i)
Select t
Case LUA_TSTRING
str:+ lua_tostring(state, i)
Case LUA_TBOOLEAN
str:+ lua_toboolean(state, i)
Case LUA_TFUNCTION
str:+ "FUNCTION"
Case LUA_TNUMBER
str:+ lua_tonumber(state, i)
Case LUA_TNIL
str:+ "NIL"
Case LUA_TNONE
str:+ "NONE"
Case LUA_TLIGHTUSERDATA
str:+ "LIGHTUSERDATA"
Case LUA_TTABLE
str:+ "TABLE"
Case LUA_TUSERDATA
str:+ "USERDATA"
Case LUA_TTHREAD
str:+ "THREAD"

Default
str:+ lua_typename(state, i)

EndSelect
If i<top
str:+", "
EndIf
Next
Print "stack: "+str
EndFunction



EndType


in the initLua:
lua_pushstring(state ,"ThreadTable");
lua_pushvalue(state , LUA_GLOBALSINDEX);
lua_settable(state ,LUA_GLOBALSINDEX);

creates a global table,

in the startsCoroutine():
lua_getfield(state, LUA_GLOBALSINDEX, "ThreadTable")
thread = lua_newthread(state)
Local refID:Int = luaL_ref(state, -2);
lua_pop(state,1);

saves a refence of the thread in the global table.

in the Update():
lua_getfield(state, LUA_GLOBALSINDEX, "ThreadTable")
lua_pushnil(state)
lua_rawseti(state, -2, c.refID)
lua_pop(state, 1)  '; /* ThreadTable */

removes the refence from the table when it's not needed anymore.



pff I hope the reast is easy sailing
ps and on the plus side: this stuff above made me read and re-read the manual, documentation, and mailing lists. So the simpler stuff i've read about too            

« Last Edit: May 08, 2012, 10:07:11 AM by nikki » Logged
eigenbom
Level 10
*****



View Profile WWW
« Reply #10 on: May 07, 2012, 02:25:53 PM »

250,000 coroutines? woah, nice one ... Tongue
Logged

Ashaman73
Level 0
**



View Profile WWW
« Reply #11 on: May 07, 2012, 10:29:38 PM »

You normaly use some kind of timing to calcualte a time dependent delta value, no need of co-routines etc. when you prefer a clean game loop.

First off, start with a global time class/data whatever you use, here a simple framework in lua:
Code:
clock = { start_time=0, current_time=0}
start_game = function()
  -- get current time in ms
  clock.start_time = os.time()

  -- game loop
  local done = false
  while done==false  do
    -- update clock
    clock.current_time = os.time() - clock.start_time

    -- call your game loop
    ..

    -- need to set done to true to exit game loop
  end
end

Co-routines and multithreading is ok, on the other hand it is a really easy way to shoot yourself in the foot. Typical game entity has some kind of game update method (finit state machine or other for more advanced handling). A simple update mechanism can look like this:

Code:
act = {red = 100, last_update_time = nil}

init = function(act)
  act.last_update_time = clock.current_time
end

update = function (act)

  -- calcualte time delta in seconds
  local delta_time = (clock.current_time - act.last_update_time) / 1000

  -- update last update time
  act.last_update_time = clock.current_time

  -- move of your entity at a rate of 2 per second
  act.x = act.x + 2 * delta_time

  -- change color with a rate of 1 per second, stop at 0
  act.red = math.max(0, act.red - 1 * delta_time)

  -- note:
  -- you have floating point number now in act.x and act.red, to
  -- get some integer values use  'math.floor(act.x)'
end


Hope this helps.
Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic