test timing and input handling
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 9 Feb 2019 11:46:41 +0000 (13:46 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 9 Feb 2019 11:46:41 +0000 (13:46 +0200)
src/ansi.c
src/ansi.h
src/game.c
src/game.h
src/main.c

index ac5185f..07ae749 100644 (file)
@@ -63,6 +63,12 @@ void ansi_setcursor(int row, int col)
        printf("\033[%d;%dH", row + 1, col + 1);
 }
 
+void ansi_cursor(int show)
+{
+       printf("\033[?25%c", show ? 'h' : 'l');
+       fflush(stdout);
+}
+
 void ansi_ibmchar(unsigned char c, unsigned char attr)
 {
        char cmd[32];
index 5e1e482..b63ed8e 100644 (file)
@@ -5,6 +5,7 @@ void ansi_reset(void);
 void ansi_clearscr(void);
 
 void ansi_setcursor(int row, int col);
+void ansi_cursor(int show);
 
 /* convert a PC cga/ega/vga char+attr to an ANSI sequence and write it to stdout */
 void ansi_ibmchar(unsigned char c, unsigned char attr);
index f1622aa..e8b47f3 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <string.h>
 #include <inttypes.h>
 #include "game.h"
 #include "pieces.h"
@@ -46,7 +47,10 @@ int init_game(void)
        int i, j;
        uint16_t *row = scr;
 
+       tick_interval = 1000;
+
        ansi_clearscr();
+       ansi_cursor(0);
 
        /* fill the screen buffer, and draw */
        for(i=0; i<SCR_ROWS; i++) {
@@ -77,15 +81,55 @@ void cleanup_game(void)
        ansi_reset();
 }
 
-void proc_input(void)
+static int pos[2] = {0, PF_COLS / 2};
+static int next_pos[2] = {0, PF_COLS / 2};
+
+long update(long msec)
 {
-       int c = fgetc(stdin);
+       static long prev_tick;
+       long dt;
+
+       dt = msec - prev_tick;
+
+       /* fall */
+       while(dt >= tick_interval) {
+               next_pos[0] = (pos[0] + 1) % PF_ROWS;
+               dt -= tick_interval;
+               prev_tick = msec;
+       }
 
+       if(memcmp(pos, next_pos, sizeof pos) != 0) {
+               ansi_setcursor(pos[0], (PF_XOFFS + pos[1]) * 2);
+               wrchar(CHAR(' ', BLACK, WHITE));
+
+               memcpy(pos, next_pos, sizeof pos);
+               ansi_setcursor(pos[0], (PF_XOFFS + pos[1]) * 2);
+               wrchar(CHAR(' ', RED, RED));
+
+               fflush(stdout);
+       }
+       return tick_interval - dt;
+}
+
+void game_input(int c)
+{
        switch(c) {
        case 27:
                quit = 1;
                break;
 
+       case 'a':
+               if(pos[1] > 0) {
+                       next_pos[1] = pos[1] - 1;
+               }
+               break;
+
+       case 'd':
+               if(pos[1] < PF_COLS - 1) {
+                       next_pos[1] = pos[1] + 1;
+               }
+               break;
+
        default:
                break;
        }
index 0fe598e..14a6620 100644 (file)
@@ -2,10 +2,12 @@
 #define GAME_H_
 
 int quit;
+long tick_interval;
 
 int init_game(void);
 void cleanup_game(void);
 
-void proc_input(void);
+long update(long msec);
+void game_input(int c);
 
 #endif /* GAME_H_ */
index 6f27d73..dc240fd 100644 (file)
@@ -5,16 +5,24 @@
 #include <fcntl.h>
 #include <termios.h>
 #include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
 #include "game.h"
 
 int init(void);
 void cleanup(void);
+long get_msec(void);
 
-const char *termfile = "/dev/tty";
-struct termios saved_term;
+static const char *termfile = "/dev/tty";
+static struct termios saved_term;
+static struct timeval tv0;
 
 int main(int argc, char **argv)
 {
+       int res, c;
+       long msec, next;
+       struct timeval tv;
+
        if(argc > 1) {
                termfile = argv[1];
        }
@@ -23,11 +31,33 @@ int main(int argc, char **argv)
                return 1;
        }
 
+       gettimeofday(&tv0, 0);
+
+       tv.tv_sec = tick_interval / 1000;
+       tv.tv_usec = (tick_interval % 1000) * 1000;
+
        for(;;) {
-               proc_input();
-               if(quit) break;
+               fd_set rdset;
+               FD_ZERO(&rdset);
+               FD_SET(0, &rdset);
+
+               while((res = select(1, &rdset, 0, 0, &tv)) == -1 && errno == EINTR);
+
+               if(res > 0 && FD_ISSET(0, &rdset)) {
+                       while((c = fgetc(stdin)) >= 0) {
+                               game_input(c);
+                               if(quit) goto end;
+                       }
+               }
+
+               msec = get_msec();
+               next = update(msec);
+
+               tv.tv_sec = next / 1000;
+               tv.tv_usec = (next % 1000) * 1000;
        }
 
+end:
        cleanup();
        return 0;
 }
@@ -37,7 +67,7 @@ int init(void)
        int fd;
        struct termios term;
 
-       if((fd = open(termfile, O_RDWR)) == -1) {
+       if((fd = open(termfile, O_RDWR | O_NONBLOCK)) == -1) {
                fprintf(stderr, "failed to open terminal device: %s: %s\n", termfile, strerror(errno));
                return -1;
        }
@@ -79,3 +109,12 @@ void cleanup(void)
        cleanup_game();
        tcsetattr(0, TCSAFLUSH, &saved_term);
 }
+
+long get_msec(void)
+{
+       struct timeval tv;
+
+       gettimeofday(&tv, 0);
+
+       return (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000;
+}