Tag Archives: programming

Arthur’s Grove: Update

So lately I’ve been working a lot with C++ to beef up my skills for possible future employment. Part of this work has involved me going back over Arthur’s Grove (AG) and writing it in an object structure. I’ve also started using Git version control for similar reasons. So the results of the week are as follows:

 

I added a non-hostile bug entity to the world. It walks around randomly and is destroyed in one hit. They are mostly there for amusement and to add to the environment.

I added the ability to sail across the ocean while riding a whale!

I also added the ability to shoot tsunamis across the sea, for future sea combat.

I added a basic worm enemy which will turn up dust in the player’s face. The movement for the worm enemy is a simplistic straight line but more intelligent enemies will come soon.

SDL 2.0 Tutorial-03: Metasprites

So last week we were able to generate a collection of textures and draw them to the screen. In terms of memory this isn’t very efficient. This week we will be creating one texture from a meta SDL_Surface* . This will be my last part of this basic tutorial, if there are any topics you would like discussed please email me at “info@stephenmeier.net”. If you do occasionally read these posts please let me know which posts you find interesting!


/* Stephen's Tutorials (https://stephenmeier.net/)
gcc main.c -o game.exe -I./include -L./lib -lSDL2main -lSDL2
running on gcc 4.8.1, SDL 2.0.1
*/
//----------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>

#include "game.h"

//----------------------------------------------------------------------
int main(int argc, char* argv[]) {

	Game.init();

	int x = Game.screen.w/2-8, y = Game.screen.h/2-8;
	SDL_Rect rect = {0, 0, 8*2, 8*2};

	int i, j;
	int** grid = (int**) malloc(sizeof(int*)*2);
	for(j=0; j<2; j++) {
		grid[j] = (int*) malloc(sizeof(int)*2);
		for(i=0; i<2; i++) {
			grid[j][i] = 2;
		}
	}

	SDL_Texture* spr = Game.gfx.buildSpr(2, 2, grid);

	SDL_Event event;
	while(Game.running) {
		while(SDL_PollEvent(&event)) {
			switch(event.type) {
				case SDL_QUIT: {
					Game.running = SDL_FALSE;
				} break;
			}
		}

		SDL_RenderClear(Game.screen.renderer);

		rect.x = 0+x, rect.y = 0+y;
		Game.screen.drawSpr(spr, &rect);

		SDL_RenderPresent(Game.screen.renderer);
	}

	Game.gfx.destroySpr(spr);

	Game.quit();

	return 0;
}

// Stephen's Tutorials (https://stephenmeier.net/)
//----------------------------------------------------------------------
#ifndef _GAME_H_
#define _GAME_H_

//----------------------------------------------------------------------
#define SCREEN_w 640
#define SCREEN_H 480
#define SCREEN_NAME "Prototype"
#define SCREEN_SCALE 1
#define SDL_MAIN_HANDLED

//----------------------------------------------------------------------
#include "SDL2/SDL.h"

//----------------------------------------------------------------------
void game_init(void);
void game_quit(void);

SDL_Texture* gfx_buildSpr(int w, int h, int** grid);
void gfx_destroySpr(SDL_Texture* spr);

void screen_drawSpr(SDL_Texture* spr, SDL_Rect* rect);

struct {
	// define "attributes"
	SDL_bool running;

	struct {
		unsigned int w;
		unsigned int h;
		const char* name;
		SDL_Window* window;
		SDL_Renderer* renderer;
		void (*drawSpr)(SDL_Texture* spr, SDL_Rect* rect);
	} screen;

	struct {
		unsigned int n;
		SDL_Surface** spritesheet;
		SDL_Texture* (*buildSpr)(int w, int h, int** grid);
		void (*destroySpr)(SDL_Texture* spr);
	} gfx;

