tetris/game-ctrl/game.c

130 lines
2.7 KiB
C
Raw Permalink Normal View History

2024-03-13 17:35:46 +01:00
#include "stddef.h"
#include "stdint.h"
#include "game.h"
2024-03-18 12:51:57 +01:00
#include "scheduler.h"
2024-03-13 17:35:46 +01:00
#include "shapes.h"
#include "canvas.h"
2024-03-22 11:59:28 +01:00
#include "../rgb-driver/colors.h"
2024-03-22 18:38:30 +01:00
#include "display.h"
2024-03-13 17:35:46 +01:00
2024-03-22 11:59:28 +01:00
#define GAME_CYCLE_TIME 100
#define GAMEOVER_DELAY 10
static uint8_t delayFactor(uint8_t level) {
return 11 - level;
}
typedef enum {
e_Phase_Game, e_Phase_GameOver
} phase_t;
typedef enum {
e_Start, e_NewStone, e_Down, e_DownDelay, e_ClearRows,
e_GameOver, e_GameOverFill, e_GameOverWipe, e_GameOverDelay
} state_t;
2024-03-13 17:35:46 +01:00
void gameExec(void *handle) {
2024-03-22 11:59:28 +01:00
static phase_t phase;
static state_t state = e_Start;
static uint8_t gameOverDelay;
static uint8_t rowIndex;
static uint8_t proceedDelay;
static uint8_t level;
2024-03-22 22:49:43 +01:00
static uint16_t score;
2024-03-13 17:35:46 +01:00
2024-03-22 11:59:28 +01:00
// --- engine begin -------------------------------------------------------
2024-03-13 17:35:46 +01:00
switch (state) {
2024-03-22 12:00:23 +01:00
// --- phase: game --------------------------------------------------------
2024-03-22 11:59:28 +01:00
case e_Start:
2024-03-13 17:35:46 +01:00
canvasClear();
2024-03-22 11:59:28 +01:00
level = 1;
2024-03-22 22:49:43 +01:00
score = 0;
2024-03-22 23:03:31 +01:00
displaySetValue(score);
2024-03-22 11:59:28 +01:00
phase = e_Phase_Game;
state = e_NewStone;
2024-03-13 17:35:46 +01:00
break;
2024-03-22 11:59:28 +01:00
case e_NewStone:
2024-03-13 17:35:46 +01:00
stoneCreate();
if (stoneDraw()) {
2024-03-22 11:59:28 +01:00
proceedDelay = delayFactor(level);
state = e_DownDelay;
2024-03-13 17:35:46 +01:00
} else {
2024-03-22 11:59:28 +01:00
state = e_GameOver;
}
break;
case e_DownDelay:
proceedDelay--;
if (proceedDelay == 0) {
rowIndex = 0;
state = e_ClearRows;
2024-03-13 17:35:46 +01:00
}
break;
2024-03-22 11:59:28 +01:00
case e_ClearRows:
state = e_Down;
break;
2024-03-13 17:35:46 +01:00
2024-03-22 11:59:28 +01:00
case e_Down:
2024-03-13 17:35:46 +01:00
if (! stoneMoveDown()) {
2024-03-22 11:59:28 +01:00
state = e_NewStone;
} else {
proceedDelay = delayFactor(level);
state = e_DownDelay;
2024-03-13 17:35:46 +01:00
}
break;
2024-03-22 12:00:23 +01:00
// --- phase: game over ---------------------------------------------------
2024-03-22 11:59:28 +01:00
case e_GameOver:
rowIndex = CANVAS_HEIGHT;
phase = e_Phase_GameOver;
state = e_GameOverFill;
break;
case e_GameOverFill:
rowIndex--;
canvasFillRow(rowIndex, _red);
if (rowIndex == 0) {
state = e_GameOverWipe;
2024-03-13 17:35:46 +01:00
}
2024-03-22 11:59:28 +01:00
break;
case e_GameOverWipe:
canvasWipeRow(rowIndex);
rowIndex++;
if (rowIndex == CANVAS_HEIGHT) {
gameOverDelay = GAMEOVER_DELAY;
state = e_GameOverDelay;
2024-03-13 17:35:46 +01:00
}
break;
2024-03-22 11:59:28 +01:00
case e_GameOverDelay:
gameOverDelay--;
if (gameOverDelay == 0) {
state = e_Start;
2024-03-13 17:35:46 +01:00
}
break;
}
2024-03-22 11:59:28 +01:00
// --- engine end ---------------------------------------------------------
2024-03-13 17:35:46 +01:00
canvasShow();
2024-03-22 11:59:28 +01:00
if (phase == e_Phase_Game) {
for (uint8_t r = 0; r < CANVAS_HEIGHT; r++) {
if (canvasIsRowFilled(r)) {
2024-03-22 22:49:43 +01:00
score += level;
displaySetValue(score);
2024-03-22 11:59:28 +01:00
canvasWipeRow(r);
canvasShow();
}
2024-03-21 11:58:42 +01:00
}
}
2024-03-13 17:35:46 +01:00
}
void gameInit() {
2024-03-22 11:59:28 +01:00
schAdd(gameExec, NULL, 0, GAME_CYCLE_TIME);
2024-03-13 17:35:46 +01:00
}