From 01147c0d35994d77d2922cb0e302857b49a49d43 Mon Sep 17 00:00:00 2001 From: Aaron Mueller Date: Wed, 16 Dec 2009 15:37:24 +0100 Subject: [PATCH] Adding game states and menu * Implement a simple state machine to simulate different game stats * Create a generic menu to display different menus * Update the Makefile for TTF support * Draw a simple diagram to show the stats --- Makefile | 2 +- snippets/state_graph.dot | 21 ++++++++++++ src/config.c | 4 +++ src/config.h | 29 ++++++++++++---- src/display.c | 44 ++++++++++++++++++++++++ src/draw.c | 16 --------- src/draw.h | 9 ++--- src/events.c | 42 +++++++++++++++++++++++ src/main.c | 40 +++++++++++----------- src/menu.c | 72 ++++++++++++++++++++++++++++++++++++++++ src/menu.h | 23 +++++++++++++ src/states.c | 17 ++++++++++ src/states.h | 34 +++++++++++++++++++ 13 files changed, 302 insertions(+), 51 deletions(-) create mode 100644 snippets/state_graph.dot create mode 100644 src/display.c create mode 100644 src/events.c create mode 100644 src/menu.c create mode 100644 src/menu.h create mode 100644 src/states.c create mode 100644 src/states.h diff --git a/Makefile b/Makefile index dc00a6c..55a5f38 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CC= gcc # Compiler flags CFLAGS= -Wall -std=c99 -ggdb # Libraries -CLIBS= `sdl-config --cflags` -lSDL -lGL +CLIBS= `sdl-config --cflags` -lSDL -lSDL_ttf -lGL ####### Commands RM= rm -r MKDIR= mkdir -p diff --git a/snippets/state_graph.dot b/snippets/state_graph.dot new file mode 100644 index 0000000..b62a316 --- /dev/null +++ b/snippets/state_graph.dot @@ -0,0 +1,21 @@ + +// dot -Tpng -Gcharset=latin1 state_graph.dot -o states.png + +digraph StateMachine { + node [style=rounded, shape=box, fontname="Helvetica"]; + edge [fontsize=9, fontname="Helvetica"]; + + Start [shape=plaintext]; + Ende [shape=plaintext]; + + Start -> "Hauptmenü"; + "Hauptmenü" -> Ende [label="Spiel beenden"]; + "Hauptmenü" -> Spielerwahl [label="Neues Spiel",labelfontsize=4.0]; + "Hauptmenü" -> Credits [label="Credits"]; + Credits -> "Hauptmenü" [label="Zurück"]; + Spielerwahl -> "Hauptmenü" [label="Zurück"]; + Spielerwahl -> "Spiel läuft" [label="1/2/3 Spieler"]; + "Spiel läuft" -> "Spiel wirklich beenden?" [label="ESC, F10"]; + "Spiel wirklich beenden?" -> "Hauptmenü" [label="Ja"]; + "Spiel wirklich beenden?" -> "Spiel läuft" [label="Nein"]; +} diff --git a/src/config.c b/src/config.c index f49bae8..e50a810 100644 --- a/src/config.c +++ b/src/config.c @@ -6,6 +6,10 @@ // Initialization for the global variables SDL_Surface *screen = NULL; SDL_Event event; +TTF_Font *menuFont; bool gameRunning = true; int *terrain = NULL; +enum states currentState; +int currentMenuActionState = 0; + diff --git a/src/config.h b/src/config.h index 9cb6ffc..e650fff 100644 --- a/src/config.h +++ b/src/config.h @@ -1,19 +1,36 @@ #include #include "SDL.h" +#include "SDL_ttf.h" // In this file we define all global variables for the whole project. All // variables definied here can be accessed from all other source files. -// Global variables and definitions -extern SDL_Surface *screen; // Screen to paint on -extern SDL_Event event; // Event storage -extern bool gameRunning; // Set this variable to false to shutdown the game -extern int *terrain; // Game terrain - // Constants +#ifndef CONFIG_H +#define CONFIG_H +enum states { + STATE_MAINMENU, + STATE_NUMPLAYERS, + STATE_CREDITS, + STATE_RUNNINGGAME, + STATE_RLYQUIT, + STATE_EXIT, + MAX_STATES +}; // Screen size static const int SCREEN_WIDTH = 800; static const int SCREEN_HEIGHT = 600; +#endif + + +// Global variables and definitions +extern SDL_Surface *screen; // Screen to paint on +extern SDL_Event event; // Event storage +extern TTF_Font *menuFont; // The font for the menu +extern int *terrain; // Game terrain +extern enum states currentState; // The current game state +extern int currentMenuActionState; // The current selected action state in a menu + diff --git a/src/display.c b/src/display.c new file mode 100644 index 0000000..f673f67 --- /dev/null +++ b/src/display.c @@ -0,0 +1,44 @@ + +#include +#include +#include "SDL.h" +#include "SDL_ttf.h" +#include "config.h" +#include "states.h" +#include "draw.h" +#include "menu.h" + +void displayMainmenu() { + drawMenu(mainMenu, 3); +} + +void displayNumplayers() { + drawMenu(numplayersMenu, 4); +} + +void displayCredits() { + drawMenu(creditsMenu, 1); +} + +void displayRunninggame() { + if (terrain == NULL) terrain = generateTerrain(150.0, 180.0); + + Uint32 sky = SDL_MapRGB(screen->format, 186, 215, 217); + Uint32 green = SDL_MapRGB(screen->format, 101, 200, 21); + Uint32 darkGreen = SDL_MapRGB(screen->format, 52, 99, 14); + Uint32 ground = SDL_MapRGB(screen->format, 124, 88, 10); + + for (int x=0; xformat, 186, 215, 217); - Uint32 green = SDL_MapRGB(screen->format, 101, 200, 21); - Uint32 darkGreen = SDL_MapRGB(screen->format, 52, 99, 14); - Uint32 ground = SDL_MapRGB(screen->format, 124, 88, 10); - - for (int x=0; x +#include +#include "config.h" +#include "states.h" +#include "menu.h" +#include "draw.h" + +void eventsMainmenu() { + handleMenuEvent(mainMenu, 3, STATE_EXIT); +} + +void eventsNumplayers() { + handleMenuEvent(numplayersMenu, 4, STATE_MAINMENU); +} + +void eventsCredits() { + handleMenuEvent(creditsMenu, 1, STATE_MAINMENU); +} + +void eventsRunninggame() { + if (event.type == SDL_KEYDOWN) { + switch (event.key.keysym.sym) { + case SDLK_RETURN: + free(terrain); + terrain = generateTerrain(150.0, 180.0); + printf("New terrain generated.\n"); + break; + case SDLK_ESCAPE: + case SDLK_F10: + currentState = STATE_RLYQUIT; + break; + default: + break; + } + } +} + +void eventsRlyquit() { + handleMenuEvent(rlyquitMenu, 2, STATE_RUNNINGGAME); +} + diff --git a/src/main.c b/src/main.c index ee29ffe..4fc146b 100644 --- a/src/main.c +++ b/src/main.c @@ -2,47 +2,45 @@ #include #include #include +#include #include "SDL.h" +#include "SDL_ttf.h" #include "config.h" #include "draw.h" +#include "states.h" +#include "menu.h" + int main(int argc, char **argv) { // Initialize SDL and open up a screen SDL_Init(SDL_INIT_VIDEO); + TTF_Init(); screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_HWSURFACE | SDL_DOUBLEBUF); + menuFont = TTF_OpenFont("/usr/share/fonts/corefonts/verdana.ttf", 50); + + currentState = STATE_MAINMENU; // Initialize internal game state srand(time(NULL)); terrain = generateTerrain(150.0, 180.0); - + + + // Choose right state + stateTable[currentState].drawFun(); + stateTable[currentState].handleEventsFun(); + // the main game loop - while (gameRunning == true) { + while (currentState != STATE_EXIT) { // Check for events if (SDL_PollEvent(&event)) { // Make it possible to close the game window - if (event.type == SDL_QUIT) gameRunning = false; - - // Keyboard interaction - if (event.type == SDL_KEYDOWN) { - switch (event.key.keysym.sym) { - case SDLK_RETURN: - free(terrain); - terrain = generateTerrain(150.0, 180.0); - printf("New terrain generated.\n"); - break; - case SDLK_ESCAPE: - case SDLK_F10: - gameRunning = false; - break; - default: - break; - } - } + if (event.type == SDL_QUIT) currentState = STATE_EXIT; + stateTable[currentState].handleEventsFun(); } // Draw the stuff on the screen and "flip" th the next frame SDL_FillRect(screen, NULL, 0x000000); - drawScreen(); + stateTable[currentState].drawFun(); SDL_Flip(screen); } diff --git a/src/menu.c b/src/menu.c new file mode 100644 index 0000000..5094666 --- /dev/null +++ b/src/menu.c @@ -0,0 +1,72 @@ + +#include "SDL.h" +#include "states.h" +#include "menu.h" + + +struct menuItem mainMenu[] = { + {"Neues Spiel", STATE_NUMPLAYERS}, + {"Credits", STATE_CREDITS}, + {"Spiel beenden", STATE_EXIT} +}; +struct menuItem numplayersMenu[] = { + {"Einspieler", STATE_RUNNINGGAME}, + {"Zweispieler", STATE_RUNNINGGAME}, + {"Dreispieller", STATE_RUNNINGGAME}, + {"Zurueck", STATE_MAINMENU} +}; +struct menuItem creditsMenu[] = { + {"Zurueck", STATE_MAINMENU} +}; +struct menuItem rlyquitMenu[] = { + {"Beenden", STATE_MAINMENU}, + {"Weiterspielen", STATE_RUNNINGGAME} +}; + +void handleMenuEvent(struct menuItem items[], int numItems, enum states prevState) { + if (event.type == SDL_KEYDOWN) { + switch (event.key.keysym.sym) { + case SDLK_DOWN: + case SDLK_j: + currentMenuActionState++; + if (currentMenuActionState > numItems-1) currentMenuActionState = 0; + break; + case SDLK_UP: + case SDLK_k: + currentMenuActionState--; + if (currentMenuActionState < 0) currentMenuActionState = numItems-1; + break; + case SDLK_RETURN: + case SDLK_SPACE: + currentState = items[currentMenuActionState].targetState; + currentMenuActionState = 0; + break; + case SDLK_ESCAPE: + case SDLK_BACKSPACE: + currentMenuActionState = 0; + currentState = prevState; + break; + default: + break; + } + } +} + +void drawMenu(struct menuItem items[], int numItems) { + SDL_Surface *text; + SDL_Rect targetPos; + + SDL_Color colorSelected = {0, 255, 66}; + SDL_Color colorNormal = {59, 71, 62}; + + for (int i=0; i