	// define "methods"
	void (*init)(void);
	void (*quit)(void);
} Game = {
	SDL_FALSE,
	{
		SCREEN_SCALE*SCREEN_w,
		SCREEN_SCALE*SCREEN_H,
		SCREEN_NAME,
		NULL, NULL,
		screen_drawSpr
	},
	{
		0,
		NULL,
		gfx_buildSpr,
		gfx_destroySpr
	},
	game_init,
	game_quit
};

//----------------------------------------------------------------------
void game_init(void) {
	if(SDL_Init(SDL_INIT_EVERYTHING)!=0) {
		printf("SDL error -> %sn", SDL_GetError());
		exit(1);
	}

	unsigned int w = Game.screen.w;
	unsigned int h = Game.screen.h;
	const char* name = Game.screen.name;

	Game.screen.window = SDL_CreateWindow(
		name,
		SDL_WINDOWPOS_CENTERED,
		SDL_WINDOWPOS_CENTERED,
		w, h, 0
	);

	Game.screen.renderer = SDL_CreateRenderer(
		Game.screen.window, -1,
		SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC
	);

	SDL_Surface* surface = SDL_LoadBMP("spritesheet.bmp");
	int n = ((surface->w/8)*(surface->h/8)+1);

	Game.gfx.n = n;
	Game.gfx.spritesheet = (SDL_Surface**) malloc(sizeof(SDL_Surface*)*n);

	int i, x, y;
	SDL_Rect rect = {0, 0, 8, 8};
	for(i=0; i<n; i++) {
		Game.gfx.spritesheet[i] = SDL_CreateRGBSurface(0, 8, 8, 24, 0x00, 0x00, 0x00, 0x00);
		SDL_SetColorKey(Game.gfx.spritesheet[i], 1, 0xFF00FF);
		SDL_FillRect(Game.gfx.spritesheet[i], 0, 0xFF00FF);
		if(i!=0) {
			x = (i-1)%(surface->w/8);
			y = (i-x)/(surface->w/8);
			rect.x = x*8;
			rect.y = y*8;
			SDL_BlitSurface(surface, &rect, Game.gfx.spritesheet[i], NULL);
		}
	}

	SDL_FreeSurface(surface);

	Game.running = SDL_TRUE;
}

//----------------------------------------------------------------------
void game_quit(void) {
	int i;
	for(i=0; i<Game.gfx.n; i++)
		SDL_FreeSurface(Game.gfx.spritesheet[i]);
	free(Game.gfx.spritesheet);
	Game.gfx.spritesheet = NULL;

	SDL_DestroyRenderer(Game.screen.renderer);
	Game.screen.renderer = NULL;

	SDL_DestroyWindow(Game.screen.window);
	Game.screen.window = NULL;

	SDL_Quit();
}

//----------------------------------------------------------------------
SDL_Texture* gfx_buildSpr(int w, int h, int** grid) {
	SDL_Surface* surface = SDL_CreateRGBSurface(0, 8*w, 8*h, 24, 0x00, 0x00, 0x00, 0x00);
	SDL_SetColorKey(surface, 1, 0xFF00FF);
	SDL_FillRect(surface, 0, 0xFF00FF);

	int i, j;
	SDL_Rect rect = {0, 0, 8, 8};
	for(j=0; j<h; j++) {
		for(i=0; i<w; i++) {
			rect.x = i*8;
			rect.y = j*8;
			SDL_BlitSurface(Game.gfx.spritesheet[grid[j][i]], NULL, surface, &rect);
		}
	}

	SDL_Texture* tex = SDL_CreateTextureFromSurface(Game.screen.renderer, surface);
	SDL_FreeSurface(surface);

	return tex;
}

//----------------------------------------------------------------------
void gfx_destroySpr(SDL_Texture* spr) {
	SDL_DestroyTexture(spr);
}

//----------------------------------------------------------------------
void screen_drawSpr(SDL_Texture* spr, SDL_Rect* rect) {
	SDL_RenderCopy(Game.screen.renderer, spr, NULL, rect);
}

#endif

There are many ways to structure game logic, and for a simple 2D game being written in C it comes down to mostly personal preference.

