How to organize your code and design your system

Started by
6 comments, last by Madolite 9 years, 8 months ago

I've taken the advices here some months ago and learned how to make simple games (pong, mario, tanks, flappy bird etc). And now I'm starting to make game that are closer to my goal (I want to make tactic games).

So I started by making a board game, Krogmaster. I know how it should be because the author of the game already have an online version running on their official website. The rules are also very simple and logical. I thought I can make it now.

But when I make it I found out that it is hundreds folds more complex than arcade games. Particularly I don't know how to design my system. I spends a week banging into dead ends before I realized I was merging my logic code with display's in the same file. But when I tried to system-ize my code I realize also I don't know how a game should be organized. I lack the knowledge to divide this game into smaller modules.

I only have experience with developing MVC web sites. But when I try to convert what I know from websites to games it doesn't seems to fit. For example for website, each page/service is a module but this game only have one map. It's puzzling me to no end.

I don't know if what I'm lacking is software design in general, or do games have a trending design process like MVC for websites and I should just learn it for starter (or am I just stupid?)

The game making tutorials I found are always small games so I didn't find anything helpful either. Could anyone help me? A book I might need to read? A name? I already spend a year self-learning, reading several more books is no problem at all so please don't hold back your ideas.

Thank you in advance!

Advertisement

I think you have to be more specific with your problem.

My tipp would be to divide your project into easier subproblems that you solve one at a time.

If it's a board game you could first start by thinking about the data structure that represents the board, special fields, opponents and so on.

And seperately you could implement some functions that render that strucutre to the screen. First with simple graphics, maybe just differently colored squares or similar.

You would also need user interaction that modifies the board data structure and gamelogic functions that use that data to advance the game progress.

From there you will slowly build your game engine just as an accumulation of the necessary functions.

I think my problem lies in spliting them logically.

I usually find overlapping or ambiguous place. Like, when I want to move a character on the map, logically it should be a function in the game engine, which take a character model and move it inside the map model, right? But then it feel like everything else fall into the game engine: changing turn, deciding which action is allowed, calculating damage, etc. and the game engine as I call it ends up being too large, and should be split into smaller parts. So I stuck there, at that point, don't know how do I break that game engine into smaller parts.


I usually find overlapping or ambiguous place. Like, when I want to move a character on the map, logically it should be a function in the game engine, which take a character model and move it inside the map model, right? But then it feel like everything else fall into the game engine: changing turn, deciding which action is allowed, calculating damage, etc. and the game engine as I call it ends up being too large, and should be split into smaller parts. So I stuck there, at that point, don't know how do I break that game engine into smaller parts.

I think you have to ease up your thinking. Why does the game engine have to move the character? In a simple system, why can't the character move itself? Why does it have to be moved inside the map "model"? Can't the "map" just have a list of characters and display them at their position?

Also one very cheap technique for seperating logic, if you feel your game engine is getting too heavy, is to just split it into different classes that you compose the game engine of


class GameEngine
{
	// theres like 50 of these
	void DoPhysicsStuff(void);
	
	// another 30 of those
	void DoRenderStuff(void);
}


class PhysicsModule
{
	// theres your 50 physics-methods
	void DoStuff(void);
}

class RenderModule
{
	// here are the 30 render methods
	void DoStuff(void);
}


// now you can compose the engine:

class GameEngine
{
private:
		
	PhysicsModule physics;
	RenderModule render;
}

The engine class in this example can still handle all the connections, like passing the world-state to the renderer & physics-module, but at least now its logically seperated. In case you have been using the GameEngine-class in your other code to call specific methods, you can now make getter-functions for the different modules. Then you can do this:


// thats how it would have looked like

void PhysicsDebugDisplay(GameEngine& engine)
{
        auto& vBodies = engine.GetBodies();

        // ...
}

PhysicsDebugDisplay(engine);

// thats how you can change it

void PhysicsDebugDisplay(PhysicsModule& physics)
{
      auto& vBodies = phyics.GetBodies();

      // ...
}


auto& physics = engine.GetPhysics();
PhysicsDebugDisplay(physics);

Now you can write your code depending only on the modules, not the whole engine. If you ever remove the engine or find a better structure, this code will go unnotified of.

Learning good design comes in part by trail and error. You find out what works and what doesn't. A few tips to help you out though.

