bookmark_borderD2TM Rewrite – Development Blog – Drawing stuff on the screen

In the previous post I have set up a raw architecture for the game. There is a Game class that has a function called execute, which allows basic stuff to happen:

– responding to events
– updating state
– and rendering state

In code it is:

while (running) {
	handleEvents();
	update();
	render();
}

The end result of the first phase was, well, a black window. Nothing to be excited about just yet…

One of the very basic needs is drawing on the screen. One way to get something on the screen is by using something called blitting. Blitting is basically taking a picture in memory (called in SDL a surface, or in Allegro a BITMAP) and then copy it onto another surface which functions as the screen.

We already have this screen SDL Surface defined in our Game class. It is not the actual (hardware) screen buffer. But, by doing SDL_Flip we can make this screen visible.

In essense this means the render function will be like this:

void Game::render() {
// draw some stuff on the screen
// flip screen at the end
SDL_Flip(screen); 
}

I want to be able to draw surfaces on the screen. SDL requires the usage of SDL_Rect‘s which allows you to draw pieces of surfaces. At this point I don’t want deal with these SDL_Rect’s directly. What i want is:

  draw (source surface, dest surface, int x, int y);

This is where I introduce a new class (again Single Responsibility Principle) that allows drawing on the screen and providing easy methods to do so. I call this the surfaceDrawer. At this point in time, its class definition looks like this:

#ifndef SURFACEDRAWER_H
#define SURFACEDRAWER_H

#include <SDL/SDL.h>

class SurfaceDrawer {

	public:
		void draw(SDL_Surface * from, SDL_Surface * dest, int x, int y);
		
	
};

#endif

The implementation looks like this:

#include "surfacedrawer.h"


void SurfaceDrawer::draw(SDL_Surface * from, SDL_Surface * dest, int x, int y) {
	if(from == NULL || dest == NULL) {
		return;
	}

	SDL_Rect rect;
	rect.x = x;
	rect.y = y;

	SDL_BlitSurface(from, NULL, dest, &rect);
}

This implementation is easy; the SDL_BlitSurface accepts:
– a from surface
– a from rectangle (ie, what to copy from the from surface?, NULL = everything)
– a destination surface
– a position given by a rect. (where to draw this? Starting with upperleft corner of from surface)

In this case, we provide NULL as 2nd argument, saying we want to copy the entire from surface. Then, the last parameter is the position where to draw it in the form of an SDL_Rect.

Next step is to actually use this function. One thing that we always need in an RTS is to draw the mouse. What we need is an SDL_Surface with a mouse bitmap loaded. I will be using:

Default mouse at 32x32 size, with purple background
Default mouse at 32x32 size, with purple background

Loading this image is done by using SDL_LoadBMP . We need to make sure that the surface we have loaded is in the same bit/color format as our screen. We can do that by using SDL_DisplayFormat. We don’t want to be bothered with this everytime, so we have to make some class responsible for loading resources into SDL_Surface’s which are suitable for drawing by the surfaceDrawer. For that I have introduced a surfaceDao class, which has the following class definition:

#ifndef SURFACEREPO
#define SURFACEREPO

// Data Access Object for fetching SDL Surfaces
#include <SDL/SDL.h>


class SurfaceDao {

	public:
		SDL_Surface * load(char * file);

};

#endif

SDL supports BMP formats out of the box. We need to use the SDL_Image library to get support for other formats. Using a DAO we can move all this format specific stuff out of our game into this single class later. For now I will be using BMP, as the main focus is drawing surfaces.

The implementation of the surfaceDao looks like this:

#include "surfacedao.h"

#include <iostream>

using namespace std;

SDL_Surface * SurfaceDao::load(char * file) {
	SDL_Surface * temp = NULL;
	SDL_Surface * result = NULL;

	if((temp = SDL_LoadBMP(file)) == NULL) {
		cout << "Failed to load [" << file << "]." << endl;
		return NULL;
	}

	result = SDL_DisplayFormat(temp);
	SDL_FreeSurface(temp);

	return result;
}