SDL 2.0 Tutorial-02: Almighty spritesheet

Last week we were able to create a window and renderer. This week we are going to read in a spritesheet image, separate it into individual 8×8 sprites and draw them to the screen.

First thing we need to do is read in the spritesheet. Here I’m using strict SDL2 so we’ll use the .bmp format with an alpha color key. Setting an alpha color key allows us to use an RGB value which acts as an alpha channel. When SDL looks over the image pixels and finds our RGB key it will replace the color with a transparent pixel. This saves on memory because instead of writing pixels in a 32-bit RGBA value we can use a 24-bit RGB value. This is only necessary if you are restricted to just SDL, ideally you would use the SDL2_image package. You can find out more about SDL2_image here.

Alright, let’s start by allocating memory for our “gfx” (graphics) module.

struct {
	// define "attributes"
	SDL_bool running;

	struct {
		unsigned int w;
		unsigned int h;
		const char* name;
		SDL_Window* window;
		SDL_Renderer* renderer;
	} screen;

	struct {
		unsigned int n;
		SDL_Surface** spritesheet;
	} gfx;

	// define "methods"
	void (*init)(void);
	void (*quit)(void);
} Game = {
	SDL_FALSE,
	{
		SCREEN_SCALE*SCREEN_w,
		SCREEN_SCALE*SCREEN_H,
		SCREEN_NAME,
		NULL, NULL
	},
	{0, NULL},
	game_init,
	game_quit
};


This takes our original Game “soliton” and adds a “gfx” module. The graphics module contains unsigned int n;  which is the number of 8×8 sprites found within our .bmp spritesheet, and SDL_Surface** spritesheet; which is an array of SDL surfaces. Each 8×8 sprite will receive its own SDL surface. Later we will arrange these surfaces into textures to be drawn with out renderer.

Next we will read in “spritesheet.bmp”, set the color key to 0xFF00FF and populate the spritesheet array with surfaces. This code should be placed within the void game_init(void); function.

SDL_Surface* surface = SDL_LoadBMP("spritesheet.bmp");
int n = ((surface->w/8)*(surface->h/8)+1);

Game.gfx.n = n;
Game.gfx.spritesheet = (SDL_Surface**) malloc(sizeof(SDL_Surface*)*n);

int i, x, y;
SDL_Rect rect = {0, 0, 8, 8};
for(i=0; i<n; i++) {
	Game.gfx.spritesheet[i] = SDL_CreateRGBSurface(0, 8, 8, 24, 0x00, 0x00, 0x00, 0x00);
	SDL_SetColorKey(Game.gfx.spritesheet[i], 1, 0xFF00FF);
	SDL_FillRect(Game.gfx.spritesheet[i], 0, 0xFF00FF);
	if(i!=0) {
		x = (i-1)%(surface->w/8);
		y = (i-x)/(surface->w/8);
		rect.x = x*8;
		rect.y = y*8;
		SDL_BlitSurface(surface, &rect, Game.gfx.spritesheet[i], NULL);
	}
}

SDL_FreeSurface(surface);

This will give us an array of sprite surfaces with the first sprite (spritesheet[0] ) being a completely transparent surface. This is done on purpose so that the surface array an easily be integrated with the Tiled map editor, which we will discuss in future tutorials.

Next we will move to our int main(int argc, char* argv[]); function where we will create textures for the sprites we wish to render. Ideally, the textures should be allocated for each room/level during the loading screen. This works well for a 2D game but isn’t required as most computers can handle the dynamic allocation without much problem. After modifying the code we are left with the following. If you would like to use the same spritesheet as I’m using here you can get it from here.

