Jump to content

AggrorJorn

Members
  • Posts

    4,816
  • Joined

  • Last visited

Everything posted by AggrorJorn

  1. I'd say try it out in the editor. Attach a material that points to a an alpha map. I haven't tried it in a while (10 years old already pfff):
  2. When you play the game via the editor, your game starts with the currently opened map in the editor. When you publish a game, the main.lua file opens the map specified with Map:Load("Maps/start.map") If left unchanged this will be start.map which is the scene with the 2 boxes.
  3. The second time you require('mymodule'), it sees that the variable 'module' already exists and will not create a new object for you. Meaning that variable2 is referencing to the same as variable1. I think I posted the same answer in discord a while back. --my module mymodule = {} function mymodule:Create() local o = {} o.someValue = "1" function o:SetValue(value) o.someValue = value end return o end usage: import "path to mymodule" local variable1 = mymodule:Create() variable1.SetValue("test1") local variable2 = require("mymodule") variable2.SetValue("test2") System:Print(variable1.v) System:Print(variable2.v)
  4. This has been brought up before, but I really think the technical forum doesn't add anything to the community forum. Its answer-based style like how stackoverflow does it, simply wont work here because the rest of the forum is reply/conversation-based. Accepting a post as an answer is nice to have, but right now it is just another confusing category that fills up space. Just my 2 cents.
  5. AggrorJorn

    Fun with JSON

    That is what Visual studio code snippets are for. Just type vec3prop or something, press tab and you get a snippet with common options. You can even tab through the parts of the property. And JSON for file format sounds great. Having a filesystem that can be merged by any versioning protocol is great to have. In the past you mentioned this would get make a bad design choice because of the file size. Is this no longer that relevant or are there good solutions to work around that?
  6. AggrorJorn

    Plugins Expanded

    @Josh Do you think you will use the plugin system like a nuget store for several core Turbo functions? It would make the editor easier to update without constantly building the entire editor. I do not entirely see the advantage of separating the menu logic from the importing logic. Lets say I make a C++ lib that works both in-game and in-editor, I would want to load it in via your second, but also make the menu options. How many projects are you working on right now? Don't overwork yourself. I find the process_event callback rather cluttering up the code. How about setting a callback for a click event? function Plugin:Load() local menu = Editor.modelEditor.menu:FindMenu("Plugins") if menu ~= nil then self.menuitem = menu:AddItem("Flip Normals") --syntax: self.menuitem.SetMenuClickEvent(callback, extraParams = {})) self.menuitem:SetMenuClickEvent( self:FlipNormals(Editor.modelEditor.model), {forceModelEditorRedraw = true, someOtherValue = 0.3} ) end end function Plugin:FlipNormals(event, params, model) if Editor.modelEditor.model ~= nil then --code: Flip normals of model if params.forceModelEditorRedraw then Editor.modelEditor:Redraw() end end end Rather than relying on this long if chain in processEvent, you set the callback for the events you really need like. MenuClick ViewPanelLeftClick ViewPanelRightClick SceneTreeChanged TransformMoved (triggered when object in scene is moved) RotateEvent (triggered when object in scene is rotated)
  7. Haven't tried it, but can't you just set an empty text?
  8. hehe, starting to have a déja vu again. I think for the past 5 years there has always been a topic each year mentioning the 'similar named' functions like "Kill", "Hurt" as well as using events. I don't see an event system happening for Turbo either unfortunately.
  9. I see your point Josh and the advantages to this method are plentiful based on your examples alone. It is an interesting idea with lots of flexibility. Maybe this is just me, but I see the level of flexibility as an increase to the complexity of the game. New users will lose track of what functions are attached to an entity. I am not trying to shoot down your ideas here btw, I am just trying to see if the advantage way up to possible disadvantages. For instance, I wonder how this works in practice when you are debugging an enemy hat has 8 different scripts applied that all have the Kill() function. With this method it seems that infinite recursion and stack overflow exceptions are constantly lurking around the corner here. If I have a bug and start debugging I would expect some sort of ListAllFunctions() that gives you an overview of all execution ordered function (duplicates) on an entity. As long as you can properly see the stack trace and easily verify which Kill() function has already been called you can can away with it. Either way, the concept of attaching these scripts is interesting and the discussion about it as well. Keep on improving and blogging.
  10. This is to this day how I would have liked the lua scripts to have worked in Leadwerks. Albeit slightly differently scripted. The example you give really describes the problem with singular scripts. The player script has no business seeking out a healthmanager subscript that should be managed by the enemy. It is the enemy's script responsibility to expose any of its subcomponents to the outside world. Personally I never check if something is a function either. By convention variables are lowercase and function are not. In this case the player only check if it has enemy and that gives it damage. --player function Script:HurtEnemy(amount) if self.enemy ~= nil then self.enemy:ApplyDamage(amount) end end The enemy has a reference to the health manager which it retrieves in the start function. If it is not there, the game should simply report an error since something is wrong in your setup. Lastly, the enemy script passes the damage value on to the right component(s). In this case only the healthmanager. Ideally you would set this up by events. --enemy script function Script:Start() self.healthManager = self:GetScript("healthManager") if (self.healthManager == nil) error("Enemy has no healthmanager. Something is wrong in your setup.") end function Script:ApplyDamage(amount) self.healthmanager:ReduceHealth(amount) end The health manager finally actually does something with it. The amount variable should only be changed by the healthmanager itself and not by other scripts. --healthmanager function Script:ReduceHealth(amount) self.amount = self.amount - amount end Now you have the logical separated scripts that are far easier to maintain due to small amount of code lines, the absence of constant nil checks and by keeping responsibility to the component and its owners. This would be my choice too Rick. Maybe that is because this is far more similar to how Unity does it with GetComponent<> or Godot with get_node. I think what plays along here is that Josh really likes to implement his own methods rather than just 'copying' the same methods others use. Both systems work, and Lua is awesome in this kind of flexibility. @Josh: have you considered using a GetComponent feature? People using other engines will recognize this function and find it perhaps an argument as too why they could potentially switch. A future documentation page I would recommend: Switching from Unity to Turbo/Leadwerks. "If you are used to using GetComponent<>(), with Leadwerks you are just as easy on your way with GetComponent(YourScript)." From the day I learned that this was possible I never even considered using multiple return values. Not that is not powerful, but merely the complexity this suddenly adds, stops me from using it. This already happens when you have a function that can have any number of arguments. If you don't deal with all these arguments you will eventually kick yourself in the knee. Especially if you program in a team, you expect that a user does something with the given values or you would need to have strict guidelines in how to deal with them. Thought you would never ask. Lets start with some basics: Zooming in and out of a current layer. Flowgraph works by creating scene level graphs and prefab/model based graphs. Level based Layers: When working with FPS levels (like the elevator demo), you want to add level logic for a certain area in a layer. eg: Starting area layer Elevator room area layer Panels These are more UI containers for your 'graph nodes' to attach to. Naming or colouring the panels is a nice addition. Improved input types: curve property material selector More advanced: Nested flows/ Object flows. Nested flows are excellent for reuseablity. Nested flows are fixed flows per entity/prefab. This means a flow is always similar regardless of what level you are playing. Example Lets say you have to 3 script in a flow: CollisionTrigger, timertrigger and EnemyTurret. The CollisionTrigger.OnCollision can activate the Turret The TimerTrigger.OnCollision can also activate the Turret after a given time Double click on the EnemyTurret opens the subflow of this turret. This flow is on an object level instead of scene level. The subflow always has its parent entry arguments coming in The subflow always has its parent exit arguments going out. This subflow produces a rocket that can again also be double clicked since it is an object flow.
  11. When you say cutscene, do you mean playing a video/animated gif or an ingame animation/camera path?
  12. Congrats Josh. As stated before in your blogs: unlike the mobile direction, VR is actually bringing back the power to the engine. So leadwerks 5 will contain the Turbo changes, minus the new editor. Do you think you will expand your team, now that you have a contract?
  13. That looks interesting. What a cool concept.
  14. When you shoot you perform a pick. If it is an enemy the Hurt function is called right? Pass along the pick position with this hurt function. Inside the hurt function, you need to have a reference to this box. You can do this by creating entity properties, or by looping over the entities children until you find the name of your headshot box. (note that when you loop, the pivot might not have been called yet and the box could possibly not exist.)
  15. Can you show a screen of your enemy in the scene tree? When the pick takes place, you get back the entity it picks. Since this is the enemy with (I assume) the AI script, you call its Hurt() function. You can pass along the hitposition with that function. In the hurt function you start looking for bones or boxes that represent body parts like the head. It would be even better if the references to the boxes are there before the Hurt function is called. Enemey (AI script) BodyHead BodyLeftArm etc
  16. A cheap way to determine if it is a headshot is by creating a box that covers the head. When you do a succesful pick on the enemy, you get an entity and a pick position back. The entity (enemy) should have a reference to the headBox. Now simply check if the picked position is in the bounds of the entities headbox. Another basic way is iterating over the enemies bones and see which one is the closest. If the bone has the name 'head' (or whatever it is called), you register it as a headshot. This might give some false positives in some situations depending on the bone structure.
  17. Put them in a separate lua file and the in main.lua use import "myscript.lua"
  18. That looks pretty good too.
  19. A second way is to draw a texture that represent 1 % of a filled healthbar. Then use @macklebee rotate image shader for every percentage of health, you draw the image with a given rotation. A third way is having a spreadsheet with all the possible health statusses and draw the one that matches your percentage.
  20. I think the best way would be an image of a circle and a custom shader which cuts away part of the circle based on the angle you specify. Maybe someone has posted a shader for this on the forum.
  21. You are drawing 4000 rectangles every frame.
  22. I recall that when you import a file a second time, it is ignored since you have already loaded that file. This is stored internally in a cache somewhere.
  23. No need to go with C++ as you can do the same things with just writing to a file using the build in leadwerks commands. Alternatively you can load in a lua to json library to make things a little easier. This one for instance: https://github.com/rxi/json.lua Remember to turn of sandbox lua in the editor settings. As for the scripts you are using, you can try altering the code so that it doesn't just use the entities name as a key, but also adds a pre/postfix. So if you have 2 oilbarrels, they would be saved as oilbarrel_1, oilbarrel_2. When loading the data, you can remove the _1 etc from the name again.
×
×
  • Create New...