I was thinking of what games could be played with a single button and a sort of Defender style cavern flying game seemed doable. This simple game has no plot, no enemies, and no brakes.
Hit/hold the button to accelerate upwards at 1 G. Release the button to stop accelerating, but plan ahead so that you coast to apogee at the right time to avoid the cavern ceiling. Remember that dx/dt = v and dv/dt = a.
Video of the game:
http://www.flickr.com/photos/osr/5562355052/
#include <pulse_os.h>
#include <pulse_types.h>
#include <app_resources.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define COLOR_BLACK ((color24_t) { 0x00, 0x00, 0x00, 0 })
#define COLOR_GREEN ((color24_t) { 0x00, 0xFF, 0x00, 0 })
#define COLOR_RED ((color24_t) { 0xF0, 0x00, 0x00, 0 })
#define PLANE_X_MAX ((SCREEN_HEIGHT-10)*16)
#define PLANE_Y_MAX ((SCREEN_WIDTH-2)*16)
static uint8_t walls[2][SCREEN_HEIGHT];
static int16_t plane_x;
static int16_t plane_y;
static int8_t plane_v;
static unsigned plane_a;
static void
reset_game(void)
{
srand(pulse_get_millis());
memset(walls[0], 0, sizeof(walls[0]));
memset(walls[1], SCREEN_WIDTH - 1, sizeof(walls[1]));
plane_y = 3 * (PLANE_Y_MAX / 4);
plane_x = PLANE_X_MAX;
plane_v = 0;
plane_a = 0;
pulse_blank_canvas();
pulse_oled_set_brightness(100);
}
void
main_app_handle_button_down(void)
{
plane_a = pulse_get_millis();
}
void
main_app_handle_button_up(void)
{
plane_a = 0;
}
static void
short_pulse()
{
pulse_vibe_on();
pulse_mdelay(100);
pulse_vibe_off();
}
static uint8_t
new_point(
int top
)
{
// Generate a random point that doesn't hit the other side
// or go off the screen to the bottom.
const uint8_t w1 = walls[top][0];
const uint8_t w2 = walls[!top][0];
const uint8_t GAP = 30;
while (1)
{
// 0-15
int8_t n = rand() & 7;
if (n == 0)
continue;
n -= 4;
if (n < 0)
{
if (-n > w1)
continue;
if (top && w1 + n - GAP <= w2)
continue;
} else
if (n > 0)
{
if (n + w1 >= SCREEN_WIDTH)
continue;
if (!top && w1 + n + GAP >= w2)
continue;
}
return w1 + n;
}
}
static void
pulse_draw_row(
uint8_t y,
uint8_t x1,
uint8_t x2,
color24_t color
)
{
if (x1 > x2)
{
uint8_t t = x1;
x1 = x2;
x2 = t;
}
pulse_set_draw_window(
x1,
y,
x2,
y
);
const uint8_t width = x2 - x1 + 1;
for (uint8_t i = 0 ; i < width ; i++)
pulse_draw_point24(color);
}
static void
move_walls(
int top,
uint8_t * const wall
)
{
// Shuffle the wall to this side
for (int i = SCREEN_HEIGHT-1 ; i >= 0 ; i--)
{
// Where was this pixel last screen draw
const uint8_t w1 = wall[i];
// Where this pixel will be this screen draw
const uint8_t w2 = (i == 0)
? new_point(top)
: wall[i-1];
wall[i] = w2;
if (!top)
{
// Adding/subtracting color
// from the left side of the screen
if (w1 < w2)
pulse_draw_row(i, w1, w2, COLOR_GREEN);
else
if (w1 > w2)
pulse_draw_row(i, w2, w1, COLOR_BLACK);
} else
{
// Adding/subtracting color
// from the right side of the screen
if (w2 < w1)
pulse_draw_row(i, w2, w1, COLOR_GREEN);
else
if (w2 > w1)
pulse_draw_row(i, w1, w2, COLOR_BLACK);
}
}
}
static void
draw_plane(
uint16_t x,
uint16_t y,
color24_t color
)
{
x /= 16;
y /= 16;
pulse_set_draw_window(y, x, y + 1, x + 1);
for (int i = 0 ; i < 4 ; i++)
pulse_draw_point24(color);
}
static void
move_plane(void)
{
const int16_t old_y = plane_y;
const int16_t old_x = plane_x;
plane_v -= 1; // gravity
plane_v += plane_a ? 3 : 0; // boost
if (plane_v > 100)
plane_v = 100;
else
if (plane_v < -100)
plane_v = -100;
plane_y += plane_v;
if (plane_y > PLANE_Y_MAX)
{
plane_y = PLANE_Y_MAX;
plane_v = 0;
} else
if (plane_y < 0)
{
plane_y = 0;
plane_v = 0;
}
if (plane_a)
{
plane_x -= 3; // boost forwards when they hold it down
if (plane_x < 0)
plane_x = 0;
} else {
plane_x++;
if (plane_x > PLANE_X_MAX)
plane_x = PLANE_X_MAX;
}
draw_plane(old_x, old_y, COLOR_BLACK);
draw_plane(plane_x, plane_y, COLOR_RED);
if (walls[0][plane_x/16] > plane_y / 16
|| walls[1][plane_x/16] < plane_y / 16)
{
short_pulse();
reset_game();
}
}
void
main_app_loop(void)
{
static unsigned last_frame;
unsigned now = pulse_get_millis();
if (now - last_frame < 30)
return;
last_frame = now;
move_walls(0, walls[0]);
move_walls(1, walls[1]);
move_plane();
}
void
main_app_init(void)
{
reset_game();
}
void
main_app_handle_doz(void)
{
}
void
main_app_handle_hardware_update(
enum PulseHardwareEvent event
)
{
}