docs: add AGENTS.md and README.md documentation files
This commit is contained in:
1 parent
5048796b7d
commit
db9013c9c5
3 files changed
+358
-6
No files matched your search
@@ -0,0 +1,209 @@
|
|||||||
|
# AGENTS.md - Developer & Agent Guide for snakePlus
|
||||||
|
|
||||||
|
This document provides a comprehensive overview of the **snakePlus** codebase for AI agents and developers. It details the project architecture, target platform, hardware constraints, build workflows, code organization, and development guidelines.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Project Overview
|
||||||
|
|
||||||
|
- **Project Name:** Snake Plus (`snakePlus`)
|
||||||
|
- **Subtitle:** *Snake with a twist*
|
||||||
|
- **Author:** Phillip Kuehne
|
||||||
|
- **Platform:** Nintendo DS (NDS) Homebrew
|
||||||
|
- **Target CPU:** ARM946E-S (`armv5te`, `-mtune=arm946e-s`, `-marm`, `-mthumb-interwork`)
|
||||||
|
- **ROM Output:** [`snakePlus.nds`](snakePlus.nds) & [`snakePlus.elf`](snakePlus.elf)
|
||||||
|
- **Primary Toolchain:** [devkitPro](https://devkitpro.org) / `devkitARM`, `libnds`, `maxmod9`, `grit`, `mmutil`, `bin2s`, `ndstool`
|
||||||
|
- **Build System:** CMake (>= 3.13) with Ninja generator
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Directory Structure & File Map
|
||||||
|
|
||||||
|
```
|
||||||
|
snakePlus/
|
||||||
|
├── CMakeLists.txt # Primary CMake cross-compilation & asset build rules
|
||||||
|
├── compile_commands.json # Exported compilation database for clangd / clang-tidy
|
||||||
|
├── icon.bmp # 32x32 banner icon embedded into the .nds ROM
|
||||||
|
├── melonDS.ini # Local configuration for melonDS emulator
|
||||||
|
│
|
||||||
|
├── include/ # C++ Header declarations
|
||||||
|
│ ├── consts.h # Grid dimensions, scores, tick rates, legacy bitmaps
|
||||||
|
│ ├── game_audio.h # AudioContext struct, MaxMod sound & BGM declarations
|
||||||
|
│ ├── game_input.h # InputContext struct, button scanning & menu logic
|
||||||
|
│ ├── game_logic.h # Snake mechanics, collision detection, apple spawning
|
||||||
|
│ ├── game_render.h # RenderAssets struct, dual-screen console/OAM draw routines
|
||||||
|
│ └── game_state.h # Core GameState struct, Scene enum, coordinate containers
|
||||||
|
│
|
||||||
|
├── source/ # C++ Implementation files
|
||||||
|
│ ├── main.cpp # Hardware setup, VBlank IRQ, timer ticks, game bootstrap
|
||||||
|
│ ├── game_audio.cpp # MaxMod soundbank loading, BGM loop, SFX dispatch
|
||||||
|
│ ├── game_input.cpp # Key mapping, inverted control logic, menu navigation
|
||||||
|
│ ├── game_logic.cpp # Position update, edge wrapping, collision resolution, RNG
|
||||||
|
│ └── game_render.cpp # OAM sprite rendering, console text HUD & menu screens
|
||||||
|
│
|
||||||
|
├── gfx/ # Graphical assets
|
||||||
|
│ ├── tilemap.png # 8bpp tile sheet (snake head/body/tail, apples)
|
||||||
|
│ ├── tilemap.grit # Grit conversion configuration (-gt, -gB8, -mRtf, etc.)
|
||||||
|
│ └── tilemap.xcf # GIMP source image
|
||||||
|
│
|
||||||
|
├── sounds/ # Audio assets (built into soundbank by mmutil)
|
||||||
|
│ ├── 0rigin.xm # FastTracker II background music track (MOD_0RIGIN)
|
||||||
|
│ ├── 273792__pacomav__plop.wav # Movement plop SFX
|
||||||
|
│ ├── 332629__treasuresounds__item-pickup.wav # Apple pickup SFX
|
||||||
|
│ ├── Boom.wav # Rotten / Cursed apple boom SFX
|
||||||
|
│ ├── 167126__crisstanza__unpause.wav # Unpause SFX
|
||||||
|
│ ├── 167127__crisstanza__pause.wav # Pause SFX
|
||||||
|
│ └── 73750__timbre__remix-of-benboncan-sad-trombone-more-wah-bright-de-clicked.wav # Fail SFX
|
||||||
|
│
|
||||||
|
├── tools/ # Tooling & automation scripts
|
||||||
|
│ └── clang_tidy_watch.sh # File watcher script running clang-tidy on file change
|
||||||
|
│
|
||||||
|
├── .vscode/ # VS Code configuration
|
||||||
|
│ ├── launch.json # GDB debugger launch for melonDS (port 3333)
|
||||||
|
│ ├── settings.json # clangd and editor settings
|
||||||
|
│ └── tasks.json # CMake build, run, clean, and clang-tidy tasks
|
||||||
|
│
|
||||||
|
├── .clang-tidy # Clang-tidy rules and naming conventions
|
||||||
|
├── .clangd # Clangd LSP configuration and system include paths
|
||||||
|
└── .gitignore # Git ignore rules for build artifacts and caches
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Game Mechanics & State Flow
|
||||||
|
|
||||||
|
### 3.1 Grid & Screen Setup
|
||||||
|
- The playfield is a **32 × 24 grid** (`X_MAX = 31`, `Y_MAX = 23`).
|
||||||
|
- Each cell corresponds to an **8 × 8 pixel** sprite tile.
|
||||||
|
- Moving outside the boundary wraps around to the opposing edge.
|
||||||
|
- **Dual-Screen Layout:**
|
||||||
|
- **Top Screen:** Console text display (Score, status effects like "CONTROLS INVERTED!", pause state, debug internals HUD).
|
||||||
|
- **Bottom Screen:** Sub-engine 2D graphics (`oamSub`), rendering the snake and apples using 8x8 256-color sprites.
|
||||||
|
- Can be swapped in real-time by pressing the **R** trigger (`lcdSwap()`).
|
||||||
|
|
||||||
|
### 3.2 Scenes & State Machine
|
||||||
|
The game operates in one of two scenes ([`Scene`](include/game_state.h#L9-L12)):
|
||||||
|
1. **`Scene::Menu`**:
|
||||||
|
- Menu options: **Start Game**, **Hard Mode: ON/OFF**, **Music: ON/OFF**.
|
||||||
|
- Navigated via D-Pad Up/Down; toggled/started via **A** or **START**.
|
||||||
|
2. **`Scene::Playing`**:
|
||||||
|
- Driven by hardware **Timer 0** executing [`do_tick()`](source/main.cpp#L127-L163).
|
||||||
|
- Interrupt handler [`handle_vblank()`](source/main.cpp#L117-L125) handles VBlank frame counting, OAM updates (`oamUpdate(&oamSub)`), and top-screen stat refreshes.
|
||||||
|
|
||||||
|
### 3.3 Game Elements & Apples
|
||||||
|
- **Snake Body:** Represented as `std::deque<std::array<int, 3>>` where each entry is `{x, y, direction}`. Alternating segments use regular and small sprite tiles. Head and tail sprites flip dynamically according to direction.
|
||||||
|
- **Normal Apple (Red):** Spawns if count < 1. Awards +10 score, increases length by 1, plays pickup sound. Flashes/blinks every 4 ticks.
|
||||||
|
- **Rotten Apple (Brown/Green):** Spawns in Hard Mode (periodic chance up to 20 on screen). Decreases length by 1, plays explosion SFX. If length drops below 2, triggers Game Over.
|
||||||
|
- **Cursed Apple (Purple):** Spawns occasionally. Inverts player steering controls (Up ↔ Down, Left ↔ Right) for `CURSE_DURATION_TICKS` (40 ticks). The sprite is procedurally constructed at startup in [`main.cpp:91-112`](source/main.cpp#L91-L112) by copying the rotten apple tile pixels and mapping them to dedicated palette entries (`CURSE_PAL_SHADOW`, `CURSE_PAL_OUTLINE`, `CURSE_PAL_FILL`, `CURSE_PAL_GLOW`).
|
||||||
|
|
||||||
|
### 3.4 Game Modes
|
||||||
|
- **Normal Mode:** Starts with length 4, timer frequency `TIMER_FREQ_1024(5)`, background color `RGB15(5,5,5)`.
|
||||||
|
- **Hard Mode:** Starts with length 2, timer frequency `TIMER_FREQ_1024(9)` (faster), background color `RGB15(10,5,5)`, spawns rotten apples.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Input & Control Mapping
|
||||||
|
|
||||||
|
| Context | Button | Action |
|
||||||
|
|---|---|---|
|
||||||
|
| **Menu** | D-Pad Up / Down | Change selected menu item |
|
||||||
|
| **Menu** | A / START | Select / Toggle option / Start game |
|
||||||
|
| **Playing** | D-Pad | Steer snake (inverted if cursed) |
|
||||||
|
| **Playing** | START | Pause / Unpause |
|
||||||
|
| **Playing** | R | Swap LCD displays (`lcdSwap()`) |
|
||||||
|
| **Playing** | SELECT | Toggle debug internals HUD overlay |
|
||||||
|
| **Playing** | START + L | Exit main loop / Quit |
|
||||||
|
| **Paused** | B | Return to Main Menu |
|
||||||
|
| **Paused** | X | Toggle background music on/off |
|
||||||
|
| **Paused** | Y | Toggle Normal/Hard mode and restart |
|
||||||
|
| **Game Over** | START | Restart game |
|
||||||
|
| **Game Over** | B | Return to Main Menu |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Build System & Toolchain
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
- `DEVKITPRO` environment variable pointing to the devkitPro root (e.g. `/opt/devkitpro`).
|
||||||
|
- `devkitARM` toolchain with GCC cross-compiler (`arm-none-eabi-gcc`, `arm-none-eabi-g++`).
|
||||||
|
- Tools on PATH or in `$DEVKITPRO/tools/bin`: `ndstool`, `grit`, `mmutil`, `bin2s`.
|
||||||
|
- Build tools: `cmake` (>= 3.13), `ninja`.
|
||||||
|
- Emulator: `melonDS`.
|
||||||
|
|
||||||
|
### Build Commands
|
||||||
|
To configure and build from the command line:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Configure with Ninja generator
|
||||||
|
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||||
|
|
||||||
|
# Copy compile_commands.json to root for clangd
|
||||||
|
cmake -E copy_if_different build/compile_commands.json compile_commands.json
|
||||||
|
|
||||||
|
# Build the NDS ROM image
|
||||||
|
cmake --build build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running & Emulation
|
||||||
|
```bash
|
||||||
|
# Run using the custom CMake target (launches melonDS)
|
||||||
|
cmake --build build --target run
|
||||||
|
|
||||||
|
# Or launch directly with melonDS
|
||||||
|
melonDS snakePlus.nds
|
||||||
|
```
|
||||||
|
|
||||||
|
### VS Code Integration
|
||||||
|
The repository includes preconfigured tasks in [`.vscode/tasks.json`](.vscode/tasks.json):
|
||||||
|
- **`Run new build`** (Default Build Task, Ctrl+Shift+B): Configures, compiles, and runs in `melonDS`.
|
||||||
|
- **`cmake build`**: Compiles the project.
|
||||||
|
- **`cmake clean`**: Cleans build artifacts.
|
||||||
|
- **`clang-tidy (all)`**: Runs `run-clang-tidy` across all source and header files.
|
||||||
|
- **`clang-tidy (watch changed)`**: Runs the background watcher [`tools/clang_tidy_watch.sh`](tools/clang_tidy_watch.sh).
|
||||||
|
- **`Copy new build to SD`**: Copies ROM to external SD card mount.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Architecture & Implementation Details
|
||||||
|
|
||||||
|
### 6.1 Hardware Subsystems ([`source/main.cpp`](source/main.cpp))
|
||||||
|
- **Video Modes:** Both Main and Sub 2D engines are initialized into `MODE_0_2D`.
|
||||||
|
- **VRAM Allocation:**
|
||||||
|
- `VRAM_A`: Assigned to Main Engine Background (`VRAM_A_MAIN_BG`).
|
||||||
|
- `VRAM_C`: Assigned to Sub Engine Background (`VRAM_C_SUB_BG`).
|
||||||
|
- `VRAM_D`: Assigned to Sub Engine Sprites (`VRAM_D_SUB_SPRITE`).
|
||||||
|
- **Consoles:** Standard text consoles are attached to both screens for debug / stats / menus.
|
||||||
|
- **OAM:** Sub-engine OAM is initialized via `oamInit(&oamSub, SpriteMapping_1D_32, false)`. Sprites are allocated with `oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_256Color)`.
|
||||||
|
- **Timer & IRQ:** Hardware Timer 0 triggers `do_tick` using `TIMER_FREQ_1024()`. Interrupt `IRQ_VBLANK` runs `handle_vblank()`.
|
||||||
|
|
||||||
|
### 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).
|
||||||
|
- **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`.
|
||||||
|
- Audio runs via `libnds`'s `maxmod9` (`mm9`).
|
||||||
|
|
||||||
|
### 6.3 Static Analysis & Tooling
|
||||||
|
- **Clang-Tidy:** Configured in [`.clang-tidy`](.clang-tidy). Enforces modern C++ guidelines, bugprone checks, readability conventions, and snake_case / CamelCase identifiers.
|
||||||
|
- **Clangd:** Configured in [`.clangd`](.clangd). Removes `-mthumb-interwork` (which clang warns against) and explicitly includes devkitARM GCC 15.2.0 system headers.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Guidelines for AI Agents Modifying the Codebase
|
||||||
|
|
||||||
|
1. **Embedded / Bare-Metal Constraints:**
|
||||||
|
- The ARM9 CPU lacks an OS runtime. Avoid throwing exceptions or relying on RTTI (`-fno-exceptions -fno-rtti` are compiler flags).
|
||||||
|
- Prefer lightweight containers (`std::array`, `std::deque`, `std::vector` with controlled growth).
|
||||||
|
- Be mindful of OAM hardware limitations (Sub engine supports up to 128 sprites; current game allocates sprite slots per apple and snake segment).
|
||||||
|
2. **Interrupt & Concurrency Safety:**
|
||||||
|
- Variables accessed across both the main loop, timer ticks, and VBlank IRQ (such as `ticks`, `frame`, `snakelength`, `snakeDirection`, `internals`) must maintain appropriate `volatile` qualifiers or thread-safe synchronization.
|
||||||
|
3. **Hardware Registers & Memory Banking:**
|
||||||
|
- Graphic tiles and palettes must be transferred using DMA (`dmaCopy`) or direct memory copies into allocated VRAM / OAM memory banks.
|
||||||
|
- Do not modify VRAM allocation configurations without ensuring compatibility with console text generators and OAM sub-engines.
|
||||||
|
4. **Toolchain Flags:**
|
||||||
|
- Keep `-mthumb-interwork`, `-march=armv5te`, `-mtune=arm946e-s`, and specs `-specs=${DEVKITPRO_ROOT}/calico/share/ds9.specs` intact in [`CMakeLists.txt`](CMakeLists.txt).
|
||||||
|
5. **Code Style:**
|
||||||
|
- Follow the naming and check options specified in [`.clang-tidy`](.clang-tidy) (functions/variables in `snake_case`, classes/structs in `CamelCase`).
|
||||||
|
- Run `cmake --build build` to verify clean compilation without warnings or errors.
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
# Snake Plus (Nintendo DS)
|
||||||
|
|
||||||
|
> **Snake with a twist** — A homebrew Snake game for the Nintendo DS developed in modern C++ with `libnds` and `devkitPro`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Classic Gameplay with a Twist:**
|
||||||
|
- Classic grid-based snake action wrapped on a 32×24 playfield with edge-wrapping.
|
||||||
|
- **Normal Apples:** Boost length and score (+10), with flashing animation and pickup sounds.
|
||||||
|
- **Rotten Apples:** Shrink snake length by 1; shrinking below length 2 results in Game Over!
|
||||||
|
- **Cursed Apples:** Invert steering controls (Up ↔ Down, Left ↔ Right) for 40 ticks, requiring quick reflexes and adapted steering.
|
||||||
|
- **Dual-Screen Layout:**
|
||||||
|
- **Top Screen:** Real-time scoreboard, status alerts (*"CONTROLS INVERTED!"*), pause overlay, and optional debug stats.
|
||||||
|
- **Bottom Screen:** Smooth 2D hardware sprite rendering using DS Sub-engine OAM.
|
||||||
|
- **LCD Swap:** Switch top and bottom screens on the fly with the **R** shoulder button.
|
||||||
|
- **Audio & Sound Effects:**
|
||||||
|
- Background tracker music ([`0rigin.xm`](sounds/0rigin.xm)) powered by MaxMod 9.
|
||||||
|
- Sound effects for movement, pickups, rotten/cursed explosions, pause, and game over.
|
||||||
|
- On-the-fly music toggle from the menu or pause screen.
|
||||||
|
- **Game Modes:**
|
||||||
|
- **Normal Mode:** Relaxed tick rate (`TIMER_FREQ_1024(5)`), starting length 4.
|
||||||
|
- **Hard Mode:** High-speed tick rate (`TIMER_FREQ_1024(9)`), starting length 2, and periodic rotten apple hazards.
|
||||||
|
- **Main Menu & Pause Screen:**
|
||||||
|
- Integrated start menu to toggle Hard Mode and Music.
|
||||||
|
- In-game pause menu with instant restarts and mode toggles.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
| Screen / Context | Button | Action |
|
||||||
|
|---|---|---|
|
||||||
|
| **Main Menu** | **D-Pad Up / Down** | Navigate menu options |
|
||||||
|
| **Main Menu** | **A** or **START** | Select option / Start game |
|
||||||
|
| **In-Game** | **D-Pad** | Steer snake (inverted while cursed) |
|
||||||
|
| **In-Game** | **START** | Pause / Resume |
|
||||||
|
| **In-Game** | **R Trigger** | Swap top and bottom screens (`lcdSwap`) |
|
||||||
|
| **In-Game** | **SELECT** | Toggle debug HUD (coordinates, ticks, raw keys) |
|
||||||
|
| **In-Game** | **START + L** | Exit game |
|
||||||
|
| **Paused** | **B** | Return to Main Menu |
|
||||||
|
| **Paused** | **X** | Toggle background music ON/OFF |
|
||||||
|
| **Paused** | **Y** | Toggle Normal / Hard mode and restart |
|
||||||
|
| **Game Over** | **START** | Restart game |
|
||||||
|
| **Game Over** | **B** | Return to Main Menu |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Building from Source
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
Ensure you have the following installed:
|
||||||
|
1. **[devkitPro](https://devkitpro.org)** with the `nds-dev` payload:
|
||||||
|
- `devkitARM` toolchain
|
||||||
|
- `libnds`, `calico`, `maxmod9`
|
||||||
|
- Utilities: `ndstool`, `grit`, `mmutil`, `bin2s`
|
||||||
|
2. **CMake** (>= 3.13)
|
||||||
|
3. **Ninja** build system
|
||||||
|
4. **[melonDS](https://melonds.kuribo64.net/)** (optional, for emulation and testing)
|
||||||
|
|
||||||
|
Ensure the `DEVKITPRO` environment variable is set:
|
||||||
|
```bash
|
||||||
|
export DEVKITPRO=/opt/devkitpro
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Instructions
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone the repository
|
||||||
|
git clone <repo-url> snakePlus
|
||||||
|
cd snakePlus
|
||||||
|
|
||||||
|
# Configure build with Ninja
|
||||||
|
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||||
|
|
||||||
|
# Compile the .nds ROM and .elf binary
|
||||||
|
cmake --build build
|
||||||
|
```
|
||||||
|
|
||||||
|
This generates:
|
||||||
|
- [`snakePlus.nds`](snakePlus.nds) — Ready to run on an emulator or flashcard.
|
||||||
|
- [`snakePlus.elf`](snakePlus.elf) — ELF binary for GDB debugging.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running & Emulation
|
||||||
|
|
||||||
|
### Using melonDS via CMake target
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake --build build --target run
|
||||||
|
```
|
||||||
|
|
||||||
|
### Direct launch
|
||||||
|
|
||||||
|
```bash
|
||||||
|
melonDS snakePlus.nds
|
||||||
|
```
|
||||||
|
|
||||||
|
### Installing to Flashcard / SD Card
|
||||||
|
|
||||||
|
A convenience target is included in CMake to copy the `.nds` ROM to an SD card path:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake --build build --target install_sd
|
||||||
|
```
|
||||||
|
*(Configure `OUTPUT_DIRECTORY` in [`CMakeLists.txt`](CMakeLists.txt) as desired).*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development & Code Quality
|
||||||
|
|
||||||
|
- **VS Code Tasks:** Built-in tasks in [`.vscode/tasks.json`](.vscode/tasks.json) support one-key build, run in melonDS, and debug with GDB.
|
||||||
|
- **Clang-Tidy:** Run `run-clang-tidy` or launch the watch script:
|
||||||
|
```bash
|
||||||
|
bash tools/clang_tidy_watch.sh
|
||||||
|
```
|
||||||
|
- **Language Standards:** C11 / C++14 targeting ARM9 (`armv5te`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture & Developer Documentation
|
||||||
|
|
||||||
|
For an in-depth architectural breakdown, hardware register mapping, OAM details, and guidelines for AI agents or contributors, refer to [`AGENTS.md`](AGENTS.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Credits & Author
|
||||||
|
|
||||||
|
- **Game Design & Code:** Phillip Kuehne
|
||||||
|
- **Music:** `0rigin.xm`
|
||||||
|
- **Sound Effects:** Freesound.org contributors (`treasuresounds`, `pacomav`, `crisstanza`, `timbre`, `benboncan`)
|
||||||
|
- **Platform Libraries:** `libnds`, `maxmod` by devkitPro team
|
||||||
+14
-6
@@ -56,7 +56,9 @@ bool check_collision_self(GameState &state) {
|
|||||||
bool check_collision_apples(GameState &state) {
|
bool check_collision_apples(GameState &state) {
|
||||||
const std::array<int, 3> headpos = state.snake.front();
|
const std::array<int, 3> headpos = state.snake.front();
|
||||||
|
|
||||||
auto it = std::find_if(state.apples.begin(), state.apples.end(), [&](const std::array<int, 2> &apple) {
|
auto it =
|
||||||
|
std::find_if(state.apples.begin(), state.apples.end(),
|
||||||
|
[&](const std::array<int, 2> &apple) {
|
||||||
return apple[0] == headpos[0] && apple[1] == headpos[1];
|
return apple[0] == headpos[0] && apple[1] == headpos[1];
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -73,7 +75,9 @@ bool check_collision_apples(GameState &state) {
|
|||||||
bool check_collision_apples_rotten(GameState &state) {
|
bool check_collision_apples_rotten(GameState &state) {
|
||||||
const std::array<int, 3> headpos = state.snake.front();
|
const std::array<int, 3> headpos = state.snake.front();
|
||||||
|
|
||||||
auto it = std::find_if(state.bad_apples.begin(), state.bad_apples.end(), [&](const std::array<int, 2> &apple) {
|
auto it =
|
||||||
|
std::find_if(state.bad_apples.begin(), state.bad_apples.end(),
|
||||||
|
[&](const std::array<int, 2> &apple) {
|
||||||
return apple[0] == headpos[0] && apple[1] == headpos[1];
|
return apple[0] == headpos[0] && apple[1] == headpos[1];
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -92,7 +96,8 @@ bool check_collision_apples_rotten(GameState &state) {
|
|||||||
bool check_collision_apples_cursed(GameState &state) {
|
bool check_collision_apples_cursed(GameState &state) {
|
||||||
const std::array<int, 3> headpos = state.snake.front();
|
const std::array<int, 3> headpos = state.snake.front();
|
||||||
|
|
||||||
auto it = std::find_if(state.cursed_apples.begin(), state.cursed_apples.end(),
|
auto it =
|
||||||
|
std::find_if(state.cursed_apples.begin(), state.cursed_apples.end(),
|
||||||
[&](const std::array<int, 2> &apple) {
|
[&](const std::array<int, 2> &apple) {
|
||||||
return apple[0] == headpos[0] && apple[1] == headpos[1];
|
return apple[0] == headpos[0] && apple[1] == headpos[1];
|
||||||
});
|
});
|
||||||
@@ -114,15 +119,18 @@ void spawn_apples(GameState &state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void spawn_apples_rotten(GameState &state) {
|
void spawn_apples_rotten(GameState &state) {
|
||||||
if ((state.ticks % 10 == 0) && state.hardMode && ((rand() % 10) < 10) && (state.bad_apples.size() < 20)) {
|
if ((state.ticks % 10 == 0) && state.hardMode && ((rand() % 10) < 10) &&
|
||||||
|
(state.bad_apples.size() < 20)) {
|
||||||
std::array<int, 2> badApple = {rand() % (X_MAX + 1), rand() % (Y_MAX + 1)};
|
std::array<int, 2> badApple = {rand() % (X_MAX + 1), rand() % (Y_MAX + 1)};
|
||||||
state.bad_apples.push_back(badApple);
|
state.bad_apples.push_back(badApple);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void spawn_apples_cursed(GameState &state) {
|
void spawn_apples_cursed(GameState &state) {
|
||||||
if (state.cursed_apples.empty() && (state.ticks % 20 == 0) && ((rand() % 5) == 0)) {
|
if (state.cursed_apples.empty() && (state.ticks % 20 == 0) &&
|
||||||
std::array<int, 2> cursedApple = { rand() % (X_MAX + 1), rand() % (Y_MAX + 1) };
|
((rand() % 5) == 0)) {
|
||||||
|
std::array<int, 2> cursedApple = {rand() % (X_MAX + 1),
|
||||||
|
rand() % (Y_MAX + 1)};
|
||||||
state.cursed_apples.push_back(cursedApple);
|
state.cursed_apples.push_back(cursedApple);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user