2
\$\begingroup\$

Say i had a Monster class

public class Monster {

}

Now this class has a set of properties like

int health
int speed
int weaponDamage

which details the core information about the monster.

in addition it also needs gui information stored in the model. probably something like this:

int positionX;
int positionY;
int positionZ;
int rotation;

So let's say those are the main properties in our Monster definition. Now we have a couple of methods that do things (besides data getters and setters).

For example:

public void move(){
  //do changes to position.. and rotation variables
}

public void eventIncomingDamage(Projectile p){
  //Incoming projectile did damage to monster
}

public void doDamage(Target aTarget){
  //fire off an damage event on target.
}

So, my question is, how should one go about separating the different data types and methods in such a way it conforms to separation of concerns? Should i have one MonsterController which has the move,eventIncomingDamage and doDamage methods, a Monster class which only has the core information (health,speed,weaponDamage) and what about a MonsterRenderer class (view), how should it fit into all this?

In my example "solution" im thinking along the lines of the MVC pattern. But are there other patterns that should be used in combination or instead?

How would you go about organizing this code into managable and separated blocks?

I hope this can start a good discussion around structuring data, actions and events.

\$\endgroup\$
2

3 Answers 3

5
\$\begingroup\$

Let's stir up the discussion with a somewhat provocative point of view. It's possible for a mind to create abstractions as beautiful as a crystal castle in the sky, and in many games it would be just as useful.

Personally, I found it quite beneficial for game architectures to "flow from below": first think about data, then about feasible limitations of various kinds, and only after that think about ways of manipulating said data, instead of conjuring up some architecture based on a currently opened page of a book about patterns. That way your code will be structured and effective in a way most optimal for your game and your task. Otherwise it is a potential end in a Procrustean bed of patterns and imaginary data. It's not that bad, especially for an enterprise application with a team of fellow developers on an outsorce basis, maybe even for beginner game developer, but we can do better. For an example on a code organization of a very complex game I would recommend looking at "Jagged Alliance 2" sources. It's definitely not the most beautiful thing in the world, but since it's basically naked functions operating on data, it shows a way of game development from times when patterned thought process wasn't a devotion.

Let's say we're developing a pathfinding for a turn-based strategy. In theory it's possible to make the pathfinding architecture ideal and abstract to the point where we can make a RTS instead of a TBS using the same architecture with ease. Do we need to do that? Pathfinding for a single unit of fixed size in a turn-based tactical game with small fixed map has substantially different data from a pathfinding for a lot of units with different sizes and traversal capabilities in real time strategy with dynamic map of large size. So in reality such approach will yield us a slower pathfinding, which will frustrate gamers, with more entities than needed for an actual task, which will frustrate developers, and only a limited ability to be more agile before it would be needed to rewrite a pathfinding engine. So nope, we don't need to design overly complex interactions to support something illusional unless developing a generic game engine or construction set.

Back to the original monster case. The most obvious, clear and blatantly generic way to express intent of moving a monster would be:

 monster.Move(position); 
 // or oif there is a reason for logic extraction, 
 MoveEngine.Move(monster, position).

It's good for a game where you often move single monsters around by hand, i gueess.

But what if our game is about wasps, and they come in numbers, and if even a single wasp comes somewhere, other needs to be notified to come after him soon? And wasps are actually controlled by evil wasp hiveminds competing for power? Moving a single monster would become like a 1% of all move cases; it's counter-productive to guide every wasp manually, and now moving intent expressed like this:

enemyHivemind.CurrentAI.AddNewTask(new ScoutTask(position)); 

Then AI engine will check that swarm can move, has scouts, can find path to the position, and create appropriate move behaviour it the to-do list with the highest priority, which will be executed the nearest update, where it fill finally move that single scout one way or the other, it doesn't matter to us much. Needless to say, all movement routines and pathfinding would be optimized for a swarm movement, not for a single unit.

You see in our mind we started with a generic single monster as a main entity, but with the actual game in mind it quickly can become just a small and insignificant part of something greater, basically a set of data for others to operate on.

So the main point is, think about your data, write a design document first, choose your architecture later, and it will be a good choice whether you decide to use naked objects, MVC, PAC, MVP, SOA, event-driven entity systems or not — in your mind you've already won.

\$\endgroup\$
2
  • \$\begingroup\$ +1, indeed requirement is fundamental, anything else is forcing a design pattern over a data model that is not even there. \$\endgroup\$
    – raine
    Aug 17, 2011 at 18:18
  • \$\begingroup\$ +1 very insightfull! it makes me wonder if bottom-up TDD could be applied to game development. \$\endgroup\$
    – netbrain
    Aug 18, 2011 at 7:36
4
\$\begingroup\$

There is a conceptual misunderstanding in your question. positionX is to the same degree a "core" property as health or speed is. In fact, speed is nothing else than the length of the rate-of-change-vector of the position.

This conceptual wrong distinction leads to a bad design. The update- and the render-logic use the same properties, i.e. position, rotation and even health. health can be rendered as a number above the monster for instance, there is no fundamental difference between those properties.

The entire question is trying to force a design pattern into data rather than the other way around, drawing a line where no such line exists.

How would you go about organizing this code into managable and separated blocks?

This data from your question:

int health
int speed
int weaponDamage
int positionX;
int positionY;
int positionZ;
int rotation;

simply belongs into 1 class. Don't over engineer, don't put unnecessary layers of complexity.

\$\endgroup\$
3
  • \$\begingroup\$ Aye, i see your point. But surely there must be some graphical properties that doesn't belong in this data model?! or maybe there isn't.. i dont know. maybe someone else has experience here? is there any cases where graphical data like positioning should belong to a separata data model? \$\endgroup\$
    – netbrain
    Aug 18, 2011 at 7:43
  • \$\begingroup\$ (I know I'm 2 years late) After reading your answer, I decided to have a single class with all the properties, but make it so the "UI" members (graphics, sounds, etc.) will be populated by a helper outside the class itself. This way, if the engine starts without the graphical client, the only "cost" will be the cost of null references. \$\endgroup\$
    – Tipx
    May 22, 2013 at 17:06
  • \$\begingroup\$ Hey, no worries :) "if the engine starts .." - Which engine? Are you writing an 'engine'? You didnt mention that. - " .. without the graphical client" - Is that a requirement of your game? Is it supposed to start without graphics? \$\endgroup\$ May 22, 2013 at 17:33
1
\$\begingroup\$

One way of doing it:

Each entity consists (as you said) of

  1. EntityModel
  2. EntityRenderData
  3. EntityController

To process these:

  1. Have a GameController class which runs all core logic by running through every EntityController on each update.
  2. Have a GameView class which extracts necessary rendering information from each EntityRenderData

(For both of the above, you can add custom logic that runs aside from entity processing.)

You can also have a GameModel which holds your "current" entity list, your "just added" entity list and your "to remove" entity list. You update your "current" list at the end of each Controller update by removing those "to remove" and adding those "to add". It can further add more general world data that doesn't specifically apply to entities, if necessary.

As an aside, you can have your GameController and your GameView on the same or separate timers in order to update. Separate is good if you want to decouple view updates from logical updates as suggested by Gaffer.

You'll obviously need to use dependency injection at the appropriate times to ensure everything has a reference to everything else (V->M, C->M, C->V) at both the Game and Entity levels.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .