Jump to content

global lua variable


Rick
 Share

Recommended Posts

So from what I know if you just make a variable and assign it a value it'll be global unless you put local in front of it. So in the fpscontroller.lua file (which seems to be the file that gets played when you run game from the editor) I make a variable and set it to true:

 

runGame = true

 

Then for the main game loop I do:

 

while runGame do

...

end

 

Then I load the monster truck entity just to test this out. I just need an entity to have it's Update() method called each frame. I make a small change inside the Update() method of the monster truck:

 

function Update(model)
local model
local entity
for model,entity in pairs(entitytable) do
	entity:UpdateTires()
end

if KeyHit(KEY_ESCAPE) == 1 then
	runGame = false
end
end

 

But when I press ESCAPE, the game doesn't end. What gives?

Link to comment
Share on other sites

Is KEY_ESCAPE defined anywhere?

 

 

I include base.lua which includes engine_const.lua which defines KEY_ESCAPE. I also tried the actual number instead of KEY_ESCAPE but that didn't work.

 

I'd love to see if my Update() method is actually getting called. What would you recommend I do to see this. Normally I would use lua's print() but that doesn't seem to do anything.

 

[EDIT]

OK, using AppLog() I see it's getting inside the KeyHit(). So it must be setting runGame to false, but that's not being seen in the main game loop inside fpscontroller.lua.

Link to comment
Share on other sites

Each model class uses its own Lua state. This allows one script to be edited at a time, but interstate communication is a little more difficult. You can use SetGlobalNumber() to communicate in this situation.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Is there something like this for lua tables also? If not, then could there be because this seems like kind of a big limitation.

 

For my coroutine system it needs to have global tables. I want this to be a "model" that users can just drag into their Sandbox scene and use instead of code files that they have to put into their custom main loop lua file. The "model" lua script would house the tables and the Update() method to run checks on entries in these tables. Another script would provide the methods to use like:

 

DoWait()

 

DoWait() would need access to these global tables to add entries.

Link to comment
Share on other sites

So I assume giving all these scripts the same lua state isn't going to ever happen for the editor? Just wondering where this stands so I can try to figure out the best way to handle this. The best way that I see is to use the same state for all of these, but that would be up to you for the editor.

Link to comment
Share on other sites

SetGlobalNumber() sets a value in the engine. GetGlobalNumber() retrieves it.

 

I don't have any plans to change the way the states are set up. It would require all the scripts to have their functions renamed like "light_directional_Update()" and who knows how else the scripts would interfere with one another.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

OK, that really hurts the logical entities idea.

 

Calling the community: How can we share variables between all entity scripts? Put on your thinking hats because you'll most likely run into a situation where you'll need this when making a game. I have a hard time believing a full game can be created without it.

Link to comment
Share on other sites

You can use GetTarget(0) to get a target entity from another, and set a EntityKey in the target entity.

I guess you could also use SendEntityMessage to send a message to the target, but that needs probably a bit more coding.

Ryzen 9 RX 6800M ■ 16GB XF8 Windows 11 ■
Ultra ■ LE 2.53DWS 5.6  Reaper ■ C/C++ C# ■ Fortran 2008 ■ Story ■
■ Homepage: https://canardia.com ■

Link to comment
Share on other sites

Sure. This all revolves around my coroutine entity that I'm creating. So the thought process goes like this:

 

1. Create an entity that is like a light in that in the editor it has properties and has an Update() method that gets called each cycle but this entity isn't shown. It has no visual to it. It's just logical.

 

2. Ideally this entity would create some global tables. These tables are iterated through in it's Update() method. So far so good.

 

3. There is another .lua file that people include in their scripts. This file defines functions like RunScript(func) & DoWait(cr, interval). The DoWait() method adds entries to the global tables that the coroutine entity created when it was placed into the scene. So this is where the table would need to be global.

 

Imagine you create a volume trigger. In the Collision() function you want to run a sequence of events. To make it simple let's say when the player collides with this trigger you want to wait 5 seconds and then end the game. In this volume trigger script you would include (dofile) this coroutine.lua file. This would give you access to the DoWait() function. To simplify in the volume trigger script you write a function that is your sequence of events. Then in the Collision() method you call RunScript() (also available because of coroutine.lua including) passing in your function to run. Inside RunScript() is where you first call DoWait(5000), then set some flag to kill the program.

 

 

 

Here is some pseudo code of what I'm trying to get done:

 

 

