working snake input, todo: motion

multi-mode
Ondřej Hruška 8 years ago
parent e99ea3d0ec
commit a4400c25f5
  1. 2
      project/hw_init.c
  2. 153
      project/mode_snake.c

@ -64,7 +64,7 @@ static void conf_subsystems(void)
timebase_init(20, 20);
// event and task queues
queues_init(30, 30);
queues_init(30, 10);
// initialize SBMP for ESP8266
// dlnk_init();

@ -1,10 +1,13 @@
#include "mode_snake.h"
#include "com/debug.h"
#include "dotmatrix.h"
#include "utils/timebase.h"
#define BOARD_W SCREEN_W
#define BOARD_H SCREEN_H
static bool snake_active = false;
/** Snake movement direction */
typedef enum {
NORTH,
@ -28,7 +31,6 @@ typedef struct __attribute__((packed)) {
/** Wall tile, invariant, used for out-of-screen coords */
static const Cell WALL_TILE = {CELL_WALL, 0};
static const Cell EMPTY_TILE = {CELL_EMPTY, 0};
/** Game board */
static Cell board[BOARD_H][BOARD_W];
@ -44,10 +46,33 @@ static Coord tail;
static Direction head_dir;
/** blinking to visually change 'color' */
static bool wall_pwm_on = 1;
static bool body_pwm_on = 1;
static bool head_pwm_on = 1;
static bool food_pwm_on = 1;
typedef struct {
bool pwm_bit;
task_pid_t on_task; // periodic
task_pid_t off_task; // scheduled
ms_time_t interval_ms;
ms_time_t offtime_ms;
} snake_pwm;
static bool moving = false;
static task_pid_t task_snake_move;
static snake_pwm food_pwm = {
.interval_ms = 400,
.offtime_ms = 330
};
static snake_pwm head_pwm = {
.interval_ms = 100,
.offtime_ms = 90
};
static ms_time_t move_interval = 500;
/** Get board cell at coord (x,y) */
static Cell *cell_at_xy(int x, int y)
@ -102,6 +127,8 @@ static void new_game(void)
head.x = tail.x + 4;
head.y = tail.y;
head_dir = EAST;
for (int x = tail.x; x < head.x; x++) {
board[tail.y][x].type = CELL_BODY;
}
@ -111,6 +138,8 @@ static void new_game(void)
static void show_board(void)
{
if (!snake_active) return;
dmtx_clear(dmtx);
for (int x = 0; x < BOARD_W; x++) {
@ -121,16 +150,15 @@ static void show_board(void)
switch (cell->type) {
case CELL_EMPTY: set = 0; break;
case CELL_BODY: set = body_pwm_on; break;
case CELL_BODY: set = 1; break;
case CELL_FOOD:
dbg("Food found @ [%d, %d]", x, y);
set = food_pwm_on;
set = food_pwm.pwm_bit;
break;
case CELL_WALL: set = wall_pwm_on; break;
case CELL_WALL: set = 1; break;
}
if (x == head.x && y == head.y) set = head_pwm_on;
if (x == head.x && y == head.y) set = head_pwm.pwm_bit;
dmtx_set(dmtx, x, y, set);
}
@ -139,26 +167,119 @@ static void show_board(void)
dmtx_show(dmtx);
}
static void snake_move_cb(void *unused)
{
(void)unused;
void mode_snake_init(void)
dbg("Move.");
}
// --- Snake PWM ---
/** Turn off a PWM bit (scheduled callback) */
static void task_pwm_off_cb(void *ptr)
{
if (!snake_active) return;
((snake_pwm*)ptr)->pwm_bit = 0;
show_board();
}
/** Turn on a PWM bit and schedule the turn-off task (periodic callback) */
static void task_pwm_on_cb(void *ptr)
{
if (!snake_active) return;
((snake_pwm*)ptr)->pwm_bit = 1;
show_board();
schedule_task(task_pwm_off_cb, ptr, ((snake_pwm*)ptr)->offtime_ms, true);
}
/** Initialize a snake PWM channel */
static void snake_pwm_init(snake_pwm *ptr)
{
ptr->on_task = add_periodic_task(task_pwm_on_cb, ptr, ptr->interval_ms, true);
enable_periodic_task(ptr->on_task, false);
}
/** Clear & start a snake PWM channel */
static void snake_pwm_start(snake_pwm *ptr)
{
ptr->pwm_bit = 1;
reset_periodic_task(ptr->on_task);
enable_periodic_task(ptr->on_task, true);
}
/** Stop a snake PWM channel */
static void snake_pwm_stop(snake_pwm *ptr)
{
//
enable_periodic_task(ptr->on_task, false);
abort_scheduled_task(ptr->off_task);
}
/** INIT snake */
void mode_snake_init(void)
{
snake_pwm_init(&head_pwm);
snake_pwm_init(&food_pwm);
task_snake_move = add_periodic_task(snake_move_cb, NULL, move_interval, true);
enable_periodic_task(task_snake_move, false);
}
/** START playing */
void mode_snake_start(void)
{
new_game();
snake_active = true;
show_board();
snake_pwm_start(&head_pwm);
snake_pwm_start(&food_pwm);
// Stop snake (make sure it's stopped)
enable_periodic_task(task_snake_move, false);
moving = false;
new_game();
}
/** STOP playing */
void mode_snake_stop(void)
{
//
snake_active = false;
snake_pwm_stop(&head_pwm);
snake_pwm_stop(&food_pwm);
enable_periodic_task(task_snake_move, false);
}
/** User button */
void mode_snake_btn(char key)
{
//
switch (key) {
case 'U': head_dir = NORTH; break;
case 'D': head_dir = SOUTH; break;
case 'L': head_dir = WEST; break;
case 'R': head_dir = EAST; break;
case 'K': // clear
// TODO reset animation
mode_snake_stop();
mode_snake_start();
break;
}
if (!moving && (key == 'U' || key == 'D' || key == 'L' || key == 'R' || key == 'J')) {
// start moving
reset_periodic_task(task_snake_move);
enable_periodic_task(task_snake_move, true);
}
// running + start -> 'pause'
if (moving && key == 'J') {
enable_periodic_task(task_snake_move, false);
}
}

Loading…
Cancel
Save