Code:
#include <SDL/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
/* Defines */
#define MAPWIDTH 20
#define MAPHEIGHT 20
#define DELAY 100
typedef enum {PLAYER1, PLAYER2, COMPUTER} Econtrol;
/* Item structure */
struct item
{
int x_pos;
int y_pos;
};
/* Structure for snake parts */
struct part
{
int x_pos, y_pos;
struct part *next_part; /* Pointer to next part */
struct part *prev_part; /* Pointer to prev part */
};
/* Snake structure */
struct snake
{
struct part *first_part; /* Pointer to the first part of the snake */
enum Estate {RIGHT, LEFT, UP, DOWN} state; /* State of the snake */
Econtrol control; /* Thing controlling snake */
struct snake *next_snake; /* Pointer to next snake */
};
/* Variables */
struct snake *first_snake; /* Player 1's snake */
struct item apple; /* The apple item's variable */
int map[MAPWIDTH][MAPHEIGHT]; /* Map array for storing tile type */
float last_time; /* Float number to store the last time the snake moved */
bool game_running = false; /* This controls the game loop */
bool paused = false; /* Used for pausing the game */
SDL_Surface *screen, *sprite_image, *item_image, *tile_image; /* Some SDL surfaces */
/* Function Declarations */
int main(int argc, char *argv[]);
bool game_init(); /* Sets the game up to start with */
void new_game(); /* Starts a new game */
void remove_snakes(); /* Remove old snakes */
void load_map(char *mapname);
void add_snake(Econtrol control,int x, int y);
void game_loop(); /* The main game loop */
void get_input(); /* Gets and deals with keyboard input */
void do_ai();
void add_apple(); /* Puts the apple in a random position */
void move_snake (struct snake *current_snake); /* Moves the snake on */
void add_part(struct snake *current_snake, int x, int y); /* Adds a new part of the snake to the frount */
void remove_part(struct snake *current_snake); /* Removes the last part of the snake */
void edge_collision(int *x, int *y); /* Checks if the part has gone over the edge */
bool apple_collision(int x, int y); /* Checks to see if the part has eaten the apple */
bool snake_collision(int x, int y);
void draw_apple(); /* Draw the apple */
void draw_snake(); /* Draw the snake */
void draw_part(int src_x, int src_y, int dest_x, int dest_y); /* Draw the part of the snake */
void draw_map(); /* Draw the map */
void draw_tile(int src_x, int src_y, int pos_x, int pos_y); /* Draw the tile of the map */
void game_close(); /* Close the game and tidy up */
int main(int argc, char *argv[])
{
atexit(game_close);
if (game_init() == false)
exit(1);
while (game_running == true)
game_loop();
}
bool game_init()
{
int x, y;
SDL_Surface *temp;
/* Initialize SDL */
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
printf("Unable to initialize SDL\n");
return false;
}
/* Set the window size up */
screen = SDL_SetVideoMode(MAPWIDTH * 10, MAPHEIGHT * 10, 16, SDL_DOUBLEBUF);
if (screen == NULL)
{
printf("Unable to set video mode\n");
return false;
}
/* Set the windows caption */
SDL_WM_SetCaption("Snake Attempt", NULL);
/* Get rid of the cursor */
SDL_ShowCursor( SDL_DISABLE );
/* Load the sprite image up */
temp = SDL_LoadBMP("sprites.bmp");
if (temp == NULL)
{
printf("Unable to load picture\n");
return false;
}
SDL_SetColorKey(temp, SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint32) SDL_MapRGB(temp->format, 255, 255, 255));
sprite_image = SDL_DisplayFormat(temp);
/* Load the item image up */
temp = SDL_LoadBMP("items.bmp");
if (temp == NULL)
{
printf("Unable to load picture\n");
return false;
}
SDL_SetColorKey(temp, SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint32) SDL_MapRGB(temp->format, 255, 255, 255));
item_image = SDL_DisplayFormat(temp);
/* Load the tiles image up */
temp = SDL_LoadBMP("tiles.bmp");
if (temp == NULL)
{
printf("Unable to load picture\n");
return false;
}
SDL_SetColorKey(temp, SDL_SRCCOLORKEY | SDL_RLEACCEL, (Uint32) SDL_MapRGB(temp->format, 255, 255, 255));
tile_image = SDL_DisplayFormat(temp);
/* Free the tempory serface we used to load the images */
SDL_FreeSurface(temp);
/* Start the game */
new_game();
game_running = true;
return true;
}
void new_game()
{
/* Pause the game */
paused = true;
/* Remove all of the snakes */
remove_snakes();
/* Add new snakes */
add_snake( PLAYER1, ((MAPWIDTH / 3) * 2) , (MAPHEIGHT / 2) - 1 );
add_snake( COMPUTER, (MAPWIDTH / 3), (MAPHEIGHT / 2) - 1 );
/* Load the map */
load_map("map.txt");
/* Sort the time out */
last_time = SDL_GetTicks();
/* Add an apple */
add_apple();
printf("test");
}
void remove_snakes()
{
struct part *current_part, *next_part;
struct snake *current_snake, *next_snake;
current_snake = first_snake;
first_snake = NULL;
while ( current_snake != NULL )
{
current_part = current_snake->first_part;
current_snake->first_part = NULL;
while ( current_part != NULL )
{
next_part = current_part->next_part;
free(current_part);
current_part = next_part;
}
next_snake = current_snake->next_snake;
free(current_snake);
current_snake = next_snake;
}
}
void load_map(char *mapname)
{
FILE *map_file;
char c;
bool in_tag, in_var;
char *var, *tag;
int x, y;
map_file = fopen(mapname, "r");
if (map_file == NULL)
{
printf("Error opening map: %s\n", mapname);
}
else
{
x = 0;
y = 0;
while(1)
{
c = fgetc(map_file);
if (c == EOF)
break;
switch (c)
{
case ' ':
continue;
break;
case '\n':
x = -1;
y ++;
break;
case '0':
map[x][y] = 0;
break;
case '1':
map[x][y] = 1;
break;
default:
break;
}
x ++;
}
fclose(map_file);
}
}
void add_snake(Econtrol control,int x, int y)
{
struct snake *new_snake;
/* Allocate the memory and set the data */
new_snake = malloc(sizeof(struct snake));
new_snake->state = RIGHT;
new_snake->control = control;
/* Add two parts to the snake */
new_snake->first_part = NULL;
add_part(new_snake, x, y);
add_part(new_snake, x + 1, y);
/* Put the snake at the frount of the list */
new_snake->next_snake = first_snake;
first_snake = new_snake;
}
void game_loop()
{
struct snake *current_snake;
float time_passed, current_time;
/* Get the time and figure out time passed since last movement */
current_time = SDL_GetTicks();
time_passed = current_time - last_time;
/* Get the input from the players and the computer AI */
get_input();
do_ai();
/* If the game isn't paused */
if (!paused)
{
/* And the time passed since movement is bigger than the delay */
if ( time_passed >= DELAY )
{
/* Add the delay amount to the last time, this is better than
setting last time to current time incase more time than the
delay has passed */
last_time += DELAY;
/* Loop through the snakes, moving them */
current_snake = first_snake;
while ( current_snake != NULL )
{
move_snake(current_snake);
current_snake = current_snake->next_snake;
}
}
}
/* Draw everything to the screen */
draw_map();
/* Loop through, drawing the snakes */
current_snake = first_snake;
while ( current_snake != NULL )
{
draw_snake(current_snake);
current_snake = current_snake->next_snake;
}
draw_apple();
/* Refresh the screen */
SDL_Flip( screen );
}
void get_input()
{
SDL_Event event;
SDL_keysym keysym;
struct snake *current_snake;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
game_running = false;
break;
case SDL_KEYDOWN:
keysym = event.key.keysym;
switch(keysym.sym)
{
case SDLK_ESCAPE:
game_running = false;
break;
case SDLK_SPACE:
if (paused == true)
paused = false;
else
paused = true;
break;
case SDLK_a:
if (!paused)
{
current_snake = first_snake;
while ( current_snake != NULL )
{
if (current_snake->control == PLAYER2)
current_snake->state = LEFT;
current_snake = current_snake->next_snake;
}
}
break;
case SDLK_d:
if (!paused)
{
current_snake = first_snake;
while ( current_snake != NULL )
{
if (current_snake->control == PLAYER2)
current_snake->state = RIGHT;
current_snake = current_snake->next_snake;
}
}
break;
case SDLK_s:
if (!paused)
{
current_snake = first_snake;
while ( current_snake != NULL )
{
if (current_snake->control == PLAYER2)
current_snake->state = DOWN;
current_snake = current_snake->next_snake;
}
}
break;
case SDLK_w:
if (!paused)
{
current_snake = first_snake;
while ( current_snake != NULL )
{
if (current_snake->control == PLAYER2)
current_snake->state = UP;
current_snake = current_snake->next_snake;
}
}
break;
case SDLK_LEFT:
if (!paused)
{
current_snake = first_snake;
while ( current_snake != NULL )
{
if (current_snake->control == PLAYER1)
current_snake->state = LEFT;
current_snake = current_snake->next_snake;
}
}
break;
case SDLK_RIGHT:
if (!paused)
{
current_snake = first_snake;
while ( current_snake != NULL )
{
if (current_snake->control == PLAYER1)
current_snake->state = RIGHT;
current_snake = current_snake->next_snake;
}
}
break;
case SDLK_UP:
if (!paused)
{
current_snake = first_snake;
while ( current_snake != NULL )
{
if (current_snake->control == PLAYER1)
current_snake->state = UP;
current_snake = current_snake->next_snake;
}
}
break;
case SDLK_DOWN:
if (!paused)
{
current_snake = first_snake;
while ( current_snake != NULL )
{
if (current_snake->control == PLAYER1)
current_snake->state = DOWN;
current_snake = current_snake->next_snake;
}
}
break;
}
break;
}
break;
}
}
void do_ai()
{
struct snake *current_snake = first_snake;
while ( current_snake != NULL )
{
if (current_snake->control == COMPUTER)
{
/* AI pathfinding stuff */
/* Line of sight-ish method */
int distance_x = apple.x_pos - current_snake->first_part->x_pos;
int distance_y = apple.y_pos - current_snake->first_part->y_pos;
if (abs(distance_x) > abs(distance_y))
{
if (distance_x > 0)
current_snake->state = RIGHT;
else if (distance_x < 0)
current_snake->state = LEFT;
}
else
{
if (distance_y > 0)
current_snake->state = DOWN;
else if (distance_y < 0)
current_snake->state = UP;
}
/* Basic Method (naf!)
if (current_snake->first_part->x_pos > apple.x_pos)
current_snake->state = LEFT;
else if (current_snake->first_part->x_pos < apple.x_pos)
current_snake->state = RIGHT;
if (current_snake->first_part->y_pos > apple.y_pos)
current_snake->state = UP;
else if (current_snake->first_part->y_pos < apple.y_pos)
current_snake->state = DOWN;*/
}
current_snake = current_snake->next_snake;
}
}
void add_apple()
{
int x, y;
x = rand() % MAPWIDTH;
y = rand() % MAPHEIGHT;
apple.x_pos = x;
apple.y_pos = y;
}
void move_snake (struct snake *current_snake)
{
int x, y;
x = current_snake->first_part->x_pos;
printf("bob");
y = current_snake->first_part->y_pos;
switch (current_snake->state)
{
case RIGHT:
x += 1;
y += 0;
break;
case LEFT:
x -= 1;
y += 0;
break;
case UP:
x += 0;
y -= 1;
break;
case DOWN:
x += 0;
y += 1;
break;
}
edge_collision(&x, &y);
if ( snake_collision(x, y) )
new_game();
else
{
add_part(current_snake, x, y);
if ( apple_collision(x, y) )
add_apple();
else
remove_part(current_snake);
}
}
void add_part(struct snake *current_snake, int x, int y)
{
/* Pointer to the next item in the list */
struct part *new_part;
new_part = malloc(sizeof(struct part));
new_part->x_pos = x;
new_part->y_pos = y;
new_part->prev_part = NULL;
if (current_snake->first_part == NULL)
{
new_part->next_part = NULL;
current_snake->first_part = new_part;
}
else
{
new_part->next_part = current_snake->first_part;
current_snake->first_part->prev_part = new_part;
current_snake->first_part = new_part;
}
}
void remove_part(struct snake *current_snake)
{
struct part *current_part, *next_part;
current_part = current_snake->first_part;
while ( current_part != NULL )
{
next_part = current_part->next_part;
if ( next_part == NULL )
{
current_part->prev_part->next_part = NULL;
free(current_part);
}
current_part = next_part;
}
}
void edge_collision(int *x, int *y)
{
if (*x > MAPWIDTH - 1)
*x = 0;
if (*x < 0)
*x = MAPWIDTH - 1;
if (*y > MAPHEIGHT - 1)
*y = 0;
if (*y < 0)
*y = MAPHEIGHT - 1;
}
bool snake_collision(int x, int y)
{
struct part *current_part;
struct snake *current_snake;
current_snake = first_snake;
while ( current_snake != NULL )
{
current_part = current_snake->first_part;
while ( current_part != NULL )
{
if ( x == current_part->x_pos && y == current_part->y_pos )
return true;
current_part = current_part->next_part;
}
current_snake = current_snake->next_snake;
}
return false;
}
bool apple_collision(int x, int y)
{
if ( (x == apple.x_pos && y == apple.y_pos) )
return true;
else
return false;
}
void draw_apple()
{
SDL_Rect src, dest;
src.x = 0;
src.y = 0;
src.w = 10;
src.h = 10;
dest.x = apple.x_pos * 10;
dest.y = apple.y_pos * 10;
dest.w = 10;
dest.h = 10;
SDL_BlitSurface( item_image, &src, screen, &dest );
}
void draw_snake(struct snake *current_snake)
{
struct part *current_part;
current_part = current_snake->first_part;
while ( current_part != NULL )
{
/* Its a head */
if (current_part->prev_part == NULL)
{
/* Left direction head */
if (current_part->x_pos > current_part->next_part->x_pos)
draw_part(0, 3, current_part->x_pos, current_part->y_pos);
/* Right direction head */
if (current_part->x_pos < current_part->next_part->x_pos)
draw_part(2, 3, current_part->x_pos, current_part->y_pos);
/* Up direction head */
if (current_part->y_pos > current_part->next_part->y_pos)
draw_part(3, 3, current_part->x_pos, current_part->y_pos);
/* Down direction head */
if (current_part->y_pos < current_part->next_part->y_pos)
draw_part(1, 3, current_part->x_pos, current_part->y_pos);
}
/* Its a tail */
if ( (current_part->next_part == NULL) && (current_part->prev_part != NULL) )
{
/* Left direction tail */
if (current_part->x_pos > current_part->prev_part->x_pos)
draw_part(0, 4, current_part->x_pos, current_part->y_pos);
/* Right direction tail */
if (current_part->x_pos < current_part->prev_part->x_pos)
draw_part(2, 4, current_part->x_pos, current_part->y_pos);
/* Up direction tail */
if (current_part->y_pos > current_part->prev_part->y_pos)
draw_part(1, 4, current_part->x_pos, current_part->y_pos);
/* Down direction tail */
if (current_part->y_pos < current_part->prev_part->y_pos)
draw_part(3, 4, current_part->x_pos, current_part->y_pos);
}
/* Its a body part */
if ( (current_part->prev_part != NULL) && (current_part->next_part != NULL) )
{
/* Left direction body */
if ( (current_part->x_pos > current_part->next_part->x_pos) && (current_part->x_pos < current_part->prev_part->x_pos) )
draw_part(2, 0, current_part->x_pos, current_part->y_pos);
/* Right direction body */
if ( (current_part->x_pos < current_part->next_part->x_pos) && (current_part->x_pos > current_part->prev_part->x_pos) )
draw_part(0, 0, current_part->x_pos, current_part->y_pos);
/* Up direction body */
if ( (current_part->y_pos > current_part->next_part->y_pos) && (current_part->y_pos < current_part->prev_part->y_pos) )
draw_part(1, 0, current_part->x_pos, current_part->y_pos);
/* Down direction body */
if ( (current_part->y_pos < current_part->next_part->y_pos) && (current_part->y_pos > current_part->prev_part->y_pos) )
draw_part(3, 0, current_part->x_pos, current_part->y_pos);
/* CORNERS */
/* Up to left corner */
if ( (current_part->prev_part->x_pos < current_part->x_pos ) && (current_part->next_part->y_pos > current_part->y_pos) )
draw_part(2, 2, current_part->x_pos, current_part->y_pos);
/* Up to Right corner -- */
if ( (current_part->prev_part->x_pos > current_part->x_pos ) && (current_part->next_part->y_pos > current_part->y_pos) )
draw_part(0, 1, current_part->x_pos, current_part->y_pos);
/* Down to Left corner */
if ( (current_part->prev_part->x_pos < current_part->x_pos ) && (current_part->next_part->y_pos < current_part->y_pos) )
draw_part(2, 1, current_part->x_pos, current_part->y_pos);
/* Down to Right corner */
if ( (current_part->prev_part->x_pos > current_part->x_pos ) && (current_part->next_part->y_pos < current_part->y_pos) )
draw_part(0, 2, current_part->x_pos, current_part->y_pos);
/* Left to Up corner */
if ( (current_part->prev_part->y_pos < current_part->y_pos ) && (current_part->next_part->x_pos > current_part->x_pos) )
draw_part(1, 1, current_part->x_pos, current_part->y_pos);
/* Left to Down corner */
if ( (current_part->prev_part->y_pos > current_part->y_pos ) && (current_part->next_part->x_pos > current_part->x_pos) )
draw_part(3, 2, current_part->x_pos, current_part->y_pos);
/* Right to up corner */
if ( (current_part->prev_part->y_pos < current_part->y_pos ) && (current_part->next_part->x_pos < current_part->x_pos) )
draw_part(1, 2, current_part->x_pos, current_part->y_pos);
/* Right to Down corner */
if ( (current_part->prev_part->y_pos > current_part->y_pos ) && (current_part->next_part->x_pos < current_part->x_pos) )
draw_part(3, 1, current_part->x_pos, current_part->y_pos);
}
current_part = current_part->next_part;
}
}
void draw_part(int src_x, int src_y, int dest_x, int dest_y)
{
SDL_Rect src, dest;
src.x = src_x * 10;
src.y = src_y * 10;
src.w = 10;
src.h = 10;
dest.x = dest_x * 10;
dest.y = dest_y * 10;
dest.w = 10;
dest.h = 10;
SDL_BlitSurface( sprite_image, &src, screen, &dest );
}
void draw_map()
{
int x, y;
int src_x, src_y;
SDL_Rect src, dest;
for (x = 0; x < MAPWIDTH; x++)
for (y = 0; y < MAPHEIGHT; y++)
{
switch (map[x][y] )
{
case 0:
src_x = 10;
src_y = 0;
break;
case 1:
src_x = 0;
src_y = 0;
break;
}
draw_tile(src_x, src_y, x, y);
}
}
void draw_tile(int src_x, int src_y, int pos_x, int pos_y)
{
SDL_Rect src, dest;
src.x = src_x;
src.y = src_y;
src.w = 10;
src.h = 10;
dest.x = pos_x * 10;
dest.y = pos_y * 10;
dest.w = 10;
dest.h = 10;
SDL_BlitSurface( tile_image, &src, screen, &dest );
}
void game_close()
{
remove_snakes();
SDL_FreeSurface(sprite_image);
SDL_Quit();
}
You should know that each snake has a linked list to store the individual sections of it, I'm starting to think there might be a problem with how I am creating / freeing those linked lists.