coroutine_coroutine.lua --- This is the entity you add in sandbox

function Spawn()
  tblWait = {} -- Creates a global table
end

function Update()
  -- loop through tblWait looking to see if entries have their time up so we can resume the function
  for k, v in pairs(tblWait) do

  end
end

 

cr.lua -- gives access to some functions

function DoWait(cr, interval)
  -- Create a timer of sorts that last for interval time and add it to tblWait global table

  coroutine.yield()  -- this actually yields the function they are in. Looping through the tblWait let's us know when a time is up to resume
end

function RunScript(func)
  cr = coroutine.create(func)

  coroutine.resume(cr, cr) -- starts the function they passed in passing to it the coroutine created for it
end

 

trigger_volume.lua -- example of how a trigger volume would work

function Spawn()
end

function Collisions(...)
  RunScript(MyScript) -- starts the script sequence
end

function MyScript(cr)
  DoWait(5000)
  endGame = true
end

Link to comment
Share on other sites

1. Create an entity called "func_endgame".

 

2. When the player hits the trigger volume, send a message with a 5 second delay to the func_endgame entity.

 

3. When the func_endgame entity receives a message called "activate", it calls SetGlobalNumber("gameover",1).

 

4. Your main loop has this code:

if GetGlobalNumber("gameover")==1 then

return

end

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

How can we share variables between all entity scripts?

If you put each entity in a separate Lua thread (bear in mind that I am only talking about having one actual Lua state) and then give that thread a separate environment while still retaining access to the globals table (fairly easy to do with metatables), then you should have the same effect without the wasted memory use, need for things like "SetGlobal*", etc. I don't think it's likely that you'll be able to do this without writing your own code to handle entities in Lua, however.

  • Upvote 1

MacBook Pro 15.4", Intel Core 2 Duo T9600 2.80GHz, 4GB 1066MHz DDR3, GeForce 9400M 256MB, GeForce 9600M GT 512MB - Mac OS 10.6.2, Vista32

Link to comment
Share on other sites

1. Create an entity called "func_endgame".

 

2. When the player hits the trigger volume, send a message with a 5 second delay to the func_endgame entity.

 

3. When the func_endgame entity receives a message called "activate", it calls SetGlobalNumber("gameover",1).

 

4. Your main loop has this code:

if GetGlobalNumber("gameover")==1 then

return

end

 

 

You are missing the point. The point wasn't to end the game. That was just an example. The point was to provide the functionality of DoWait() to the engine. And DoWait() is just the start. DoSound(), DoMove() will all act similar but their conditions to start the function back up will be when the sound is finished playing, and when the entity has reached a destiation. So a message delay isn't enough in these situations.

Link to comment
Share on other sites

You are missing the point. The point wasn't to end the game. That was just an example. The point was to provide the functionality of DoWait() to the engine. And DoWait() is just the start. DoSound(), DoMove() will all act similar but their conditions to start the function back up will be when the sound is finished playing, and when the entity has reached a destiation. So a message delay isn't enough in these situations.

 

 

Your example and my example do the same thing but they do them very differently. That difference is the key because when the examples get more complex my example will work. Think of stepping out of the function completely only to return at another time.

 

-- This is the coroutine way
function MyScript()
  DoWait(5000)
  i = 5
  DoWait(10000)
  i = 10
end

-- This is the way you are talkinga bout
function YourScript()
  SendMessage(x, y, z)
  i = 5
  SendMessage(x, y, z)
  i = 10
end

 

Let's imagine stepping through these functions. In YourScript() we would step right through it. First SendMessage(), then i = 5, then SendMessage() again. Stepping through YourScript() would take about a second and it would be finished. Stepping through my script would take 15 seconds minimum. Because when we hit the DoWait() function it actually leaves MyScript() and comes back into it 5 seconds later. So if we stepped through it when we ran the DoWait() function it would actually go back to whatever called MyScript() and continue on with the engine loop. This is where the global tables come in. DoWait() added an entry to this global table that says MyScript() is to run again in 5 seconds. Then that global table is iterated over inside the Update() of the coroutine model class to see if 5 seconds has past. Once it has, we call the function again, but because it was setup as a coroutine it will start up where it left off. So if we were stepping through the function it would come to the i = 5.

 

So you see in my example i will = 5 for 10 seconds, but in your example i will = 5 for about a millisecond because it'll just continue on to SendMessage() which just continues.

 

So you can think of DoWait() as blocking to the function it's in, but not to what called it.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...