From 9ecd65467232071b18a7c6f782a22264046ebf45 Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Sat, 22 Jul 2023 13:58:05 +0100 Subject: Joystick support --- README.md | 18 ++++----- TODO.md | 2 - src/control.c | 36 +++++++++++++++++ src/control.h | 15 +++++++ src/joy.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/joy.h | 10 +++++ src/main.c | 4 ++ src/player.c | 11 ++++-- 8 files changed, 204 insertions(+), 15 deletions(-) create mode 100644 src/control.c create mode 100644 src/control.h create mode 100644 src/joy.c create mode 100644 src/joy.h diff --git a/README.md b/README.md index 4ef2ecf..c77c57e 100644 --- a/README.md +++ b/README.md @@ -12,15 +12,15 @@ Running the game: - At least 4MB of RAM - Sound Blaster (or no sound) -The game can be controlled by keyboard. - -| Key | Action | -| --- | --- | -| Cursor up | Jump | -| Cursor left | Move left | -| Cursor right | Move Right | -| P | Pause / resume game | -| ESC | Exit the game | +The game can be controlled by keyboard or joystick. + +| Key | Joystick | Action | +| --- | --- | --- | +| Cursor left | Joytick left | Move left | +| Cursor right | Joystick right | Move Right | +| Z | Button 1 | Jump | +| P | - | Pause / resume game | +| ESC | - | Exit the game | Check `-h` CLI flag for options. diff --git a/TODO.md b/TODO.md index d639df5..29fee2b 100644 --- a/TODO.md +++ b/TODO.md @@ -8,8 +8,6 @@ - menu? - screens - end game -- input - - joystick? # REVIEW diff --git a/src/control.c b/src/control.c new file mode 100644 index 0000000..ee103f0 --- /dev/null +++ b/src/control.c @@ -0,0 +1,36 @@ +#include + +#include "keyb.h" +#include "joy.h" + +#include "control.h" + +static uint8_t joy = 0; + +void control_init() +{ + joy = joy_detect(); +} + +uint8_t control_read() +{ + uint8_t r = CTL_NONE; + + if (keys[KEY_UP]) + r |= CTL_UP; + if (keys[KEY_DOWN]) + r |= CTL_DOWN; + if (keys[KEY_LEFT]) + r |= CTL_LEFT; + if (keys[KEY_RIGHT]) + r |= CTL_RIGHT; + if (keys[KEY_Z]) + r |= CTL_FIRE1; + if (keys[KEY_X]) + r |= CTL_FIRE2; + + if (joy) + r |= joy_read(); + + return r; +} diff --git a/src/control.h b/src/control.h new file mode 100644 index 0000000..f4f02c7 --- /dev/null +++ b/src/control.h @@ -0,0 +1,15 @@ +#ifndef _CONTROL_H +#define _CONTROL_H + +#define CTL_NONE 0 +#define CTL_UP 1 +#define CTL_DOWN 2 +#define CTL_RIGHT 4 +#define CTL_LEFT 16 +#define CTL_FIRE1 32 +#define CTL_FIRE2 64 + +void control_init(); +uint8_t control_read(); + +#endif /* _CONTROL_H */ diff --git a/src/joy.c b/src/joy.c new file mode 100644 index 0000000..cda2fcf --- /dev/null +++ b/src/joy.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include + +#include "vga.h" +#include "keyb.h" +#include "control.h" + +#include "joy.h" + +#define PORT 0x201 + +#define BUTTON1 0x10 +#define BUTTON2 0x20 +#define AXISX 1 +#define AXISY 2 + +#define TIMEOUT 16000 + +static uint16_t j_up, j_down, j_left, j_right; + +static uint16_t read_axis(uint8_t axis) +{ + uint16_t i; + + disable(); + outportb(PORT, 0xff); + for (i = 0; i < TIMEOUT; i++) + if (!(inportb(PORT) & axis)) + break; + enable(); + + return i; +} + +static uint8_t calibrate(uint16_t *v, uint16_t *h) +{ + while (1) + { + if (keys[KEY_ESC]) + { + while (keys[KEY_ESC]) + wait_vsync(); + return 0; + } + + *v = read_axis(AXISY); + *h = read_axis(AXISX); + + if (!(inportb(PORT) & BUTTON1)) + { + while (!(inportb(PORT) & BUTTON1)) + wait_vsync(); + return 1; + } + + wait_vsync(); + } +} + +uint8_t joy_detect() +{ + if (read_axis(AXISX) == TIMEOUT) + return 0; + + printf("Joystick detected!\n"); + + printf("Please move UP + LEFT and press BUTTON 1 (ESC to abort)\n"); + if (!calibrate(&j_up, &j_left)) + return 0; + printf("Please move DOWN + RIGHT and press BUTTON 1 (ESC to abort)\n"); + if (!calibrate(&j_down, &j_right)) + return 0; + +#ifdef DEBUG + printf("Joystick reads: up=%04d, down=%04d, left=%04d, right=%04d\n", + j_up, j_down, j_left, j_right); +#endif + + j_up += j_up >> 4; + j_down -= j_down >> 4; + j_left += j_left >> 4; + j_right -= j_right >> 4; + +#ifdef DEBUG + printf(" Adjusted: up=%04d, down=%04d, left=%04d, right=%04d\n", + j_up, j_down, j_left, j_right); + + printf("(press X to continue)\n"); + while (!keys[KEY_X]) + wait_vsync(); +#endif + + return 1; +} + +uint8_t joy_read() +{ + uint8_t r = CTL_NONE; + uint8_t b; + uint16_t v; + + b = inportb(PORT); + if (!(b & BUTTON1)) + r |= CTL_FIRE1; + if (!(b & BUTTON2)) + r |= CTL_FIRE2; + + v = read_axis(AXISY); + if (v <= j_up) + r |= CTL_UP; + if (v >= j_down) + r |= CTL_DOWN; + + v = read_axis(AXISX); + if (v <= j_left) + r |= CTL_LEFT; + if (v >= j_right) + r |= CTL_RIGHT; + + return r; +} diff --git a/src/joy.h b/src/joy.h new file mode 100644 index 0000000..f510c2a --- /dev/null +++ b/src/joy.h @@ -0,0 +1,10 @@ +#ifndef _JOY_H +#define _JOY_H + +/* it also calibrates */ +uint8_t joy_detect(); + +/* returns the bits specified in control.h */ +uint8_t joy_read(); + +#endif /* _JOY_H */ diff --git a/src/main.c b/src/main.c index 5cdcb1b..3a1aca6 100644 --- a/src/main.c +++ b/src/main.c @@ -7,6 +7,7 @@ #include "timer.h" #include "keyb.h" #include "sound.h" +#include "control.h" #include "vga.h" #include "data.h" #include "menu.h" @@ -75,6 +76,9 @@ int main(int argc, char *argv[]) keyb_init(); atexit(free_all); + /* requires keyboard */ + control_init(); + /* to update mikmod */ timer_user_fn(sound_update); diff --git a/src/player.c b/src/player.c index 96fb283..28ad76e 100644 --- a/src/player.c +++ b/src/player.c @@ -1,6 +1,6 @@ #include -#include "keyb.h" +#include "control.h" #include "vga.h" #include "sound.h" #include "map.h" @@ -133,6 +133,7 @@ static void player_dying() void player_update() { uint8_t moved = 0; + uint8_t ctl = CTL_NONE; ox = x; oy = y; @@ -143,6 +144,8 @@ void player_update() return; } + ctl = control_read(); + if (invuln) invuln--; @@ -158,7 +161,7 @@ void player_update() moved = 1; } - if (keys[KEY_UP]) + if (ctl & CTL_FIRE1) { if ((gravity == GRAVITY_OFF || momentum) && !jump) { @@ -172,7 +175,7 @@ void player_update() else jump = 0; - if (keys[KEY_RIGHT] && !keys[KEY_LEFT]) + if (ctl & CTL_RIGHT && !(ctl & CTL_LEFT)) { moved = 1; dir = DIR_RIGHT; @@ -192,7 +195,7 @@ void player_update() } } - if (keys[KEY_LEFT] && !keys[KEY_RIGHT]) + if (ctl & CTL_LEFT && !(ctl & CTL_RIGHT)) { moved = 1; dir = DIR_LEFT; -- cgit v1.2.3