#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
#include "snake.h"
#include "game.h"
#include "constants.h"
int startMenu(SDL_Surface* screen)
{
int go = 1; /* 0 = the game doesn't start and we quit the game */
SDL_Event event; /* catch an event (keyboard or mouse) */
/* create the surface for the "welcome image" */
SDL_Surface *background = NULL;
/* the image's position on the screen */
SDL_Rect positionBackground;
/* Load it and give its position */
background = SDL_LoadBMP("snake_start.bmp");
positionBackground.x = 0;
positionBackground.y = 0;
/* clean the screen */
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 111, 55, 0));
/* display the image on the screen */
SDL_BlitSurface(background, NULL, screen, &positionBackground);
SDL_Flip(screen);
do {
SDL_WaitEvent(&event); /* waiting for an event */
if (event.type == SDL_QUIT)
go = 0;
} while (event.type != SDL_KEYDOWN && event.type != SDL_QUIT);
/* we don't need the image anymore */
SDL_FreeSurface(background);
return go;
}
void play(SDL_Surface* screen)
{
/* the snake in game */
Snake s = NULL;
Snake tmpSnake = NULL;
/* we'll use surfaces SDL type to represent everything :
snake, target, menu, game screen, .. */
SDL_Surface *menu = NULL;
SDL_Surface *head = NULL; /* snake's head */
SDL_Surface *body = NULL; /* snake's body */
SDL_Surface *apple = NULL;
SDL_Rect positionApple; /* contains the (x;y) current apple's position */
SDL_Rect positionMenu = {0,(WINDOW_HEIGHT-MENU_HEIGHT)}; /* contains the (x;y) menu's position */
/* catch an event (keyboard or mouse) */
SDL_Event event;
int keepgoing; /* 1: the game continuer, 0: byebye */
int retry = 1; /* game can restart if the user loses */
int direction = 0; /* give the new/current snake's direction (UP here, see the enum in game.h) */
int score = 0; /* number of points */
int games = 0; /* number of games */
int timer = 100; /* time between 2 flips in ms */
/* help us to calculate the time between 2 flips */
int previousTime = 0;
int currentTime = 0;
/* the surface are created and filled with the appropriate colors */
menu = SDL_CreateRGBSurface(SDL_HWSURFACE, MENU_WIDTH, MENU_HEIGHT, 32, 0, 0, 0, 0);
SDL_FillRect(menu, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
head = SDL_CreateRGBSurface(SDL_HWSURFACE, SNAKE_WIDTH, SNAKE_HEIGHT, 32, 0, 0, 0, 0);
SDL_FillRect(head, NULL, SDL_MapRGB(screen->format, 0, 80, 0));
body = SDL_CreateRGBSurface(SDL_HWSURFACE, SNAKE_WIDTH, SNAKE_HEIGHT, 32, 0, 0, 0, 0);
SDL_FillRect(body, NULL, SDL_MapRGB(screen->format, 0, 100, 0));
apple = SDL_LoadBMP("apple.bmp");
/*apple = SDL_CreateRGBSurface(SDL_HWSURFACE, SNAKE_WIDTH, SNAKE_HEIGHT, 32, 0, 0, 0, 0);
SDL_FillRect(apple, NULL, SDL_MapRGB(screen->format, 170, 0, 0));*/
/* the (x;y) apples' position are initialized.
(0;0) means there isn't an apple in the game */
positionApple.x = 0;
positionApple.y = 0;
/* the main loop */
while (retry) {
keepgoing = 1; /* .. until we lose.. */
/* the new snake is created */
s = initializeSnake(s,5);
direction = 2;
/* display number of games and score. it'll be updated when snake eats an apple */
games = games+1;
score = 0;
*menu = scoreTTF(menu, games, score);
timer = 100;
/* the game loop, game takes place in */
while (keepgoing) {
/* if there isn't an apple, we generate a new position for the new apple */
if (positionApple.x == 0 && positionApple.y == 0) {
positionApple = generateApplePosition(s);
}
/* if the snake eats an apple... */
if ((s->position).x == positionApple.x && (s->position).y == positionApple.y) {
positionApple.x = 0;
positionApple.y = 0;
/* ... it grows up */
s = addBodyPart2SnakeTail(s);
score = score+1;
*menu = scoreTTF(menu, games, score);
timer = timer-2; /* speed increases too */
}
/* make a pause between 2 flips (2 updates of the screen) */
currentTime = SDL_GetTicks();
if (currentTime - previousTime > timer) { /* value in ms */
/* to continue, user hasn't to close the window and snake has to be still alive */
keepgoing = verifyGame(s,direction) && keepgoing;
if (keepgoing) /* if everything is ok, the game continue and snake can move */
s = moveSnake(s, direction); /* see snake.c */
previousTime = currentTime;
}
else {
SDL_Delay(timer - (currentTime - previousTime));
}
/* the screen is filled, so everything disappear (snake, apple, ..) */
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 111, 55, 0));
/* surfaces are blitting on screen */
SDL_BlitSurface(apple, NULL, screen, &positionApple);
/* we traverse the linked list and we also blit each body parts */
tmpSnake = s->next;
while (tmpSnake != NULL) {
SDL_BlitSurface(body, NULL, screen, &tmpSnake->position);
tmpSnake = tmpSnake->next;
}
/* for the snake's head */
SDL_BlitSurface(head, NULL, screen, &s->position);
/* for the game menu */
SDL_BlitSurface(menu, NULL, screen, &positionMenu);
/* the the screen is updated */
SDL_Flip(screen);
/* if an event (from the keyboard or the mouse) is sent by the
gamer/user we take it */
SDL_PollEvent(&event);
/* in the first case, we test the event and we use it to... */
switch (event.type) {
/* ... close the window */
case SDL_QUIT:
keepgoing = 0;
retry = 0;
break;
/* ... change the snake's position */
case SDL_KEYDOWN:
direction = newDirection(event, direction);
break;
default:
break;
}
}
/* done for this party! */
s = deleteSnake(s); /* free all the snake's parts */
if (retry == 0) {
/* the gamer clicked to close the window, the game have to stop right now */
}
else {
/* case where the gamer lost his party, may be he want to retry */
retry = retryGame(screen);
}
}
/* end of the game, we can free the surfaces */
SDL_FreeSurface(head);
SDL_FreeSurface(body);
SDL_FreeSurface(apple);
}
/* make the bottom menu : use font and SDL ttf to display score and other information */
SDL_Surface scoreTTF(SDL_Surface* menu, int games, int score)
{
/* the font used */
TTF_Font *font = NULL;
/* the surface and its position for the text */
SDL_Surface* text;
SDL_Rect positionText;
SDL_Color colorFont = {255, 255, 255}; /* text's color */
SDL_Color colorBack = {0, 0, 0}; /* background's color of the text */
/* this string will give the text to write on screen */
char string[20] = "";
sprintf(string, "Game #%d Score %d ", games, score);
font = TTF_OpenFont("font.ttf", 30); /* load the font */
/* write the text on the surface menu */
text = TTF_RenderText_Shaded(font, string, colorFont, colorBack);
positionText.x = 10;
positionText.y = (MENU_HEIGHT/2)-(text->h/2);
SDL_BlitSurface(text, NULL, menu, &positionText);
/* update menu */
SDL_Flip(menu);
TTF_CloseFont(font);
return *menu;
}
/* Not bored yet? */
int retryGame(SDL_Surface* screen)
{
SDL_Event eventRetry;
/* retry? */
do {
SDL_WaitEvent(&eventRetry); /* waiting for an event */
if (eventRetry.type == SDL_QUIT)
return 0; /* don't retry the game */
} while (eventRetry.type != SDL_KEYDOWN);
return 1; /* ok, retry! */
}
/* set up as many as body parts asked for the snake, at least 3 */
Snake initializeSnake(Snake s, int nbParts)
{
int i; /* just use for the loop */
SDL_Rect positionSnake; /* contains the position of a snake's body part */
/* At least 3 parts in the beginning */
if (nbParts < 3)
nbParts = 3;
/* the head is in the middle of the screen */
positionSnake.x = (WINDOW_WIDTH/2)-(SNAKE_WIDTH/2);
positionSnake.x = positionSnake.x + positionSnake.x%(SNAKE_WIDTH);
positionSnake.x = positionSnake.x - nbParts*SNAKE_WIDTH; /* because we'll add in head */
positionSnake.y = (WINDOW_HEIGHT/2)-(SNAKE_HEIGHT/2);
positionSnake.y = positionSnake.y + positionSnake.y%(SNAKE_HEIGHT);
/* we add nbParts of byd parts to our snake */
for (i = 0 ; i < nbParts ; i = i+1) {
s = addBodyPart2SnakeHead(s, positionSnake);
positionSnake.x += SNAKE_WIDTH; /* on the left */
}
return s;
}
/* return the new direction if the user changes it or the old one */
int newDirection(SDL_Event event, int direction)
{
switch(event.key.keysym.sym) {
case SDLK_UP: /* key UP was pressed */
/* direction changes if snake doesn't go in a reverse direction */
if (direction != DOWN)
direction = UP;
break;
/* same for others */
case SDLK_DOWN:
if (direction != UP)
direction = DOWN;
break;
case SDLK_RIGHT:
if (direction != LEFT)
direction = RIGHT;
break;
case SDLK_LEFT:
if (direction != RIGHT)
direction = LEFT;
break;
default:
/* nothing */
break;
}
return direction;
}
/* generate a position (x;y) for a new apple */
SDL_Rect generateApplePosition(Snake s)
{
Snake tmpSnake = NULL;
SDL_Rect positionApple; /* will contains (x;y) */
/* we use rand() to generate "random" numbers.
the cartesian coordinates of the apple must not be the
same as those of a snake's part */
int ok;
/* to solve this problem, in the first time, we generate a x
which is different from all the x of the snake's parts */
do {
ok = 0;
positionApple.x = (rand()%((WINDOW_WIDTH)-(SNAKE_WIDTH))); /* the apple must be on the game screen... */
positionApple.x = positionApple.x - positionApple.x%(SNAKE_WIDTH);
tmpSnake = s;
while (tmpSnake != NULL && ok == 0) {
if (tmpSnake->position.x == positionApple.x)
ok = 1;
tmpSnake = tmpSnake->next;
}
} while(ok);
/* we do the same for y */
do {
ok = 0;
positionApple.y = (rand()%((WINDOW_HEIGHT)-(SNAKE_HEIGHT+MENU_HEIGHT))); /* the apple must be on the game screen... */
positionApple.y = positionApple.y - positionApple.y%(SNAKE_HEIGHT);
tmpSnake = s;
while (tmpSnake != NULL && ok == 0) {
if (tmpSnake->position.y == positionApple.y)
ok = 1;
tmpSnake = tmpSnake->next;
}
} while(ok);
/* we have the new position */
return positionApple;
}
int verifyGame(Snake s, int direction)
{
Snake tmpSnake;
int ok = 1; /* 1 means everything is ok */
/* just in case */
if (s == NULL)
return ok;
/* test collisions with the borders/edges */
if ((s->position.x <= 0 && direction == LEFT) || (s->position.x >= (WINDOW_WIDTH-SNAKE_WIDTH) && direction == RIGHT) || (s->position.y <= 0 && direction == UP) || (s->position.y >= (WINDOW_HEIGHT-MENU_HEIGHT-SNAKE_HEIGHT) && direction == DOWN))
ok = 0;
/* test collision of the head with the body */
tmpSnake = s->next;
while (tmpSnake != NULL && ok == 1) {
/* it means 2 snake's parts have the same (x;y) positions */
if (tmpSnake->position.x == s->position.x && tmpSnake->position.y == s->position.y)
ok = 0;
tmpSnake = tmpSnake->next;
}
return ok;
}