We load the BMP, when that is succesful, we convert it to the current display format. We have to free the temp surface using SDL_FreeSurface, to prevent memory leaks.

Now, in the Game class, this all comes together, first the class definition is expanded and gets (at the private section) the following code:

#ifndef GAME_H
#define GAME_H

#include <SDL/SDL.h>

#include "surfacedao.h"
#include "surfacedrawer.h"

class Game {

	.. snip ..

	private:
	.. snip ..		
		
		SDL_Surface * mouse;

	// Dependencies
		SurfaceDao surfaceDao;
		SurfaceDrawer surfaceDrawer;

};

#endif

As you can see, I already have prepared the SDL_Surface for the mouse. Now in the Game implementation, loading the mouse is using the surfaceDao:

int Game::init() {
	... snip ...

	// load resources
	mouse = surfaceDao.load("resources/images/MS_Normal.bmp");

	return 0;
}

In the render function I use the surfaceDrawer to draw the mouse at the current X and Y position of the mouse:


void Game::render() {
	int mouseX, mouseY;
	SDL_GetMouseState(&mouseX, &mouseY); 

	surfaceDrawer.draw(mouse, screen, mouseX, mouseY);

	// flip screen at the end
	SDL_Flip(screen); 
}

This all finally results into:

Drawing the mouse! Isn't that cute.
Drawing the mouse! Isn't that cute.

Finally, we have something to draw! yay! But we need to make this a little bit better first:
– remove the system cursor (you don’t see this on the picture, but when running this your system cursor is on top)
– make sure we don’t have a trail of the mouse, ie, clean the screen before drawing
– we also see the purple background of the mouse, we don’t want to draw that…

Lets fix these things:

Hide system cursor

int Game::init() {
	... snip ...
	SDL_ShowCursor(0); 

	// load resources
	... snip ...
}

Clean screen before drawing
Add function to the surfaceDrawer

class SurfaceDrawer {

	public:
		... snip ...
		void clearToColor(SDL_Surface * target, Uint32 color);

And implement this:

void SurfaceDrawer::clearToColor(SDL_Surface * target, Uint32 color) {
	if (target == NULL) return;
	SDL_FillRect (target, NULL, color); 	
}

Don’t draw the purple background
What we want is to skip a certain color when blitting a surface to another surface. We can do this by specifying a color key. This color will be skipped with drawing. The nice thing about the surfaceDrawer is that all have to do is add a function there to do this and change the call in Game to use the new function:

Add function to the surfaceDrawer

class SurfaceDrawer {

	public:
		... snip ...
		void drawTransparant(SDL_Surface * from, SDL_Surface * to, int x, int y);

One thing to note, in D2TM the assumption is that all colors with RGB: 255,0,255 (purple) will be skipped. That is the reason the surfaceDrawer does not have a color parameter. We could add this if it is needed later on.

Implementation:


void SurfaceDrawer::drawTransparant(SDL_Surface * from, SDL_Surface * dest, int x, int y) {
 	Uint32 colorkey = SDL_MapRGB(from->format, 255, 0, 255);
    SDL_SetColorKey(from, SDL_SRCCOLORKEY, colorkey);
    draw(from, dest, x, y);
    SDL_SetColorKey(from, 0, 0); 
}

The first line actually creates the purple color. The code is not that selfdescribing. Later on I will introduce a Colors class that basically says “give me purple”, and does the SDL_MapRGB in its implementation.

Of course, now in the Game we have to make a few adjustments.

void Game::render() {
	surfaceDrawer.clearToColor(screen, Colors::black(screen));

	int mouseX, mouseY;
	SDL_GetMouseState(&mouseX, &mouseY); 

	surfaceDrawer.drawTransparant(mouse, screen, mouseX, mouseY);

	// flip screen at the end
	SDL_Flip(screen); 
}

Two lines are added, first clear the screen to a specific color (black), and then for drawing the mouse we use the new drawTransparant function.

And after compiling, it looks like this:

Drawing a mouse, that leaves no 'trail', and skips the purple color
Drawing a mouse, that leaves no 'trail', and skips the purple color

Next blog post
Although we are able to draw stuff on the screen, it is far from efficient. If we want to draw a terrain we have up to 16 different surfaces for one terrain type (lets say, rocks). It is not doable to hold 16 different SDL_Surface’s and then draw the correct one. Besides, we also have spice, mountains, sand, hills, spicehills. So we need to do something clever. Thats where a tileset comes in. The next blog will be about that.

A side note about including SDL in every header file
One thing you’ll notice about my class definitions, is that I seem to include SDL all the time. Tutorials will say you’ll provide this at the top of your project in your main class (in this case it has to be main.cpp). Although I understand why (since the preprocessor will put the SDL code there, and will be accessible to all other files), it violates the SRP. In fact, you cannot compile a single CPP class anymore using SDL, since you do not refer to this.

As you can see in all my header files, there is a piece:

#ifndef SOMETHING
#define SOMETTHING
 // here is code
#endif

This basically says “whenever I have not yet defined SOMETHING include the piece of code, and define SOMETHING”. This allows us to include the same files over and over again, but we are sure the preprocessor only includes it once. This is needed because else your program will not compile due multiple definitions of the same class.

So now:
– I can compile any CPP file seperately (and, the big plus: I can use that for testing later on! :))
– I know what all my dependencies are, they are not somewhere else hidden

End of side-note

bookmark_borderD2TM Rewrite – Development Blog – SDL initialization & initial game setup

In my previous post I have described a way to compile your project with a Maven style like project structure. Using that as basis I am busy rewriting my project Dune II – The Maker. This time I am using SDL.

Because I have started over I thought of writing blog posts about my progress. Blog posts will be about progress made, decisions taken, etc. This is by no means a real tutorial sequence, but you could follow the blog posts probably and make something out of it. Do note: In reality I am much further in development then my blog posts. The blog posts are based upon older revisions than HEAD. If you are interested in the most recent version you can get the source yourself.

In this blog post I will describe how I have started to setup the project. I already have a directory structure as described in my previous blog post.

My goal is to have a primitive architecture set up, I have used the first SDL tutorial as starting point.

The reason I went with a tutorial is that I wanted to be inspired by a different approach than I have done myself in the past. In fact, I have always just tried to do what I thought what was best. In this case I took the tutorial and from there I will change it how I think it should be. Its never bad to take a fresh look at things 🙂

The very first start was to create a Game class, it has the following class declaration:

#ifndef GAME_H
#define GAME_H

#include <SDL/SDL.h>   /* All SDL App's need this */

class Game {

	public:
		int execute();

	private:
		bool running;

		int init();
		void shutdown();

		void handleEvents();
		void update();
		void render();

		void onEvent(SDL_Event * event);

		SDL_Surface * screen;

};

#endif

The only function that needs to be exposed is the execute method. All other functions are used internally.
The SDL surface screen represents the main display (screen).

The Game class is implemented as follows:

#include "gamerules.h"
#include "game.h"

#include <iostream>

using namespace std;

int Game::init() {
	if((SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)==-1)) {
        	printf("Could not initialize SDL: %s.n", SDL_GetError());
	        return -1;
	}

	screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);
	if ( screen == NULL ) {
		printf("Unable to set 640x480 video: %sn", SDL_GetError());
		return -1;
	}

	return 0;
}

void Game::handleEvents() {
	SDL_Event event;
	while (SDL_PollEvent(&event)) {
		onEvent(&event);
	}
}

void Game::onEvent(SDL_Event * event) {
	if(event->type == SDL_QUIT) {
		running = false;
	}
}

void Game::update() {

}

void Game::render() {

}

void Game::shutdown() {
	SDL_Quit();
}

int Game::execute() {
	if (init() != 0) {
		return -1;
	}

	while (running) {
		handleEvents();
		update();
		render();
	}

	shutdown();

	return 0;
}

The execute function does basically everything. A game loop is in essence very simple. In fact the game is one big loop which does two things:
– update state
– show state

To update state, in this case we have separated two things:
– handle events (in SDL terminology, this means we handle input events. Which can have effect on the game state)
– update (here you actually update the game state)

That still remains updating game state, though a bit more split up. We could later split it into keyboard/mouse states. But, these things all are depended on the certain kind of game state you’re in. A main menu screen should react differently on mouse input than lets say the actual game playing. The current design has not given any direction yet what to do. We could have one big switch statement, but we could also do something better… I’ll come to that in a future blog post.

The init function basically sets up the application. I am not too happy about this in this stage, but for the initial setup it is good enough. I believe the factory pattern should be used for constructing a game object though, so I have already created a class for it. The reason is that i want to respect the Single Responsibility Principle. Constructing a Game object, which requires loading resources, setup SDL, etc, has nothing to do really with the basic Game object itself. In fact, as you will see in later blog posts, the Game object has the only responsibility and that’s calling all the right collaborator classes that make the game what it is.

Since I already know I will be using a factory class I already introduce one which for now does nothing spectacular:

Header:

#ifndef GAMEFACTORY_H
#define GAMEFACTORY_H

#include "game.h"

class GameFactory {

	public:
		Game create();

};

#endif

Implementation:

#include "gamefactory.h"

Game GameFactory::create() {
	Game game;

	// TODO: load resources for game, do SDL initialization, etc.

	return game;
}

Finally the main.cpp which has the entry point of the application:

#include "gamefactory.h"

int main(int argc, char **argv) {
	GameFactory gameFactory;
	Game game = gameFactory.create();
	return game.execute();
}

And thats it! The result is a game that is able to start, it has functions that declare several phases in the game and allows us to expand it further. Because of the factory we can also easily move initialization code out of the Game class.

If you would compile this, and run it, you would see:

A running application

As for developing applications, I believe a certain principle lies behind it. Most of it, you won’t really see. Often, with a few lines of code you can make a lot of stuff happen on the screen. But the actual work is ‘under water’:

bookmark_borderAn example of refactoring

As I have promised in my previous post, I would post an example of small refactorings in order to greatly improve the readability and understandability of code.

I own a little project called Dune II – The Maker, and I started writing it a little over 10 years ago. In those years I have learned a lot. I did not have much time in those days to apply my new knowledge to the project. You could say the software was rotting. In order to make it better I need to refactor a lot and I encounter the best examples to improve code without pointing fingers :). In any case I have experienced you have to make mistakes in order to get better. I hope you will learn from the mistakes I made.

So here is a little example I have just checked in the dune2themaker repository, I’ll give you the before (revision 411) and after (revision 412). Of course, I have taken smaller steps to get to the end result. First the original piece of code:

Revision 411 (before)

void cGame::think_winlose() {
	bool bSucces = false;
	bool bFailed = true;

	// determine if player is still alive
	for (int i = 0; i < MAX_STRUCTURES; i++)
		if (structure[i])
			if (structure[i]->getOwner() == 0) {
				bFailed = false; // no, we are not failing just yet
				break;
			}

	// determine if any unit is found
	if (bFailed) {
		// check if any unit is ours, if not, we have a problem (airborn does not count)
		for (int i = 0; i < MAX_UNITS; i++)
			if (unit[i].isValid())
				if (unit[i].iPlayer == 0) {
					bFailed = false;
					break;
				}
	}

	// win by money quota
	if (iWinQuota > 0) {
		if (player[0].credits >= iWinQuota) {
			// won!
			bSucces = true;
		}
	} else {
		// determine if any player (except sandworm) is dead
		bool bAllDead = true;
		for (int i = 0; i < MAX_STRUCTURES; i++)
			if (structure[i])
				if (structure[i]->getOwner() > 0 && structure[i]->getOwner()
						!= AI_WORM) {
					bAllDead = false;
					break;
				}

		if (bAllDead) {
			// check units now
			for (int i = 0; i < MAX_UNITS; i++)
				if (unit[i].isValid())
					if (unit[i].iPlayer > 0 && unit[i].iPlayer != AI_WORM)
						if (units[unit[i].iType].airborn == false) {
							bAllDead = false;
							break;
						}

		}

		if (bAllDead)
			bSucces = true;

	}

	// On succes...
	if (bSucces) {
		// <snip>

	}

	if (bFailed) {
		// <snip>

	}
}

The intention of the think_winlose() function is to determine if the player has won or lost, and if so it transitions the game state. These transitions have been snipped.

So when does a player win or lose? It depends if there is a ‘win quota’, or not. The win quota is a number, whenever it is above zero it means the player has to collect at least that many of credits (spice) in order to win. If the win quota is not set, the default win rule : destroy everything of the enemy, will be used. (do you notice I need this much text for just a simple rule? Which I could have prevented If I had code that said this in the first place? At the bottom of this post you can see what I mean :))

Lets take a look at the code and point out what could be done better:

  • There are two booleans bSuccess and bFailed. Which is confusing and ambigious. What is succesfull? What did fail? Why aren’t they one boolean?
  • There are comments all over the place, meaning we could refactor these pieces to code so comments are not needed. (Comments are seen as clutter and should be removed)
  • The code formatting could be done better. If statements should start with { and end with }, even with one line.

And there are more things you will probably find yourself. What I’ll do is point out a few things that could be improved. If you just want to see the final result, just take a look below.

Lets start with the booleans bSuccess and bFailed. Why are there two booleans and whey are they called so vaguely? A little bit of searching in the code and we find out that bSuccess actually means “Mission is accomplished” (player has won), and bFailed means the player has no units and structures (which implicates the player has lost the game). They are not the same boolean, because a player could be alive and not have yet won the game of course. Now we know they are not actually the same boolean, but their naming was vague. A simple “rename variable” made things easier to understand!

void cGame::think_winlose() {
	bool bMissionAccomplished = false;
	bool isPlayerAlive= true;

(when posting this I realize the two booleans are named differently, consistency is also important to improve readability, so either both should start with “is” or both with a “b”, I prefer the first though)

Right after the booleans a few for loops are used just to find out if there is anything alive for the player. A little bit below we see such for loops again, but for the AI. This is duplicate code and should be removed. Extracting them into a method and make them return a boolean value is easy to do:

bool cGame::playerHasAnyStructures(int iPlayerId) {
    for (int i = 0; i < MAX_STRUCTURES; i++) {
		if (structure[i]) {
			if (structure[i]->getOwner() == iPlayerId) {
				return true;
			}
		}
	}
    return false;
}

(Again, while posting this I realize this could be even improved a bit more, the iPlayerId should be called ownerId (or the getOwner should be a getPlayerId), so it is obvious we match two of the same kind. Now it could confuse us: is an owner the same as the playerId? Since I know it is, why isn’t it called that way?… :))

Since we extract these for loops we can now set the isPlayerAlive boolean immidiately instead of setting a variable within the loop as it was done in the original example above. Reducing 24 lines into one!:

bool isPlayerAlive = playerHasAnyStructures(HUMAN) || playerHasAnyGroundUnits(HUMAN);

The final result of revision 412 is shown below. It will clearly show the major improvement regarding readability and understandability. Any other developer who comes to this code can see what it does and it is almost a no-brainer.

Result revision 412

void cGame::think_winlose() {
	bool bMissionAccomplished = false;
	bool isPlayerAlive = playerHasAnyStructures(HUMAN) || playerHasAnyGroundUnits(HUMAN);

    if (isWinQuotaSet()) {
		bMissionAccomplished = playerHasMetQuota(HUMAN);
	} else {
		bool isAnyAIPlayerAlive = false;
		for (int i = (HUMAN + 1); i < AI_WORM; i++ ) {
			if (playerHasAnyStructures(i) || playerHasAnyGroundUnits(i)) {
				isAnyAIPlayerAlive = true;
				break;
			}
		}

		bMissionAccomplished = !isAnyAIPlayerAlive;
	}

    if (bMissionAccomplished) {
		// <snip>
		
	} else if (!isPlayerAlive) {
		// <snip>

	}
}

