Jump to content
  • Advertisement
Sign in to follow this  
Medo Mex

Game Engine World Class Structure

This topic is 1008 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

Hello,

 

I have few classes: GameObject, World, Entity, PointLight, and so on...

 

Every object that can be added in World must inherit from GameObject, so I can do:

World->AddGameObject(...); // I can add entity, light, camera, or anything using this function...

 

Now, I'm trying to understand what is the correct way to handle the list of Game Objects inside World?

 

How do I store objects correctly inside World so I can have each type of objects do it's own job (Entity GameObject will be rendered, Light GameObject will be sent to Pixel Shader, etc...)?

Share this post


Link to post
Share on other sites
Advertisement

The way this is normally done is you have a list of GameObjects and then (in C++) several virtual functions that you call on all objects that implement them at certain times during the frame update.  So you could have Update() and Render() as your starting functions.  You go through your list calling Update() on everything, and then you do it again calling Render().  That's a very basic setup, but most engines do something like that.  Then each object can do whatever it does, assuming that that behavior can be broken up into stuff that can happen in either the update or the render pass.

Share this post


Link to post
Share on other sites

@Alberth: I'm trying to create world class that's easily expandable.

 

I could do different things, but I'm not sure which way is the most efficient.

 

For example: I could create LightingSystem class and create instance for that class inside World, and then add the lights to "class LightingSystem"

 

I could also create vector for each type of class, for example:

class World
{
public:
// ...
// ...
// ...

private:
vector<DirLight*> dirLights;
vector<PointLight*> pointLights;
vector<SpotLight*> spotLights;
vector<Entity*> entities;
vector<Camera*> cameras;
vector<GameObject*> otherGameObjects; // Store all other unknown game objects
// ...
// ...
// ...
};

and add GameObject to the correct vector whenever World->AddGameObject() is called.

 

What is the most efficient approach?

Edited by Medo3337

Share this post


Link to post
Share on other sites

You can't just send Light GameObject to Pixel Shader. Alot depends on the rendering technique you use. For singlepass forward render you first need to find closest lights for each entity to be rendered and 'send' all these lights along with an entity to a shader. For deferred lighting pipeline things are different: opaque objects are rendered in a first pass to G-buffer without lighting, then each light is rendered into accumulation buffer using data from G-buffer and then final fullscreen pass draws to front buffer. As you can see each of these rendering techniques needs information about GameObjects to render. You can have one single 'World' list or hierarchy (google Scene graph) with some type info mechanism. But I dont think it is the best choice.

 

Better approach in my opinion is to separate concepts. You can have Meshes, Lights lists in Render and Entities list in World. And LightGameObject is a composite object containing pointers to light data in the Render and entity data in the World. And Entity data only contains method relative to the world. For example, it might be transformation functions (move, rotate, etc) or (meta-)methods for exposing entity data to the editor.

Edited by Alex Mekhed

Share this post


Link to post
Share on other sites

@Alberth: I'm trying to create world class that's easily expandable.

 

I could do different things, but I'm not sure which way is the most efficient.

 

For example: I could create LightingSystem class and create instance for that class inside World, and then add the lights to "class LightingSystem"

 

I could also create vector for each type of class, for example:

class World
{
public:
// ...
// ...
// ...

private:
vector<DirLight*> dirLights;
vector<PointLight*> pointLights;
vector<SpotLight*> spotLights;
vector<Entity*> entities;
vector<Camera*> cameras;
vector<GameObject*> otherGameObjects; // Store all other unknown game objects
// ...
// ...
// ...
};

and add object to the correct vector whenever World->AddGameObject() is called.

 

What is the most efficient approach?

Why would World contain LightingSystem?

You first need to answer a question: "why do I need to add game objects to the world in a first place?" and you'll figure out what you need to do. Now it looks like you're piling up everything into a single class, which is not good, IMO.

 

P.S.: Your intentions are similar to a scene graph. There is alot of info in the net regarding it pro's and con's. Earlier it was widely used approach, but now scene graph is usually just a transformation graph.

Edited by Alex Mekhed

Share this post


Link to post
Share on other sites

@Alex Mekhed: I looked at some game engines such as Unreal Engine and found that the engine have variety of classes (Actors) that can be added into the world for example:, PointLight, SpotLight, Box, Sphere, Cylinder, BlockingVolume, Camera, etc..., all of them are actors that can be placed in World.

 

I'm trying to accomplish something similar.

Share this post


Link to post
Share on other sites

@Alberth: I'm trying to create world class that's easily expandable.
How are you going to expand into my Foo class which has great functionality, but your engine doesn't know?

 

You can't just expand functionality without hooking new support for it into the engine. At that point, you can also add a way to say to the engine "this is a Foo thing", eg by adding a "addFoo" method or so.

Share this post


Link to post
Share on other sites

@Alex Mekhed: I looked at some game engines such as Unreal Engine and found that the engine have variety of classes (Actors) that can be added into the world for example:, PointLight, SpotLight, Box, Sphere, Cylinder, BlockingVolume, Camera, etc..., all of them are actors that can be placed in World.

 

I'm trying to accomplish something similar.

I would treat the world class as a metadata of game entities while the real processing of game entities would be done elsewhere. Somethings like this:

void CreateLight()
{
   Light *light = Light::Create();
   GameObject *lightMetadata = CreateLightGameObject(light);
    
   LightingSystem::AddLight(light);
   World::AddGameObject(lightMetadata);
}

class GameObject
{
public:
   virtual void SetProperty(const std::string &name, Property value) = 0;
   virtual Property GetProperty(const std::string &name) = 0; 

   virtual void EnumerateProperties(std::vector<std::string> &properties) = 0; // to be used by editor
   // you can also have some 'baked' methods like SetPosition() for simplicity. 
   // As if the entity is added to the world then it is most probably will have position
   // Even if it is not, it can just ignore the calls to SetPosition()
   // Additionally you can add some functions for type inference
};

class LightGameObject : public GameObject
{
    Light *m_light; 
public:
    ...
};

LightGameObject::SetProperty(const std::string &name, float value)
{
   if (name.compare("color") == 0) m_light->color = value; 
   // or map m_lights members to strings in constructor:
   // m_properties["color"] = Property<float>(&m_light->color);
   // and use it here like this: 
   // return m_properties[name];
   ...
}

Similar to binding your classes to external script engine (Lua, for example).

 

It makes sense to do World class like this if you intend to use it with somekind of editor. Otherwise you can just have GameObject base class and other classes inheriting it.

class GameObject
{
    int m_type;
public:

    int GetType();
};

...

GameObject *object = World->GetObjectByName("my light");
if (object->GetType() == GameObjectTypes::Light)
{
   LightGameObject *light = (LightGameObject*)object;
}

But I would still process objects in a place they belong. That is you create light as in CreateLight function.

 

P.S.: Actually, second approach can be used with an editor too and is easier for small engines.

Edited by Alex Mekhed

Share this post


Link to post
Share on other sites

On a side note. Depending on the complexity of your worlds, it might also be worth while to split the world up into "Scenes". These scenes will primarily be responsible in creating a few different things, with an interface to talk to other scenes.

A. Your game world in it's own right is just one big scene where all it's logic happens here, and only here.
B. Your UI is a scene with an orthographic graphic camera. It relies on it's own logic to maintain it's self, but it's dependent on the data in the main world scene, and it's capable of sending back event data.

C. Your main world might need different methods to optimally handle scenes of X type.

 

For example, an outside world needs to be able to handle everything outside. This includes lighting from the sun. Updating the skybox's vertex colors. Paging terrain. A Quadtree or Octree to help with culling. Etc.

 

While an indoors scene might need methods to handle rooms and large corridors. In this case, a basic portal system... or just frustum culling and occludes. You don't need logic for terrain rendering. you might not need a skybox, and you certainly won't need a camera to render massive distances.

The scenes will have similar interfaces and methods when it comes to it's publicaly known API. But other wise, it will simply do all of it's work internally.

But the main take away here is that the scenes are to separate logical entities. If everything is stored in one big heap, some algorithms might test against something that it generally shouldn't. Rayman actually did something like this, where it was a multi layered 2D level. AI in the back layers continued doing their things, and generally ignored Rayman till he jumped back to their layer.

 

My current project is also doing something like this, to allow AI units to pathfind on surfaces that are moving.

Edited by Tangletail

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!