Game Architecture/Design Pattern?

Started by
16 comments, last by ApochPiQ 11 years ago

Hello,

I want to know if there are any game architectures that are recommended, well, actually I don't know if I can call them architectures or design patterns.

Basically what I want to know is how do you structure your games at a logical for example I tend to the following.

I create an object named GameMaster, this object controls the game (enemies, ambient, etc) and knows the state of everything in the game, the control is done through Managers, for example EnemieManager, AmbientManager, etc. This managers don't communicate directly, the communication has to go throught the GameMaster.

In a more plactical way say we have the following:


class GameMaster
{
	Player player;
	EnemyManager enemyManager;
	GameStatus status;

	void update()
	{
		if(enemyManager.enemies == 0)
		{
			status = GameStatus.EndGame;
		}

		if(status == GameStatus.EndGame)
		{
			player.stopInteraction();
		}
	}

	void draw()
	{
		drawString(status);
	}
}

Sure, the managers can also have control of a few elements... what I see in some friends code is more like...


class Player
{
	GameStatus status;

	void update()
	{
		if(status == GameStatus.EndGame)
		{
			player.stopInteraction();
		}
	}
        
        void draw()
        {
                drawString(status);
        }
}

class EnemiesManager
{
	Player player;
	int enemies; 

	void update()
	{
		if(enemies == 0)
		{
			player.status = GameStatus.EndGame;
		}
	}
}

So my doubt are, what is better? what is worse? are there any architecture/patterns for structuring the objects in the videogames?.

I follow the GameMaster pattern because it's easier to me to structure things like this, but maybe this is not the best pattern...

Any literature on the topic is appreaciated wub.png

Advertisement
I like this book:

http://www.gameenginebook.com/

There's a link to a sample chapter at the bottom which is quite interesting.
The more general you can make the core of your game the more flexible it will be. Also, you should try to minimize what certain classes know about each other. For small game projects this usually wont become an issue but as a game grows if your design has problems it will become very difficult to if you want to do something that Let me just point out a couple of things that I would reconsider in your design.

First, when I think of design and what objects know about each other, I like to think of it as a tree. Objects only know about their branches, but branches shouldn't know what object is their parent nor should they know about their sibling branches. This cannot be the case all the time but try to follow this as much as you can. So you may have a game manager class that knows about the enemies and the player but the they don't know about the game manager class nor do they know about each other.

Keeping that in mind your end game logic is handled in your enemy manager. Keep that logic in the game class. I would add a method to the EnemyManager that checks to see if all enemies are dead and returns a boolean instead of having the game manager check the integer value directly. Classes should not know about the internal workings of each other. They shouldn't access data members directly, instead they should interact through method calls.

I wouldn't have your enemies know about the player, rather I would create an interface, perhaps you could call it EnemyTarget. Add methods to the EnemyTarget interface such as getting the target location and whatever other information you need from it and have the player implement that interface, then when you create the EnemyManager you can pass it the player class, but the enemies don't know it is the player, they just know it as their target. This adds flexibility to your game and would allow enemies to target other objects, if you later decide you want to do that. Also, avoid the temptation of setting the player state and other data in the player class, rather use the interface to send method calls to the player and have the player handle updating its damage and state, for example.


interface EnemyTarget
{
    Point getPosition();
    void applyDamage(int amount);
    // anything else applicable here
}

class Player implements EnemyTarget
{
    Point getPosition()
    {
        return position;
    }

    void applyDamage(int amount)
    {
        hitPoints -= amount;
        if (hitPoints <= 0)
           status = PlayerStatus.Dead;
    }
}

class EnemiesManager
{
    EnemyTarget target;
}
Also, don't have your player modify the GameStatus, have the player only modify its own status and have the game manager check the player status and have it determine what to do from there. This would make it easier to change the behavior when the player dies.

