Jump to content

Josh

Staff
  • Posts

    24,629
  • Joined

  • Last visited

Everything posted by Josh

  1. Josh

    LE3 Lua

    I do not like the idea of per-entity values, because the next step is another interface for editing entity-level values, and the next step after that is per-entity scripts!
  2. Josh

    LE3 Lua

    I would do this by dragging lines in the flowgraph editor from a "CollisionTrigger" script attached to the volume, to the following inputs: Entity-Script-Function Light-HideShow-Show() Light-AmbientSound-Play() Emitter-EmitterControl-Resume() The trigger script would looks something like this: function CollisionTrigger:Collision(entity,normal,speed) if entity.components.Player then self:CallOutputs("Trigger") end end What I do not like about this is you can't set a per-entity value like "CausesTrigger" to the player entity. Everything has to be written with the expectation of certain other classes. If someone wants to add a "MySuperPlayer" class in, it doesn't work with existing scripts that weren't written to accommodate it.
  3. Josh

    LE3 Lua

    It works right now. On the C++ side, it looks like this (not that you have to actually deal with this): Entity* box = Model::Box(); Component* component = box->AddComponent("Scripts/MyComponent.lua");
  4. Josh

    LE3 Lua

    Here's how a multiple script approach could work. This treats scripts as "components" and each entity can only have a component of one class: MyComponent.target=nil--Entity MyComponent.newtarget=nil--Entity --This function gets called when the component is attached to the entity function MyComponent:Attach() --We're going to find the component "MyComponent" on our own entity and call a function with it. --This can be used to find other components on the entity, not just our own. self.entity.components.MyComponent:MyFunc() --Of course normally to call a component's own functions you just do this: self:MyFunc() end function MyComponent:MyFunc() System:Notify("I can't believe it worked.") end
  5. Josh

    LE3 Lua

    Since "script" is not very accurate, and "component" is long and abstract, I am using the script name as a "class": LookAt.target=nil--Entity LookAt.lookspeed=1--float function LookAt:Update() if self.target then self.entity:Point(self.target,2,self.lookspeed*Time:GetSpeed()) end end
  6. Josh

    LE3 Lua

    I'm totally fine with text linking but I think flowgraphs will strike a decisive blow at the heart of the unity beast.
  7. Josh

    LE3 Lua

    Thanks for your input. With this script, you can specify the function to call in the editor. It reminds me of the input/output system in HL2: script.target=nil--Entity script.key=Key.Space--keycode script.functionname="Activate"--choiceedit "Enable","Disable","Activate","Open","Close","ToggleEnabled","ToggleActive" function script:KeyDown(keycode) if keycode==self.key then if self.target then if self.target.script[self.functionname] then self.target.script[self.functionname](self.target.script) end end end end
  8. Josh

    LE3 Lua

    I have renamed the "SwitchTarget" script to "ToggleTarget". I added a KeyDown script function. This entity is now linked to the space key. When the space key is pressed, the ToggleTarget() function is called. script.target=nil--Entity script.newtarget=nil--Entity function script:ToggleTarget() local temp = self.target.script.target self.target.script.target=self.newtarget self.newtarget=temp end function script:KeyDown(keycode) if keycode==Key.Space then self:ToggleTarget() end end I have a chain of about five entities linked together now so that when I hit a key, they react. The flexibility of Lua works really well here. I'm not even sure a flowgraph mode is needed if you can assign entities in the editor. I'll keep playing around with this.
  9. Josh

    LE3 Lua

    Here's an example of a single script that looks at an entity. The "target" value is an entity that you drag onto script properties in the editor: script.target=nil--Entity script.lookspeed=0.1--float function script:Update() self.entity:Point(self.target,self.lookspeed) end And then this script can be used to switch the target entity. The two entities are assigned by drag and drop in the editor: script.entitytomodify=nil--Entity script.replacement=nil--Entity function script:SwitchTarget() self.entitytomodify.script.target=replacement end What's nice here is the SwitchTarget script can be used with anything, instead of only working with one type of companion script you decide on ahead of time.
  10. Josh

    LE3 Lua

    That's a good point for consideration. I can't attach values directly to entities in Lua and be able to access them from C++ (which I absolutely need for the script debugger) so there has to be a script table associated with the entity. Fortunately, I can make it a little cleaner than LE2. If you perform a raycast or something, the resulting entity you get will have a script or scripts table attached to it, only accessible in Lua. This is a way to directly access an entity's script object: pick = CameraPick(camera,x,y) if pick then pick.entity.script:DoSomething() end Here's a comparison of two approaches for script attachments. The top one uses a single script. The bottom one uses multiple scripts. Both are manageable: function script:Collision(entity,normal,speed) if entity.script~=nil then entity.script:AddDamage(5) end end function script:Collision(entity,normal,speed) if entity.scripts~=nil then for index,script in ipairs(entity.scripts) do script:AddDamage(5) end end end The big reason we aren't getting general-purpose scripts written now includes: -No script debugging. -One script file per model file design discourages reuse. -Only models can have scripts. -LE2 scripts include a lot of class stuff that I should have skipped. I'll do some experiments next with multiple scripts, and have outputs linked between entity scripts, instead of entities.
  11. Josh

    LE3 Lua

    -What if you have the same script attached twice? -My entity:AddDamage() approach allows you to add new scripts with the AddDamage() function, to act in ways that were not originally accounted for. For example, a can of paint might explode and fling paint everywhere when its health reaches zero. Looking at Unity's system, I think they have sacrificed their script system for the purpose of making people think they can simply click on options to make a game. I mean, the multiple script attachments has a benefit to the total non-programmer. Let's say they get 20 "utils" more functionality than if they chose from a library of single pre-made scripts. But the cost when they crack open those scripts is -60 utils. Their scripts are a mess, and are fragmented between three script languages.
  12. In my opinion, you need a project plan and a manager that assigns tasks, verifies outputs, and holds contributors accountable and on schedule. I don't think the project manager should even try to do anything else but manage it.
  13. Josh

    LE3 Lua

    That's correct. With this approach, the differences are: -Script debugger -Any script can be attached to any entity, instead of having one script per model file. -Entity get/set Lua values directly, instead of string-based keys. This includes drag and drop fields in entity properties for materials, textures, other entities, etc. -Visual logic editor connects entity script functions, instead of entity target/message system. -Much simpler scripts, with no attempt to implement hierarchical OO or control properties through string-based keys. -Script values and functions are attached directly to the entity itself. That's the big question. Multiple scripts need multiple spaces for variables. The variables have to be attached to some kind of Entity-Script attachment object. I have implemented this without a problem, and it works well. The problems arise when you try to access that entity's values from another script, or from C++ code. For example, if you want a bullet to affect a character it hits, you would have to do something like this: function script:Collision(entity,normal,speed) local script local n for n=0 to entity:CountScripts()-1 script=entity:GetScript(n) script:AddDamage(self.damage) end end Okay, we can do some tricks to just call the function for the one entity, and it gets called for all scripts attached to that entity, so then it would look like this: function script:Collision(entity,normal,speed) entity:CallFunction("AddDamage",self.damage) end What if the function needs to return a value? There is no version of this we can do with a simplified per-entity function like we used above: function script:Collision(entity,normal,speed) local script local n for n=0 to entity:CountScripts()-1 script=entity:GetScript(n) if script:GetHealth()>0 then script:AddDamage(self.damage) end end end There's very little you can do within a script itself. Gameplay comes from the interactions between scripts. Without that, you'll add one script to make an object spin around, another to make it blink colors, another to make it emit a noise, and that's pretty much all you can do. With a single script per entity, this becomes very easy: function entity:Collision(entity,normal,speed) if entity:GetHealth()>0 then entity:AddDamage(self.damage) end end I originally started off making the logic editor connect script-entity attachment objects, not entities, but I could quickly see that it was way too abstract, so I just made it connect entities, and merged the list of available functions. However, this causes problems because if an input is called, and multiple scripts have the function, if that function has an output to another entity, it will be called for each script that has the function. I could take stricter control of the flow on the C++ side, but I thought the idea was that when a script function was called, from anywhere, it would trigger any outputs it's connected to. I don't doubt I can implement a system that has a way to control all of this, but it's a question of keeping things simple. I made the LE2 script system complex to try to accommodate the feature requests I was getting (like hierarchical OO script objects). One question is just how frequently will the end user be combining multiple scripts to create emergent behavior? It's a nice idea, but beyond really simple stuff like a blinking spinning light, what can you do with multiple scripts that couldn't be done with one flexible script with some adjustable properties? I bet beginners love it, because it gives them the appearance of controlling behavior without modifying any code, but are we crippling the usability of the system to make easy stuff easier? It seems like we have two kinds of functions. We want engine hooks to have multiple definitions, be called in order, and have unique variable spaces. On the other hand, we want script functions to be attached directly to the Entity object, share variables, and only have one definition. Maybe the former needs some kind of AddScriptHook() mechanism, while conventional script functions would simply be overridden if they exist in two scripts attached to the same entity. It's also worth considering that the Unity script kiddies are the least likely demographic we will attract. They've got brand loyalty like crazy, they tend to be on the low end of the technical proficiency spectrum, and are mostly using free stuff. That's unlikely to be a potential customer. That's the goal, but this needs some more thought on the design.
  14. Josh

    LE3 Lua

    Don't worry about the parsing, I am pretty thorough with that stuff. Connectivity is a major issue with multiple scripts. I decided early on that the connectable objects in the logic editor should just be entities, because a "script attachment" class was too abstract and confusing, i.e. connecting scripts attached to entities instead of entities. However, if an entity has an output to another entity that gets called when an "Enable" function gets called, if it has five scripts with that function, it's very hard to prevent that output from being activated five times. I'm experimenting right now with a one-script per entity approach that looks like this: entity.state=true entity.message = "Hello!" entity.movespeed = Vec3(1,2,3) entity.turnspeed = Vec3(0,0.1,0) entity.moveglobal = false entity.turnglobal = true function entity:Update() self:SetColor(0,1,0,1) self:Turn(0,0.1,0,true) end What's nice about this is you can get and set values from the C++ side to Lua, like the old key/value pairs, but more advanced: Model* box = Model::Box(); box->SetInt("health",100) box->SetObject("friend",Model::Sphere()); Object* o = box->GetObject("friend") And all those values are available on the Lua side: box.health box.friend It also makes Lua scripts nice and easy to work with: --Bullet collides with anything, doesn't matter what function entity;Collision(entity,position,normal,speed) if entity:Hurt~=nil then entity:Hurt(5) end end
  15. Josh

    LE3 Lua

    Yet another way: script.movespeed = Vec3(1,2,3) --public script.turnspeed = Vec3(0) --public script.moveglobal = false --public script.turnglobal = true --public script.state = true --public
  16. Josh

    LE3 Lua

    Yes, this is so the editor knows how to display the visual control. The Sound, Entity, etc. fields prevent the user from dragging a sound onto a field that expects a material, for example. The other alternative would be something like this: --Expose values here you want to modify in the editor: script.state=true--bool script.mode=2--int script.name="Bob"--string But you get into mode complex parsing issues when you start using classes and constructors: --Expose values here you want to modify in the editor: script.movement=Vec3(1,2,3)--Vec3 script.rasterpos=Vec2(0)--Vec2
  17. Josh

    LE3 Lua

    Here's what a script with a lot of unnecessary variables looks like: --Expose values here you want to modify in the editor --Vec3 speed 1,2,3 --bool state true --Entity target --int health 100 --float smoothness 10 --Material material --Sound opensound --choice style "fast","slow","blinking" --choiceedit style "fast","slow","blinking" --string name "Bob" --path file "test.txt" --Vec2 rasterpos 2,2 --Vec4 shape 0,0,1,1 --Do initialization stuff here. function script:Create() end --This function gets called once per world update. function script:Update() end -This function gets called once per physics update. function script:UpdatePhysics() if self.state then self.entity:Move(self.speed,false) end end --This functin gets called any time an entity moves function script:UpdateMatrix() end --This function gets called once per world render, if the entity is drawn at all. It will only be called once at most. Animation should be performed here. function script:Draw() end --This function gets called once per camera render. It will be called each time an entity is drawn. function script:DrawEach(camera) end --This function is called when the entity is freed. function script:Free() end function script:Enable()--in,out self.state=true end function script:Disable()--in,out self.state=false end
  18. The fastest way to do this is to render from one texture to a buffer, halving it each time. This is how downsampling for bloom works. Any downsampling done on the CPU would be far too slow. I don't generally worry about devoting time to stuff for real-time cube mapping because it isn't a feasible technique to begin with. You're talking about rendering the scene 6 extra times.
  19. One thing I love about constructive solid geometry modeling is that texture mapping is sooooo much simpler than 3ds Max. Most of the time the automatic texture mapping works fine, and when you do need to adjust texture mapping by hand, CSG texture mapping tools are still much easier. The justify buttons line a texture up along a face, or a group of faces. Although using these tools is fun and easy, programming them is another matter. I dreaded the implementation of the texture justify buttons, but it wasn't that hard. It doesn't account for rotation and scale yet, but a basic implementation turned out to be surprisingly easy. I guess after writing 3D World Studio five times, I am starting to get the hang of this: Smooth groups are working as well. Leadwerks3D will be the first CSG editor ever (AFAIK) to support real-time smooth groups. In the example below, we have a beveled corner we want to make rounded: To round the corner, select all the faces you want smoothed together, and press one of the smoothing group buttons. This will assign the selected faces to use the smoothing group you press. You can add multiple smooth groups to a face. Faces that have one or more smooth groups in common will be smoothed together: Here is the resulting rounded corner: Finally, I am starting to narrow down the visual theme for the new editor. Since we use the standard Windows and Mac interfaces on each operating system, it makes sense to use the standard Windows Office/VS icons whenever possible. One side benefit is they also look great on Mac, strangely enough: That's all for now. I've had a lot of fun designing the "perfect" workflow for game development, and can't wait to show you all the finished product this summer!
  20. There might be an option like "Export vertex normals" or "Export smooth groups" you can change.
  21. This is an issue with your modeling program. Whatever the normals are in the exported FBX file are what Leadwerks loads.
  22. You don't need to do that by hand. The engine does it automatically.
  23. I like this, it's a GUI library that isn't complete garbage. Garry is a good coder.
  24. That's a pretty good description of how the vegetation system works. Of course that is all automated.
  25. CSG is a great way to quickly and easily produce levels, and the editor is even fun to write. I added another tab next to the scene and project tabs where you can select objects to create. The CSG texture mapping and smoothing controls also reside on this panel. I'm still playing around with the layout, but here is what I have now: CSG brushes are now entities, and can be arranged in a hierarchy. Check out the scene hierarchy that gets created when you create a compound brush object (a shape made of many brushes): You can drag brushes around and change the hierarchy, and traditional CSG editing still works, amazingly. I'm sure glad we have reliable transformation commands or this would be impossible! Here's another nice shot:
×
×
  • Create New...