Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

879792 Posts in 33006 Topics- by 24379 Members - Latest Member: alisiahl87

May 25, 2013, 12:46:27 AM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)[Engine] Shared Data of GameObjects for Components
Pages: [1]
Print
Author Topic: [Engine] Shared Data of GameObjects for Components  (Read 548 times)
roflha
Level 0
*


View Profile
« on: December 10, 2011, 02:17:28 AM »

Let me start of by just saying hello to everyone. Hello.
I hope this is the correct board for this kind of post. I have been reading for a while but just recently decided to actually become active and was hoping that somebody would be help to help me with an issue I just ran into.

My question is this: When using a GameObject-Component design with a game engine, what is the best way to have data to describe the game objects, but can be accessed from multiple components? Should this even be needed, or does it indicate some deeper design flaw?

Now for some more detail...
I am currently changing up an engine and moving it away from an ugly Entity based setup for in game characters and such. I want to get everything working nicely using GameObject and components (the engine is in C++). I have already changed it to use GameObject and Components, but I am worried about performance issues.

Data about my GameObjects are currently held in various maps with name/value pairs. For example, a value could be added to a game using a method such as AddInteger(string name, int value). Values are then stored in a map for values of that particular type (int, char, string, etc.). Values can later be read back into integers using methods like ReadInteger(string name, int default), where default is the value returned if name is not found in the map.

For those of you who are familiar with Android, you may recognize this approach as being the same used in Android's SharedPreferences. http://developer.android.com/reference/android/content/SharedPreferences.html

This approach seems great on paper as values like velocity can be stored in one place and components for collision and physics and other can all access it. The components are also not punished for trying to reference a nonexistant value and can control what they default to after a failed read. Note, some values can be hardcoded into GameObject (such as a Transform for position) but I would like to avoid that as much as possible.

My concern is that when there are many GameObjects being updated at once, the time needed for lookups from the maps will be nontrivial. Does anybody have any advice to offer about this or any suggestions? I haven't tested it yet, I plan to tomorrow, but I am worried it will get slow.
Logged
randomnine
Level 1
*


View Profile WWW
« Reply #1 on: December 10, 2011, 04:18:19 AM »

Hey, and welcome.

There's a perfectly adequate mechanism for storing data in C++. It's called "member variables" and they're a hell of a lot faster than string lookup on a map...

Generally, you should be storing entity data in components. Data which is common to all or almost all entities, you can store on the game object class itself. Taking the example of a position Transform, you could either have a TransformComponent which stores a Transform variable, or store the Transform on the GameObject. You might have a PhysicsComponent which stores velocity, acceleration, etc., and is responsible for basic integration and collision checking. Your AI component would store AI state data while also manipulating and acting on that data.

Components which need to access other data simply communicate with the components that hold it. One useful abstraction is to allow multiple components to implement a given interface, which can then be accessed by other components - meaning that different component types can provide the same data or functionality to other components. For example, you may have a few different types of physics component, but all of them might provide velocity, etc.

Don't try to store all your data in one generic place without strong typing. It may sound easy and simple, but it will make your code more complicated and harder to read in the long run. Without any explicit declaration of variables or their types somewhere in the code, you're quite likely to run into situations where you accidentally use the same variable name to mean two different things, or forget what type a variable is meant to be. Without tight, explicit ideas in your code about data ownership and access control, you will have no real idea which components are dependent upon which other components to function. You'll end up in situations where a variable is not what you expect, anything in the entire codebase could have changed it, and you won't even have a good place to set a breakpoint since the data write goes through a generic "write to named variable" method.

Good programming means making what things are and how they interact explicit, such that the amount of code which could be affecting each given bit of data or section of code is both minimal and clear. Working with this objective in mind will make your code simpler, easier to read, easier to debug and easier to improve or extend.
Logged

roflha
Level 0
*


View Profile
« Reply #2 on: December 10, 2011, 04:38:04 AM »

Member variables... I think I have heard of those...haha

You make some excellent points. I have a bad habit of makings things in a way I find elegant and running with it. One of the goals of the engine is to eventually get a structure similar to Unity (for the sake of comfort with many programmers). Which brings me to my next point...

I debated on the whole is-a vs has-a for a Transform, and if I were to for with has-a and use TransformComponent. Since there will eventually be a scripting component, would you suggest actually declaring member variables for things like physics and rendering components, then having an array of scripts? I considered doing it this way, so a script could just call parent.collider instead of anything more complicated.

That's just one example. It would allow easier access to GameObject data to have a declared component of each type rather than an array of just components. Wouldn't that also potentially reduce virtual call lookups?

I hope that all made sense. I am on my phone now...
Logged
Triplefox
Level 9
****



View Profile WWW Email
« Reply #3 on: December 10, 2011, 02:22:38 PM »

My advice: Don't worry too much about trying for the globally optimal case for entities themselves. Instead make entities powerful enough that when you do find the narrow case for optimizing, you can represent multiple instances of a thing(e.g. a whole particle system or a group of AIs) within one entity with a component containing hardcoded behavior. Done in that fashion, your total number of entities can always stay in low-ish numbers regardless of what the game itself is demanding.

