Jump to content

All Activity

This stream auto-updates     

  1. Past hour
  2. Today
  3. reepblue

    Using Multiple Entity Scripts in Turbo Game Engine

    I'll probably never use the multiple return value feature and mostly stick with mono-scripting mostly However, it's really cool to have multiple script attachments for those cases in which multiple scripts would make sense. I rarely run into it, but it does happen. Overall the Lua implementation looks much better than it is in Leadwerks. Really stoked about using an entity as a table for other scripts to add, remove or manipulate. You made this much better, hopefully you can hit the same bar with the flowgraph/io system. 🙂
  4. This is the goal of having multiple scripts which is why some of us asked for it. I think the implementation is a little strange but we'll see how it works out.
  5. @Rick that is EXACTLY the kind of thing I want to avoid, and this system does a nice job of it! However, you could do put all of one script's values in a special table if you wanted: function Script:HurtEnemy(amount) if self.enemy == nil then return end local healthMgr = self.enemy.HealthManager if healthMgr == nil then return end if healthMgr.TakeDamage == nil then return end healthMgr:TakeDamage(amount); end Or even simpler, just add a prefix to the function name that is unlikely to be used by another script: function Script:HurtEnemy(amount) if self.enemy == nil then return end if self.enemy.HealthManager_TakeDamage == nil then return end self.enemy.HealthManager_TakeDamage(amount); end But the default behavior is just going to call all occurrences of the TakeDamage function like this: function Script:HurtEnemy(amount) if self.enemy == nil then return end if self.enemy.TakeDamage == nil then return end self.enemy.TakeDamage(amount); end I hope to see some really neat emergent behavior come from this system when two scripts work together that weren't written with the other in mind.
  6. I've waited a few years for this. Hooray! Why the change of heart? The implementation seems a little strange to me. I get you're trying to keep it simple and avoid having to prefix variables and methods with the script name but sometimes you may just really want to call one scripts function and not have all the ones with the same name called. I would rewrite your HurtEnemy() method like the below and then it's not that bad. This assumes GetScript() on an entity gets the instance of said script on that entity and that system is in place. This allows us to not have to type self.enemy as much and also reduces the indentation so it's easier to follow. function Script:HurtEnemy(amount) if self.enemy == nil then return end local healthMgr = self.enemy:GetScript("HealthManager") if healthMgr == nil then return end if healthMgr.TakeDamage == nil then return end healthMgr:TakeDamage(amount); end I don't see anything wrong with the above. It's short and to the point. It really only does 1 extra check that a script with that name is attached. To call multiple functions have some sort of self:CallMethods("TakeDamage", args)? This might not be bad anyway as it can do the check internally if it exists so we don't have to continually do that check each time we want to call a function that we think might exist.
  7. You will also get a set of very easy to use command to get and set values in Lua from C++. There are all part of the Entity class: void Entity::SetValue(const std::string& name, shared_ptr<Object> o); void Entity::SetValue(const std::string& name, const std::string& s); void Entity::SetValue(const std::string& name, const bool b); void Entity::SetValue(const std::string& name, const float f); std::string Entity::GetValueType(const std::string& name); std::string Entity::GetValueString(const std::string& name); bool Entity::GetValueBool(const std::string& name); float Entity::GetValueNumber(const std::string& name); shared_ptr<Object> Entity::GetValueObject(const std::string& name); An entity does not need to have any script attached to it to have values added, so you can use these to attach values to your entities even if you aren't using Lua!
  8. Yesterday
  9. During development of Leadwerks Game Engine, there was some debate on whether we should allow multiple scripts per entity or just associate a single script with an entity. My first iteration of the scripting system actually used multiple scripts, but after using it to develop the Darkness Awaits example I saw a lot of problems with this. Each script used a different classname to store its variables and functions in, so you ended up with code like this: function Script:HurtEnemy(amount) if self.enemy ~= nil then if self.enemy.healthmanager ~= nil then if type(self.enemy.healthmanager.TakeDamage)=="function" then self.enemy.healthmanager.TakeDamage(amount) end end end end I felt this hurt script interoperability because you had to have a bunch of prefixes like healthmanager, ammomanager, etc. I settled on using a single script, which I still feel was the better choice between these two options: function Script:HurtEnemy(amount) if self.enemy ~= nil then if type(self.enemy.TakeDamage)=="function" then self.enemy.TakeDamage(amount) end end end Scripting in Turbo Game Engine is a bit different. First of all, all values and functions are attached to the entity itself, so there is no "script" table. When you access the "self" variable in a script function you are using the entity object itself. Here is a simple script that makes an entity spin around its Y axis: function Entity:Update() self:Turn(0,0.1,0) end Through some magic that is only possible due to the extreme flexibility of Lua, I have managed to devise a system for multiple script attachments that makes sense. There is no "component" or "script" objects itself, adding a script to an entity just executes some code that attached values and functions to an entity. Adding a script to an entity can be done in C++ as follows: model->AttachScript("Scripts/Objects/spin.lua"); Or in Lua itself: model:AttachScript("Scripts/Objects/spin.lua"); Note there is no concept of "removing" a script, because a script just executes a bit of code that adds values and functions to the entity. Let's say we have two scripts named "makeHealth100 and "makeHealth75". MakeHealth100.lua Entity.health=100 MakeHealth75.lua Entity.health=75 Now if you were to run the code below, which attaches the two scripts, the health value would first be set to 100, and then the second script would set the same value to 75, resulting in the number 75 being printed out: model->AttachScript("Scripts/Objects/MakeHealth100.lua"); model->AttachScript("Scripts/Objects/MakeHealth75.lua"); Print(entity->GetNumber("health")); Simple enough, right? The key point here is that with multiple scripts, variables are shared between scripts. If one scripts sets a variable to a value that conflicts with another script, the two scripts won't work as expected. However, it also means that two scripts can easily share values to work together and create new functionality, like this health regeneration script that could be added to work with any other scripts that treat the value "health" as a number. HealthRegen.lua Entity.healthregendelay = 1000 function Entity:Start() self.healthregenupdatetime = CurrentTime() end function Entity:Update() if self.health > 0 then if CurrentTime() - self.healthregenupdatetime > self.healthregendelay then self.health = self.health + 1 self.health = Min(self.health,100) end end end What about functions? Won't adding a script to an entity overwrite any functions it already has attached to it? If I treated functions the same way, then each entity could only have one function for each name, and there would be very little point in having multiple scripts! That's why I implemented a special system that copies any added functions into an internal table. If two functions with the same name are declared in two different scripts, they will both be copied into an internal table and executed. For example, you can add both scripts below to an entity to make it both spin and make the color pulse: Spin.lua function Entity:Update() self:Turn(0,0.1,0) end Pulse.lua function Entity:Update() local i = Sin(CurrentTime()) * 0.5 + 0.5 self:SetColor(i,i,i) end When the engine calls the Update() function, both copies of the function will be called, in the order they were added. But wait, there's more. The engine will add each function into an internal table, but it also creates a dummy function that iterates through the table and executes each copy of the function. This means when you call functions in Lua, the same multi-execution feature will be available. Let's consider a theoretical bullet script that causes damage when the bullet collides with something: function Entity:Collision(entity,position,normal,speed) if type(entity.TakeDamage) == "function" then entity:TakeDamage(20) end end If you have two (or more) different TakeDamage functions on different scripts attached to that entity, all of them would get called, in order. What if a function returns a value, like below?: function Entity:Update() if self.target ~= nil then if self.target:GetHealth() <= 0 then self.target = nil --stop chasing if dead end end end If multiple functions are attached that return values, then all the return values are returned. To grab multiple returned values, you can set up multiple variables like this: function foo() return 1,2,3 end a, b, c = foo() print(a) --1 print(b) --2 print(c) --3 But a more practical usage would be to create a table from the returned values like so: function foo() return 1,2,3 end t = { foo() } print(t[1]) --1 print(t[2]) --2 print(t[3]) --3 How could this be used? Let's say you had a script that was used to visually debug AI scripts. It did this by checking to see what an entity's target enemy was, by calling a GetTarget() function, and then creating a sprite and aligning it to make a line going from the AI entity to its target it was attacking: function Entity:UpdateDisplay() local target = self:GetTarget() self.sprite = CreateSprite() local p1 = self.entity:GetPosition() local p2 = target:GetPosition() self.sprite:SetPosition((p1 + p2) * 0.5) self.sprite:AlignToVector(p2 - p1) self.sprite:SetSize(0.1,(p2-p1):Length()) end Now let's imagine we had a tank with a main gun as well as an anti-aircraft gun that would ward off attacks from above, like this beauty I found on Turbosquid: Let's imagine we have two different scripts we attach to the tank. One handles AI for driving and shooting the main turret, while the other just manages the little machine gun. Both the scripts have a GetTarget() function, as the tank may be attacking two different enemies at once. We can easily modify our AI debugging script to handle multiple returned values as follows: function Entity:UpdateDisplay() local targets = { self:GetTarget() } --all returned values get put into a table for n,target in ipairs(targets) do local sprite = CreateSprite() self.sprites.insert(sprite) local p1 = self.entity:GetPosition() local p2 = target:GetPosition() sprite:SetPosition((p1 + p2) * 0.5) sprite:AlignToVector(p2 - p1) sprite:SetSize(0.1,(p2-p1):Length()) end end However, any scripts that are not set up to account for multiple returned values from a function will simply use the first returned value, and proceed as normal. This system supports both easy mix and match behavior with multiple scripts, but keeps the script code simple and easy to use. Scripts have easy interoperability by default, but if you want to make your function and variable names unique to the script it is easy to do so. Let me know if you have any other ideas for scripting in Turbo Game Engine.
  10. I just realized that with this system, any object could have a script attached to it now and it would work just fine.
  11. catch22

    What the Heck is Josh Doing?

    Take a look at Oregon, Josh. Not like Portland, I mean like the rest of the state. It's still fairly rural, and much more conservative in terms of laws and liberties. The festering wounds of WA and CA haven't crept in entirely yet. Or maybe Idaho.
  12. Wafflesoft

    Upload bug

    Thank you soo much guys. Absolute legends. Using this system of compressing sub-folders works perfectly. Now when I make a small change to the game it will only upload a few mb. Also using this system greatly reduces the upload time to steam after the initial build is uploaded.
  13. Wafflesoft

    Upload bug

    Thanks heaps mate this was actually very simple. I simply had to add my text for password to one line of code and then zip everything up myself. I will let you know how it goes with the uploads. Uploading to steam takes a really long time.
  14. Josh

    Loading from the encrypted data file

    It is very weird when I search for something and find myself asking the same question years ago: https://www.gamedev.net/forums/topic/603062-minizip-encrypted-file-passwords/
  15. Josh

    Loading from the encrypted data file

    I do not know. It uses a crc table that is 256 elements in length to check if the password is valid.
  16. gamecreator

    Upload bug

    Sure, the specific function usage is here: https://www.leadwerks.com/community/topic/17491-loading-from-the-encrypted-data-file/?do=findComment&amp;comment=113622 Some more code here: https://www.leadwerks.com/community/topic/16566-reading-a-text-file-from-a-package/ And you can find another thread or two if you just search the forums for the word password.
  17. Wafflesoft

    Upload bug

    Do you possibly have a link? Using search gives me alot of stuff to filter through.
  18. gamecreator

    Upload bug

    You can zip and password protect files yourself then open them via code. Code is available on the forums.
  19. Wafflesoft

    Upload bug

    So I tried this and it worked great for fixing the patch sizes. But doing this way offers like no file protection. Steam say they encrypt files. But I can't see any evidence of that. Is there a way to keep my file protection and fix the patch sizes? So I had a look into how other games on other engines do it. And I think I came up with a middle ground that would work. But I'm not sure if its possible to do on my end. So I noticed other games create package files. These act almost exactly the same way as the data zip file created when I use the publish standalone feature in leadwerks. What I would like to do if possible is configure the leadwerks publish feature so that instead of creating a single encrypted zip file for all files in the project. It creates one for each of the sub folders in the main folder. For example, (My project Folder is called Waffles) configure it so that it creates a zip for; Addons folder, Prefabs, Scripts and so on and so forth until it has everything contained in a subfolder in an encrypted/compressed zip of the same name. That way when patching; Steam says that it can't scan any folder that is encrypted or compressed. But it should only replace the ones that have changed in size. Because it replaces folders and files that have changed in size. Is this possible? And would it even work?
  20. I think they must have made a D3D port for that.
  21. Rick

    Map exploration how to

    Populating big islands is tough and if it's not populated then it'll be a walking simulator. For dev reasons it might be best to have smaller islands so multiple people can work on some maps since only 1 person can work on an LE map at a time.
  22. Last week
  23. Thirsty Panther

    Island/Character size

    Like these ones. Goes with our fantasy/SciFi vibe.
  24. Thirsty Panther

    Map exploration how to

    I think we need to keep the number of levels low. Better to have 4 or 5 great islands than 20 boring ones. A straight progression from 1 - 2 - 3 -4. Keep it simply make it great.
  25. I'm just making some notes here. This is how to open VSCode with a specific file and line: And to also open a folder: To add a specific character in the line:
  26. gamecreator

    Map exploration how to

    Depends on how many levels/islands we end up creating. I don't think a hub makes sense for just 3 or 4 levels but it's good for 10+ or so.
  27. Slastraf

    Map exploration how to

    first and last interwire Imo. And also the second one
  28. How we advance from island to island
  29. Fantasy, magic, islands in sky was already choosen. Choose fantasy world setting and enemy types so we can start modeling I gathered what was discussed in forums so far. If i miss something post here.
  1. Load more activity
×