Jump to content

AggrorJorn

Members
  • Posts

    4,816
  • Joined

  • Last visited

Blog Comments posted by AggrorJorn

  1. Quote

    However, it is more typing than just quickly writing a line of Lua code.

    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.

    156376771_leadwerksvscodeextension3.gif.d23fc18bcc49f3c66d1e58ce61dcbd4a.gif

     

    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?

  2. @Josh 

    1. 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.
    2. 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.
    3. 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)
  3. 2 hours ago, Rick said:

    In practice I don't think you will get this smooth interaction. If you look at the examples in this blog you'll see that 3 different people named a function with similar functionality differently. ReduceHealth()/TakeDamage()/HurtEnemy(). The chances that different programmers all name their functions the same in order to add different functionality is pretty slim. There will just be little cohesion to make this act as the bridge for adding different scripts from different programmers who weren't working together.

    I think you'd be better off using an event system to get what you want so things are more explicit. Define an event in one master script on the entity and in it's Start() get references to all the scripts attached and add their Reset() methods to the event. Then raise the event and it'll chain call all those methods. While for your specific case it may seem like more work, for a more generic case, like our games, it gives more flexibility in chaining functions with different names by raising 1 event, it gives explicit intent which makes debugging easier, and it makes it so the community isn't trying to come up with consistent naming conventions which will never happen.

    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.

    • Like 1
  4. 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.

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

    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.

     

    9 hours ago, Rick said:

    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.

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

     

    8 hours ago, reepblue said:

    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.

    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.

     

    5 hours ago, Josh said:

    Do you guys have any ideas for changes or things you would like to see in the flowgraph system?

    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.
      • Image result for flow editor game visual
    • 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
        • 1401584236_Levellayer.jpg.311ccee461d06b059f4a3e38ffdc1153.jpg
        • 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.
          • 1315515817_Objectsublayer.jpg.28084323cbae997c7edec6ee04b92389.jpg
    • Upvote 2

    What Makes a Good Brand Name?

    On 6/8/2018 at 10:15 PM, EdzUp(GD) said:

    I would have something like "Lightning game engine" or "Shock game engine".

    Lightning engine sounds really good to be honest. Fast as lightning, 

    16 hours ago, macklebee said:

    Honestly, the more I say it out loud and look at this- I agree with cangojoe initial response. 'Turbo' seems dated and maybe since I'm old I can remember the 80's where everything had turbo as its name or feature to the point that it really meant nothing. It's like the 90's version concerning the usage of the word 'EXTREME'. Or maybe thats your plan. Version1 is turbo, version2 is super turbo, version3 is extreme turbo... ? Dunno. I think its a shame you are abandoning a brandname with recognition and reputation because some person might not be able to pronounce it correctly the first time they come across it in print. I just hope your idea here doesn't turn into New Coke ™️

    Edit -- Not trying to be rude here, just upfront and honest with you. You seem to get a lot of fanboyish, yes-men feedback here. But if memory serves, some of the people I see posting here about how much they like this name are some of the same people that encouraged you to make LE3 initially for mobile.

    It is is good of you to give your opinion macklebee, that is what is needed to make it better. I agree that giving up Leadwerks as a brandname is a bit of a shame. Purely changing the name for pronunciation sake would not be my main reason though. I see it more as a fresh start. I have been pronouncing Leadwerks like 'leedworks' in my first year with Leadwerks. A message from Annika changed that when she corrected me on it. I think the name change to something shorter and using a more universal existing word was the right thing to do. However, I do see your point on the word 'Turbo' being an 'outdated' word. Like CangoJoe, the first thing that came to mind when reading the word 'Turbo', was Far cry blood dragon with its neon style. Since Josh has trademarked the engine and bought an expensive domain name, I just don't think it is going to change. 

  6. This is so cool looking. I remember this presentation of a game developer on college where a similar technique was used for the game Delta Force.  How terrible is the performance when doing this on the goblin? Have you ever thought about using a technique like this for the terrain? No idea if it is a valid technology, but terminology like voxels often make it to the screen when the terrain topic.

  7. Because the description was written in array form I need to use comma's to specify a new line. The extension somehow included that comma. I can solve this by just cramming everything on 1 line. It is not that people would read that document anyway. Why the ' Leadwerks' is inserted is not clear to me yet. It is not comming from the code and does also not appear in the snippet file. Vs code is adding it for some reason.

    Pushed a new build that fixes the comma.

×
×
  • Create New...