int main(int argc, char* argv[]) {

	Game.init();

	int x = Game.screen.w/2-8, y = Game.screen.h/2-8;
	
	SDL_Rect rect = {0, 0, 8*2, 8*2};
	SDL_Texture* texture1 = SDL_CreateTextureFromSurface(Game.screen.renderer, Game.gfx.spritesheet[17]);
	SDL_Texture* texture2 = SDL_CreateTextureFromSurface(Game.screen.renderer, Game.gfx.spritesheet[18]);
	SDL_Texture* texture3 = SDL_CreateTextureFromSurface(Game.screen.renderer, Game.gfx.spritesheet[29]);
	SDL_Texture* texture4 = SDL_CreateTextureFromSurface(Game.screen.renderer, Game.gfx.spritesheet[30]);

	SDL_Event event;
	while(Game.running) {
		while(SDL_PollEvent(&event)) {
			switch(event.type) {
				case SDL_QUIT: {
					Game.running = SDL_FALSE;
				} break;
			}
		}

		SDL_RenderClear(Game.screen.renderer);

		rect.x = 0+x, rect.y = 0+y;
		SDL_RenderCopy(Game.screen.renderer, texture1, NULL, &rect);

		rect.x = 8*2+x, rect.y = 0+y;
		SDL_RenderCopy(Game.screen.renderer, texture2, NULL, &rect);

		rect.x = 0+x, rect.y = 8*2+y;
		SDL_RenderCopy(Game.screen.renderer, texture3, NULL, &rect);

		rect.x = 8*2+x, rect.y = 8*2+y;
		SDL_RenderCopy(Game.screen.renderer, texture4, NULL, &rect);

		SDL_RenderPresent(Game.screen.renderer);
	}

	SDL_DestroyTexture(texture1);
	SDL_DestroyTexture(texture2);
	SDL_DestroyTexture(texture3);
	SDL_DestroyTexture(texture4);

	Game.quit();

	return 0;
}


This will draw a chest in the middle of the screen. Here we are creating a texture for each 8×8 sprite. This is highly inefficient, what we will learn to do later is create a surface with all the 8×8 sprites and then create a texture from this bigger surface. This will help a lot but for now we are fine to do this. The last step here is to clean up the sprite array.

void game_quit(void) {
	int i;
	for(i=0; i<Game.gfx.n; i++)
		SDL_FreeSurface(Game.gfx.spritesheet[i]);
	free(Game.gfx.spritesheet);
	Game.gfx.spritesheet = NULL;

	SDL_DestroyRenderer(Game.screen.renderer);
	Game.screen.renderer = NULL;

	SDL_DestroyWindow(Game.screen.window);
	Game.screen.window = NULL;

	SDL_Quit();
}

That’s it for now, at this point you should be able to play and experiment on your own, till next week. Good luck!

SDL 2.0 Tutorial-01: The game window

Last week we discussed how to setup a basic game loop. We were missing a few critical components, one being the window! This week we are going to learn how to create a basic window and renderer using SDL. SDL 2.0 works hard to get us the optimal display for the system we are working on. Most often that means OpenGL or DirectX, although, SDL provides a wrapper to a build-in renderer to make drawing easy – so we won’t be considered with what type of renderer we get. If you wish to work on a 3D game (or 2D with shaders/effects) it is possible to do with SDL but you’ll have to write a custom renderer which communicates with OpenGL/DirectX.

First thing we’ll want to do is take last week’s anonymous “Game” structure and add a module for our screen. We’ll only use one screen here so the module will adhere to the same anonymous struct style which we used for “Game”.

struct {
	// define "attributes"
	SDL_bool running;
	struct {
		unsigned int w;
		unsigned int h;
		const char* name;
		SDL_Window* window;
		SDL_Renderer* renderer;
	} screen;

	// define "methods"
	void (*init)(void);
	void (*quit)(void);
} Game = {
	SDL_FALSE,
	{
		SCREEN_SCALE*SCREEN_w,
		SCREEN_SCALE*SCREEN_H,
		SCREEN_NAME,
		NULL,
		NULL
	},
	game_init,
	game_quit
};

So now we have access to Game.screen who’s properties are w the width of the window, h the height of the window, name the string which will appear and the top of our window, window a pointer to our SDL window, and renderer a pointer to our SDL renderer. The width, height, scale, and name are specified as follows in the game header file.

