Jump to content

Rick

Members
  • Posts

    7,936
  • Joined

  • Last visited

Posts posted by Rick

  1. I think a GetEntity(name) function would be very helpful. With each model class script kind of being on an island (since they all use their own lua states) a way to get any loaded entity from anywhere could be beneficial. This should be possible if GetEntity(name) is a C function that is exposed to lua from the executable. In the executable every entity is available so it should be that hard to give all scripts access to any entity. The name parameter would be a key setting called "Name". So if I add a model to my scene and set the name property to "Rick" I should be able to access that entity in a different model class lua file by calling:

     

    GetEntity("Rick")

     

    I know Targets() can be used for this, but setting all sorts of targets for all different kinds of interactions gets cumbersome and error prone. Would be better to just be able to call 1 function to get the entity. I would think this would be an easy feature to add and give a ton of help to us.

  2. 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.

  3. Every entity does not have its own state. Every model class has its own state, which means all instances of any model share a state and can access everything about each other.

     

    For communication between different kinds of models, I recommend the messaging system.

     

     

    I think you are going to find that the messaging system doesn't handle every situation. Sometimes entity communication with each other needs to be more advanced than just sending messages to each other.

  4. 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.

  5. Well honestly I'm ok with lua, but lua with LE is a little different. With each entity being it's own lua state, it complicates sharing data between entities. There are some design things that are different and don't have anything to do with just knowing lua but instead how Josh exposed LE to lua and how he's using it.

  6. 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
    

  7. 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.

  8. Trying to check for key inputs in lua but struggling.

     

    I tried :

    if KeyDown(KEY_SPACE)==1 then                        
    	model1body:AddForce(Vec3(0,0,100))	
    end

     

    Which didnt work, so i then tried :

    if KeyDown(KEY_SPACE)==1 then                        
    	AppTerminate=1	
    end

     

    Which also does nothing....

     

    thanks

    Andy

     

     

    Are you including dofile('\Scripts\base.lua') to your script at the top? I think it's required for the key constants.

     

    Try KeyHit() also. Just to make sure. Also put an AppLog() inside your if statement and check your engine log to make sure it's getting inside there.

  9. 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.

  10. I don't know how that would be done.

     

     

    How is SetGlobalNumber() working currently? I would imagine you would have to loop through all the lua states you have and set a variable for each one and give it the value.

  11. My guess would be that the propeller code is adding torque to the plane as well. This is my confusion around what is stored in entitytable and how to find the entity you want when looping over it. From my understanding entitytable holds all entities loaded. So this would mean your plane and propellers are in this table. If that's the case it would be adding torque to both, which is what you are seeing.

     

    Other possible things:

     

    You have 2 model variables. The param coming in is named model also, so there might be confusion there. Is the parameter to UpdatePhysics() the model or the world? I know Update() passes in the world but one of the scripts I saw named it model, which Josh said was a bad variable name because it should have been world.

  12. I tried to add a propeller to the rear of the airplane, but no matter how I joint it, it always rotates the airplane too, when I turn the propeller (model is the airplane, target is the propeller), and I try to turn the target around its Z axis:

    CreateJointHinge(model,target,Vec3(-1,0,-1.67),Vec3(0,0,-1.67))

    A similar code works fine in C++, and I can turn the target around its Y axis:

    CreateJointHinge(model,target,Vec3(-1,3,0),Vec3(0,3,0))

    Btw, a documentation how joints should be used would be also nice, so far I've been only guessing :D

     

    Can you show the complete lua code.

  13. Ah, that was it!

    It doesn't really matter in which order the 2 models are spawned, since both need to be loaded first.

    I need to make a delayed initialize, so around 5 seconds after the scene is loaded, I need to call my custom Initialize() function for all models:

    function Initialize()
    for model,entity in pairs(entitytable) do
    	local target = model:GetTarget(0)
    	if target~=nil then
    		AppLog("TARGET 0 FOUND")
    	end
    end
    end

    I don't know if there is somekind of function which would inform me that all models are loaded, or do I really have to wait for a random amount of time before I can call this Initialize for all models.

     

    Actually I have one idea how to make this automatic: I could create a SceneReady model, which I manually place at the end of the sbx file, and it would have an script which sets a global flag that now the whole scene is loaded. Then the UpdatePhysics() function of each Model checks for that flag, and calls the Initialize() function once.

     

    Or I could have a frame counter, which is raised by 1 each time the UpdateWorld() is called. The FrameCounter would be a model too, and only if it has the value 2, then the Initialize function would be called from each Model's UpdatePhysics() function.

     

     

    Couldn't you make a boolean flag in the spawn and set it to false. Then in your Update() check if the flag is false and if so run an init function and then set it to true. It'll make this check each call to Update() but that wouldn't cause any significant performance hit. The though being that when Update() is called everything should be loaded by that point.

  14. Would that return the actual entity/model or just the name of it? If it returns the entity/model then it's possible that it hasn't been spawned yet. This is something I notice we have to be careful about in the Spawn() function. We really can't be guaranteed any other entities are loaded at that point.

     

    It would be nice if our entities had a method that is called once after everything has been loaded. Because we may wish to store references to other entities in an entity. Currently to do that we'd have to create some sort of loaded flag and check it/set it in the entities Update() method.

  15. 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.

  16. Global variables are bound to a lua state, not a specific script. So they should keep their values if you keep reusing the lua state.

     

    Is this what's happening the in editor? I assume only one lua_State* is being used to call all these scripts?

  17. 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.

  18. 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?

×
×
  • Create New...