bookmark_borderThe tremendous power of tiny refactorings

More and more I am being intrigued by the power of a small code refactorings. The positive impact it has on the readability, the maintainability and understandability of your code is great. It keeps code clean(er) and since the changes you make are really small (I’ll demonstrate how small), the chance they will break things is small. Of course, with unit tests (you are writing them right?) making sure you did not break anything: a small refactoring is a low-risk high-benefit practice.

In my experience, small refactorings are undervalued. In fact, I undervalued them much myself since not too long ago. They are disregarded as refactorings that don’t help at all, because it is obvious what the code does. However, the flaw in this rationale, as I see it, is that the intended audience is not only you but also the other developer you work with. Also, you know what code does right now. But would you understand it as quickly if you did not look at it for a week and came back? Would another developer understand the code right away?

When working on code, you’re constantly trying to ‘translate’ the code in your mind in order to know what it is doing. Doing this it leads you to where the bugs are or the areas where you need to make changes, etcetera. This process of ‘translating’ code in your mind comes at a price. Literally the energy you need to burn in your brain to grasp the meaning of a piece of code: brainpower; The easier we understand code, the less brainpower we need. The less energy we burn by understanding what is going on, the more energy we have left to create new things, or fix that bug.

I’ve created a little example. The code below represents an implementation of a mail service. The mail service allows you to send an email using a method that uses 4 parameters: to, from, the subject and the message. When all parameters are filled, the email needs to be sent. That is the only requirement for now. Of course, later we might want to validate if the given email adress of from and to are valid. But for the sake of the argument, lets keep it simple. The following code is ‘mind-boggling’, compared to its simple intention:

public class MailServiceImpl implements MailService {

	public void sendMail(String from, String to, String subject, String message) {
		if (from != null && !"".equals(from) &&
			to != null && !"".equals(to) &&
			subject != null && !"".equals(subject) &&
			message != null && !"".equals(subject)) {
			// send the email
		}
	}

}

Basically what this says it that any field may not be null or an empty string. It took 4 lines for just to show. Even though you recognize the pattern of a ‘null or empty check’, it costs you time and energy to make that translation happen. So here is a first suggestion to make it read easier:

public class MailServiceImpl implements MailService {

	public void sendMail(String from, String to, String subject, String message) {
		if (parametersAreNotNullOrEmpty(from, to, subject, message)) {
			// send the email
		}
	}

	private boolean parametersAreNotNullOrEmpty(String from, String to, String subject,
			String message) {
		return from != null && !"".equals(from) &&
			to != null && !"".equals(to) &&
			subject != null && !"".equals(subject) &&
			message != null && !"".equals(subject);
	}

}

When another developer is reading the sendMail method, he will now know that when the parametersAreNotNullOrEmpty the mail will be sent. It does not need any translation, the method name just says what it does! Simple! By doing this, you greatly reduce the needed brainpower to understand what is going on. The refactoring method used is called Extract method.

Reading code is sometimes easy for your brain to handle. Sometimes your brain seems to explode because of the complex statements and context you need to be aware of. It is strongly tied with the Cyclomatic Complexity, the Coupling between Objects (CBO) and the lack of Cohesion in your code. If you are using any tools to measure your code, like Sonar for example, look for these metrics to find code that needs attention. But it is always better to refactor while you have made the translation in your brain, if you see things can be written simpler to reduce the needed brainpower, by all means do so. Not giving software the appropriate attention might let your code rot. Small refactorings help you prevent that.

I hope you have seen a bit of the power of small refactorings. I will get back to them in my future posts as I will post more concrete examples and how I would/have dealt with them. To me, small refactorings need to be part of your system and are introduced when you do TDD. All too often when the code works, it is not looked at again. Making these small refactorings can make a big difference and take relatively no time.