Another point I would like to make is to separate the code that handles drawing, from code that handles collision detection, from the code that handles the game logic. It appears you are doing a text adventure so this may not directly apply but lets say for example we have a character in our scene. Rather then having that one character class have a draw, update, and collision detection code. Break them up. Create a scene graph where you can add objects you want to draw to it and that part of the code only handles drawing the scene. Then add a collision space where you can add objects for collision detection. Then you create a player class that ties these things together. The player class creates a sprite and inserts it into the scene graph, the player creates a collision shape and adds it to the collision scene. Then whenever you update, you ask the collision space for any contacts the player is making in the scene, update accordingly, then change the position of player in the scene graph and the collision space. The details of this can vary but the important thing is that you have separate parts of code that don't know about each other meaning you could take out that subsystem and have it work independently of the rest of the code.
My current game project Platform RPG

I think what you have is pretty good. However, instead of making your update check specific information about how many enemies there are, I would recommend creating a statically available boolean called shutDown = false; (or an enum for GameState) Then what ever might decide to shut off your game can just call the variable change for it. Your update method won't check each area for reasons to shut down then. Instead it just checks the one value.

But the key issue, is performance vs maintainability. Your engine, 3D rendering, timing handlers, etc... should be performance based. I.e. forgo easier to maintenance architectures for architectures that employ speed. This for instance might be to use arrays instead of dynamic lists, pointers (bark bark) instead of copies and static references instead of lookups. The layers of code that manage logic such as AI, level details, and mob generations would be best in a more manage able code approach. I.e. highly structured code, preferring clearly named abstraction over direct but vague variable references. Also larger separations of object code, to help organize data, instead of compressing more code purpose into one location. Also preferring Dynammic easy to use lists, instead of additional code required for locked array sizes.

I see no problem in having a split in your architectures layout, as long as it is easy to distinguish where one stops and the other begins. If your using an existing engine, like XNA, Unity, DirectX even, then you'll probably want all your code to be a logic oriented architecture (more maintainable)

That being said, I typically create an interface called "IModifier" (having .Modify()) and another called and "IPaintable". (having .Paint(View/Paint Object reference))

Then my main class will have a List<IModifier> Modifiers. My update method does any generic things it needs to, like initializing the mouse coordinate variable, or keyboard variables, but then just calls ForEach(IModifier mod in Modifiers) mod.Modify();

And of course having a second loop that removes any objects marked for removal (either another static list, or a flag on each game object to mark them for deletion)

I'll usualyl wrap that code up into a layer to manage its own cleanup.

The IModifable/IPaintable interfaces are a form of an Object Based Decorator Pattern. Which I've found highly useful. I typically create different Lists for managing different sets of objects, like playershots, enemy shots, enemies, stars, etc... Then each object also gets a List inside for all its modifiers. Modifiers would include things like friction, reactToMoustMovement, Gravity, TakeImpactFromEnemyShots, TakeImpactFromPlayerShots, etc... Anytime I create an object, I simply create a generic GameOBject, set the image and position, and other variables, then apply a bunch of decorators to do what ever things it needs to. Makes for something inredibly easy to manage.

I'll also say that I'm sure there are many architectures that can work, I think the key is learning which to apply for your case that won't damage your performance. Don't look for one perfect architecture. Look for options, and figure out in what circumstances each work.

I recommend looking through this to start out: Wikipedia's Software Design Pattern's List (the list is a page or two down, and broken apart a bit)

Moltar - "Do you even know how to use that?"

Space Ghost - “Moltar, I have a giant brain that is able to reduce any complex machine into a simple yes or no answer."

Dan - "Best Description of AI ever."

I "found" another way to look at variables: instead of imagining them as container, I think of them as things that change how my functions behave.

So instead of focusing on making variables accessible, think of them as evil/good things that can influence behavior of your code.

Think of function arguments as a scope for something to happen. Think of different arguments as another scope for something else to happen.

Think of a class as an environment which changes how ALL functions in it behave.

I found that thinking this way helps to keep number of available variables for my code to minimum, because I start thinking more about the reasons I am introducing yet another field for class. Do all functions inside REALLY need to know about it? Maybe passing it as parameter when actually needed is just cleaner.

The main principle one should follow is separation of concerns. Think of controller/view/model - separating concerns of getting data, displaying data, and data itself.

However, design patterns are just ways to organize the code and communicate this organization. Never try to fit something into a design pattern, that often does not work by the book :). Most likely it needs adjustments for your project.

