refactor: optimize snake sprite rendering using preloaded directional assets and implement HUD caching
This commit is contained in:
1 parent
db9013c9c5
commit
60740a53c2
5 files changed
+268
-152
No files matched your search
@@ -179,7 +179,9 @@ The repository includes preconfigured tasks in [`.vscode/tasks.json`](.vscode/ta
|
||||
### 6.2 Asset Pipeline
|
||||
- **Graphics Pipeline:**
|
||||
- [`gfx/tilemap.png`](gfx/tilemap.png) + [`gfx/tilemap.grit`](gfx/tilemap.grit) are processed by `grit` into `${CMAKE_CURRENT_BINARY_DIR}/tilemap.s` and `tilemap.h`.
|
||||
- Sprites are referenced by index: tile 1 (segment), 2 (small segment), 3 (head), 5/6 (apple flash frames), 7/8/9/10 (tail variations), 11 (rotten apple).
|
||||
- Sprites are referenced by index: tile 1 (segment), 2 (small segment), 3 (head horizontal), 4 (head vertical), 5/6 (apple flash frames), 7/8/9/10 (tail variations), 11 (rotten apple). All 12 sprite tiles are preloaded once into VRAM at startup; directional and blinking variants are rendered via pointer selection and hardware flipping flags without mid-frame DMA transfers.
|
||||
- Active OAM sprites are clamped at hardware limit (128) and trailing unused sprites are hidden every frame via `oamClear(&oamSub, oamId, 128 - oamId)`.
|
||||
- Console text HUD rendering in `draw_stats()` is throttled via dirty-flag caching (`HudCache`), eliminating redundant `iprintf` calls on VBlank.
|
||||
- **Audio Pipeline:**
|
||||
- Audio files in [`sounds/`](sounds/) are compiled by `mmutil` into `soundbank.bin` and header `soundbank.h`.
|
||||
- `bin2s` embeds `soundbank.bin` into assembly source `soundbank_bin.S` and header `soundbank_bin.h`.
|
||||
|
||||
+20
-4
@@ -5,22 +5,38 @@
|
||||
|
||||
#include "game_state.h"
|
||||
|
||||
struct HudCache {
|
||||
int score = -1;
|
||||
bool cursed = false;
|
||||
bool paused = false;
|
||||
bool gameOver = false;
|
||||
bool musicEnabled = false;
|
||||
bool hardMode = false;
|
||||
bool dirty = true;
|
||||
};
|
||||
|
||||
struct RenderAssets {
|
||||
PrintConsole *topScreen = nullptr;
|
||||
PrintConsole *bottomScreen = nullptr;
|
||||
|
||||
u16 *gfx_segment = nullptr;
|
||||
u16 *gfx_segment_small = nullptr;
|
||||
u16 *gfx_head = nullptr;
|
||||
u16 *gfx_head_h = nullptr;
|
||||
u16 *gfx_head_v = nullptr;
|
||||
u16 *gfx_apple = nullptr;
|
||||
u16 *gfx_tail = nullptr;
|
||||
u16 *gfx_apple_blink = nullptr;
|
||||
u16 *gfx_tail_h[2] = {nullptr, nullptr};
|
||||
u16 *gfx_tail_v[2] = {nullptr, nullptr};
|
||||
u16 *gfx_apple_rotten = nullptr;
|
||||
u16 *gfx_apple_cursed = nullptr;
|
||||
|
||||
HudCache hudCache;
|
||||
};
|
||||
|
||||
void invalidate_hud(RenderAssets &assets);
|
||||
void draw_game(const GameState &state, const RenderAssets &assets);
|
||||
void draw_stats(const GameState &state, bool internals, bool musicEnabled, uint8_t frame);
|
||||
void draw_menu(const GameState &state, const RenderAssets &assets, bool musicEnabled);
|
||||
void draw_stats(const GameState &state, RenderAssets &assets, bool internals, bool musicEnabled, uint8_t frame);
|
||||
void draw_menu(const GameState &state, RenderAssets &assets, bool musicEnabled);
|
||||
void blink_apples(const GameState &state, u16 *gfx_apple);
|
||||
|
||||
#endif
|
||||
@@ -26,6 +26,7 @@ bool handle_input_frame(InputContext &ctx) {
|
||||
setBackdropColor(RGB15(0, 0, 0));
|
||||
consoleSelect(ctx.topScreen);
|
||||
consoleClear();
|
||||
invalidate_hud(*ctx.renderAssets);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,11 +116,13 @@ bool handle_input_frame(InputContext &ctx) {
|
||||
audio_play_pause(*ctx.audio);
|
||||
audio_pause_music_if_enabled(*ctx.audio);
|
||||
puts("\x1b[11;12HPaused");
|
||||
invalidate_hud(*ctx.renderAssets);
|
||||
} else {
|
||||
audio_resume_music_if_enabled(*ctx.audio);
|
||||
audio_play_unpause(*ctx.audio);
|
||||
consoleSelect(ctx.topScreen);
|
||||
consoleClear();
|
||||
invalidate_hud(*ctx.renderAssets);
|
||||
}
|
||||
} else {
|
||||
ctx.init_game();
|
||||
|
||||
+222
-139
@@ -8,190 +8,273 @@
|
||||
|
||||
namespace {
|
||||
|
||||
const void *get_sprite_pointer(uint16_t spriteIndex) {
|
||||
return &tilemapTiles[spriteIndex * 16];
|
||||
void draw_snake_head(const GameState &state, const RenderAssets &assets,
|
||||
uint16_t &oamId) {
|
||||
if (oamId >= 128 || state.snake.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::array<int, 3> dot = state.snake.front();
|
||||
u16 *headGfx = nullptr;
|
||||
bool hflip = false;
|
||||
bool vflip = false;
|
||||
|
||||
switch (state.snakeDirection) {
|
||||
case 0: // Up
|
||||
headGfx = assets.gfx_head_v;
|
||||
break;
|
||||
case 1: // Right
|
||||
headGfx = assets.gfx_head_h;
|
||||
break;
|
||||
case 2: // Down
|
||||
headGfx = assets.gfx_head_v;
|
||||
vflip = true;
|
||||
break;
|
||||
case 3: // Left
|
||||
headGfx = assets.gfx_head_h;
|
||||
hflip = true;
|
||||
break;
|
||||
default:
|
||||
headGfx = assets.gfx_head_h;
|
||||
break;
|
||||
}
|
||||
|
||||
oamSet(&oamSub, oamId, dot[0] * 8, dot[1] * 8, 0, 0, SpriteSize_8x8,
|
||||
SpriteColorFormat_256Color, headGfx, -1, false, false, hflip, vflip,
|
||||
false);
|
||||
oamId++;
|
||||
}
|
||||
|
||||
void draw_snake_head(const GameState &state, const RenderAssets &assets, uint16_t &oamId) {
|
||||
const std::array<int, 3> dot = state.snake.front();
|
||||
bool hflip = false;
|
||||
bool vflip = false;
|
||||
void draw_snake_tail(const GameState &state, const RenderAssets &assets,
|
||||
uint16_t &oamId) {
|
||||
if (oamId >= 128 || state.snake.size() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (state.snakeDirection) {
|
||||
case 0:
|
||||
dmaCopy(&tilemapTiles[64], assets.gfx_head, 64);
|
||||
break;
|
||||
case 1:
|
||||
dmaCopy(&tilemapTiles[48], assets.gfx_head, 64);
|
||||
break;
|
||||
case 2:
|
||||
dmaCopy(&tilemapTiles[64], assets.gfx_head, 64);
|
||||
vflip = true;
|
||||
break;
|
||||
case 3:
|
||||
dmaCopy(&tilemapTiles[48], assets.gfx_head, 64);
|
||||
hflip = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
const std::array<int, 3> dot = state.snake.back();
|
||||
const size_t var = (state.snake.size() - 1) % 2;
|
||||
u16 *tailGfx = nullptr;
|
||||
bool hflip = false;
|
||||
bool vflip = false;
|
||||
|
||||
switch (state.snake.at(state.snake.size() - 2).at(2)) {
|
||||
case 0: // Up
|
||||
tailGfx = assets.gfx_tail_v[var];
|
||||
vflip = true;
|
||||
break;
|
||||
case 1: // Right
|
||||
tailGfx = assets.gfx_tail_h[var];
|
||||
hflip = true;
|
||||
break;
|
||||
case 2: // Down
|
||||
tailGfx = assets.gfx_tail_v[var];
|
||||
break;
|
||||
case 3: // Left
|
||||
tailGfx = assets.gfx_tail_h[var];
|
||||
break;
|
||||
default:
|
||||
tailGfx = assets.gfx_tail_h[var];
|
||||
break;
|
||||
}
|
||||
|
||||
oamSet(&oamSub, oamId, dot[0] * 8, dot[1] * 8, 0, 0, SpriteSize_8x8,
|
||||
SpriteColorFormat_256Color, tailGfx, -1, false, false, hflip, vflip,
|
||||
false);
|
||||
oamId++;
|
||||
}
|
||||
|
||||
void draw_snake(const GameState &state, const RenderAssets &assets,
|
||||
uint16_t &oamId) {
|
||||
if (state.snake.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
draw_snake_head(state, assets, oamId);
|
||||
|
||||
for (size_t i = 1; i + 1 < state.snake.size(); i++) {
|
||||
if (oamId >= 128) {
|
||||
return;
|
||||
}
|
||||
|
||||
oamSet(&oamSub, oamId, dot[0] * 8, dot[1] * 8, 0, 0, SpriteSize_8x8, SpriteColorFormat_256Color,
|
||||
assets.gfx_head, -1, false, false, hflip, vflip, false);
|
||||
oamSet(&oamSub, oamId, state.snake[i][0] * 8, state.snake[i][1] * 8, 0, 0,
|
||||
SpriteSize_8x8, SpriteColorFormat_256Color,
|
||||
(i % 2) ? assets.gfx_segment_small : assets.gfx_segment, -1, false,
|
||||
false, false, false, false);
|
||||
oamId++;
|
||||
}
|
||||
|
||||
void draw_snake_tail(const GameState &state, const RenderAssets &assets, uint16_t &oamId) {
|
||||
const std::array<int, 3> dot = state.snake.back();
|
||||
bool hflip = false;
|
||||
bool vflip = false;
|
||||
|
||||
switch (state.snake.at(state.snake.size() - 2).at(2)) {
|
||||
case 0:
|
||||
dmaCopy(get_sprite_pointer(9 + ((state.snake.size() - 1) % 2)), assets.gfx_tail, 64);
|
||||
vflip = true;
|
||||
break;
|
||||
case 1:
|
||||
dmaCopy(get_sprite_pointer(7 + ((state.snake.size() - 1) % 2)), assets.gfx_tail, 64);
|
||||
hflip = true;
|
||||
break;
|
||||
case 2:
|
||||
dmaCopy(get_sprite_pointer(9 + ((state.snake.size() - 1) % 2)), assets.gfx_tail, 64);
|
||||
break;
|
||||
case 3:
|
||||
dmaCopy(get_sprite_pointer(7 + ((state.snake.size() - 1) % 2)), assets.gfx_tail, 64);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
oamSet(&oamSub, oamId, dot[0] * 8, dot[1] * 8, 0, 0, SpriteSize_8x8, SpriteColorFormat_256Color,
|
||||
assets.gfx_tail, -1, false, false, hflip, vflip, false);
|
||||
oamId++;
|
||||
}
|
||||
|
||||
void draw_snake(const GameState &state, const RenderAssets &assets, uint16_t &oamId) {
|
||||
draw_snake_head(state, assets, oamId);
|
||||
|
||||
for (size_t i = 1; i < state.snake.size() - 1; i++) {
|
||||
oamSet(&oamSub, oamId, state.snake[i][0] * 8, state.snake[i][1] * 8, 0, 0, SpriteSize_8x8,
|
||||
SpriteColorFormat_256Color, (i % 2) ? assets.gfx_segment_small : assets.gfx_segment, -1,
|
||||
false, false, false, false, false);
|
||||
oamId++;
|
||||
}
|
||||
}
|
||||
|
||||
if (state.snake.size() > 1) {
|
||||
draw_snake_tail(state, assets, oamId);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_apples(const GameState &state, const RenderAssets &assets, uint16_t &oamId) {
|
||||
for (const std::array<int, 2> &apple : state.apples) {
|
||||
oamSet(&oamSub, oamId, apple[0] * 8, apple[1] * 8, 0, 0, SpriteSize_8x8,
|
||||
SpriteColorFormat_256Color, assets.gfx_apple, -1, false, false, false, false, false);
|
||||
oamId++;
|
||||
void draw_apples(const GameState &state, const RenderAssets &assets,
|
||||
uint16_t &oamId) {
|
||||
u16 *appleGfx =
|
||||
(state.ticks % 4 == 0) ? assets.gfx_apple_blink : assets.gfx_apple;
|
||||
for (const std::array<int, 2> &apple : state.apples) {
|
||||
if (oamId >= 128) {
|
||||
return;
|
||||
}
|
||||
oamSet(&oamSub, oamId, apple[0] * 8, apple[1] * 8, 0, 0, SpriteSize_8x8,
|
||||
SpriteColorFormat_256Color, appleGfx, -1, false, false, false, false,
|
||||
false);
|
||||
oamId++;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_apples_rotten(const GameState &state, const RenderAssets &assets, uint16_t &oamId) {
|
||||
for (const std::array<int, 2> &apple : state.bad_apples) {
|
||||
oamSet(&oamSub, oamId, apple[0] * 8, apple[1] * 8, 0, 0, SpriteSize_8x8,
|
||||
SpriteColorFormat_256Color, assets.gfx_apple_rotten, -1, false, false, false, false,
|
||||
false);
|
||||
oamId++;
|
||||
void draw_apples_rotten(const GameState &state, const RenderAssets &assets,
|
||||
uint16_t &oamId) {
|
||||
for (const std::array<int, 2> &apple : state.bad_apples) {
|
||||
if (oamId >= 128) {
|
||||
return;
|
||||
}
|
||||
oamSet(&oamSub, oamId, apple[0] * 8, apple[1] * 8, 0, 0, SpriteSize_8x8,
|
||||
SpriteColorFormat_256Color, assets.gfx_apple_rotten, -1, false,
|
||||
false, false, false, false);
|
||||
oamId++;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_apples_cursed(const GameState &state, const RenderAssets &assets, uint16_t &oamId) {
|
||||
for (const std::array<int, 2> &apple : state.cursed_apples) {
|
||||
oamSet(&oamSub, oamId, apple[0] * 8, apple[1] * 8, 0, 0, SpriteSize_8x8,
|
||||
SpriteColorFormat_256Color, assets.gfx_apple_cursed, -1, false, false, false, false,
|
||||
false);
|
||||
oamId++;
|
||||
void draw_apples_cursed(const GameState &state, const RenderAssets &assets,
|
||||
uint16_t &oamId) {
|
||||
for (const std::array<int, 2> &apple : state.cursed_apples) {
|
||||
if (oamId >= 128) {
|
||||
return;
|
||||
}
|
||||
oamSet(&oamSub, oamId, apple[0] * 8, apple[1] * 8, 0, 0, SpriteSize_8x8,
|
||||
SpriteColorFormat_256Color, assets.gfx_apple_cursed, -1, false,
|
||||
false, false, false, false);
|
||||
oamId++;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void invalidate_hud(RenderAssets &assets) { assets.hudCache.dirty = true; }
|
||||
|
||||
void draw_game(const GameState &state, const RenderAssets &assets) {
|
||||
uint16_t oamId = 0;
|
||||
uint16_t oamId = 0;
|
||||
|
||||
if (!state.gameOver) {
|
||||
draw_apples(state, assets, oamId);
|
||||
draw_apples_rotten(state, assets, oamId);
|
||||
draw_apples_cursed(state, assets, oamId);
|
||||
draw_snake(state, assets, oamId);
|
||||
return;
|
||||
if (!state.gameOver) {
|
||||
draw_apples(state, assets, oamId);
|
||||
draw_apples_rotten(state, assets, oamId);
|
||||
draw_apples_cursed(state, assets, oamId);
|
||||
draw_snake(state, assets, oamId);
|
||||
|
||||
// Hide all unused sprites up to hardware limit (128) to eliminate trailing
|
||||
// ghost sprites
|
||||
if (oamId < 128) {
|
||||
oamClear(&oamSub, oamId, 128 - oamId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
iprintf("\x1b[11;12HGAME OVER!");
|
||||
consoleSelect(assets.topScreen);
|
||||
iprintf("\x1b[10;13HGAME OVER!");
|
||||
// On Game Over, hide all sprites so none are left dangling
|
||||
oamClear(&oamSub, 0, 128);
|
||||
|
||||
iprintf("\x1b[11;12HGAME OVER!");
|
||||
consoleSelect(assets.topScreen);
|
||||
iprintf("\x1b[10;13HGAME OVER!");
|
||||
}
|
||||
|
||||
void draw_stats(const GameState &state, bool internals, bool musicEnabled, uint8_t frame) {
|
||||
if (internals) {
|
||||
iprintf("\x1b[0;0HFrame = %i\nTick = %i\ndir = %i", frame, state.ticks, state.snakeDirection);
|
||||
iprintf("\x1b[3;0HLength: %i", state.snakelength);
|
||||
iprintf("\x1b[4;0Hx=%i\ny=%i", state.snake.front()[0], state.snake.front()[1]);
|
||||
void draw_stats(const GameState &state, RenderAssets &assets, bool internals,
|
||||
bool musicEnabled, uint8_t frame) {
|
||||
if (internals) {
|
||||
iprintf("\x1b[0;0HFrame = %i\nTick = %i\ndir = %i", frame, state.ticks,
|
||||
state.snakeDirection);
|
||||
iprintf("\x1b[3;0HLength: %i", state.snakelength);
|
||||
if (!state.snake.empty()) {
|
||||
iprintf("\x1b[4;0Hx=%i\ny=%i", state.snake.front()[0],
|
||||
state.snake.front()[1]);
|
||||
}
|
||||
}
|
||||
|
||||
HudCache &cache = assets.hudCache;
|
||||
const bool cursed = (state.curseTicksRemaining > 0);
|
||||
|
||||
const bool needs_score_update = cache.dirty || (cache.score != state.score);
|
||||
const bool needs_curse_update = cache.dirty || (cache.cursed != cursed);
|
||||
const bool needs_pause_update =
|
||||
cache.dirty || (cache.paused != state.paused) ||
|
||||
(cache.musicEnabled != musicEnabled) ||
|
||||
(cache.hardMode != state.hardMode) || (cache.gameOver != state.gameOver);
|
||||
|
||||
if (needs_score_update) {
|
||||
iprintf("\x1b[10;12HScore: %i", state.score);
|
||||
cache.score = state.score;
|
||||
}
|
||||
|
||||
if (state.curseTicksRemaining > 0) {
|
||||
iprintf("\x1b[1;7HCONTROLS INVERTED!");
|
||||
if (needs_curse_update) {
|
||||
if (cursed) {
|
||||
iprintf("\x1b[1;7HCONTROLS INVERTED!");
|
||||
} else {
|
||||
iprintf("\x1b[1;7H ");
|
||||
iprintf("\x1b[1;7H ");
|
||||
}
|
||||
cache.cursed = cursed;
|
||||
}
|
||||
|
||||
if (needs_pause_update) {
|
||||
if (!state.paused) {
|
||||
if (state.gameOver) {
|
||||
iprintf("\x1b[23;0HB = Main Menu");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
iprintf("\x1b[21;0HB = Main Menu");
|
||||
|
||||
if (musicEnabled) {
|
||||
iprintf("\x1b[23;0HX = Disable Music");
|
||||
if (state.gameOver) {
|
||||
iprintf("\x1b[23;0HB = Main Menu");
|
||||
} else if (cache.paused) {
|
||||
// Clear any leftover pause strings if previously paused
|
||||
iprintf("\x1b[21;0H ");
|
||||
iprintf("\x1b[22;0H ");
|
||||
iprintf("\x1b[23;0H ");
|
||||
}
|
||||
} else {
|
||||
iprintf("\x1b[23;0HX = Enable Music ");
|
||||
}
|
||||
|
||||
if (state.hardMode) {
|
||||
iprintf("\x1b[21;0HB = Main Menu");
|
||||
if (state.hardMode) {
|
||||
iprintf("\x1b[22;0HY = Restart in normal mode");
|
||||
} else {
|
||||
iprintf("\x1b[22;0HY = Restart in Hard mode");
|
||||
} else {
|
||||
iprintf("\x1b[22;0HY = Restart in Hard mode ");
|
||||
}
|
||||
if (musicEnabled) {
|
||||
iprintf("\x1b[23;0HX = Disable Music");
|
||||
} else {
|
||||
iprintf("\x1b[23;0HX = Enable Music ");
|
||||
}
|
||||
}
|
||||
cache.paused = state.paused;
|
||||
cache.musicEnabled = musicEnabled;
|
||||
cache.hardMode = state.hardMode;
|
||||
cache.gameOver = state.gameOver;
|
||||
}
|
||||
|
||||
cache.dirty = false;
|
||||
}
|
||||
|
||||
void draw_menu(const GameState &state, const RenderAssets &assets, bool musicEnabled) {
|
||||
oamClear(&oamSub, 0, 0);
|
||||
oamUpdate(&oamSub);
|
||||
void draw_menu(const GameState &state, RenderAssets &assets,
|
||||
bool musicEnabled) {
|
||||
invalidate_hud(assets);
|
||||
|
||||
consoleSelect(assets.bottomScreen);
|
||||
consoleClear();
|
||||
oamClear(&oamSub, 0, 128);
|
||||
oamUpdate(&oamSub);
|
||||
|
||||
consoleSelect(assets.topScreen);
|
||||
consoleClear();
|
||||
consoleSelect(assets.bottomScreen);
|
||||
consoleClear();
|
||||
|
||||
iprintf("\x1b[3;10HSNAKE PLUS");
|
||||
iprintf("\x1b[5;5H---------------------");
|
||||
consoleSelect(assets.topScreen);
|
||||
consoleClear();
|
||||
|
||||
const char *hardModeLabel = state.hardMode ? "ON " : "OFF";
|
||||
const char *musicLabel = musicEnabled ? "ON " : "OFF";
|
||||
iprintf("\x1b[3;10HSNAKE PLUS");
|
||||
iprintf("\x1b[5;5H---------------------");
|
||||
|
||||
iprintf("\x1b[8;7H%c Start Game", state.menuSelection == 0 ? '>' : ' ');
|
||||
iprintf("\x1b[10;7H%c Hard Mode: %s", state.menuSelection == 1 ? '>' : ' ', hardModeLabel);
|
||||
iprintf("\x1b[12;7H%c Music: %s", state.menuSelection == 2 ? '>' : ' ', musicLabel);
|
||||
const char *hardModeLabel = state.hardMode ? "ON " : "OFF";
|
||||
const char *musicLabel = musicEnabled ? "ON " : "OFF";
|
||||
|
||||
iprintf("\x1b[19;3HUP/DOWN: Navigate");
|
||||
iprintf("\x1b[20;3HA/START: Select");
|
||||
iprintf("\x1b[8;7H%c Start Game", state.menuSelection == 0 ? '>' : ' ');
|
||||
iprintf("\x1b[10;7H%c Hard Mode: %s", state.menuSelection == 1 ? '>' : ' ',
|
||||
hardModeLabel);
|
||||
iprintf("\x1b[12;7H%c Music: %s", state.menuSelection == 2 ? '>' : ' ',
|
||||
musicLabel);
|
||||
|
||||
iprintf("\x1b[19;3HUP/DOWN: Navigate");
|
||||
iprintf("\x1b[20;3HA/START: Select");
|
||||
}
|
||||
|
||||
void blink_apples(const GameState &state, u16 *gfx_apple) {
|
||||
if (state.ticks % 4) {
|
||||
dmaCopy(get_sprite_pointer(5), gfx_apple, 64);
|
||||
} else {
|
||||
dmaCopy(get_sprite_pointer(6), gfx_apple, 64);
|
||||
}
|
||||
void blink_apples(const GameState & /*state*/, u16 * /*gfx_apple*/) {
|
||||
// Blinking is now handled directly by draw_apples() via sprite pointer
|
||||
// selection without DMA.
|
||||
}
|
||||
+20
-8
@@ -47,7 +47,7 @@ AudioContext audioContext;
|
||||
|
||||
RenderAssets renderAssets;
|
||||
|
||||
const void * get_sprite_pointer(uint16 spriteIndex) {
|
||||
const void * get_sprite_pointer(uint16_t spriteIndex) {
|
||||
return &tilemapTiles[spriteIndex*16];
|
||||
}
|
||||
|
||||
@@ -69,16 +69,27 @@ void setup() {
|
||||
|
||||
renderAssets.gfx_segment = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_segment_small = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_head = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_head_h = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_head_v = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_apple = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_apple_blink = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_tail_h[0] = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_tail_h[1] = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_tail_v[0] = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_tail_v[1] = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_apple_rotten = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_apple_cursed = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
renderAssets.gfx_tail = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color);
|
||||
|
||||
dmaCopy(get_sprite_pointer(1), renderAssets.gfx_segment, 64);
|
||||
dmaCopy(get_sprite_pointer(2), renderAssets.gfx_segment_small, 64);
|
||||
dmaCopy(get_sprite_pointer(3), renderAssets.gfx_head, 64);
|
||||
dmaCopy(get_sprite_pointer(3), renderAssets.gfx_head_h, 64);
|
||||
dmaCopy(get_sprite_pointer(4), renderAssets.gfx_head_v, 64);
|
||||
dmaCopy(get_sprite_pointer(5), renderAssets.gfx_apple, 64);
|
||||
dmaCopy(get_sprite_pointer(6), renderAssets.gfx_apple_blink, 64);
|
||||
dmaCopy(get_sprite_pointer(7), renderAssets.gfx_tail_h[0], 64);
|
||||
dmaCopy(get_sprite_pointer(8), renderAssets.gfx_tail_h[1], 64);
|
||||
dmaCopy(get_sprite_pointer(9), renderAssets.gfx_tail_v[0], 64);
|
||||
dmaCopy(get_sprite_pointer(10), renderAssets.gfx_tail_v[1], 64);
|
||||
dmaCopy(get_sprite_pointer(11), renderAssets.gfx_apple_rotten, 64);
|
||||
|
||||
consoleSelect(&topScreen);
|
||||
@@ -118,7 +129,7 @@ void handle_vblank() {
|
||||
frame++;
|
||||
if (gameState.scene == Scene::Playing) {
|
||||
consoleSelect(&topScreen);
|
||||
draw_stats(gameState, internals, audio_is_music_enabled(audioContext), frame);
|
||||
draw_stats(gameState, renderAssets, internals, audio_is_music_enabled(audioContext), frame);
|
||||
}
|
||||
oamUpdate(&oamSub);
|
||||
//flashy_colors();
|
||||
@@ -155,7 +166,6 @@ void do_tick() {
|
||||
audio_stop_music();
|
||||
audio_play_fail(audioContext);
|
||||
}
|
||||
blink_apples(gameState, renderAssets.gfx_apple);
|
||||
//consoleSelect(&bottomScreen);
|
||||
draw_game(gameState, renderAssets);
|
||||
}
|
||||
@@ -179,9 +189,10 @@ void init_game() {
|
||||
gameState.cursed_apples.clear();
|
||||
consoleSelect(&topScreen);
|
||||
consoleClear();
|
||||
invalidate_hud(renderAssets);
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
oamClear(&oamSub,0,0);
|
||||
oamClear(&oamSub,0,128);
|
||||
audio_start_music(audioContext);
|
||||
}
|
||||
else
|
||||
@@ -198,9 +209,10 @@ void init_game() {
|
||||
gameState.cursed_apples.clear();
|
||||
consoleSelect(&topScreen);
|
||||
consoleClear();
|
||||
invalidate_hud(renderAssets);
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
oamClear(&oamSub,0,0);
|
||||
oamClear(&oamSub,0,128);
|
||||
audio_start_music(audioContext);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user