Jump to content
  • Advertisement
Sign in to follow this  
Penance

Game Object Organization

This topic is 4838 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

My current project is a client/server based 3D game engine. I've been thinking a lot about how to organize the objects within the engine. I'm doing it in C#. What have you found to be a good choice for object organization in your own projects? So far I've had three ideas: 1) Everythig is an Entity. Every Entity has a unique id and its contents are specified by a list of the id's of the Entities that it owns. Pro: Very simple. Con: Must loop through every single Entity every frame to update it since you can't distinguish between players, maps, items, etc. Neutral: Weird ownerships can occur. Items could own players or even Rooms. 2) Everything is an Entity, but Entities have a Type property so they can be distinguished. Pro: Rooms can be stored separately, providing a kind of spatial partitioning. You can iterate over Rooms and update only their contents. Rooms could be deactivated if they are not being used so CPU cycles aren't wasted. Con: Seems kind of hackey and everything would need to have hardcoded checks to see what kind of Entity it is. 3) Everything is an Entity but specialized types are subclassed. Pro: Same as 2. Con: Things get weird because a Room doesn't necessarily need stuff like a Physics object to maintain position, velocity, etc that other Entity subclass would need. The hierarchy becomes more complicated and loses the simplicity of the previous choices. One problem common to all of the options is the issue of static vs. transient Entities within rooms. For example, when a Room is loaded you will want to load all of its triggers, colliders, and items (all of which can be modelled as Entities) but not players that were in the room when the game last shut down. The player (also modelled as an Entity) should only be loaded when the player logs on. Just looking to hear from anyone who may have prior experience with a design like this.

Share this post


Link to post
Share on other sites
Advertisement
I know you'll hate to hear it, but it depends on the size of the project, how much you care about wading through lots of ugly code, and how embarassed you're willing to be about your code. All I have to say is that the more easily managed and easy to understand your code is, the easier your project will be.

As long as everything is organized well and easy to access, modify, and use, and it works for you, then great.

Remember to comment.

Share this post


Link to post
Share on other sites
Some caveats. I am no expert, so this is merely my experience. My experience was not 3D, merely network 2D turn based.

Generally, my game objects are different. Not all an entity, but they all inherit from a ID class. Network communication will refer to objects via ID, and if an ID isn't in a lookup table [hash_map], then the client requests the full info about the ID. The object is then serialized [with a type] on the server, and unserialized [as that type] on the client, and stuffed where it belongs, as well as in the ID lookup table.

Certainly, if your game makes it easier to make everything an entity, by all means. But for serialization and orginization, they don't really have to be.

Share this post


Link to post
Share on other sites
I would recommend either composition, or interfacing.

With composition, you write Physics, Rendering, Stats, Effects, and other components for various kinds of behavior an object can have, and you create an actual Entity by combining some number of these behaviors. Some of the behavior kinds can be empty for some entities; others can have multiple implementations with chaining. Communication between components is typically done with messaging.

With interfacing, your object instance derives from entity, and implements query-interface to expose the various kinds of extra functionality it's interested in. It's easier to get going than composition, and doesn't need messaging for object-internal communication, but in the end, it's not as flexible as composition (you can't mix-and-match existing code).

Share this post


Link to post
Share on other sites
Hey,

Yeah in the original post you never mentioned a viable fourth option. You should look into the whole "Inheritance vs Aggregance" debate ( a great article is http://www.gamearchitect.net/Articles/GameObjects1.html ).

You should definately look into what hplus is saying there :-)

Share this post


Link to post
Share on other sites
Interesting article. I'm a *little* familiar with component type design, but I do not have much experience actually coding it.

The idea is interesting, but I'm not sure how to actually implement it, especially in C# because only single inheritance is allowed. Therefore I couldn't "flatten" my design like I could in C++.

Interfaces might work. Say for example that I wanted to solve my problem by having a Map/Location interface, a PhysicsObject interface, a Scriptable interface, a CommandObject interface, etc. Then I'd have to run each object though all of my subsystems and do
if(x is IInterfaceA){...}

Not sure what kind of impact on performance interface checks like that would have, though.

Also, this approach would lead to a lot of duplicate code since every object that exposes interface A, B, C would have to implement it. The only other alternative I can think of is that I would have to create a class that implements the interface and then wrap it inside any other classes that want to implement the interface, right?

Do you have any links to examples or further discussions? That was a very nice resource, thank you.

Share this post


Link to post
Share on other sites
With interfacing, your object instance derives from entity, and implements query-interface to expose the various kinds of extra functionality it's interested in. It's easier to get going than composition, and doesn't need messaging for object-internal communication, but in the end, it's not as flexible as composition (you can't mix-and-match existing code).


Sorry, this didn't make very much sense to me. What do you mean by "object instance?" Speaking from an OOP standpoint, an instance is an object that belongs to a certain class, right?

What do you mean by query-interface and exposing functionality it's interested in? How can (or why would) an object expose functionality to itself? If it contains the functionality, then it can already access it, right?

Could you give some concrete examples or link to some resources? I'd really appreciate it.

Share this post


Link to post
Share on other sites
Quote:

The idea is interesting, but I'm not sure how to actually implement it, especially in C# because only single inheritance is allowed. Therefore I couldn't "flatten" my design like I could in C++.


Wait.. how exactly does component design work? I was under the impression that each Entity would just have a bunch of instances of components (such as Physics, Render, State, OwnedObjects, etc.) in them, and wouldnt use inheritance at all.

Share this post


Link to post
Share on other sites
Maybe I misunderstood the article that xmen90's posted. The author talks about flattening the object hierarchy, which I took to mean that instead of having a deep hierarchy, you have a broad one.

I know what you mean about having a list of components though, but I'm still not sure how I'd implement it cleanly because I have very little experience with it. Any ideas?

Share this post


Link to post
Share on other sites
I think I came up with an "ok" solution to my problem. I'm sure there's a more elegant solution and maybe a better way to check for services, but as far as working and doing what I need it to do, I can't complain.

Any comments?


using System;

namespace GameEngineDemo2
{

public class TestObject
{
private TestObject decorated;
public TestObject(TestObject obj)
{
decorated = obj;
}
public object GetService(Type t)
{
if( this.GetType().GetInterface(t.Name) != null )
{
return this;
}
else if(decorated != null)
{
return decorated.GetService(t);
}
else
{
return null;
}
}
}

public interface ITestPhysics
{
float speed
{
get;
}
}
public class TestPhysicsObj:TestObject,ITestPhysics
{

public TestPhysicsObj(TestObject obj):base(obj)
{
}
#region ITestPhysics Members

public float speed
{
get
{
return 100;
}
}

#endregion
}

public interface ITestScriptable
{
string script
{
get;
}
}
public class TestScriptableObj:TestObject,ITestScriptable
{

public TestScriptableObj(TestObject obj):base(obj)
{
}

#region ITestScriptable Members

public string script
{
get
{
// TODO: Add TestScriptableObj.script getter implementation
return "hi";
}
}

#endregion

}

}


...........
...........
...........


TestObject x = new TestPhysicsObj(null);
x = new TestScriptableObj(x);

ITestPhysics y = ( ( x.GetService( typeof(ITestPhysics) ) ) as ITestPhysics );
ITestScriptable w = ( ( x.GetService( typeof(ITestScriptable) ) ) as ITestScriptable );

Print(y.speed.ToString());
Print(w.script);

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!