Each class should only do one thing. Other classes should not need to know the inner workings of another class to use it. As an example below, say there is a class, Foo, where every time you assign fooBar you should incriment bar


////////////////////////
// The wrong way to do it
class Foo
{
    public int bar = 0;
    public int fooBar = 0;
}

Foo foo = new Foo();

++foo.bar;
foo.fooBar = x;

////////////////////////
// The better way to do it
class Foo
{
   private int bar = 0;
   private int fooBar = 0;

   public void SetFooBar(int value)
   {
        ++bar;
        fooBar = value;
   }
}

Foo foo = new Foo();
foo.SetFooBar(x);

If you find that you are repeating the same lines of code over and over again try to find a way to make a method out of it and make that method part of a class where it makes the most sense, the method should work with either members of the class or parameters passed to the method. Do not use global variables or singletons. Global constants are good though, they help you avoid magic numbers.

Only use inheritance when you need polymorphism. If you just need the functionality of another class just make it use the other class


////////////////////////
// Bad
class Foo extends Array
{

}

Foo foo = new Foo();
foo.Add(item);

//////////////////////
// Better
class Foo
{
    private Array array;
    void Add(Item item)
    {
        array.Add(item);
    }
}

If any single function gets long split it up into smaller functions where each function does one well defined thing and the original function uses these small functions. This practice when done right will also help your reduce duplicate code. The same goes for large classes. If you have a large class, split up the functionality. There is no exact value for what is too long, but when a functions is over 50 lines of code you should consider breaking it up. If a class is approaching a few hundred lines of code, you should break it up.


/////////////////////////
// Bad
void Update(float timeStep)
{
  // update position 
  position.x = position.x + velocity.x * timeStep;  position.y = position.y + velocity.y * timeStep;
  velocity.x = velocity.x + acceleration.x * timeStep;  velocity.y = velocity.y + acceleration.y * timeStep;

  if (doesCollide(world))
  {
     // collision code
  }

  // update AI
}

////////////////////////////
// Better
Point Add(Point a, Point b)
{
    return new Point(a.x + b.x, a.y + b.y)
}

Point Scale(Point a, float b)
{
   return new Point(a.x * b, a.y * b);
}

void UpdatePhysics(float timeStep)
{
  position = Add(position, Scale(velocity, timeStep));
  velocity = Add(velocity, Scale(acceleration, timeStep));
}

void UpdateCollision(float timeStep)
{ 
  if (doesCollide(world))
  {
     // collision code
  }
}

void UpdateAI(float timeStep)
{
  // update AI
}

void Update(float timeStep)
{
  UpdatePhysics(timeStep);
  UpdateCollision(timeStep);
  UpdateAI(timeStep);
}

I am going to stop there for now before I turn this into an article, but hopefully this is useful to you.

EDIT:

I would also suggest looking at Unity to see how they use a component based system. It by no means is the only way to organize a game, but it is a good example of how to solve the problem, it definitely isn't an easy one to solve.

My current game project Platform RPG

Thank you both. Those are very interesting example you made there. I... kind of get it, but kind of not really get it. It hard to say yet if I understand correctly your points.

I guess I will have to sit down and draw some more blocks before I can clearly figure out if I can exhaustively break my game into logically-loosely-coupled chunks or not.

What I'm scared of most is making a huge mess. In the small games I made, the code were well documented and organized, so even now if I look at a game I made last year I can still understand what I was doing. But the code I wrote while making this game look like gibberish runes and I always feel lost scrolling through the files. Hm...


What I'm scared of most is making a huge mess.


Learning good design comes in part by trial and error.

Don't worry. You'll get there. While it makes you scared, the fact that you are actually making mistakes is a good thing, and you shouldn't be afraid of it. Your computer is not going to break if you code something wrong, so what's there to be afraid of?

If you feel your current design is wrong, then you should re-do it over and over again until it feels right. That's what "trial and error" means. If you think your code is a mess, that might only because this is YOUR code. With the simple games, you got used to having everything wrapped in a neat little package, mostly probably because everything was already explained to you. Now it's time you let go of that and focus on your own code, especially on providing your own explanation for what the code does. If you can't remember things, you should write a lot of comments in your code, explaining things in your own words (you can even use swear words if something doesn't look right - don't worry, nobody's going to read them smile.png - advanced programmers do this a lot, actually).

(Deleted post)

This topic is closed to new replies.

Advertisement