#define SCREEN_w 640
#define SCREEN_H 480
#define SCREEN_SCALE 1
#define SCREEN_NAME "Prototype"

Defining our variables in this way allows for the w, h, scale, and name to be accessed from other points within our code base. Now we need to rewrite void game_init(void); and void game_quit(void); to get our screen to display and to clean up any memory left when we’re finished.

void game_init(void) {
	if(SDL_Init(SDL_INIT_EVERYTHING)!=0) {
		printf("SDL error -> %sn", SDL_GetError());
		exit(1);
	}

	unsigned int w = Game.screen.w;
	unsigned int h = Game.screen.h;
	const char* name = Game.screen.name;

	Game.screen.window = SDL_CreateWindow(
		name,
		SDL_WINDOWPOS_CENTERED,
		SDL_WINDOWPOS_CENTERED,
		w, h, 0
	);
	Game.screen.renderer = SDL_CreateRenderer(
		Game.screen.window, -1,
		SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC
	);

	Game.running = SDL_TRUE;
}

Here we make the necessary library calls to get a window and renderer. The SDL_WINDOWPOS_CENTERED flag will center our window when it pops up for the player. It is possible to setup a fullscreen window however if you are using pixel art this isn’t recommended for reasons that will become obvious once we write code for setting up our sprites. To destroy our renderer and window we’ll code void game_quit(void); the following way.

void game_quit(void) {
	SDL_DestroyRenderer(Game.screen.renderer);
	SDL_DestroyWindow(Game.screen.window);

	Game.screen.window = NULL;
	Game.screen.renderer = NULL;

	SDL_Quit();
}

At this point if you are encountering errors it is recommended to wrap the library function returns with if-statements to print any errors to stdout as we have done in the past. Now we need to modify our main game loop to provide continuous rendering as well as exiting functionality. It’s quite interesting to note that a window not polling for events (i.e. keypresses, mouse movements, etc.) will show as being non-responsive by the operating system. If on the other hand you are polling for events but aren’t listening for when the window is closed (i.e. red X at top right on windows) then the window will remain open and the only way to close it will require Ctrl+Alt+Delete. Let’s write a new game loop which polls for events and listens for when the window is closed.

int main(int argc, char* argv[]) {

	Game.init();

	SDL_Event event;
	while(Game.running) {
		while(SDL_PollEvent(&event)) {
			switch(event.type) {
				case SDL_QUIT: {
					Game.running = SDL_FALSE;
				} break;
			}
		}

		SDL_RenderClear(Game.screen.renderer);
		SDL_RenderPresent(Game.screen.renderer);
	}

	Game.quit();

	return 0;
}

Here we are simply polling for events and clearing/presenting an empty renderer. That’s all for this week! Next week we’ll look at how to read in a single image, split it into an array of sprites and display those sprites based on a gird/map. If you are getting the hang of C development I highly recommend picking up a GCW handheld – think of it as a hobby expense! Take care.

SDL 2.0 Tutorial-00: The Basic Sturcture

Throughout this series of weekly tutorials I’ll be guiding you through SDL 2.0 game development in C. I’m sticking with the C-programming language to keep things simple, and this will no doubt make learning C++ A LOT easier if you ever decide to step things up a bit.

Our first step is to setup a basic game structure. We need a chunk of memory where we can store all the components that will persist over the entire existence of our program. This is a reasonable thing to do since components like the game window will run for as long as the game runs.

First let’s include some fundamental header files. These files are part of the C standard library and provide some basic functions like printing statements to a standard output stream.

#include <stdio.h>
#include <stdlib.h>

For a detailed description of the C standard library and how to use it check out this reference.

Now we have some bare-bones functionality. Next we need to include the SDL 2.0 function and variable definitions so that we can use the SDL library.

#define SDL_MAIN_HANDLED
#include "SDL2/SDL.h"

This first line here tells SDL that we won’t be needing any special entry point for our program. We’ll be handling the entry and library initiation ourselves within int main(int argc, char* argv[]); .