I generally agree with the property-bag convention to storing common data, because it serves a purpose of fast prototyping, and it maps particularly well to dynamic-typed languages, which is what I work in. As the data schema settles down it can be pushed into a component and given more formal structure - this is a thing that depends on your own discipline of course, but it's worked for me so far.

The vast majority of new entities I've implemented follow this convention:

1. Must hook up collision and visualization components
2. Must be hooked into AI behavior loop
3. Behavior of AI may access and change arbitrary variables of entity and world

And because those three conventions are so consistent, I've optimized towards making them mostly implied so that they're easier to write. The AI can vary a lot, but the relationship of collision and rendering tends to be very strong, with rare exceptions that I admittedly haven't gotten good at dealing with yet.
Logged

Danmark
Level 7
**



View Profile
« Reply #4 on: December 10, 2011, 07:21:59 PM »

One of the goals of the engine is to eventually get a structure similar to Unity (for the sake of comfort with many programmers).

Then consider what Unity's component system offers, and the simplest/most efficient way to implement it.

components
A Component contains pertinent data and functionality. A GameObject is tied to zero or one Components of each type. A Component is tied to exactly one GameObject. Components may refer to other Components.

behaviour
All Components of one type are updated before the next type. The user supplies an update function to handle each individual Component.

lifetime management
A GameObject & all its Components can be easily destroyed together. Also, any Components can be destroyed while leaving the rest of the GameObject intact.

instantiation
Duplicates of a GameObject can be placed in the world at any time. Also, any Component can be instantiated & added to an existing GameObject.

prefabrication
Prefabs are GameObjects that don't exist in the world, but that can be instantiated, and can be designed ahead of time.
Logged
roflha
Level 0
*


View Profile
« Reply #5 on: December 10, 2011, 10:26:32 PM »

@Veracity Regarding your components point, that is one of the things that I am trying to accomplish but I am always double guessing myself about the best way to do it. Unity's scripting interface can access the components as if they were member variables, or at least some of them, so I am tempted to does what I said earlier: have a member variable for specific types and then afterwards have an array of script components afterwards.

I am moving towards that, I originally just had a list of generic Component objects and called all of their update functions, but that did not allow for direct access using GameObject.Component.

Thanks for the tips. I think I know what I am going to try and do with this.
Logged
Danmark
Level 7
**



View Profile
« Reply #6 on: December 11, 2011, 01:56:28 AM »

Unity's scripting interface can access the components as if they were member variables, or at least some of them, so I am tempted to does what I said earlier: have a member variable for specific types and then afterwards have an array of script components afterwards.

Right, I didn't understand that from your last post. It's pretty common for component systems. IMO, it doesn't lend itself to easily maintainable code.

Part of the reason why it makes sense in Unity is that there are a number of commonly-used built-in component types, as opposed to ones created by users. This distinction is nonexistent when you're building the thing from scratch. While you could have the most commonly-used components as member variables, it would unnecessarily inflate the size of GameObjects at runtime, & create more maintenance work on your part, with negligible benefits. All you really gain is the ability to do gameObject.transform versus gameObject.GetComponent<Transform>().

It'd only be suitable if you had few component types.


I am moving towards that, I originally just had a list of generic Component objects and called all of their update functions, but that did not allow for direct access using GameObject.Component.

In the component system I've made recently, each Component subsystem maps entity IDs to its Components via an array. Each Component knows its entity ID, and an entity itself is nothing more than a state enum referred to by Components across various types. The elimination of concrete Entities is a common trend in component systems- a sensible one when you consider that Entities don't do anything.
Logged
roflha
Level 0
*


View Profile
« Reply #7 on: December 11, 2011, 02:10:49 AM »

Right, I didn't understand that from your last post. It's pretty common for component systems. IMO, it doesn't lend itself to easily maintainable code.

Part of the reason why it makes sense in Unity is that there are a number of commonly-used built-in component types, as opposed to ones created by users. This distinction is nonexistent when you're building the thing from scratch. While you could have the most commonly-used components as member variables, it would unnecessarily inflate the size of GameObjects at runtime, & create more maintenance work on your part, with negligible benefits. All you really gain is the ability to do gameObject.transform versus gameObject.GetComponent<Transform>().

It'd only be suitable if you had few component types.

In my opinion at least, some of these stipulations make sense for the engine. This engine is not one I started, just one I am working on. It is strictly 2D, and in the end, it aims to allow game creation through nothing but scripts. Given that, it is not really necessary to stick to leaving it modifiable. It just seems nicer from a scripting standpoint to use the member variable format, but I suppose even that could be simulated for the scripting side of things and left in the raw GetComponent form if somebody were so inclined as to add in C++ components or something. (The engine is open source so that is completely possible (I feel like I am being too cryptic, I am working with the monocle engine, or at least what is there so far)).

I do find your idea about removing the Entity/GameObject class entirely interesting, though. I may play around with it at some point, but for now removing the Entity would alter the scene graph too greatly for one round of changes... maybe down the road.
Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic