Not logged in, Join Here! or Log In Below:  
 
News Articles Search    
 

 Home / Game Design & Programming / Game entities question Account Manager
 
Archive Notice: This thread is old and no longer active. It is here for reference purposes. This thread was created on an older version of the flipcode forums, before the site closed in 2005. Please keep that in mind as you view this thread, as many of the topics and opinions may be outdated.
 
LustDeville

February 27, 2005, 06:33 AM

Hello everyone, I was thinking quite a while on this problem, but could not figure it out!
It is all about entities in a game: monsters, pickup items, static objects, etc., how to realize them in C++? I really hesitated about using inheritance, so i created a
CEntityData class, which contained position, move vector, entity ID, and instead of using inheritance, i instanced it in every other class that would use it: CNPC, CPlayer, CItem...
And, for the game editor's saving-to-file purposes, a lightweight class was created, weirdly named entity_t, which contatined the only properties that are static and not generated, no IDs, FSM and so on. One of my university techers proposed that inhertiance should be used, in order to absract the monsters from the engine, or as he said: "The engine should not know what monster has called some method". I am in a hole right now, and any help is appreciated. The game I intend to create is an FPS.

 
Jari Komppa

February 27, 2005, 06:44 AM

There are many ways of doing what you want, but here's one suggestion.

What's common with all the entities? Position, orientation, collision volume.

- A mine is an entity which explodes and causes damage when collided with.
- A pickup is an entity which gives the player something (health, ammo, etc) when a player collides with it. It ignores collisions with non-players.
- A grenade is an entity which moves based on physics in the game world, and, upon timeout, blows up, causing damage to entities within range.
- A monster is an entity which knows how to move, is affected by physics, and can shoot and spawn grenades and mines.
- A player is an entity which is controlled by the player's input, is affected by physics and can shoot and spawn grenades and mines.

So,
entity
->collisionTriggerEntity
->->mine
->->pickup
->character
->->monster
->->player

On the other hand, a pickup might be a monster which simply decides not to move, etc..

 
Scoot

February 27, 2005, 08:07 AM

I think your teacher is basically trying to make you understand the difference between a *game* and an *engine*.

Typically an engine can be reused for *any* (unlikely) type of game, so it should not contain any game-specific features - e.g. monsters, weapons etc.

These objects should be added as an extra layer on top of your engine, each one inheriting from its base functionality, in much the way that Jari has explained above.

The important point to keep in mind is that while your game can communicate and *see* your engine (through its inherited parents), your engine should not really have any knowledge of the game-specific layer above.

Hmmm... not sure if I explained that very well, but I did my best...
-Scoot

 
LustDeville

February 27, 2005, 08:56 AM

I am indeed happy to understand one very simple, in fact straightforward concept: "What is"! What is a grenade, a mine, a door, etc... :) You opened my eyes, thank you!!! Another question is if the messages, or events that are happening are also two categories: game-specific and engine-specific. And I obviously have a difficulty separating game from engine. I can tell why: for example player pressed '2' key, which changes from current weapon to the second one. The change of skins should happen when the animation of "holster current weapon" is over. Here I stuck in the mud. Animation shoud be part of the "engine" and weapons part of the "game", should they? How will the engine send a message to something it doesn't "know" about? Most of all, changing of skins is not a common functionality of all entities, or am i wrong?
Hope you can give me some enlightment.

 
LustDeville

February 27, 2005, 09:01 AM

One more thing I doubt about: For example, when some explosion(visual) has to happen, the engine must be able to render it. So, I suppose that engine should support it, and render through the basic funcionality data, no matter how deep in the entity hierarchy is the caller???

 
Scoot

February 27, 2005, 11:42 AM

OK, I see an example is in order - you asked that if the engine needs to control game-specific elements, how can it accomplish this if it has no knowledge of the game built upon its foundation functionality?

Inheritance solves this problem for you, using virtual function calls and polymorphism.

e.g:
You may have a base class in your *engine* called, say engineInputObject. This object is added to some list held in your engine. Whenever an input event occurs, the event is routed through to all engineInputObjects with, say a handleInputEvent() function (passed an object describing the event). Inside this function the object will react to the input event (be it key press or mouse movement, etc).

Thats all well and good. Now in your game-specific code, whenever you want to make an object react to an input event, you simply inherit from engineInputObject, and overload the handleInputEvent() function. Now when an input event occurs, the messages will be routed to the *overloaded* function, and your game-specific object can react to an input event.

Woefully inadequate example:

  1.  
  2. //input object class...
  3. class engineInputObject
  4. {
  5. public:
  6.    //make this a pure virtual function to aid debugging...
  7.    virtual void handleInputEvent( engineInputEvent &inEvent ) = 0;
  8. }
  9.  
  10. //character class needs to react to input...
  11. class gameCharacter : public engineInputObject
  12. {
  13. public:
  14.    //the overloaded function...
  15.    virtual void handleInputEvent( engineInputEvent &inEvent );
  16. }
  17.  


Now the engine need only store a list of engineInputObject's, and call handleInputEvent on them, the magic of inheritance will do the rest (pah).

The same technique can be expanded to all of your game and engine related classes... possibly :o)

-Scoot

 
Reedbeta

February 27, 2005, 02:44 PM

Scoot answered part of your question, about event handling, but not the part about skin changes. So you're basically wondering: playing an animation is the engine's business, but how will the engine know that it has to do something (change the skin) after the animation has finished?

The answer is interfaces. Your engine will provide an interface to the game - that is just a set of fuctions that the game can call to make the engine do things. For instance, you might have a function in the engine called PlayAnimation() that the game calls to start the holster anim, and another function, let's say SetSkin(), that the game calls to change the skin of the weapon model. So now the engine doesn't need to know that it has to do something after the animation has finished. Only the game needs to be able to know when the animation is finished, so that the game can then call SetSkin() at that point. You could do this in several different ways, for example having an event routing system and let the finishing of the animation be an event, or the engine could provide a function IsAnimationFinished() that the game layer would call every frame.

Your engine will probably have to know that entities exist - but it won't know the specifics of any particular entity, and it won't ever know what a given entity wants to do, except through that entity calls a function in the engine's interface, either to tell the engine to do something or ask the engine for information about something.

 
Scoot

February 27, 2005, 05:49 PM

I still think you should try to completely divorce your engine from game code. The animation and skinning part can all be accomplished using inheritance in much the same way as the input-handling mechanism i explained earlier...

Your engine could define - for instance - an engineAnimationObject class. This class will contain functions for setting the current skin, the current animation, and define functions for signalling when an animation has completed.

Another crap example:

  1.  
  2.  
  3. //class to support an animatable object
  4. //NOTE: this will have to be extended further to actually
  5. //include the geometry and animation...
  6.  
  7. enum engineAnimationState { engineAnimState_started,
  8.                             engineAnimState_finished  };
  9.  
  10. class engineAnimationObject
  11. {
  12. public:
  13.    //set the current anim...
  14.    virtual void setAnimation(...) = 0;
  15.  
  16.    //set the current geometry...
  17.    virtual void setSkin(...) = 0;
  18.  
  19.    //function called by engineAnimationObject
  20.    //once current anim has completed...
  21.    virtual void animationStateChange(engineAnimationState nState) = 0;
  22. }
  23.  
  24. //inherited class gains functionality from the base parent...
  25. class gameCharacter : public engineAnimationObject
  26. {
  27. public:
  28.  
  29.    //overload this function to react to animation state changes...
  30.    virtual void animationStateChange(engineAnimationState nState);
  31. }
  32.  
  33.  


NOTE: all of the base functions are fully overridable to produce totally different behaviour in more advanced objects.

I hope you can see how this base object can be extended to support any type of geometry and animation data, and can then be further extended to react to events signalled by the base objects (in much the same way as my previous post). In this way your engine can operate solely on base objects, with the inherent functionality *automatically* called - all with the engine needing no knowledge of the way you have overridden the base objects.

-Scoot

 
LustDeville

March 01, 2005, 04:57 AM

I read "Game entity factory" in GPG3, where a gameCharacter can own a State and Media manager, while you suggest that the character 'is a' animation object... Well, I certainly cannot immediately decide which is more suitable :)
Let's say we have a total of 20 different characters in a game, and only 5 are in the current map/level. Their skins are indexed from 0 to 5 ofcourse,
So you say, that for each entity I load from the map, the engine calls:
pEntity->setSkin( 0 );
pEntity->setAnimation( IDLE );
Hm, your idea is cool :) I was wondering how to let the engine load and bind only the needed skins to characters, and I leaned towards using a hastable for index correction... blah!
Isn't it better if object composition is used instead? An entity 'snapshot' passed as a parameter to the (state and media manager)->Update()?

 
Scoot

March 01, 2005, 08:43 AM

Well i don't really understand your reply - because I would need to know a lot more about your engine construction.

A couple of points though:

The classes I explained above are of course totally incomplete examples.

Character definitions could be loaded into gameCharacterType classes from description files (.txt or your own format) which tell the game/engine which skin resource(s) to use, and maps the correct animation resources to the correct animation states.

Then your map editor simply tells the game which description files to load, and all needed resources are loaded from that. You can then create a gameCharacter object by passing in a gameCharacterType object (and other needed parameters, e.g. position) which will define all of the character's behaviour - animation and otherwise.

 
Brian Legge

March 01, 2005, 10:22 AM

While inheritance is an absolutely valid way to construct your object system, it can make it brittle. I don't have a good concrete example, so here are a few ugly ones:

* What if you want to have a character made out of two models? Sure, one can be the 'character', and the other an attached model, but that feels less unified than if both models were homogenous.

* What if you want to change an object from a model to a sprite/billboard? If billboard and model are different base classes in your hierarchy, this may not be trivial.

Another possibility would be something more like this (shamelessly stealing Scoots example):

  1.  
  2. class Model
  3. {
  4. public:  
  5.     //set the current anim...  
  6.     virtual void setAnimation(...) = 0;  
  7.  
  8.     //set the current geometry...  
  9.     virtual void setSkin(...) = 0;  
  10.  
  11.     //function called by engineAnimationObject    
  12.     //once current anim has  completed...  
  13.     virtual void animationStateChange(engineAnimationState nState) = 0;
  14. };
  15.  
  16. class IModelUser
  17. {
  18.     //overload this function to react to animation state changes...  
  19.     virtual  void animationStateChange(Model*, engineAnimationState ) = 0;
  20. };
  21.  
  22. class gameCharacter : public IModelUser
  23. {
  24. public:
  25.     // React to a animation state change
  26.     virtual  void animationStateChange(Model*, engineAnimationState );
  27.  
  28. private:
  29.     Model m_Model;
  30. };
  31.  


Again, this is a pretty incomplete example, but here your Character isn't locked into a single representation. It can do whatever it wants, as the gameCharacter is the 'controller' of any engine supplied functionality that exists.

Inheritance is certainly an okay starting place; if your hierarchy is likely to stay shallow, it may work very well. In my experience, the deeper a hierarchy gets and the more problematic it can be.

 
theAntiELVIS

March 01, 2005, 01:52 PM

In reality it is very difficlut to COMPLETELY separate the engine from the game. So you must decide on general things vs. specific things.

ENGINE: ANY weapon that "shoots"

GAME: rifle, machine gun, laser gun, etc.

ENGINE: ANY weapon you "throw"

GAME: gas grenade, fire grenade, knife, rock, etc.

ENGINE: ANY entity that can move and animate

GAME: player model, monster model, etc.

The engine should provide generic handling of types of things, without needing specifics about what the thing is. The game should provide the specifics: media (meshes, textures, animation, sounds) and behavior (projectile, ray, bouncing object, etc.).

This is why scripting has become such a big deal, to separate the game-specific stuff out of the engine. The engine knows how to use the script, and operate based on what the script tells it. But the engine doesn't care what model is used, what sound is used, or what animation is used - it just uses them.

But you don't HAVE to use scripting. You can just design your system with two layers of classes. The "bottom" layer is the engine code, and the "top" layer that drives it is the game code. Design in such a way that you could completely strip out the game layer and put another in its place. The way to do that is to expose interfaces to the engine layer in the game layer. So your game code will create and use instances of engine classes, passing pointers of game-specific objects into them.

 
LustDeville

March 10, 2005, 07:51 AM

I was off the discussion so I could read and exeriment, and I got to some ideas.
1. A game session should be clearly declared
2. There must be lists of necessary visual elements like sprites and skins
3. These lists must be maintained by a media manager, initialized each time a gamesession is started.
4. Each entity is best to have a "snapshot", which is also based on the abstract interface + inheritance scheme. This way an entity may use sprites skins or billboards without much trouble. A snapshot contains the info needed to make the sprite in a unique visual state (current frame, some fT, current animation)
5. Each sprite/skin/billboard/etc. visual element must be named uniquely, and for this naming I currently use strings.
6. Each entity must have a 'visual item index', which is to be used only by the media manager
7. Engine, MediaManager and GameSessoin must be global variables/singletons to ease usage, and probably ease 'loose-coupling'
8. (I have no timlemented this yet) The logical behavior should be controlled by a LogcalStateManager, or the GameSession itself. That is, each entity should override parts of this logical behavior, some method Think(...) or Decide(...) or HandleInput(...), which the LogicalStateManager calls with the required parameters.
9. Since this all makes the game a layer on top of the engine, the LogicalStateManager and the MediaManager may communicate, providing a way to make a visual change when logical state changes and vice versa.

In case someone understands what I wrote, please give some feedback. I read your posts time by time, and possibly a new idea will come. Just about a day ago I pinced into the part of the LithTech engine, distributed with the "ContractJack" game. Well, I think what I wrote here is used by Monolith, but if I got it wrong, please inform me!

 
Slazer777

March 10, 2005, 09:53 AM

Here is a class I am currently making in c# that addresses the gameentity/gameobject issue.

  1. ::
  2. using System;
  3. using System.Drawing;
  4. using Microsoft.DirectX;
  5. using Microsoft.DirectX.Direct3D;
  6.  
  7.  
  8. namespace TheBattleEngine
  9. {
  10.  
  11. public class GameObject:IDisposable
  12. {
  13.   private Device storedDevice = null;
  14.   private Mesh gameObjectMesh = null;
  15.   private Material gameObjectMaterial;
  16.   private Texture gameObjectTexture=null;
  17.  
  18.                 //Camera information
  19. private static readonly Vector3 CameraPos = new Vector3(0, 20.0f, -85.0f);
  20. private static readonly Vector3 CameraTarget= new Vector3(0, 20, 0);
  21. private static readonly Vector3 CameraUp = new Vector3(0,1.0f,0);
  22.  
  23. //Texture State Names
  24. public static string textureNameAlive;
  25. public static string textureNameDamaged;
  26. public static string textureNameDead;
  27.                
  28.  
  29. //Texture State Enumeration
  30.                
  31. public enum GameObjTextureState
  32. {
  33. alive,damaged,dead
  34. }
  35.  
  36. private GameObjTextureState textstate = GameObjTextureState.alive;
  37. #region GameObjectConstructor
  38.  
  39. public GameObject(string MeshName, string dead, string alive, string damaged, Mesh Msh, Material Mat, Device device)
  40. {
  41.   storedDevice = device;
  42. gameObjectMesh = Msh;
  43. Msh= Mesh.FromFile(BattleEngine.MediaPath + MeshName, MeshFlags.Managed, device);
  44. textureNameAlive = alive;
  45. textureNameDead = dead;
  46. textureNameDamaged= damaged;
  47. CreateTexture(device);
  48. gameObjectMaterial = Mat;
  49. Mat = new Material();
  50. Mat.Diffuse = Mat.Ambient = Color.White;
  51. }
  52. #endregion //GameObjectConstructor
  53. #region CreateTexture
  54. private void CreateTexture(Device device)
  55. {
  56.  if (gameObjectTexture !=null)
  57.  {
  58.   gameObjectTexture.Dispose();
  59.  }
  60. gameObjectTexture = GetTextureFromFileState(device, textstate);
  61. }//EndCreateTexture
  62.  
  63. #endregion //CreateTexture
  64. #region GetTextureFromFileState
  65.  
  66. private static string GetTextureFromFileState(Device device, GameObjTextureState state)
  67. {
  68. switch(state)
  69.   {
  70.    case GameObjTextureState.alive:
  71.    return TexturePool.CreateTexture(device, textureNameAlive);
  72.    case GameObjTextureState.dead:
  73.    return TexturePool.CreateTexture(device, textureNameDead);
  74.    case GameObjTextureState.damaged:
  75.    return TexturePool.CreateTexture(device, textureNameDamaged);
  76.    default:
  77.    throw new ArgumentException("Texture Not found");
  78.   }
  79. }
  80.                 #endregion //GetTextureFromFileState
  81.  
  82. #region Draw()
  83. public void Draw(float totalTime)
  84. {
  85. storedDevice.Transform.View = Matrix.LookAtLH(CameraPos,CameraTarget, CameraUp);
  86. storedDevice.Transform.World = Matrix.RotationY totalTime *2);
  87. storedDevice.SetTexture(0,gameObjectTexture);
  88. storedDevice.Material = gameObjectMaterial;
  89. gameObjectMesh.DrawSubset(0);
  90. }
  91. #endregion //Draw()
  92.  
  93. ~GameObject()
  94. {
  95. Dispose();
  96. }
  97.  
  98. #region Dispose
  99. public void Dispose()
  100. {
  101.  GC.SuppressFinalize(this);
  102.  if(gameObjectMesh !=null)
  103.  {
  104.   gameObjectMesh.Dispose();
  105.  }
  106.  
  107.  if(gameObjectTexture !=null)
  108.  {
  109.   gameObjectTexture.Dispose();
  110.  }
  111.  gameObjectMesh = null;
  112.  gameObjectTexture=null;
  113. }
  114. #endregion //Dispose()
  115.  
  116. }
  117. }
  118. ::


As you can see the actual texture that the object in question would use is determined by the texture state enumeration. So if the state of the object in question has changed from Alive, Damaged, or dead it loads the appropriate texture. Of course a lot more code would have to go into control what actually changes the states.

  1. ::
  2. public virtual bool Attack(GameEntity other)
  3. {
  4.  int ws =this.AttackSkill;
  5.  int ds = other.AttackSkill;
  6.  bool HitOutcome = HitChart(DieRoll(6), ws, ds);
  7.  bool WoundOutcome=false;
  8.  if (HitOutcome == true)
  9.  WoundOutcome = WoundChart(6, this.Strength, other.Toughness);
  10.  if(WoundOutcome == true)
  11.  this.KillCount++;
  12.  other.Wounds--;
  13.  if(other.Wounds == 0)
  14.  other.Alive=false;
  15.  if(other.Alive==false)
  16.  other.Dead();
  17.  return WoundOutcome;
  18. }
  19. ::


GameObject could be abstract and GameEntity could inherit the base information from GameObject. GameObject defines base characteristics that any object would require to appear (be rendered) in a game world. Where GameEntity defines the behaviour of a particular type of gameobject in the world.

GameObject(render) -> GameEntity(behavior) -> GameObjectOrc(A Orc)
GameObject(render) -> GameStaticObject(static items) -> GameObjectTree(a tree)

We could go further and make a Class called ORC and have it inherit from
GameEntity -> the Orc class could then define the actual properties of the GameEntity class and possibly override the Methods defined within GameEntity.


Start thinking in terms of Abstraction. If something is a type of something else look at the commom functions/and properties that may be required for commom items, and group these in a class.


Slazer777

 
This thread contains 14 messages.
 
 
Hosting by Solid Eight Studios, maker of PhotoTangler Collage Maker.