From b873ac24ca858c647f6bd88c24411ba651fc6df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Phillip=20K=C3=BChne?= Date: Sun, 29 Mar 2026 00:59:27 +0100 Subject: [PATCH] Let AI refactor everything and see if it breaks. --- .vscode/settings.json | 3 +- include/game_audio.h | 33 +++ include/game_input.h | 23 ++ include/game_logic.h | 13 + include/game_render.h | 24 ++ include/game_state.h | 24 ++ source/game_audio.cpp | 128 +++++++++ source/game_input.cpp | 89 ++++++ source/game_logic.cpp | 104 +++++++ source/game_render.cpp | 152 ++++++++++ source/main.cpp | 639 +++++------------------------------------ 11 files changed, 656 insertions(+), 576 deletions(-) create mode 100644 include/game_audio.h create mode 100644 include/game_input.h create mode 100644 include/game_logic.h create mode 100644 include/game_render.h create mode 100644 include/game_state.h create mode 100644 source/game_audio.cpp create mode 100644 source/game_input.cpp create mode 100644 source/game_logic.cpp create mode 100644 source/game_render.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json index 1e64964..c059d3c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "files.associations": { - "array": "cpp" + "array": "cpp", + "*.c": "c" }, "clangd.arguments": [ "--query-driver=${env:DEVKITPRO}/devkitARM/bin/arm-none-eabi-*", diff --git a/include/game_audio.h b/include/game_audio.h new file mode 100644 index 0000000..537419f --- /dev/null +++ b/include/game_audio.h @@ -0,0 +1,33 @@ +#ifndef GAME_AUDIO_H +#define GAME_AUDIO_H + +#include + +struct AudioContext { + bool musicEnabled = true; + + mm_sound_effect sfx_pickup; + mm_sound_effect sfx_boom; + mm_sound_effect sfx_pause; + mm_sound_effect sfx_unpause; + mm_sound_effect sfx_plop; + mm_sound_effect sfx_fail; +}; + +void audio_setup(AudioContext &audio); +void audio_start_music(const AudioContext &audio); +void audio_stop_music(); +void audio_pause_music_if_enabled(const AudioContext &audio); +void audio_resume_music_if_enabled(const AudioContext &audio); + +void audio_play_pickup(const AudioContext &audio); +void audio_play_boom(const AudioContext &audio); +void audio_play_plop(const AudioContext &audio); +void audio_play_pause(const AudioContext &audio); +void audio_play_unpause(const AudioContext &audio); +void audio_play_fail(const AudioContext &audio); + +bool audio_toggle_music(AudioContext &audio); +bool audio_is_music_enabled(const AudioContext &audio); + +#endif diff --git a/include/game_input.h b/include/game_input.h new file mode 100644 index 0000000..da0b7f5 --- /dev/null +++ b/include/game_input.h @@ -0,0 +1,23 @@ +#ifndef GAME_INPUT_H +#define GAME_INPUT_H + +#include + +#include "game_audio.h" +#include "game_render.h" +#include "game_state.h" + +struct InputContext { + GameState *state = nullptr; + RenderAssets *renderAssets = nullptr; + AudioContext *audio = nullptr; + + volatile bool *internals = nullptr; + PrintConsole *topScreen = nullptr; + + void (*init_game)() = nullptr; +}; + +bool handle_input_frame(InputContext &ctx); + +#endif diff --git a/include/game_logic.h b/include/game_logic.h new file mode 100644 index 0000000..6dfec77 --- /dev/null +++ b/include/game_logic.h @@ -0,0 +1,13 @@ +#ifndef GAME_LOGIC_H +#define GAME_LOGIC_H + +#include "game_state.h" + +void update_snake(GameState &state); +bool check_collision_self(GameState &state); +bool check_collision_apples(GameState &state); +bool check_collision_apples_rotten(GameState &state); +void spawn_apples(GameState &state); +void spawn_apples_rotten(GameState &state); + +#endif diff --git a/include/game_render.h b/include/game_render.h new file mode 100644 index 0000000..f3e69f9 --- /dev/null +++ b/include/game_render.h @@ -0,0 +1,24 @@ +#ifndef GAME_RENDER_H +#define GAME_RENDER_H + +#include + +#include "game_state.h" + +struct RenderAssets { + PrintConsole *topScreen = nullptr; + PrintConsole *bottomScreen = nullptr; + + u16 *gfx_segment = nullptr; + u16 *gfx_segment_small = nullptr; + u16 *gfx_head = nullptr; + u16 *gfx_apple = nullptr; + u16 *gfx_tail = nullptr; + u16 *gfx_apple_rotten = nullptr; +}; + +void draw_game(const GameState &state, const RenderAssets &assets); +void draw_stats(const GameState &state, bool internals, bool musicEnabled, uint8_t frame); +void blink_apples(const GameState &state, u16 *gfx_apple); + +#endif diff --git a/include/game_state.h b/include/game_state.h new file mode 100644 index 0000000..913ec65 --- /dev/null +++ b/include/game_state.h @@ -0,0 +1,24 @@ +#ifndef GAME_STATE_H +#define GAME_STATE_H + +#include +#include +#include +#include + +struct GameState { + volatile uint16_t ticks = 0; + volatile uint16_t snakelength = 0; + volatile uint16_t snakeDirection = 1; + volatile uint16_t score = 0; + + bool gameOver = false; + bool paused = false; + bool hardMode = false; + + std::deque> snake; + std::vector> apples; + std::vector> bad_apples; +}; + +#endif diff --git a/source/game_audio.cpp b/source/game_audio.cpp new file mode 100644 index 0000000..4fb674a --- /dev/null +++ b/source/game_audio.cpp @@ -0,0 +1,128 @@ +#include "game_audio.h" + +#include "soundbank.h" +#include "soundbank_bin.h" + +void audio_setup(AudioContext &audio) { + mmInitDefaultMem((mm_addr)soundbank_bin); + + mmLoad(MOD_0RIGIN); + + mmLoadEffect(SFX_332629__TREASURESOUNDS__ITEM_PICKUP); + mmLoadEffect(SFX_BOOM); + mmLoadEffect(SFX_167127__CRISSTANZA__PAUSE); + mmLoadEffect(SFX_167126__CRISSTANZA__UNPAUSE); + mmLoadEffect(SFX_273792__PACOMAV__PLOP); + mmLoadEffect(SFX_73750__TIMBRE__REMIX_OF_BENBONCAN_SAD_TROMBONE_MORE_WAH_BRIGHT_DE_CLICKED); + + audio.sfx_pickup = { + { SFX_332629__TREASURESOUNDS__ITEM_PICKUP }, + (int)(1.0f * (1 << 10)), + 0, + 255, + 128, + }; + + audio.sfx_boom = { + { SFX_BOOM }, + (int)(1.0f * (1 << 10)), + 1, + 255, + 128, + }; + + audio.sfx_pause = { + { SFX_167127__CRISSTANZA__PAUSE }, + (int)(1.0f * (1 << 10)), + 2, + 255, + 128, + }; + + audio.sfx_unpause = { + { SFX_167126__CRISSTANZA__UNPAUSE }, + (int)(1.0f * (1 << 10)), + 3, + 255, + 128, + }; + + audio.sfx_plop = { + { SFX_273792__PACOMAV__PLOP }, + (int)(1.0f * (1 << 10)), + 4, + 128, + 128, + }; + + audio.sfx_fail = { + { SFX_73750__TIMBRE__REMIX_OF_BENBONCAN_SAD_TROMBONE_MORE_WAH_BRIGHT_DE_CLICKED }, + (int)(1.0f * (1 << 10)), + 4, + 255, + 128, + }; +} + +void audio_start_music(const AudioContext &audio) { + mmStart(MOD_0RIGIN, MM_PLAY_LOOP); + if (!audio.musicEnabled) { + mmPause(); + } +} + +void audio_stop_music() { + mmStop(); +} + +void audio_pause_music_if_enabled(const AudioContext &audio) { + if (audio.musicEnabled) { + mmPause(); + } +} + +void audio_resume_music_if_enabled(const AudioContext &audio) { + if (audio.musicEnabled) { + mmResume(); + } +} + +void audio_play_pickup(const AudioContext &audio) { + mmEffectEx(&audio.sfx_pickup); +} + +void audio_play_boom(const AudioContext &audio) { + mmEffectEx(&audio.sfx_boom); +} + +void audio_play_plop(const AudioContext &audio) { + mmEffectEx(&audio.sfx_plop); +} + +void audio_play_pause(const AudioContext &audio) { + mmEffectEx(&audio.sfx_pause); +} + +void audio_play_unpause(const AudioContext &audio) { + mmEffectEx(&audio.sfx_unpause); +} + +void audio_play_fail(const AudioContext &audio) { + mmEffectEx(&audio.sfx_fail); +} + +bool audio_toggle_music(AudioContext &audio) { + audio.musicEnabled = !audio.musicEnabled; + + if (audio.musicEnabled) { + mmResume(); + } else { + mmPause(); + } + + return audio.musicEnabled; +} + +bool audio_is_music_enabled(const AudioContext &audio) { + return audio.musicEnabled; +} diff --git a/source/game_input.cpp b/source/game_input.cpp new file mode 100644 index 0000000..496770f --- /dev/null +++ b/source/game_input.cpp @@ -0,0 +1,89 @@ +#include "game_input.h" + +#include +#include + +bool handle_input_frame(InputContext &ctx) { + scanKeys(); + const int keys = keysDown(); + + if (keys && *ctx.internals) { + consoleSelect(ctx.topScreen); + iprintf("\x1b[6;0Hkeys = %s", std::bitset<16>(keys).to_string().c_str()); + } + + if ((keys & KEY_START) && (keys & KEY_L)) { + return false; + } + + if (keys & KEY_SELECT) { + *ctx.internals = !(*ctx.internals); + if (*ctx.internals) { + setBackdropColor(RGB15(0, 0, 7)); + } else { + setBackdropColor(RGB15(0, 0, 0)); + consoleSelect(ctx.topScreen); + consoleClear(); + } + } + + if (!ctx.state->paused && !ctx.state->gameOver) { + if (keys & KEY_UP) { + ctx.state->snakeDirection = 0; + draw_game(*ctx.state, *ctx.renderAssets); + } + + if (keys & KEY_RIGHT) { + ctx.state->snakeDirection = 1; + draw_game(*ctx.state, *ctx.renderAssets); + } + + if (keys & KEY_DOWN) { + ctx.state->snakeDirection = 2; + draw_game(*ctx.state, *ctx.renderAssets); + } + + if (keys & KEY_LEFT) { + ctx.state->snakeDirection = 3; + draw_game(*ctx.state, *ctx.renderAssets); + } + } + + if (ctx.state->paused) { + if (keys & KEY_X) { + audio_toggle_music(*ctx.audio); + } + + if (keys & KEY_Y) { + ctx.state->hardMode = !ctx.state->hardMode; + ctx.init_game(); + draw_game(*ctx.state, *ctx.renderAssets); + } + } + + if (keys & KEY_R) { + lcdSwap(); + } + + if (keys & KEY_START) { + if (!ctx.state->gameOver) { + ctx.state->paused = !ctx.state->paused; + + if (ctx.state->paused) { + consoleSelect(ctx.topScreen); + audio_play_pause(*ctx.audio); + audio_pause_music_if_enabled(*ctx.audio); + iprintf("\x1b[11;12HPaused"); + } else { + audio_resume_music_if_enabled(*ctx.audio); + audio_play_unpause(*ctx.audio); + consoleSelect(ctx.topScreen); + consoleClear(); + } + } else { + ctx.init_game(); + } + } + + return true; +} diff --git a/source/game_logic.cpp b/source/game_logic.cpp new file mode 100644 index 0000000..d8832e0 --- /dev/null +++ b/source/game_logic.cpp @@ -0,0 +1,104 @@ +#include "game_logic.h" + +#include +#include + +#include + +void update_snake(GameState &state) { + std::array headpos = state.snake.front(); + std::array newHead = headpos; + + if (state.snakeDirection == 0) { + newHead = { headpos[0], headpos[1] - 1, state.snakeDirection }; + } else if (state.snakeDirection == 1) { + newHead = { headpos[0] + 1, headpos[1], state.snakeDirection }; + } else if (state.snakeDirection == 2) { + newHead = { headpos[0], headpos[1] + 1, state.snakeDirection }; + } else if (state.snakeDirection == 3) { + newHead = { headpos[0] - 1, headpos[1], state.snakeDirection }; + } + + if (newHead[0] > X_MAX) { + newHead[0] = 0; + } + if (newHead[1] > Y_MAX) { + newHead[1] = 0; + } + if (newHead[0] < 0) { + newHead[0] = X_MAX; + } + if (newHead[1] < 0) { + newHead[1] = Y_MAX; + } + + state.snake.push_front(newHead); + state.snake.resize(state.snakelength); +} + +bool check_collision_self(GameState &state) { + if (state.snake.size() < 2 || state.gameOver) { + return false; + } + + const std::array headpos = state.snake.front(); + + for (auto it = state.snake.begin() + 1; it != state.snake.end(); ++it) { + if ((*it)[0] == headpos[0] && (*it)[1] == headpos[1]) { + state.gameOver = true; + return true; + } + } + + return false; +} + +bool check_collision_apples(GameState &state) { + const std::array headpos = state.snake.front(); + + auto it = std::find_if(state.apples.begin(), state.apples.end(), [&](const std::array &apple) { + return apple[0] == headpos[0] && apple[1] == headpos[1]; + }); + + if (it == state.apples.end()) { + return false; + } + + state.score += APPLE_SCORE; + state.snakelength++; + state.apples.erase(it); + return true; +} + +bool check_collision_apples_rotten(GameState &state) { + const std::array headpos = state.snake.front(); + + auto it = std::find_if(state.bad_apples.begin(), state.bad_apples.end(), [&](const std::array &apple) { + return apple[0] == headpos[0] && apple[1] == headpos[1]; + }); + + if (it == state.bad_apples.end()) { + return false; + } + + state.snakelength--; + state.bad_apples.erase(it); + if (state.snakelength < 2) { + state.gameOver = true; + } + return true; +} + +void spawn_apples(GameState &state) { + if (state.apples.size() < 1) { + std::array apple = { rand() % (X_MAX + 1), rand() % (Y_MAX + 1) }; + state.apples.push_back(apple); + } +} + +void spawn_apples_rotten(GameState &state) { + if ((state.ticks % 10 == 0) && state.hardMode && ((rand() % 10) < 10) && (state.bad_apples.size() < 20)) { + std::array badApple = { rand() % (X_MAX + 1), rand() % (Y_MAX + 1) }; + state.bad_apples.push_back(badApple); + } +} diff --git a/source/game_render.cpp b/source/game_render.cpp new file mode 100644 index 0000000..5e5f09c --- /dev/null +++ b/source/game_render.cpp @@ -0,0 +1,152 @@ +#include "game_render.h" + +#include +#include +#include + +#include "tilemap.h" + +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) { + const std::array dot = state.snake.front(); + bool hflip = false; + bool vflip = false; + + 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; + } + + oamSet(&oamSub, oamId, dot[0] * 8, dot[1] * 8, 0, 0, SpriteSize_8x8, SpriteColorFormat_256Color, + assets.gfx_head, -1, false, false, hflip, vflip, false); + oamId++; +} + +void draw_snake_tail(const GameState &state, const RenderAssets &assets, uint16_t &oamId) { + const std::array 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++; + } + + draw_snake_tail(state, assets, oamId); +} + +void draw_apples(const GameState &state, const RenderAssets &assets, uint16_t &oamId) { + for (const std::array &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_rotten(const GameState &state, const RenderAssets &assets, uint16_t &oamId) { + for (const std::array &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++; + } +} + +} // namespace + +void draw_game(const GameState &state, const RenderAssets &assets) { + uint16_t oamId = 0; + + if (!state.gameOver) { + draw_apples(state, assets, oamId); + draw_apples_rotten(state, assets, oamId); + draw_snake(state, assets, oamId); + return; + } + + 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]); + } + + iprintf("\x1b[10;12HScore: %i", state.score); + + if (!state.paused) { + return; + } + + if (musicEnabled) { + iprintf("\x1b[23;0HX = Disable Music"); + } else { + iprintf("\x1b[23;0HX = Enable Music "); + } + + if (state.hardMode) { + iprintf("\x1b[22;0HY = Restart in normal mode"); + } else { + iprintf("\x1b[22;0HY = Restart in Hard mode"); + } +} + +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); + } +} diff --git a/source/main.cpp b/source/main.cpp index da2d8bb..afd00aa 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,45 +1,42 @@ #include -#include #include #include #include #include #include -#include -#include - -#include "soundbank.h" -#include "soundbank_bin.h" +#include +#include +#include +#include +#include #include "tilemap.h" using namespace std; volatile uint8_t frame = 0; -volatile uint16_t ticks = 0; volatile bool internals = false; -std::deque> snake; +GameState gameState; -std::vector> apples; -std::vector> bad_apples; - -volatile uint16_t snakelength; +volatile uint16_t &ticks = gameState.ticks; +volatile uint16_t &snakelength = gameState.snakelength; /*** * 0 = up * 1 = right * 2 = down * 3 = left ***/ -volatile uint16_t snakeDirection; +volatile uint16_t &snakeDirection = gameState.snakeDirection; +volatile uint16_t &score = gameState.score; -volatile uint16_t score; +bool &gameOver = gameState.gameOver; +bool &paused = gameState.paused; +bool &hardMode = gameState.hardMode; -bool gameOver = false; -bool paused = false; - -bool musicEnabled = true; -bool hardMode = false; +std::deque> &snake = gameState.snake; +std::vector> &apples = gameState.apples; +std::vector> &bad_apples = gameState.bad_apples; // 31x23 PrintConsole topScreen; @@ -47,20 +44,9 @@ PrintConsole bottomScreen; int sound; -mm_sound_effect sfx_pickup; -mm_sound_effect sfx_boom; -mm_sound_effect sfx_pause; -mm_sound_effect sfx_unpause; -mm_sound_effect sfx_plop; -mm_sound_effect sfx_fail; +AudioContext audioContext; -//Sprites -u16* gfx_segment; -u16* gfx_segment_small; -u16* gfx_head; -u16* gfx_apple; -u16* gfx_tail; -u16* gfx_apple_rotten; +RenderAssets renderAssets; const void * get_sprite_pointer(uint16 spriteIndex) { return &tilemapTiles[spriteIndex*16]; @@ -78,480 +64,67 @@ void setup() { consoleInit(&bottomScreen, 3,BgType_Text4bpp, BgSize_T_256x256, X_MAX, 0, false, true); oamInit(&oamSub, SpriteMapping_1D_32, false); - gfx_segment = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color); - gfx_segment_small = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color); - gfx_head = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color); - gfx_apple = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color); - gfx_apple_rotten = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color); - gfx_tail = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color); + renderAssets.topScreen = &topScreen; + renderAssets.bottomScreen = &bottomScreen; - dmaCopy(get_sprite_pointer(1),gfx_segment,64); - dmaCopy(get_sprite_pointer(2),gfx_segment_small,64); - dmaCopy(get_sprite_pointer(3),gfx_head,64); - dmaCopy(get_sprite_pointer(5),gfx_apple,64); - dmaCopy(get_sprite_pointer(11),gfx_apple_rotten,64); + 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_apple = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color); + renderAssets.gfx_apple_rotten = 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(5), renderAssets.gfx_apple, 64); + dmaCopy(get_sprite_pointer(11), renderAssets.gfx_apple_rotten, 64); consoleSelect(&topScreen); dmaCopy(tilemapPal,SPRITE_PALETTE_SUB,tilemapPalLen); - mmInitDefaultMem((mm_addr)soundbank_bin); - // Background Music - mmLoad( MOD_0RIGIN ); - - // Load SFX - mmLoadEffect( SFX_332629__TREASURESOUNDS__ITEM_PICKUP ); - mmLoadEffect( SFX_BOOM ); - mmLoadEffect( SFX_167127__CRISSTANZA__PAUSE ); - mmLoadEffect( SFX_167126__CRISSTANZA__UNPAUSE ); - mmLoadEffect( SFX_273792__PACOMAV__PLOP ); - mmLoadEffect( SFX_73750__TIMBRE__REMIX_OF_BENBONCAN_SAD_TROMBONE_MORE_WAH_BRIGHT_DE_CLICKED ); - - - sfx_pickup = { - { SFX_332629__TREASURESOUNDS__ITEM_PICKUP } , // id - (int)(1.0f * (1<<10)), // rate - 0, // handle - 255, // volume - 128, // panning - }; - - sfx_boom = { - { SFX_BOOM } , - (int)(1.0f * (1<<10)), - 1, - 255, - 128, - }; - - sfx_pause = { - { SFX_167127__CRISSTANZA__PAUSE } , - (int)(1.0f * (1<<10)), - 2, - 255, - 128, - }; - - sfx_unpause = { - { SFX_167126__CRISSTANZA__UNPAUSE } , - (int)(1.0f * (1<<10)), - 3, - 255, - 128, - }; - - sfx_plop = { - { SFX_273792__PACOMAV__PLOP } , - (int)(1.0f * (1<<10)), - 4, - 128, - 128, - }; - - sfx_fail = { - { SFX_73750__TIMBRE__REMIX_OF_BENBONCAN_SAD_TROMBONE_MORE_WAH_BRIGHT_DE_CLICKED } , - (int)(1.0f * (1<<10)), - 4, - 255, - 128, - }; + audio_setup(audioContext); } - - -void check_collision_self() { - - std::array headpos = snake.front(); - - std::deque>::iterator testit = snake.begin(); - testit++; //skip head, no collision here - for(testit; testit != snake.end(); testit++) - { - std::array dot = *testit; - if ((dot[0] == headpos[0] && dot[1] == headpos[1] ) && !gameOver) { - gameOver = true; - mmStop(); - } - } - -} - -void check_collision_apples() { - - std::array headpos = snake.front(); - - std::vector>::iterator testit = apples.begin(); - for(testit; testit <= apples.end(); testit++) - { - std::array apple = *testit; - if ((apple[0] == headpos[0] && apple[1] == headpos[1] )) { - score += 10; - snakelength++; - apples.erase(testit); - mmEffectEx(&sfx_pickup); - } - } - -} - -void check_collision_apples_rotten() { - - std::array headpos = snake.front(); - - std::vector>::iterator testit = bad_apples.begin(); - for(testit; testit <= bad_apples.end(); testit++) - { - std::array apple = *testit; - if ((apple[0] == headpos[0] && apple[1] == headpos[1] )) { - snakelength--; - bad_apples.erase(testit); - mmEffectEx(&sfx_boom); - if (snakelength < 2) { - gameOver = true; - } - } - } - -} - -void draw_snake_head(uint16 &oamId) { - std::array dot = snake.front(); - bool hflip = false; - bool vflip = false; - switch (snakeDirection) - { - case 0: //going up - dmaCopy(&tilemapTiles[64],gfx_head,64); - break; - - case 1: //going right - dmaCopy(&tilemapTiles[48],gfx_head,64); - break; - - case 2: //going down - dmaCopy(&tilemapTiles[64],gfx_head,64); - vflip = true; - break; - - case 3: //going left - /*for(int i = 0; i < 8 * 8; i=i+2) - { - gfx_head[i/2] = ((BITMAP_HEAD_RIGHT[i+1]<<8) | BITMAP_HEAD_RIGHT[i]); - }*/ - dmaCopy(&tilemapTiles[48],gfx_head,64); - hflip = true; - break; - - default: - break; - } - oamSet(&oamSub, // oam - oamId, //id - dot[0]*8, // x - dot[1]*8, // y - 0, // priority - 0, // palette_alpha - SpriteSize_8x8, // size - SpriteColorFormat_256Color, // color format - gfx_head, // gfxoffset - -1, // affineIndex - false, // sizeDouble - false, // hide - hflip, // hflip - vflip, // vflip - false // mosaic - ); - oamId++; -} - -void draw_snake_tail(uint16 &oamId) { - std::array dot = snake.back(); - bool hflip = false; - bool vflip = false; - switch (snake.at(snake.size()-2).at(2)) - { - case 0: //going up - dmaCopy(get_sprite_pointer(9+((snake.size()-1)%2)),gfx_tail,64); - vflip = true; - break; - - case 1: //going right - dmaCopy(get_sprite_pointer(7+((snake.size()-1)%2)),gfx_tail,64); - hflip = true; - break; - - case 2: //going down - dmaCopy(get_sprite_pointer(9+((snake.size()-1)%2)),gfx_tail,64); - break; - - case 3: //going left - /*for(int i = 0; i < 8 * 8; i=i+2) - { - gfx_tail[i/2] = ((BITMAP_tail_RIGHT[i+1]<<8) | BITMAP_tail_RIGHT[i]); - }*/ - dmaCopy(get_sprite_pointer(7+((snake.size()-1)%2)),gfx_tail,64); - break; - - default: - break; - } - oamSet(&oamSub, // oam - oamId, //id - dot[0]*8, // x - dot[1]*8, // y - 0, // priority - 0, // palette_alpha - SpriteSize_8x8, // size - SpriteColorFormat_256Color, // color format - gfx_tail, // gfxoffset - -1, // affineIndex - false, // sizeDouble - false, // hide - hflip, // hflip - vflip, // vflip - false // mosaic - ); - oamId++; -} - -void draw_snake(uint16 &oamId) { - draw_snake_head(oamId); - for(size_t i = 1; i < snake.size()-1; i++) - { - if(i%2) { - oamSet(&oamSub, // oam - oamId, //id - snake[i][0]*8, // x - snake[i][1]*8, // y - 0, // priority - 0, // palette_alpha - SpriteSize_8x8, // size - SpriteColorFormat_256Color, // color format - gfx_segment_small, // gfxoffset - -1, // affineIndex - false, // sizeDouble - false, // hide - false, // hflip - false, // vflip - false // mosaic - ); - } else { - oamSet(&oamSub, // oam - oamId, //id - snake[i][0]*8, // x - snake[i][1]*8, // y - 0, // priority - 0, // palette_alpha - SpriteSize_8x8, // size - SpriteColorFormat_256Color, // color format - gfx_segment, // gfxoffset - -1, // affineIndex - false, // sizeDouble - false, // hide - false, // hflip - false, // vflip - false // mosaic - ); - } - oamId++; - } - draw_snake_tail(oamId); -} - -void draw_apples(uint16 &oamId) { - - for(std::array apple : apples) - { - oamSet(&oamSub, // oam - oamId, //id - apple[0]*8, // x - apple[1]*8, // y - 0, // priority - 0, // palette_alpha - SpriteSize_8x8, // size - SpriteColorFormat_256Color, // color format - gfx_apple, // gfxoffset - -1, // affineIndex - false, // sizeDouble - false, // hide - false, // hflip - false, // vflip - false // mosaic - ); - oamId++; - } - -} - -void draw_apples_rotten(uint16 &oamId) { - - for(std::array apple : bad_apples) - { - oamSet(&oamSub, // oam - oamId, //id - apple[0]*8, // x - apple[1]*8, // y - 0, // priority - 0, // palette_alpha - SpriteSize_8x8, // size - SpriteColorFormat_256Color, // color format - gfx_apple_rotten, // gfxoffset - -1, // affineIndex - false, // sizeDouble - false, // hide - false, // hflip - false, // vflip - false // mosaic - ); - oamId++; - } - -} - -void draw_game() { - uint16 oamid = 0; - if (!gameOver) { - draw_apples(oamid); - draw_apples_rotten(oamid); - draw_snake(oamid); - } - else - { - iprintf("\x1b[11;12HGAME OVER!"); - mmStop(); - mmEffectEx(&sfx_fail); - consoleSelect(&topScreen); - iprintf("\x1b[10;13HGAME OVER!"); - } - /*iprintf("\x1b[7;0HoamIDmax=%i",oamid);*/ - -} - -void draw_stats() { - if ( internals ) { - iprintf("\x1b[0;0HFrame = %i\nTick = %i\ndir = %i", frame, ticks, snakeDirection); - iprintf("\x1b[3;0HLength: %i", snakelength); - iprintf("\x1b[4;0Hx=%i\ny=%i",snake.front()[0], snake.front()[1]); - } - iprintf("\x1b[10;12HScore: %i", score); - - if (paused) { - - if (musicEnabled) { - iprintf("\x1b[23;0HX = Disable Music"); - } else { - iprintf("\x1b[23;0HX = Enable Music "); - } - - if (hardMode) { - iprintf("\x1b[22;0HY = Restart in normal mode"); - } else { - iprintf("\x1b[22;0HY = Restart in Hard mode"); - } - - } - -} - void handle_vblank() { frame++; consoleSelect(&topScreen); - draw_stats(); + draw_stats(gameState, internals, audio_is_music_enabled(audioContext), frame); oamUpdate(&oamSub); //flashy_colors(); } - -void update_snake() { - - std::array headpos = snake.front(); - std::array newHead; - if (snakeDirection == 0) { - newHead = { headpos[0], headpos[1]-1, snakeDirection }; - } - else if (snakeDirection == 1) - { - newHead = { headpos[0]+1, headpos[1], snakeDirection }; - } - else if (snakeDirection == 2) - { - newHead = { headpos[0], headpos[1]+1, snakeDirection }; - } - else if (snakeDirection == 3) - { - newHead = { headpos[0]-1, headpos[1], snakeDirection }; - } - - if (newHead[0] > X_MAX) { - newHead[0] = 0; - } - - if (newHead[1] > Y_MAX) { - newHead[1] = 0; - } - - if (newHead[0] < 0) { - newHead[0] = X_MAX; - } - - if (newHead[1] < 0) { - newHead[1] = Y_MAX; - } - snake.push_front(newHead); - snake.resize(snakelength); - -} - -void spawn_apples() { - - if (apples.size() < 1 ) { - std::array apple; - apple[0] = rand() % (X_MAX+1); - apple[1] = rand() % (Y_MAX+1); - apples.push_back(apple); - } - -} - -void spawn_apples_rotten() { - if ( (ticks%10==0) && hardMode && ((rand() % 10)<10) && (bad_apples.size()<20)) { - std::array badApple; - badApple[0] = rand() % (X_MAX+1); - badApple[1] = rand() % (Y_MAX+1); - bad_apples.push_back(badApple); - } -} - -void blink_apples() { - - if (ticks % 4) { - dmaCopy(get_sprite_pointer(5),gfx_apple,64); - } else { - dmaCopy(get_sprite_pointer(6),gfx_apple,64); - } -} - void do_tick() { if (!paused) { ticks++; if (!gameOver){ + const bool wasGameOver = gameOver; /*if (hardMode) { timerStop(0); timerStart(0, ClockDivider_1024, TIMER_FREQ_1024(ticks+5), do_tick); }*/ - update_snake(); - mmEffectEx(&sfx_plop); - check_collision_self(); - check_collision_apples(); - check_collision_apples_rotten(); - spawn_apples(); - spawn_apples_rotten(); - blink_apples(); + update_snake(gameState); + audio_play_plop(audioContext); + check_collision_self(gameState); + if (check_collision_apples(gameState)) { + audio_play_pickup(audioContext); + } + if (check_collision_apples_rotten(gameState)) { + audio_play_boom(audioContext); + } + spawn_apples(gameState); + spawn_apples_rotten(gameState); + if (!wasGameOver && gameOver) { + audio_stop_music(); + audio_play_fail(audioContext); + } + blink_apples(gameState, renderAssets.gfx_apple); //consoleSelect(&bottomScreen); - draw_game(); + draw_game(gameState, renderAssets); } } } @@ -574,10 +147,7 @@ void init_game() { consoleSelect(&bottomScreen); consoleClear(); oamClear(&oamSub,0,0); - mmStart( MOD_0RIGIN, MM_PLAY_LOOP ); - if (!musicEnabled) { - mmPause(); - } + audio_start_music(audioContext); } else { @@ -594,10 +164,7 @@ void init_game() { consoleSelect(&bottomScreen); consoleClear(); oamClear(&oamSub,0,0); - mmStart( MOD_0RIGIN, MM_PLAY_LOOP ); - if (!musicEnabled) { - mmPause(); - } + audio_start_music(audioContext); } @@ -614,96 +181,18 @@ int main(void) { // Start timer for game ticks + InputContext inputContext; + inputContext.state = &gameState; + inputContext.renderAssets = &renderAssets; + inputContext.audio = &audioContext; + inputContext.internals = &internals; + inputContext.topScreen = &topScreen; + inputContext.init_game = init_game; + while(1) { - - scanKeys(); - - int keys = keysDown(); - - if (keys && internals) { - consoleSelect(&topScreen); - iprintf("\x1b[6;0Hkeys = %s", std::bitset<16>(keys).to_string().c_str()); - } - - if ((keys & KEY_START) && (keys & KEY_L) ) break; - - if (keys & KEY_SELECT) { - internals = !internals; - if (internals) { - setBackdropColor(RGB15(0,0,7)); - } else { - setBackdropColor(RGB15(0,0,0)); - consoleSelect(&topScreen); - consoleClear(); - } - } - - if (!paused && !gameOver) { - if (keys & KEY_UP) { - snakeDirection = 0; - draw_game(); - } - - if (keys & KEY_RIGHT) { - snakeDirection = 1; - draw_game(); - } - - if (keys & KEY_DOWN) { - snakeDirection = 2; - draw_game(); - } - - if (keys & KEY_LEFT) { - snakeDirection = 3; - draw_game(); - } - } - - if (paused) { - if (keys & KEY_X) { - musicEnabled = !musicEnabled; - } - if (keys & KEY_Y) { - hardMode = !hardMode; - init_game(); - draw_game(); - } - } - - if (keys & KEY_R) { - lcdSwap(); - } - - - if (keys & (KEY_START)) { - if (!gameOver) { - paused = !paused; - if (paused) { - consoleSelect(&topScreen); - mmEffectEx(&sfx_pause); - if ( musicEnabled ) { - mmPause(); - } - iprintf("\x1b[11;12HPaused"); - } - else - { - if (musicEnabled) { - mmResume(); - } - mmEffectEx(&sfx_unpause); - consoleSelect(&topScreen); - consoleClear(); - } - - } - else - { - init_game(); - } - + if (!handle_input_frame(inputContext)) { + break; } }