commit 3f9b4e6f1a3cb716f36c7770eadb9294567a000f
parent 44a75937ae887d6ef3d08be3165e4fc609560d71
Author: Matsuda Kenji <info@mtkn.jp>
Date: Tue, 27 Dec 2022 09:53:40 +0900
copy to ex7
Diffstat:
A | ex7/Makefile | | | 14 | ++++++++++++++ |
A | ex7/ex7.c | | | 761 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 775 insertions(+), 0 deletions(-)
diff --git a/ex7/Makefile b/ex7/Makefile
@@ -0,0 +1,14 @@
+INCS=-I/usr/X11R6/include
+CFLAGS=-Wall -W -Wextra -Wpointer-arith -Wbad-function-cast -std=c11
+LIBS=-L/usr/X11R6/lib -lX11 -lXext -lm
+IN=*.c
+OUT=ex7
+
+all: $(IN)
+ $(CC) $(INCS) $(CFLAGS) -o $(OUT) $(IN) $(LIBS)
+
+run: all
+ ./$(OUT)
+
+clean:
+ rm -f $(OUT)
diff --git a/ex7/ex7.c b/ex7/ex7.c
@@ -0,0 +1,761 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+
+#include <X11/Xlib.h>
+
+/* macros */
+#define INIT_WIDTH (800)
+#define INIT_HEIGHT (600)
+#define FPS (60)
+#define SUB_TICK (4)
+#define NUM_RECT (200)
+#define GRAVITY (1000)
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define WORLD_WIDTH (80)
+#define WORLD_HEIGHT (60)
+#define BLOCK_SIZE (10)
+
+// #define COUNT_FPS
+
+enum keys {
+ KEY_D,
+ KEY_S,
+ KEY_A,
+ KEY_W,
+ KEY_Q,
+ KEY_SPACE,
+ NUM_KEY, //number of keys in this enum
+};
+enum key_state {
+ KEY_UP,
+ KEY_DOWN,
+};
+enum next_menu {
+ START_MENU,
+ GAME_PLAY,
+ GAME_OVER,
+ QUIT,
+};
+
+struct rect {
+ float ppx, ppy; // previous position
+ float px, py; // top left corner
+ float vx, vy;
+ float ax, ay;
+ int w, h;
+ int m;
+};
+
+struct circle {
+ float ppx, ppy;
+ float px, py;
+ float vx, vy;
+ float ax, ay;
+ int r;
+ int m;
+};
+
+char world_map[WORLD_WIDTH * WORLD_HEIGHT + 1] =
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"........b......................................................................."
+"................................................................................"
+"................................................................................"
+"....b..........................................................................."
+"................................................................................"
+"................b..............................................................."
+"..........................................................b..........b.........."
+"................................................................................"
+".......................b........................................................"
+"...........................................b...................................."
+"...........................................b...................................."
+"................................................................................"
+"..................b............................................................."
+"................................................................................"
+"...........................................b...................................."
+"................................................................................"
+"................................................................................"
+"...........................b...................................................."
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"....................................bbbbbbbbbb.................................."
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"..............................................bbbbbbbbbb........................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"....................................bbbbbbbbbb.................................."
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"..........................bbbbbbbbbb............................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................bbbbbbbbbb......................................................"
+"................................................................................"
+"................................................................................"
+"...p............................................................................"
+"bbbbbbbbbbbbbbbbbbbbbbbbb.......bbbbbbbbbbbbbbbbbbbbbbbb...bbbbbbbbbbbbbbbbbbbbb"
+"........................b.......b......................b...b...................."
+"........................b.......b......................b...b...................."
+"........................b.......b......................b...b...................."
+"........................b.......b......................b...b....................";
+
+/* variables */
+Display *display;
+Window window;
+unsigned int win_width = INIT_WIDTH, win_height = INIT_HEIGHT;
+GC gc, sgc[NUM_RECT];
+Atom wm_delete_window;
+struct rect block[NUM_RECT];
+struct rect player;
+int player_is_falling;
+int next_menu = START_MENU;
+
+
+/* function prototypes */
+void setup(void);
+void cleanup(void);
+void start_menu(void);
+void game_play(void);
+void receive_events(int[]);
+void handle_inputs(int[]);
+void rect_next_tick(struct rect *, long);
+int rect_test_collision(struct rect *, struct rect *);
+void rect_handle_collision_mf(struct rect *, struct rect *);
+void rect_handle_collision(struct rect *, struct rect *);
+void rect_handle_collision_elastic(struct rect *, struct rect *);
+void circle_next_tick(struct circle *, long);
+int circle_test_collision(struct circle *, struct circle *);
+void update_falling_status(struct rect *, long);
+void game_over(void);
+
+
+void
+setup(void)
+{
+ if ((display = XOpenDisplay(NULL)) == NULL){
+ fprintf(stderr, "ERROR: could not open display\n");
+ exit(1);
+ }
+ window = XCreateSimpleWindow(
+ display,
+ XDefaultRootWindow(display),
+ 0, 0,
+ win_width, win_height,
+ 0, 0,
+ 0);
+ XStoreName(display, window, "UNKO");
+ gc = XCreateGC(display, window, 0, NULL);
+ XSetForeground(display, gc, 0x00FFFF);
+ for (int i = 0; i < NUM_RECT; i++){
+ sgc[i] = XCreateGC(display, window, 0, NULL);
+ XSetForeground(display, sgc[i], 0x00FF00);
+ }
+
+ wm_delete_window = XInternAtom(display,
+ "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(display, window, &wm_delete_window, 1);
+
+ XSelectInput(display, window,
+ ExposureMask | KeyPressMask | KeyReleaseMask);
+
+ XMapWindow(display, window);
+}
+
+void
+start_menu(void)
+{
+ XEvent event;
+ char *menu_char_q = "press q to quit.";
+ char *menu_char_s = "press <space> to start.";
+
+ XClearArea(display, window,
+ 0, 0, // position
+ win_width, win_height, // width and height
+ False);
+ XDrawString(display, window, gc,
+ win_width/2 - strlen(menu_char_q)/2, win_height/2,
+ menu_char_q, strlen(menu_char_q));
+ XDrawString(display, window, gc,
+ win_width/2 - strlen(menu_char_s)/2, win_height/2 + 20,
+ menu_char_s, strlen(menu_char_s));
+
+ while (next_menu == START_MENU) {
+ XNextEvent(display, &event);
+ switch (event.type) {
+ case Expose: {
+ XDrawString(display, window, gc,
+ win_width/2 - strlen(menu_char_q)/2,
+ win_height/2,
+ menu_char_q, strlen(menu_char_q));
+ XDrawString(display, window, gc,
+ win_width/2 - strlen(menu_char_s)/2,
+ win_height/2 + 20,
+ menu_char_s, strlen(menu_char_s));
+
+ } break;
+ case KeyPress: {
+ switch (XLookupKeysym(&event.xkey, 0)) {
+ case 'q':
+ next_menu = QUIT;
+ break;
+ case ' ':
+ next_menu = GAME_PLAY;
+ break;
+ default:
+ break;
+ }
+ } break;
+ case ClientMessage: {
+ if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
+ next_menu = QUIT;
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+}
+
+void
+receive_events(int key_state[])
+{
+ XEvent event;
+ XWindowAttributes wattr;
+
+ while (XPending(display) > 0) {
+ XNextEvent(display, &event);
+ switch (event.type) {
+ case Expose: {
+ XGetWindowAttributes(display, window, &wattr);
+ win_width = wattr.width;
+ win_height = wattr.height;
+ } break;
+ case KeyPress: {
+ switch (XLookupKeysym(&event.xkey, 0)) {
+ case 'q':
+ //next_menu = GAME_OVER;
+ key_state[KEY_Q] = KEY_DOWN;
+ break;
+ case 'd':
+ key_state[KEY_D] = KEY_DOWN;
+ break;
+ case 'a':
+ key_state[KEY_A] = KEY_DOWN;
+ break;
+ case 'w':
+ key_state[KEY_W] = KEY_DOWN;
+ break;
+ case 's':
+ key_state[KEY_S] = KEY_DOWN;
+ break;
+ case ' ':
+ key_state[KEY_SPACE] = KEY_DOWN;
+ break;
+ default:
+ break;
+ }
+ } break;
+ case KeyRelease: {
+ switch (XLookupKeysym(&event.xkey, 0)) {
+ case 'q':
+ key_state[KEY_Q] = KEY_UP;
+ break;
+ case 'd':
+ key_state[KEY_D] = KEY_UP;
+ break;
+ case 'a':
+ key_state[KEY_A] = KEY_UP;
+ break;
+ case 'w':
+ key_state[KEY_W] = KEY_UP;
+ break;
+ case 's':
+ key_state[KEY_S] = KEY_UP;
+ break;
+ case ' ':
+ key_state[KEY_SPACE] = KEY_UP;
+ break;
+ default:
+ break;
+ }
+ } break;
+ case ClientMessage: {
+ if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
+ next_menu = QUIT;
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+}
+
+void
+handle_inputs(int key_state[])
+{
+ if (key_state[KEY_Q] == KEY_DOWN){
+ next_menu = GAME_OVER;
+ return;
+ }
+ if (key_state[KEY_D] == KEY_DOWN) {
+ if (player.vx > 0) {
+ player.ax = 500;
+ } else {
+ player.ax = 1000;
+ }
+ } else if (key_state[KEY_A] == KEY_DOWN) {
+ if (player.vx > 0) {
+ player.ax = -1000;
+ } else {
+ player.ax = -500;
+ }
+ } else {
+ if (player_is_falling)
+ player.ax = -player.vx;
+ else
+ player.ax = -3 * player.vx;
+ }
+
+ if (player.vx < -200) player.vx = -200;
+ if (player.vx > 200) player.vx = 200;
+ /*
+ if (key_state[KEY_S] == KEY_DOWN)
+ player.vy += 300;
+ if (key_state[KEY_W] == KEY_DOWN)
+ player.vy += -300;
+ */
+ if (!player_is_falling && key_state[KEY_SPACE] == KEY_DOWN)
+ player.vy = -450;
+}
+
+void
+rect_next_tick(struct rect *s, long ndt) // nano second
+{
+ s->ppx = s->px;
+ s->ppy = s->py;
+ s->vx += s->ax * ndt / 1000 / 1000 / 1000;
+ s->vy += s->ay * ndt / 1000 / 1000 / 1000;
+ s->px += s->vx * ndt / 1000 / 1000 / 1000;
+ s->py += s->vy * ndt / 1000 / 1000 / 1000;
+
+ // bind within the window
+ if (s->px < 0) {
+ s->px = 0;
+ //s->vx *= -1;
+ }
+ if (win_width < s->px + s->w) {
+ s->px = win_width - s->w;
+ //s->vx *= -1;
+ }
+ /*
+ if (s->py < 0) {
+ s->py = 0;
+ s->vy *= -1;
+ }
+ if (win_height < s->py + s->h) {
+ s->py = win_height - s->h;
+ s->vy *= -1;
+ }
+ */
+ // game over when fall out of the screen
+ if (s->py > win_height)
+ next_menu = GAME_OVER;
+}
+
+void
+circle_next_tick(struct circle *c, long ndt)
+{
+ c->ppx = c->px;
+ c->ppy = c->py;
+ c->vx += c->ax * ndt / 1000 / 1000 / 1000;
+ c->vy += c->ay * ndt / 1000 / 1000 / 1000;
+ c->px += c->vx * ndt / 1000 / 1000 / 1000;
+ c->py += c->vy * ndt / 1000 / 1000 / 1000;
+
+ // bind within the window
+ if (c->px - c->r < 0) {
+ c->px = c->r;
+ c->vx *= -1;
+ }
+ if (win_width < c->px + c->r) {
+ c->px = win_width - c->r;
+ c->vx *= -1;
+ }
+ if (c->py - c->r < 0) {
+ c->py = c->r;
+ c->vy *= -1;
+ }
+ if (win_height < c->py + c->r) {
+ c->py = win_height - c->r;
+ c->vy *= -1;
+ }
+}
+
+int
+rect_test_collision(struct rect *s1, struct rect *s2)
+{
+ return s1->px < s2->px + s2->w && s2->px < s1->px + s1->w &&
+ s2->py < s1->py + s1->h && s1->py < s2->py + s2->h;
+}
+
+int
+circle_test_collision(struct circle *c1, struct circle *c2)
+{
+ return (c1->px - c2->px) * (c1->px - c2->px) +
+ (c1->py - c2->py) * (c1->py - c2->py) <
+ (c1->r + c2->r) * (c1->r + c2->r);
+}
+
+/*
+ * Handle collision of a moving rect against fixed rect
+ */
+void
+rect_handle_collision_mf(struct rect *sm, struct rect *sf)
+{
+ if (!rect_test_collision(sm, sf))
+ return;
+ if (sm->ppx + sm->w <= sf->ppx && sf->px < sm->px + sm->w) {
+ // collisioin from left to right
+ sm->px = sf->px - sm->w;
+ sm->vx = 0;
+ }
+ if (sf->ppx + sf->w <= sm->ppx && sm->px < sf->px + sf->w) {
+ // collision from right to left
+ sm->px = sf->px + sf->w;
+ sm->vx = 0;
+ }
+
+ if (sm->ppy + sm->h <= sf->ppy && sf->py < sm->py + sm->h) {
+ // collision from up to down
+ sm->py = sf->py - sm->h;
+ sm->vy = 0;
+ }
+ if (sf->ppy + sf->h <= sm->ppy && sm->py < sf->py + sf->h) {
+ // collision from dohn to up
+ sm->py = sf->py + sf->h;
+ sm->vy = 0;
+ }
+
+}
+
+/*
+ * Handle collision of a moving rect against another moving rect
+ */
+void
+rect_handle_collision_mm(struct rect *s1, struct rect *s2)
+{
+ if (!rect_test_collision(s1, s2))
+ return;
+
+ float lapx = min(s1->px + s1->w, s2->px + s2->w) - max(s1->px, s2->px);
+ float lapy = min(s1->py + s1->h, s2->py + s2->h) - max(s1->py, s2->py);
+
+ if (lapx < lapy) {
+ if (s1->px + s1->w < s2->px + s2->w / 2) {
+ s1->px -= lapx / 2;
+ s2->px += lapx / 2;
+ } else {
+ s1->px += lapx / 2;
+ s2->px -= lapx / 2;
+ }
+ } else {
+ if (s1->py + s1->h < s2->py + s2->h / 2) {
+ s1->py -= lapy / 2;
+ s2->py += lapy / 2;
+ } else {
+ s1->py += lapy / 2;
+ s2->py -= lapy / 2;
+ }
+ }
+}
+
+void
+circle_handle_collision_mm(struct circle *c1, struct circle *c2)
+{
+ if (!circle_test_collision(c1, c2))
+ return;
+
+ float col_px = c2->px - c1->px;
+ float col_py = c2->py - c1->py;
+ float col_pr = sqrtf(col_px * col_px + col_py * col_py);
+ col_px /= col_pr;
+ col_py /= col_pr;
+
+ c1->px = c1->px - col_px / 2;
+ c1->py = c1->py - col_py / 2;
+ c2->px = c2->px + col_px / 2;
+ c2->py = c2->py + col_py / 2;
+}
+
+void
+rect_handle_collision_elastic(struct rect *s1, struct rect *s2)
+{
+ if(!rect_test_collision(s1, s2))
+ return;
+
+ rect_handle_collision_mm(s1, s2);
+
+ float v1, v2;
+ float m1 = s1->m;
+ float m2 = s2->m;
+
+ float lapx = min(s1->px + s1->w, s2->px + s2->w) - max(s1->px, s2->px);
+ float lapy = min(s1->py + s1->h, s2->py + s2->h) - max(s1->py, s2->py);
+
+ if (lapx < lapy) {
+ v1 = s1->vx;
+ v2 = s2->vx;
+ s1->vx = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1;
+ s2->vx = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2;
+ } else {
+ v1 = s1->vy;
+ v2 = s2->vy;
+ s1->vy = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1;
+ s2->vy = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2;
+ }
+}
+
+void
+circle_handle_collision_elastic(struct circle *c1, struct circle *c2)
+{
+ if(!circle_test_collision(c1, c2))
+ return;
+
+ circle_handle_collision_mm(c1, c2);
+
+ float col_px = c2->px - c1->px;
+ float col_py = c2->py - c1->py;
+ float col_pr = sqrtf(col_px * col_px + col_py * col_py);
+ col_px /= col_pr;
+ col_py /= col_pr;
+ float nor_px = col_py;
+ float nor_py = -col_px;
+
+ float m1 = c1->m;
+ float m2 = c2->m;
+
+ float col_1v = c1->vx * col_px + c1->vy * col_py;
+ float col_2v = c2->vx * col_px + c2->vy * col_py;
+
+ float col_1vxn = (2*m2/(m1+m2)*col_2v + (m1-m2)/(m1+m2)*col_1v) * col_px;
+ float col_1vyn = (2*m2/(m1+m2)*col_2v + (m1-m2)/(m1+m2)*col_1v) * col_py;
+ float col_2vxn = (2*m1/(m1+m2)*col_1v + (m2-m1)/(m1+m2)*col_2v) * col_px;
+ float col_2vyn = (2*m1/(m1+m2)*col_1v + (m2-m1)/(m1+m2)*col_2v) * col_py;
+
+ float nor_1vx = nor_px * (c1->vx * nor_px + c1->vy * nor_py);
+ float nor_1vy = nor_py * (c1->vx * nor_px + c1->vy * nor_py);
+ float nor_2vx = nor_px * (c2->vx * nor_px + c2->vy * nor_py);
+ float nor_2vy = nor_py * (c2->vx * nor_px + c2->vy * nor_py);
+
+ c1->vx = col_1vxn + nor_1vx;
+ c1->vy = col_1vyn + nor_1vy;
+ c2->vx = col_2vxn + nor_2vx;
+ c2->vy = col_2vyn + nor_2vy;
+}
+
+void
+update_falling_status(struct rect *player, long ndt)
+{
+ int collision = 0;
+ struct rect r = {0};
+ r.ppx = player->ppx;
+ r.ppy = player->ppy;
+ r.px = player->px;
+ r.py = player->py;
+ r.vx = 0;
+ r.vy = 0;
+ r.ax = 0;
+ r.ay = GRAVITY;
+ r.w = player->w;
+ r.h = player->h;
+ r.m = player->m;
+
+ rect_next_tick(&r, ndt);
+ for (int i = 0; i < NUM_RECT; i++)
+ if (rect_test_collision(&r, &block[i]))
+ collision = 1;
+
+ if (collision == 1)
+ player_is_falling = 0;
+ else
+ player_is_falling = 1;
+}
+
+void
+game_play(void)
+{
+ int key_state[NUM_KEY];
+ long t0, t1, dt;
+#ifdef COUNT_FPS
+ int fps_count = 0;
+#endif
+ struct timespec ts;
+
+ int bi = 0;
+ for (int i = 0; i < WORLD_WIDTH * WORLD_HEIGHT; i++) {
+ if (world_map[i] == 'b') {
+ block[bi].ppx = block[bi].px = i % WORLD_WIDTH * BLOCK_SIZE;
+ block[bi].ppy = block[bi].py = i / WORLD_WIDTH * BLOCK_SIZE;
+ block[bi].ax = 0;
+ block[bi].ay = 0;
+ block[bi].vx = 0;
+ block[bi].vy = 0;
+ block[bi].w = block[bi].h = BLOCK_SIZE;
+ block[bi].m = block[bi].w * block[bi].h;
+ bi++;
+ } else if (world_map[i] == 'p') {
+ player.ppx = player.px = i % WORLD_WIDTH * BLOCK_SIZE;
+ player.ppy = player.py = i / WORLD_WIDTH * BLOCK_SIZE;
+ player.vx = 0;
+ player.vy = 0;
+ player.ax = 0;
+ player.ay = GRAVITY;
+ player.w = player.h = BLOCK_SIZE;
+ player.m = player.w * player.h;
+ }
+ }
+
+ while (next_menu == GAME_PLAY){
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t0 = ts.tv_nsec;
+ receive_events(key_state);
+ handle_inputs(key_state);
+
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t0 = ts.tv_nsec;
+
+ int collision[NUM_RECT] = {0};
+ for (int k = 0; k < SUB_TICK; k++) {
+ update_falling_status(&player, 1000 * 1000 * 1000 / FPS / SUB_TICK);
+ if (player_is_falling)
+ player.ay = GRAVITY;
+ else
+ player.ay = 0;
+ rect_next_tick(&player, 1000 * 1000 * 1000 / FPS / SUB_TICK);
+ for (int i = 0; i < NUM_RECT; i++)
+ rect_next_tick(&block[i], 1000 * 1000 * 1000 / FPS / SUB_TICK);
+
+ for (int i = 0; i < NUM_RECT; i++){
+ rect_handle_collision_mf(&player, &block[i]);
+ if (rect_test_collision(&player, &block[i]))
+ collision[i] = 1;
+ }
+ }
+ for (int i = 0; i < NUM_RECT; i++)
+ if (collision[i] == 1)
+ XSetForeground(display, sgc[i], 0xFFFF00);
+ else
+ XSetForeground(display, sgc[i], 0x90FF90);
+
+ // fix fps
+ // TODO: This method create some strange stripe when
+ // rendered in 60fps on a 60fps monitor.
+ dt = 0;
+ while (dt < 1.0 * 1000 * 1000 * 1000 / FPS){
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t1 = ts.tv_nsec;
+ dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000;
+ }
+#ifdef COUNT_FPS
+ // count fps.
+ fps_count++;
+ if (t1 < t0){
+ printf("fps: %u\n", fps_count);
+ fps_count = 0;
+ }
+#endif
+
+ XClearArea(display, window,
+ 0, 0, // position
+ win_width, win_height, // width and height
+ False);
+ for (int i = 0; i < NUM_RECT; i++) {
+ XDrawRectangle(display, window, sgc[i],
+ block[i].px,
+ block[i].py, // position
+ block[i].w, block[i].h);
+ }
+ XDrawRectangle(display, window, gc,
+ player.px,
+ player.py, // position
+ player.w, player.h);
+ char status_string[128];
+ snprintf(status_string, 128, "falling: %d", player_is_falling);
+ XDrawString(display, window, gc,
+ 0, 20,
+ status_string,
+ strlen(status_string));
+ }
+}
+
+void
+game_over(void)
+{
+ char *menu_char = "GAME OVER";
+
+ XClearArea(display, window,
+ 0, 0, // position
+ win_width, win_height, // width and height
+ False);
+ XDrawString(display, window, gc,
+ win_width/2 - strlen(menu_char)/2, win_height/2,
+ menu_char, strlen(menu_char));
+ XFlush(display);
+
+ sleep(1);
+ next_menu = START_MENU;
+}
+
+void
+cleanup(void)
+{
+ XCloseDisplay(display);
+}
+
+int
+main(void)
+{
+ setup();
+ while (next_menu != QUIT){
+ switch (next_menu){
+ case START_MENU:
+ start_menu();
+ break;
+ case GAME_PLAY:
+ game_play();
+ break;
+ case GAME_OVER:
+ game_over();
+ break;
+ default:
+ break;
+ }
+ }
+
+ cleanup();
+ return 0;
+}