commit 800429750907d7f1041a9af4199bc2ae6d45969b
parent 9abbafd3e1c0f82f85bd210d5958f802a246b98c
Author: Matsuda Kenji <info@mtkn.jp>
Date: Fri, 23 Dec 2022 13:11:41 +0900
add menu
Diffstat:
M | ex3/ex3.c | | | 167 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- |
1 file changed, 133 insertions(+), 34 deletions(-)
diff --git a/ex3/ex3.c b/ex3/ex3.c
@@ -2,6 +2,7 @@
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
+#include <string.h>
#include <math.h>
#include <X11/Xlib.h>
@@ -15,18 +16,24 @@
#define COUNT_FPS
*/
-
enum keys {
KEY_D,
- KEY_S,
- KEY_A,
- KEY_W,
- KEY_SPACE,
- NUM_KEY, //number of keys in this enum
+ 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,
+ KEY_UP,
+ KEY_DOWN,
+};
+enum next_menu {
+ START_MENU,
+ GAME_PLAY,
+ GAME_OVER,
+ QUIT,
};
/* variables */
@@ -35,18 +42,21 @@ Window window;
unsigned int win_width = INIT_WIDTH, win_height = INIT_HEIGHT;
GC gc;
Atom wm_delete_window;
-int key_state[NUM_KEY];
-int quit;
float px = 200, py = 200;
float vx = 0, vy = 0;
int width = 40, height = 40;
+int next_menu = START_MENU;
/* function prototypes */
void setup(void);
void cleanup(void);
-void receive_events(void);
-void handle_inputs(void);
+void start_menu(void);
+void game_play(void);
+void receive_events(int *);
+void handle_inputs(int *);
+void next_tick(long);
+void game_over(void);
void
@@ -66,19 +76,74 @@ setup(void)
XStoreName(display, window, "UNKO");
gc = XCreateGC(display, window, 0, NULL);
- wm_delete_window = XInternAtom(display,
+ wm_delete_window = XInternAtom(display,
"WM_DELETE_WINDOW", False);
XSetWMProtocols(display, window, &wm_delete_window, 1);
XSelectInput(display, window,
ExposureMask|KeyPressMask|KeyReleaseMask);
-
+
XSetForeground(display, gc, 0x00FFFF);
XMapWindow(display, window);
}
void
-receive_events(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;
@@ -94,7 +159,8 @@ receive_events(void)
case KeyPress: {
switch (XLookupKeysym(&event.xkey, 0)) {
case 'q':
- quit = 1;
+ //next_menu = GAME_OVER;
+ key_state[KEY_Q] = KEY_DOWN;
break;
case 'd':
key_state[KEY_D] = KEY_DOWN;
@@ -114,6 +180,9 @@ receive_events(void)
} 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;
@@ -132,7 +201,7 @@ receive_events(void)
} break;
case ClientMessage: {
if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
- quit = 1;
+ next_menu = QUIT;
}
} break;
default:
@@ -142,8 +211,12 @@ receive_events(void)
}
void
-handle_inputs(void)
+handle_inputs(int key_state[])
{
+ if (key_state[KEY_Q] == KEY_DOWN){
+ next_menu = GAME_OVER;
+ return;
+ }
vx = vy = 0;
if (key_state[KEY_D] == KEY_DOWN)
vx += 300;
@@ -159,7 +232,7 @@ void
next_tick(long ndt) // nano second
{
px = px + vx * ndt / 1000 / 1000 / 1000;
- py = py + vy * ndt / 1000 / 1000 / 1000;
+ py = py + vy * ndt / 1000 / 1000 / 1000;
// bind within the window
if (px < 0)
px = 0;
@@ -172,30 +245,24 @@ next_tick(long ndt) // nano second
}
void
-cleanup(void)
-{
- XCloseDisplay(display);
-}
-
-int
-main(void)
+game_play(void)
{
+ int key_state[NUM_KEY];
long t0, t1, dt;
#ifdef COUNT_FPS
int fps_count = 0;
#endif
struct timespec ts;
- setup();
- quit = 0;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- t0 = ts.tv_nsec;
-
- while (!quit){
- receive_events();
- handle_inputs();
+ while (next_menu == GAME_PLAY){
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t0 = ts.tv_nsec;
+ receive_events(key_state);
+ handle_inputs(key_state);
// fix fps
+ // TODO: This method create some strange stripe when
+ // rendered in 60fps monitor.
dt = 0;
while (dt < 1.0 * 1000 * 1000 * 1000 / FPS){
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -223,7 +290,39 @@ main(void)
XFillRectangle(display, window, gc,
px, py, // position
width, height); // width and height
+ }
+}
+
+void
+game_over(void)
+{
+ 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();