The second line provides references to all the SDL functions and variables we will be using. It is worth noting that #define SDL_MAIN_HANDLED should be before #include “SDL2/SDL.h” so that when the SDL library is being preprocessed the custom entry points aren’t included.

The next part varies a bit based on personal preference but I have found it to be a nice and simple way of defining, what is essentially, a Singleton within C.

void game_init(void);
void game_quit(void);

static struct {
	// define "attributes"
	SDL_bool running;

	// define "methods"
	void (*init)(void);
	void (*quit)(void);
} Game = {
	SDL_FALSE,
	game_init,
	game_quit
};

This provides us with a globally defined game object which will be used to house all persistent game information. Doing things this way will help cut down on function parameters, which can easily get out-of-hand if not kept in check.

Now it is time to actually implement the void game_init(void); and void game_quit(void); functions.

void game_init(void) {
	printf("game_init()n");
	SDL_Init(SDL_INIT_EVERYTHING);
	Game.running = SDL_TRUE;
}

void game_quit(void) {
	printf("game_quit()n");
	SDL_Quit();
	Game.running = SDL_FALSE;
}

What we are doing here in the initialization step is printing the function name to the standard out stream, initializing the SDL library, and setting the game to a “running” state. During the SDL initialization the library will build and allocate all the objects and variables needed to make a game window, provide game audio, timers, events, joystick controls, etc.

Depending on how you are setting up your program it is possible that you might run into errors at this point due to SDL not being able to initialize correctly. In that case you will need to wrap your code in the following way so that SDL will tell you what the issue may be.

void game_init(void) {
	printf("game_init()n");

	if(SDL_Init(SDL_INIT_EVERYTHING)!=0) {
		printf("SDL error -> %sn", SDL_GetError());
		exit(1);
	}

	Game.running = SDL_TRUE;
}

Once all the issues are resolved, we are ready to actually make a little magic happen. The following is a simple game loop which initializes and quits the game in one iteration. Not a fun game but it does provide the structure we’ll need for next week’s project when we actually get a window up and running!

int main(int argc, char* argv[]) {

	Game.init();

	printf("running = %dn", Game.running);

	while(Game.running) {
		Game.quit();
	}

	printf("running = %dn", Game.running);

	return 0;
}

Here our main function takes two parameters. int argc stands for “argument count” and provides us with the number of command line arguments passed to our function during execution. char* argv[] stands for “argument vector” and provides us with the actual string arguments which where passed to our function. Once the game has successfully executed our code we return 0; to tell the operating system that we achieved everything we set out to do.

All together we get the following piece of code!

/* Stephen's Tutorials (https://stephenmeier.net/)
gcc main.c -o game.exe -I./include -L./lib -lSDL2main -lSDL2
running on gcc 4.8.1, SDL 2.0.1
*/

//----------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>

//----------------------------------------------------------------------
#define SDL_MAIN_HANDLED
#include "SDL2/SDL.h"

//----------------------------------------------------------------------
void game_init(void);
void game_quit(void);

static struct {
	// define "attributes"
	SDL_bool running;

	// define "methods"
	void (*init)(void);
	void (*quit)(void);
} Game = {
	SDL_FALSE,
	game_init,
	game_quit
};

//----------------------------------------------------------------------
void game_init(void) {
	printf("game_init()n");

	if(SDL_Init(SDL_INIT_EVERYTHING)!=0) {
		printf("SDL error -> %sn", SDL_GetError());
		exit(1);
	}

	Game.running = SDL_TRUE;
}

//----------------------------------------------------------------------
void game_quit(void) {
	printf("game_quit()n");
	SDL_Quit();
	Game.running = SDL_FALSE;
}

//----------------------------------------------------------------------
int main(int argc, char* argv[]) {

	Game.init();

	printf("running = %dn", Game.running);

	while(Game.running) {
		Game.quit();
	}

	printf("running = %dn", Game.running);

	return 0;
}

Till next week, take care!