Thank you very mucho for all your comments, I liked the idea on Performance vs Maintainability, also because a lot of the code I do is also read by other team members so it's important to have maintanable code

I'll take a look at the Game Engine book

Until know there's no clear best one, it appears as everyone has different approaches, that's what I am searching, how people create the architecture of the code.

Does anyone has an example on how MVC pattern will work in a videogame? particulary on Unity blink.png

Thank you very mucho for all your comments, I liked the idea on Performance vs Maintainability, also because a lot of the code I do is also read by other team members so it's important to have maintanable code

I'll take a look at the Game Engine book

Until know there's no clear best one, it appears as everyone has different approaches, that's what I am searching, how people create the architecture of the code.

Does anyone has an example on how MVC pattern will work in a videogame? particulary on Unity blink.png

No idea about unity, but:

- You can think about your game state Update function as Controller.

- You can think of your Draw as View.

- You can think of your game objects as Model.

The main point here is to never Draw from Controller or Model, never Update game state from View, keeping game-state related things only in Model.

Separation of Concerns.

You can think about your game state Update function as Controller.

Update functions, and components in general in most cases.

Does anyone has an example on how MVC pattern will work in a videogame? particulary on Unity

The MVC pattern is good for games, but I tend to find a stronger blur between Model and Controller. Separating the code is good, and I'll do that in most things I do, but I'm not going to let MVC stand as a permanent requirement, when sometimes it just makes more sense to have some data and logic floating intermingled for performance needs. I.e. if you keep the MVC model, would typically require an impact controller to loop through all the game objects for collisions with particular objects. But then you also have Momentum controllers, AI controllers, gravity controllers, etc... Each one needing to loop through your gameobject list to make changes. Or, you could blur the Model-Controller, and add an update function to the game object that takes care of all the same logic, but this structure requires only one loop through the game objects.

MVC is good, but games some times need more efficiency.

(I should include that I certainly think MVC is possible in game development, and that it can be done elegantly in many situations. For a web app or forms app, I will typically impliment MVC, MVVM or a similar model. For games, while while still defaulting to MVC, I just don't lock myself to it. I don't step away from it without good reason either)

Moltar - "Do you even know how to use that?"

Space Ghost - “Moltar, I have a giant brain that is able to reduce any complex machine into a simple yes or no answer."

Dan - "Best Description of AI ever."

- You can think about your game state Update function as Controller.
- You can think of your Draw as View.
- You can think of your game objects as Model.

I agree, but maybe with a little twist:

- The Controller handles all input from keyboard, mouse, timers and OS signals.

- The Model knows about the game state and all objects in it. It is not real-time. It has input functions called by the Controller that will trig actions and update the time.

- The View asks the Model about its state, and draws it accordingly. The View will also take orders from the Controller, e.g. toggling between first person and third person or showing/disabling a chat window.

[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

The Controller handles all input from keyboard, mouse, timers and OS signals.

Typically the controller is also the place for handling all logic. If you look at the MVC Wiki page, it shows the Controller as manipulating the model.

The Model knows about the game state and all objects in it. It is not real-time. It has input functions called by the Controller that will trig actions and update the time.

'real-time' has to do with the total time it takes for something to get back to the user in a way that they don't perceive a lag between their interactions and what they see, including all model changes. I can't think of a game where the MVC as a whole is not in real time, unless your talking about a save/load button, or the start of a level. But typically once going, the model/controller/view all act as one real-time responsive unit.

The View asks the Model about its state, and draws it accordingly. The View will also take orders from the Controller, e.g. toggling between first person and third person or showing/disabling a chat window.

Your right about the view asking the model for the state, but typically the toggling between 1st/3rd Person Perspectives would also be stored as model data. You should see the controller as the implementer of change, not as a constant updater of things that aren't changing. I.e. something happens and the controller will change the state, view state being included in the model.

Moltar - "Do you even know how to use that?"

Space Ghost - “Moltar, I have a giant brain that is able to reduce any complex machine into a simple yes or no answer."

Dan - "Best Description of AI ever."

This topic is closed to new replies.

Advertisement