Use shared memory space for game data (#14727)
This commit is contained in:
committed by
Scott Lahteine
parent
17abb94532
commit
fec52e61ea
@@ -65,20 +65,12 @@
|
||||
|
||||
constexpr fixed_t snakev = FTOP(0.20);
|
||||
|
||||
int8_t snake_dir, // NESW
|
||||
foodx, foody, food_cnt,
|
||||
old_encoder;
|
||||
fixed_t snakex, snakey;
|
||||
|
||||
// Up to 50 lines, then you win!
|
||||
typedef struct { int8_t x, y; } pos_t;
|
||||
uint8_t head_ind;
|
||||
pos_t snake_tail[50];
|
||||
snake_data_t &sdat = marlin_game_data.snake;
|
||||
|
||||
// Remove the first pixel from the tail.
|
||||
// If needed, shift out the first segment.
|
||||
void shorten_tail() {
|
||||
pos_t &p = snake_tail[0], &q = snake_tail[1];
|
||||
pos_t &p = sdat.snake_tail[0], &q = sdat.snake_tail[1];
|
||||
bool shift = false;
|
||||
if (p.x == q.x) {
|
||||
// Vertical line
|
||||
@@ -91,21 +83,21 @@ void shorten_tail() {
|
||||
shift = p.x == q.x;
|
||||
}
|
||||
if (shift) {
|
||||
head_ind--;
|
||||
for (uint8_t i = 0; i <= head_ind; ++i)
|
||||
snake_tail[i] = snake_tail[i + 1];
|
||||
sdat.head_ind--;
|
||||
for (uint8_t i = 0; i <= sdat.head_ind; ++i)
|
||||
sdat.snake_tail[i] = sdat.snake_tail[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
// The food is on a line
|
||||
inline bool food_on_line() {
|
||||
for (uint8_t n = 0; n < head_ind; ++n) {
|
||||
pos_t &p = snake_tail[n], &q = snake_tail[n + 1];
|
||||
for (uint8_t n = 0; n < sdat.head_ind; ++n) {
|
||||
pos_t &p = sdat.snake_tail[n], &q = sdat.snake_tail[n + 1];
|
||||
if (p.x == q.x) {
|
||||
if ((foodx == p.x - 1 || foodx == p.x) && WITHIN(foody, _MIN(p.y, q.y), _MAX(p.y, q.y)))
|
||||
if ((sdat.foodx == p.x - 1 || sdat.foodx == p.x) && WITHIN(sdat.foody, _MIN(p.y, q.y), _MAX(p.y, q.y)))
|
||||
return true;
|
||||
}
|
||||
else if ((foody == p.y - 1 || foody == p.y) && WITHIN(foodx, _MIN(p.x, q.x), _MAX(p.x, q.x)))
|
||||
else if ((sdat.foody == p.y - 1 || sdat.foody == p.y) && WITHIN(sdat.foodx, _MIN(p.x, q.x), _MAX(p.x, q.x)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -114,54 +106,54 @@ inline bool food_on_line() {
|
||||
// Add a new food blob
|
||||
void food_reset() {
|
||||
do {
|
||||
foodx = random(0, GAME_W);
|
||||
foody = random(0, GAME_H);
|
||||
sdat.foodx = random(0, GAME_W);
|
||||
sdat.foody = random(0, GAME_H);
|
||||
} while (food_on_line());
|
||||
}
|
||||
|
||||
// Turn the snake cw or ccw
|
||||
inline void turn_snake(const bool cw) {
|
||||
snake_dir += cw ? 1 : -1;
|
||||
snake_dir &= 0x03;
|
||||
head_ind++;
|
||||
snake_tail[head_ind].x = FTOB(snakex);
|
||||
snake_tail[head_ind].y = FTOB(snakey);
|
||||
sdat.snake_dir += cw ? 1 : -1;
|
||||
sdat.snake_dir &= 0x03;
|
||||
sdat.head_ind++;
|
||||
sdat.snake_tail[sdat.head_ind].x = FTOB(sdat.snakex);
|
||||
sdat.snake_tail[sdat.head_ind].y = FTOB(sdat.snakey);
|
||||
}
|
||||
|
||||
// Reset the snake for a new game
|
||||
void snake_reset() {
|
||||
// Init the head and velocity
|
||||
snakex = BTOF(1);
|
||||
snakey = BTOF(GAME_H / 2);
|
||||
sdat.snakex = BTOF(1);
|
||||
sdat.snakey = BTOF(GAME_H / 2);
|
||||
//snakev = FTOP(0.25);
|
||||
|
||||
// Init the tail with a cw turn
|
||||
snake_dir = 0;
|
||||
head_ind = 0;
|
||||
snake_tail[0].x = 0;
|
||||
snake_tail[0].y = GAME_H / 2;
|
||||
sdat.snake_dir = 0;
|
||||
sdat.head_ind = 0;
|
||||
sdat.snake_tail[0].x = 0;
|
||||
sdat.snake_tail[0].y = GAME_H / 2;
|
||||
turn_snake(true);
|
||||
|
||||
// Clear food flag
|
||||
food_cnt = 5;
|
||||
sdat.food_cnt = 5;
|
||||
|
||||
// Clear the controls
|
||||
ui.encoderPosition = 0;
|
||||
old_encoder = 0;
|
||||
sdat.old_encoder = 0;
|
||||
}
|
||||
|
||||
// Check if head segment overlaps another
|
||||
bool snake_overlap() {
|
||||
// 4 lines must exist before a collision is possible
|
||||
if (head_ind < 4) return false;
|
||||
if (sdat.head_ind < 4) return false;
|
||||
// Is the last segment crossing any others?
|
||||
const pos_t &h1 = snake_tail[head_ind - 1], &h2 = snake_tail[head_ind];
|
||||
const pos_t &h1 = sdat.snake_tail[sdat.head_ind - 1], &h2 = sdat.snake_tail[sdat.head_ind];
|
||||
// VERTICAL head segment?
|
||||
if (h1.x == h2.x) {
|
||||
// Loop from oldest to segment two away from head
|
||||
for (uint8_t n = 0; n < head_ind - 2; ++n) {
|
||||
for (uint8_t n = 0; n < sdat.head_ind - 2; ++n) {
|
||||
// Segment p to q
|
||||
const pos_t &p = snake_tail[n], &q = snake_tail[n + 1];
|
||||
const pos_t &p = sdat.snake_tail[n], &q = sdat.snake_tail[n + 1];
|
||||
if (p.x != q.x) {
|
||||
// Crossing horizontal segment
|
||||
if (WITHIN(h1.x, _MIN(p.x, q.x), _MAX(p.x, q.x)) && (h1.y <= p.y) == (h2.y >= p.y)) return true;
|
||||
@@ -171,9 +163,9 @@ bool snake_overlap() {
|
||||
}
|
||||
else {
|
||||
// Loop from oldest to segment two away from head
|
||||
for (uint8_t n = 0; n < head_ind - 2; ++n) {
|
||||
for (uint8_t n = 0; n < sdat.head_ind - 2; ++n) {
|
||||
// Segment p to q
|
||||
const pos_t &p = snake_tail[n], &q = snake_tail[n + 1];
|
||||
const pos_t &p = sdat.snake_tail[n], &q = sdat.snake_tail[n + 1];
|
||||
if (p.y != q.y) {
|
||||
// Crossing vertical segment
|
||||
if (WITHIN(h1.y, _MIN(p.y, q.y), _MAX(p.y, q.y)) && (h1.x <= p.x) == (h2.x >= p.x)) return true;
|
||||
@@ -189,14 +181,14 @@ void SnakeGame::game_screen() {
|
||||
if (game_frame()) do { // Run logic twice for finer resolution
|
||||
|
||||
// Move the snake's head one unit in the current direction
|
||||
const int8_t oldx = FTOB(snakex), oldy = FTOB(snakey);
|
||||
switch (snake_dir) {
|
||||
case 0: snakey -= snakev; break;
|
||||
case 1: snakex += snakev; break;
|
||||
case 2: snakey += snakev; break;
|
||||
case 3: snakex -= snakev; break;
|
||||
const int8_t oldx = FTOB(sdat.snakex), oldy = FTOB(sdat.snakey);
|
||||
switch (sdat.snake_dir) {
|
||||
case 0: sdat.snakey -= snakev; break;
|
||||
case 1: sdat.snakex += snakev; break;
|
||||
case 2: sdat.snakey += snakev; break;
|
||||
case 3: sdat.snakex -= snakev; break;
|
||||
}
|
||||
const int8_t x = FTOB(snakex), y = FTOB(snakey);
|
||||
const int8_t x = FTOB(sdat.snakex), y = FTOB(sdat.snakey);
|
||||
|
||||
// If movement took place...
|
||||
if (oldx != x || oldy != y) {
|
||||
@@ -207,17 +199,17 @@ void SnakeGame::game_screen() {
|
||||
break; // ...out of do-while
|
||||
}
|
||||
|
||||
snake_tail[head_ind].x = x;
|
||||
snake_tail[head_ind].y = y;
|
||||
sdat.snake_tail[sdat.head_ind].x = x;
|
||||
sdat.snake_tail[sdat.head_ind].y = y;
|
||||
|
||||
// Change snake direction if set
|
||||
const int8_t enc = int8_t(ui.encoderPosition), diff = enc - old_encoder;
|
||||
const int8_t enc = int8_t(ui.encoderPosition), diff = enc - sdat.old_encoder;
|
||||
if (diff) {
|
||||
old_encoder = enc;
|
||||
sdat.old_encoder = enc;
|
||||
turn_snake(diff > 0);
|
||||
}
|
||||
|
||||
if (food_cnt) --food_cnt; else shorten_tail();
|
||||
if (sdat.food_cnt) --sdat.food_cnt; else shorten_tail();
|
||||
|
||||
// Did the snake collide with itself or go out of bounds?
|
||||
if (snake_overlap()) {
|
||||
@@ -225,11 +217,11 @@ void SnakeGame::game_screen() {
|
||||
_BUZZ(400, 40); // Bzzzt!
|
||||
}
|
||||
// Is the snake at the food?
|
||||
else if (x == foodx && y == foody) {
|
||||
else if (x == sdat.foodx && y == sdat.foody) {
|
||||
_BUZZ(5, 220);
|
||||
_BUZZ(5, 280);
|
||||
score++;
|
||||
food_cnt = 2;
|
||||
sdat.food_cnt = 2;
|
||||
food_reset();
|
||||
}
|
||||
}
|
||||
@@ -251,8 +243,8 @@ void SnakeGame::game_screen() {
|
||||
#if SNAKE_WH < 2
|
||||
|
||||
// At this scale just draw a line
|
||||
for (uint8_t n = 0; n < head_ind; ++n) {
|
||||
const pos_t &p = snake_tail[n], &q = snake_tail[n + 1];
|
||||
for (uint8_t n = 0; n < sdat.head_ind; ++n) {
|
||||
const pos_t &p = sdat.snake_tail[n], &q = sdat.snake_tail[n + 1];
|
||||
if (p.x == q.x) {
|
||||
const int8_t y1 = GAMEY(_MIN(p.y, q.y)), y2 = GAMEY(_MAX(p.y, q.y));
|
||||
if (PAGE_CONTAINS(y1, y2))
|
||||
@@ -267,8 +259,8 @@ void SnakeGame::game_screen() {
|
||||
#elif SNAKE_WH == 2
|
||||
|
||||
// At this scale draw two lines
|
||||
for (uint8_t n = 0; n < head_ind; ++n) {
|
||||
const pos_t &p = snake_tail[n], &q = snake_tail[n + 1];
|
||||
for (uint8_t n = 0; n < sdat.head_ind; ++n) {
|
||||
const pos_t &p = sdat.snake_tail[n], &q = sdat.snake_tail[n + 1];
|
||||
if (p.x == q.x) {
|
||||
const int8_t y1 = GAMEY(_MIN(p.y, q.y)), y2 = GAMEY(_MAX(p.y, q.y));
|
||||
if (PAGE_CONTAINS(y1, y2 + 1))
|
||||
@@ -286,8 +278,8 @@ void SnakeGame::game_screen() {
|
||||
#else
|
||||
|
||||
// Draw a series of boxes
|
||||
for (uint8_t n = 0; n < head_ind; ++n) {
|
||||
const pos_t &p = snake_tail[n], &q = snake_tail[n + 1];
|
||||
for (uint8_t n = 0; n < sdat.head_ind; ++n) {
|
||||
const pos_t &p = sdat.snake_tail[n], &q = sdat.snake_tail[n + 1];
|
||||
if (p.x == q.x) {
|
||||
const int8_t y1 = _MIN(p.y, q.y), y2 = _MAX(p.y, q.y);
|
||||
if (PAGE_CONTAINS(GAMEY(y1), GAMEY(y2) + SNAKE_SIZ - 1)) {
|
||||
@@ -311,9 +303,9 @@ void SnakeGame::game_screen() {
|
||||
#endif
|
||||
|
||||
// Draw food
|
||||
const int8_t fy = GAMEY(foody);
|
||||
const int8_t fy = GAMEY(sdat.foody);
|
||||
if (PAGE_CONTAINS(fy, fy + FOOD_WH - 1)) {
|
||||
const int8_t fx = GAMEX(foodx);
|
||||
const int8_t fx = GAMEX(sdat.foodx);
|
||||
u8g.drawFrame(fx, fy, FOOD_WH, FOOD_WH);
|
||||
if (FOOD_WH == 5) u8g.drawPixel(fx + 2, fy + 2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user