Behavior/Component System discussion
by Jeff Raab · in Torque 3D Professional · 06/02/2013 (6:36 am) · 63 replies
It seemed like a better idea to do proper discussion about what my blog covered in a forum thread, since they're, you know, for discussing.
So this thread is more or less going to be about 2 things. Release plans, and suggestions on what behaviors/components should come with as a starter/example set.
I mentioned in my comment that my personal goal with the Actor class and it's use of components is to pretty much get rid of ShapeBase and most of the need for specialized object classes derived from it by exploiting the behaviors system.
So any suggestions on examples are welcome, even if it's something like 'the ShapeBaseImage state machine as a behavior' or 'the entire player physics/movement code'. Lets just throw ideas at the wall and see which ideas stick as a good starting batch out the door.
Ones that will be released with this, regardless:
Core behaviors:
BaseBehavior - script-only behavior, no engine side work, general purpose for gameplay stuff
RenderBehavior - core render behavior template that other render behaviors would derive from
TickBehavior - hooks with Actor's processTick allowing you to do ticked code with the behaviors
NetworkBehavior - this will be useful as a more direct approach to gameplay/event feedback to the client than having to jump hoops through the commandTo* calls.
Unique Behaviors:
RenderShape - accepts a shape file, and renders it
RenderBillboard - accepts a material and renders a billboard of it
AnimationController - if you have a RenderShape, you can do this, and have the ability to animate the shape. What animations can be used will be entirely script defined. No need for the ActionAnimationList.
ControlObject - this lets a client take control of this object. Allows you to make use of the next behavior...
UpdateMove - this lets you intercept the move updates from a controller object and move the shape around
This is what I've got slated thus far. Please throw out your own suggestions and we can try and hash out a solid list of things people need/want to see when it comes out.
So this thread is more or less going to be about 2 things. Release plans, and suggestions on what behaviors/components should come with as a starter/example set.
I mentioned in my comment that my personal goal with the Actor class and it's use of components is to pretty much get rid of ShapeBase and most of the need for specialized object classes derived from it by exploiting the behaviors system.
So any suggestions on examples are welcome, even if it's something like 'the ShapeBaseImage state machine as a behavior' or 'the entire player physics/movement code'. Lets just throw ideas at the wall and see which ideas stick as a good starting batch out the door.
Ones that will be released with this, regardless:
Core behaviors:
BaseBehavior - script-only behavior, no engine side work, general purpose for gameplay stuff
RenderBehavior - core render behavior template that other render behaviors would derive from
TickBehavior - hooks with Actor's processTick allowing you to do ticked code with the behaviors
NetworkBehavior - this will be useful as a more direct approach to gameplay/event feedback to the client than having to jump hoops through the commandTo* calls.
Unique Behaviors:
RenderShape - accepts a shape file, and renders it
RenderBillboard - accepts a material and renders a billboard of it
AnimationController - if you have a RenderShape, you can do this, and have the ability to animate the shape. What animations can be used will be entirely script defined. No need for the ActionAnimationList.
ControlObject - this lets a client take control of this object. Allows you to make use of the next behavior...
UpdateMove - this lets you intercept the move updates from a controller object and move the shape around
This is what I've got slated thus far. Please throw out your own suggestions and we can try and hash out a solid list of things people need/want to see when it comes out.
#22
Quick question, I've been looking at a few other engines and I came across an engine called s2 engine HD. It kind of uses a system similar to what you are trying to do. My question is, if there is a cutscene editor added to core of T3D. Would the behavior system be able to control that as well?
Here is a video showing kind of what I was trying to explain:
www.youtube.com/watch?v=skvf0mcvlmk&feature=c4-overview-vl&list=PLe8a3Ky...
07/09/2013 (7:05 pm)
Jeff Quick question, I've been looking at a few other engines and I came across an engine called s2 engine HD. It kind of uses a system similar to what you are trying to do. My question is, if there is a cutscene editor added to core of T3D. Would the behavior system be able to control that as well?
Here is a video showing kind of what I was trying to explain:
www.youtube.com/watch?v=skvf0mcvlmk&feature=c4-overview-vl&list=PLe8a3Ky...
#23
Given that behaviors can function at the engine OR script level, as long as any system has functionality hooks accessable for the rest of the code, a behavior could feasibly control it.
I'd been eyeing a cutscene edtior of sorts as a distant side project, so I have some inklings on how it'd run(really, I'd like it to basically be SFM-level controls in T3D).
Like I'd mentioned in a prior post, I'm willing to reach out and work with other devs working on resources or kits to have behavior versions of their stuff as well, so if someone cranks out a cutscene edtior, I'd be willing to work with them to hash out the behaviors.
On the behavior front, I've mostly fixed the collision issues for now.
It's not perfect, but it works fairly well outside of a bit of jitter with the phyiscs.
I basically peeled the player collision code apart to work with that, as the player collisions were designed to pretty much never penetrate(the exact opposite of the regular rigid/convex collision stuff).
I'll see about adding additional primitive shapes(and arbitrary convex meshes) going forward, but the box collider works for now.
Now I just need to clean the code up, do bugfixes for the handful of currently known bugs and I'll get the payment campaign rolling.
07/10/2013 (12:22 pm)
@KoryGiven that behaviors can function at the engine OR script level, as long as any system has functionality hooks accessable for the rest of the code, a behavior could feasibly control it.
I'd been eyeing a cutscene edtior of sorts as a distant side project, so I have some inklings on how it'd run(really, I'd like it to basically be SFM-level controls in T3D).
Like I'd mentioned in a prior post, I'm willing to reach out and work with other devs working on resources or kits to have behavior versions of their stuff as well, so if someone cranks out a cutscene edtior, I'd be willing to work with them to hash out the behaviors.
On the behavior front, I've mostly fixed the collision issues for now.
It's not perfect, but it works fairly well outside of a bit of jitter with the phyiscs.
I basically peeled the player collision code apart to work with that, as the player collisions were designed to pretty much never penetrate(the exact opposite of the regular rigid/convex collision stuff).
I'll see about adding additional primitive shapes(and arbitrary convex meshes) going forward, but the box collider works for now.
Now I just need to clean the code up, do bugfixes for the handful of currently known bugs and I'll get the payment campaign rolling.
#26
07/10/2013 (5:42 pm)
If all behaviors are networked then how would you do a client side only object? I felt like a component system would include networking as a component that is made aware of data to be networked. So if that component was not included there is no networking. That way single player games could theoretically never need to ghost anything.
#27
Going off some people's suggestions, I'm going to add a bit of a buffer for indie gogo's take, so the price will be $750.
@Demo
Torque by default operates on a client/server setup, even in single player, so for the initial release it was easier to work within that assumption.
I agree that going forward it should be broken out a bit more, but that does bolster the intricacy of the system quite a lot, so for the initial release I opted for the always-networked assumption.
For client side-only effects, there are workarounds. I'm including an example behavior that basically takes a provided list of clients, sends a specific command to them all, and the command basically passes the object's ghost ID. On the clients called, it has the ghost ID of the object, and hides it.
So you could do stuff like the weapon image system, where player A sees the first person model, and not the third person one while player B sees the opposite arrangement.
I felt that's a sufficient example of workable behavior until we can iron out the best approach for network-independent behaviors(since that gets a bit tricky).
07/10/2013 (7:25 pm)
@KoryGoing off some people's suggestions, I'm going to add a bit of a buffer for indie gogo's take, so the price will be $750.
@Demo
Torque by default operates on a client/server setup, even in single player, so for the initial release it was easier to work within that assumption.
I agree that going forward it should be broken out a bit more, but that does bolster the intricacy of the system quite a lot, so for the initial release I opted for the always-networked assumption.
For client side-only effects, there are workarounds. I'm including an example behavior that basically takes a provided list of clients, sends a specific command to them all, and the command basically passes the object's ghost ID. On the clients called, it has the ghost ID of the object, and hides it.
So you could do stuff like the weapon image system, where player A sees the first person model, and not the third person one while player B sees the opposite arrangement.
I felt that's a sufficient example of workable behavior until we can iron out the best approach for network-independent behaviors(since that gets a bit tricky).
#28
I understand the way the system operates now. However, it was designed that way because it was designed to operate as a multiplayer FPS. One concern I have with basing the object upon a NetObject is you automatically inherit some class bloat/overhead there. And once you design your system around networked objects then you end up relying on that and kind of paint yourself in a corner don't you? I don't know, I have not seen how you are approaching this code wise.
When I started looking at this I was thinking about going all the way down to the SimObject level, but was considering having components themselves not be based on the SimObject hierarchy. That way they would not consume SimObject IDs and would be managed by the controlling SimObject. That way bad scripting could not futz with an object that may be allowing memory access of its internals to another component (networking). That way the components themselves would be very lightweight.
BTW, this is not a criticism, I just want to understand where you are going with this. I am glad someone is tackling this. Perhaps I should sit down and start hashing away at how I wanted to tackle this. Then I can send you code if it works out how I want. There is no reason you could not benefit from someone else working on this. I like getting into that part of the engine anyway.
Do you have any articles I could look at to understand how you are approaching this? It sounds like there are other implementations you are referencing on this.
07/11/2013 (11:47 am)
@Jeff,I understand the way the system operates now. However, it was designed that way because it was designed to operate as a multiplayer FPS. One concern I have with basing the object upon a NetObject is you automatically inherit some class bloat/overhead there. And once you design your system around networked objects then you end up relying on that and kind of paint yourself in a corner don't you? I don't know, I have not seen how you are approaching this code wise.
When I started looking at this I was thinking about going all the way down to the SimObject level, but was considering having components themselves not be based on the SimObject hierarchy. That way they would not consume SimObject IDs and would be managed by the controlling SimObject. That way bad scripting could not futz with an object that may be allowing memory access of its internals to another component (networking). That way the components themselves would be very lightweight.
BTW, this is not a criticism, I just want to understand where you are going with this. I am glad someone is tackling this. Perhaps I should sit down and start hashing away at how I wanted to tackle this. Then I can send you code if it works out how I want. There is no reason you could not benefit from someone else working on this. I like getting into that part of the engine anyway.
Do you have any articles I could look at to understand how you are approaching this? It sounds like there are other implementations you are referencing on this.
#29
Wouldn't that drastically complicate scripting though? As it stands, the fact that the behavior instances are their own objects, with their own id's, you can use the standard OOP deal. So you can get the behavior object from the owner, and call functions on it, or use variables it has, etc. While the owner can push function calls, variables and stuff script side wouldn't be so easy to work with anymore.
For the network stuff, I agree it does add some bloat but it boils down to I couldn't think of a straightforward, practical, not-house-of-cards setup to it that wouldn't take a ton of additional time to hash out.
If you've got ideas on it, by all means, lets brainstorm.
Also, the way you're talking makes it sound kind of like I'd be the one working on all the code. While I'm getting the behaviors system on it's feet, and will definitely continue work on it as agressively as I can going forward, the idea being that after the community purchase, it will be fully opened to the community.
So I can understand why you would want to nip the theoretical boxing into a corner issue pre-emptively, I imagine post-release there will be a bunch of people that will look at the code go 'sure that worked, but THIS is way better' and we can polish it into a much better state than I could on my own.
At that point, hopefully we can get it worked into the engine.
So yeah, seriously by all means, if you've got some ideas throw them up. They may not go into the first release, but we can danged sure do changes once it's open too.
I don't really have any articles or anything. I looked at unity a bit for the basic approach they took, as well as T2D(which is the overall direction I've taken).
Past that, I'm kinda winging it, lol.
07/11/2013 (6:57 pm)
[quote] When I started looking at this I was thinking about going all the way down to the SimObject level, but was considering having components themselves not be based on the SimObject hierarchy. That way they would not consume SimObject IDs and would be managed by the controlling SimObject. That way bad scripting could not futz with an object that may be allowing memory access of its internals to another component (networking). That way the components themselves would be very lightweight. [/qoute]Wouldn't that drastically complicate scripting though? As it stands, the fact that the behavior instances are their own objects, with their own id's, you can use the standard OOP deal. So you can get the behavior object from the owner, and call functions on it, or use variables it has, etc. While the owner can push function calls, variables and stuff script side wouldn't be so easy to work with anymore.
For the network stuff, I agree it does add some bloat but it boils down to I couldn't think of a straightforward, practical, not-house-of-cards setup to it that wouldn't take a ton of additional time to hash out.
If you've got ideas on it, by all means, lets brainstorm.
Also, the way you're talking makes it sound kind of like I'd be the one working on all the code. While I'm getting the behaviors system on it's feet, and will definitely continue work on it as agressively as I can going forward, the idea being that after the community purchase, it will be fully opened to the community.
So I can understand why you would want to nip the theoretical boxing into a corner issue pre-emptively, I imagine post-release there will be a bunch of people that will look at the code go 'sure that worked, but THIS is way better' and we can polish it into a much better state than I could on my own.
At that point, hopefully we can get it worked into the engine.
So yeah, seriously by all means, if you've got some ideas throw them up. They may not go into the first release, but we can danged sure do changes once it's open too.
I don't really have any articles or anything. I looked at unity a bit for the basic approach they took, as well as T2D(which is the overall direction I've taken).
Past that, I'm kinda winging it, lol.
#30
T2D is probably one of the best examples. I should take a closer look at that. Thanks for the tip.
Come to think about it, just because networking is in the object chain does not mean the object needs to use it at all. Maybe make sure all the networking calls can be controlled just like in existing objects (always ghosted, not ghosted, etc), and even be able to shut it off. That should satisfy not eating up bandwidth.
I was hoping to find a way to allow data from objects to be allowed to be fed into the networking optionally based upon the needs of that object. Perhaps a way to register fields with the networking component of the object(s). Or did you say you were putting networking in each component? I just thought it might be better to have a component act as a network broker for other components. Like, maybe have an object register fields at runtime with a flag that determines if it is networked, what flags that trigger transfer, and the number of bits. It would be similar to registering a field at compile time, but able to be done with script. Does that even make sense to you?
It might work similar to this:
07/11/2013 (7:44 pm)
Quote:Wouldn't that drastically complicate scripting though?The way I was thinking about it was to add commands to a SimObject based component object that added the components to itself. That way it could properly setup/cleanup the components. So it does not do away with any benefits of scripting, it just is managed through the component objects. You are right in that the SimObject base does allow a fair amount of introspection that would either have to be added to a custom component system or done away with. So you are probably right in that keeping SimObject style design is a good thing.
Quote:I imagine post-release there will be a bunch of people that will look at the code go 'sure that worked, but THIS is way better' and we can polish it into a much better state than I could on my own.Yes that is true. People always can see more than what the original author could see.
T2D is probably one of the best examples. I should take a closer look at that. Thanks for the tip.
Come to think about it, just because networking is in the object chain does not mean the object needs to use it at all. Maybe make sure all the networking calls can be controlled just like in existing objects (always ghosted, not ghosted, etc), and even be able to shut it off. That should satisfy not eating up bandwidth.
I was hoping to find a way to allow data from objects to be allowed to be fed into the networking optionally based upon the needs of that object. Perhaps a way to register fields with the networking component of the object(s). Or did you say you were putting networking in each component? I just thought it might be better to have a component act as a network broker for other components. Like, maybe have an object register fields at runtime with a flag that determines if it is networked, what flags that trigger transfer, and the number of bits. It would be similar to registering a field at compile time, but able to be done with script. Does that even make sense to you?
It might work similar to this:
void RenderRTTExample::initPersistFields()
{
addGroup( "Settings" );
addField( "textureTargetName", TypeRealString, Offset(mTexTargetName, RenderRTTExample),
"Name used to define NamedTexTarget");
endGroup( "Settings" );
// SceneObject already handles exposing the transform
Parent::initPersistFields();
}So the addGroup might be flags that actually determine if the data is tranferred say addFlag. The addField could be the actual field of the object to be transferred that could have type data, number of bits and any other relevant data. In the script call to do the addition it could query the object for the field and if it exists it could add it to a descriptor for the object (or however you intended to track that). I hope I am making sense here.
#31
I should mention, I actually did set it up so when the behavior template and instances are created, the constructor would let you override the default ghostAlways to have different ghosting rules(or none at all). So even with the current networked implementation, all it'd really take is just setting them to never ghost and none of the networking happens.
For the registering a field idea, that'd probably work pretty well and still be pretty simple.
When adding a behavior field in script, we could just have an additional, optional field to the call that define the field being associated to a network mask. Something similar-ish would work for in engine.
That lets you easily diffuse out certain updates to happen in groups, etc. And if the field isn't set, it doesn't get networked.
I'll still go with the full networked for the initial release because it's already working, but I think this would be a pretty good angle for going forward.
07/12/2013 (12:50 pm)
That actually makes for a pretty solid idea, I think.I should mention, I actually did set it up so when the behavior template and instances are created, the constructor would let you override the default ghostAlways to have different ghosting rules(or none at all). So even with the current networked implementation, all it'd really take is just setting them to never ghost and none of the networking happens.
For the registering a field idea, that'd probably work pretty well and still be pretty simple.
When adding a behavior field in script, we could just have an additional, optional field to the call that define the field being associated to a network mask. Something similar-ish would work for in engine.
That lets you easily diffuse out certain updates to happen in groups, etc. And if the field isn't set, it doesn't get networked.
I'll still go with the full networked for the initial release because it's already working, but I think this would be a pretty good angle for going forward.
#32
07/12/2013 (4:42 pm)
Yeah, that makes sense since you already have some momentum. Sorry if I am distracting you too much.
#33
The whole point of this thread was feedback and ideas, so the input is appreciated.
07/12/2013 (7:48 pm)
Haha, not at all.The whole point of this thread was feedback and ideas, so the input is appreciated.
#34
Do you have some pointers about how to implement a graphical component/behavior to work with your system? I am going to start down the road of a polyvox terrain/object system and it would be very nice if it could work with your stuff.
I understand if it is still early too early for that kind of question.
Edit:
I forgot to mention that I really like your approach to the networking. My fear on that was every object would eat up bandwidth even if it was not useful.
07/18/2013 (12:27 pm)
@Jeff,Do you have some pointers about how to implement a graphical component/behavior to work with your system? I am going to start down the road of a polyvox terrain/object system and it would be very nice if it could work with your stuff.
I understand if it is still early too early for that kind of question.
Edit:
I forgot to mention that I really like your approach to the networking. My fear on that was every object would eat up bandwidth even if it was not useful.
#35
Cleanup and polish goes well.
I gutted out the old, terrible editor GUI stuff as it was mostly written in engine code and distressingly rigid. Now it has the same proper inspector hooks, but it calls back into script, where the rest of the stuff is handled. This gives me some, frankly, hilarious flexibility that I'll be expanding/working on post-release.
To give a bit of a teaser to it: sub-editors built right into the behaviors themselves.
I've also implemented dependency code in there, so that's nice.
I've also got behavior field grouping, which lets you define fields being in certain groupings, and it'll make sub-rollouts to contain them for coherency.
However, due to a bug in how roll outs-containing-rollouts works, I've had to make them not be collapsible for now. Once the bug is tracked down and fixed, they can be collapsed as normal again.
I've also got the GUI behavior almost completely implemented. Once that's sorted, I just need to do a polish pass clearing out any detritus and document the code.
@Demo
I could probably just pass you the renderShape behavior to get you rolling, but as close as this is to almost being done it may be just as easy to wrap it up and and get the CP Campaign done and get it all public. If I haven't finalized stuff by the end of the week, I'll pass ya the renderShape behavior so you can mull it over for ideas.
Honestly though, it's simpler an implementation than you may think(not that that's a bad thing ;) )
07/23/2013 (3:37 am)
Giving a bump via an update on this.Cleanup and polish goes well.
I gutted out the old, terrible editor GUI stuff as it was mostly written in engine code and distressingly rigid. Now it has the same proper inspector hooks, but it calls back into script, where the rest of the stuff is handled. This gives me some, frankly, hilarious flexibility that I'll be expanding/working on post-release.
To give a bit of a teaser to it: sub-editors built right into the behaviors themselves.
I've also implemented dependency code in there, so that's nice.
I've also got behavior field grouping, which lets you define fields being in certain groupings, and it'll make sub-rollouts to contain them for coherency.
However, due to a bug in how roll outs-containing-rollouts works, I've had to make them not be collapsible for now. Once the bug is tracked down and fixed, they can be collapsed as normal again.
I've also got the GUI behavior almost completely implemented. Once that's sorted, I just need to do a polish pass clearing out any detritus and document the code.
@Demo
I could probably just pass you the renderShape behavior to get you rolling, but as close as this is to almost being done it may be just as easy to wrap it up and and get the CP Campaign done and get it all public. If I haven't finalized stuff by the end of the week, I'll pass ya the renderShape behavior so you can mull it over for ideas.
Honestly though, it's simpler an implementation than you may think(not that that's a bad thing ;) )
#36
Simple machines that perform the same work are always better then Rube Goldberg death traps.
07/23/2013 (4:00 am)
@Jeff,Simple machines that perform the same work are always better then Rube Goldberg death traps.
#37
When you have time, can you please contact me at pyoskowitz@winterleafentertainment.com
I have a few questions for you about this system.
Paul
07/23/2013 (11:13 am)
@Jeff:When you have time, can you please contact me at pyoskowitz@winterleafentertainment.com
I have a few questions for you about this system.
Paul
#38
07/25/2013 (3:02 pm)
@Jeff I'd like to write about this in the 1st edition of the T3D magazine I'm working on! Could you please contact me on ljorgensen@winterleafentertainment.com ?
#39
Seriously, I'm sort of working on a thread pool system for a completely different project and I'm really trying to stick to the ol' KISS paradigm. Threading has enough pitfalls without adding any of my own.
07/25/2013 (8:27 pm)
@Demo - how dare you?!? Rube Goldberg's are the best thing EVER! lolSeriously, I'm sort of working on a thread pool system for a completely different project and I'm really trying to stick to the ol' KISS paradigm. Threading has enough pitfalls without adding any of my own.
#40
07/25/2013 (8:34 pm)
Never heard of "Rude Goldberg" machines before, lol... sometimes I think that best describes the next release of DNT I'm working on...
Torque Owner Jeff Raab
[ghc]games
You could easily just build a state machine-based behavior with certain settings/states calibrated into it for each type(soldierAI, civilianAI, enemyAI, etc) and then just spawn the actor/entity with the behavior and it'll go. Heck, you could spawn them with multiple types and just have only one enabled(or add/remove them on the fly) at a time for swapping behavior profiles.
For the granular behavior, that gets a bit more specific, but there's nothing inherent in stopping you from doing stuff like the goals. You'd create a behavior that during the process tick or whatnot, it attempts to enact the goal associated to the behavior. So you could have a 'lowHealth' behavior, where once you go below a certain amount of health, it scans for and tries to find health items. Stuff like that is totally doable.
I'd actually planned on reaching out to some of the developers working on cool stuff like AI, or Lukas' fancy particle systems and seeing if they'd like help getting behavior versions implemented for their packs once this thing is released.
Speaking on that, as a progress update, a majority of everything is implemented for the core release, I'm just working on bug fixing at the moment.
The current list of behaviors that are in and at least partially functional are:
-Box Collider
-Simple Physics
-Camera
-Control Object
-Input/Keybinds
-Render Shape
-Client visibility Control(of rendered shapes)
I plan on implementing a GUI behavior as well.
For the input behavior, it gives the attached object FPS controls, WASD + Pitch/Yaw mouse controls.
Most of them are otherwise pretty self-explanatory, but I think the client visibility one is interesting.
You add it to a behavior that has render behaviors attached. It lets you set clients that either can, or cannot, see the shape. This would be used for replicating something like the WeaponImage functionality, where you'd have a first person and third person weapon, and which one is visibile is determined by if you're the controlling client or not.
Could also be used for displaying certain elements for a specific team, etc, etc.
Other than the GUI example behavior needing to be implemented, the only major sticker at this point is sorting out the bugs with the collision/physics stuff.
They weren't ever designed to be separated in Torque, so getting them separate and agreeable has been tricky. Collisions happen correctly, but I'm still getting some penetration issues so it's not correctly updating the physical forces in time to prevent the penetration from happening.
Once that's fixed, I just need a final bugfix pass, list all the changes made, clear the code and implement any remaining callbacks to script needed.