feat: add bomb mechanic with explosion to kill rats
This commit is contained in:
+109
@@ -0,0 +1,109 @@
|
||||
#include "bomb.h"
|
||||
#include "maze.h"
|
||||
#include "rat.h"
|
||||
#include "music.h"
|
||||
#include <gb/gb.h>
|
||||
|
||||
extern const unsigned char BombSpriteData[];
|
||||
|
||||
#define BOMB_STATE_INACTIVE 0
|
||||
#define BOMB_STATE_TICKING 1
|
||||
#define BOMB_STATE_EXPLODING 2
|
||||
|
||||
typedef struct {
|
||||
uint8_t state;
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint16_t timer;
|
||||
} Bomb;
|
||||
|
||||
static Bomb bomb;
|
||||
|
||||
void init_bombs(void) {
|
||||
bomb.state = BOMB_STATE_INACTIVE;
|
||||
set_sprite_data(5, 6, BombSpriteData);
|
||||
for(uint8_t i = 34; i <= 38; i++) {
|
||||
move_sprite(i, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void drop_bomb(uint8_t x, uint8_t y) {
|
||||
if (bomb.state == BOMB_STATE_INACTIVE) {
|
||||
bomb.state = BOMB_STATE_TICKING;
|
||||
bomb.x = x;
|
||||
bomb.y = y;
|
||||
bomb.timer = 180; // 3 seconds
|
||||
play_sfx_plop(); // Generic drop sound
|
||||
}
|
||||
}
|
||||
|
||||
static void hide_explosion() {
|
||||
for(uint8_t i = 34; i <= 38; i++) {
|
||||
move_sprite(i, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_explosion_damage(uint8_t ex, uint8_t ey) {
|
||||
kill_rats_at(ex, ey);
|
||||
}
|
||||
|
||||
void update_bombs(void) {
|
||||
if (bomb.state == BOMB_STATE_TICKING) {
|
||||
bomb.timer--;
|
||||
|
||||
uint8_t px = bomb.x * 8 + 12;
|
||||
uint8_t py = bomb.y * 8 + 20;
|
||||
|
||||
if (bomb.timer > 120) {
|
||||
set_sprite_tile(38, 5); // bomb_3
|
||||
} else if (bomb.timer > 60) {
|
||||
set_sprite_tile(38, 6); // bomb_2
|
||||
} else {
|
||||
if (bomb.timer & 4) {
|
||||
set_sprite_tile(38, 7); // bomb_1
|
||||
} else {
|
||||
set_sprite_tile(38, 5);
|
||||
}
|
||||
}
|
||||
|
||||
move_sprite(38, px, py);
|
||||
|
||||
if (bomb.timer == 0) {
|
||||
bomb.state = BOMB_STATE_EXPLODING;
|
||||
bomb.timer = 30; // 0.5s explosion
|
||||
|
||||
play_sfx_explosion();
|
||||
|
||||
set_sprite_tile(38, 8);
|
||||
move_sprite(38, px, py);
|
||||
do_explosion_damage(bomb.x, bomb.y);
|
||||
|
||||
if (bomb.y > 0 && maze[bomb.y - 1][bomb.x] == 0) {
|
||||
set_sprite_tile(34, 10);
|
||||
move_sprite(34, px, py - 8);
|
||||
do_explosion_damage(bomb.x, bomb.y - 1);
|
||||
}
|
||||
if (bomb.y < MAZE_HEIGHT - 1 && maze[bomb.y + 1][bomb.x] == 0) {
|
||||
set_sprite_tile(35, 10);
|
||||
move_sprite(35, px, py + 8);
|
||||
do_explosion_damage(bomb.x, bomb.y + 1);
|
||||
}
|
||||
if (bomb.x > 0 && maze[bomb.y][bomb.x - 1] == 0) {
|
||||
set_sprite_tile(36, 9);
|
||||
move_sprite(36, px - 8, py);
|
||||
do_explosion_damage(bomb.x - 1, bomb.y);
|
||||
}
|
||||
if (bomb.x < MAZE_WIDTH - 1 && maze[bomb.y][bomb.x + 1] == 0) {
|
||||
set_sprite_tile(37, 9);
|
||||
move_sprite(37, px + 8, py);
|
||||
do_explosion_damage(bomb.x + 1, bomb.y);
|
||||
}
|
||||
}
|
||||
} else if (bomb.state == BOMB_STATE_EXPLODING) {
|
||||
bomb.timer--;
|
||||
if (bomb.timer == 0) {
|
||||
bomb.state = BOMB_STATE_INACTIVE;
|
||||
hide_explosion();
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
#ifndef BOMB_H
|
||||
#define BOMB_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void init_bombs(void);
|
||||
void drop_bomb(uint8_t x, uint8_t y);
|
||||
void update_bombs(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
const unsigned char BombSpriteData[] = {
|
||||
// bomb_3
|
||||
0x18, 0x18, 0x3C, 0x3C, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x3C, 0x3C, 0x00, 0x00,
|
||||
// bomb_2
|
||||
0x00, 0x00, 0x18, 0x18, 0x3C, 0x3C, 0x7E, 0x7E, 0x7E, 0x7E, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// bomb_1
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
// exp_center
|
||||
0xC3, 0xC3, 0xA5, 0xA5, 0x3C, 0x3C, 0x7E, 0x7E, 0x7E, 0x7E, 0x3C, 0x3C, 0xA5, 0xA5, 0xC3, 0xC3,
|
||||
// exp_horiz
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7E, 0x7E, 0x7E, 0x7E, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
// exp_vert
|
||||
0x3C, 0x3C, 0x3C, 0x3C, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x3C, 0x3C, 0x3C, 0x3C,
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "cursor.h"
|
||||
#include "maze.h"
|
||||
#include <gb/gb.h>
|
||||
#include "bomb.h"
|
||||
|
||||
const unsigned char CursorSpriteData[] = {
|
||||
// Bordo quadrato 8x8 (Nero, colore 3 -> 11)
|
||||
@@ -44,6 +45,11 @@ void update_cursor(void) {
|
||||
if (cursor_x < MAZE_WIDTH - 1) cursor_x++;
|
||||
}
|
||||
|
||||
// Tasto A per sganciare la bomba
|
||||
if ((keys & J_A) && !(previous_keys & J_A)) {
|
||||
drop_bomb(cursor_x, cursor_y);
|
||||
}
|
||||
|
||||
previous_keys = keys;
|
||||
|
||||
// Effetto lampeggiante: nascondi il cursore per metà del ciclo (ogni 16 frame)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "rat.h"
|
||||
#include "music.h"
|
||||
#include "cursor.h"
|
||||
#include "bomb.h"
|
||||
|
||||
void main(void) {
|
||||
uint8_t y, x;
|
||||
@@ -86,6 +87,8 @@ void main(void) {
|
||||
// Inizializza il cursore controllato dal giocatore
|
||||
init_cursor();
|
||||
|
||||
init_bombs();
|
||||
|
||||
// Inizializza il sequencer musicale
|
||||
init_music();
|
||||
|
||||
@@ -126,6 +129,9 @@ void main(void) {
|
||||
// Aggiorna l'input del cursore del giocatore
|
||||
update_cursor();
|
||||
|
||||
// Aggiorna le bombe
|
||||
update_bombs();
|
||||
|
||||
// Attendi la sincronizzazione con il monitor
|
||||
wait_vbl_done();
|
||||
}
|
||||
|
||||
@@ -422,3 +422,10 @@ void play_game_over_music(void) {
|
||||
|
||||
NR22_REG = 0x00; NR32_REG = 0x00; NR42_REG = 0x00; // Zittisce tutto
|
||||
}
|
||||
|
||||
void play_sfx_explosion(void) {
|
||||
// Esplosione forte e lunga sul canale 4
|
||||
NR42_REG = 0xF7;
|
||||
NR43_REG = 0x6E;
|
||||
NR44_REG = 0xC0;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ void update_music(void);
|
||||
|
||||
void play_sfx_moan(void);
|
||||
void play_sfx_plop(void);
|
||||
void play_sfx_explosion(void);
|
||||
|
||||
void play_game_over_music(void);
|
||||
|
||||
|
||||
@@ -297,3 +297,18 @@ void update_rats(void) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kill_rats_at(uint8_t x, uint8_t y) {
|
||||
for (uint8_t i = 0; i < MAX_RATS; i++) {
|
||||
if (rats[i].active) {
|
||||
// Uccidi se il topo è esattamente sulla cella esplosa
|
||||
// Oppure se ci stava andando.
|
||||
if ((rats[i].rat_x == x && rats[i].rat_y == y) ||
|
||||
(rats[i].target_x == x && rats[i].target_y == y)) {
|
||||
rats[i].active = 0;
|
||||
move_sprite(rats[i].sprite_base_idx, 0, 0);
|
||||
move_sprite(rats[i].sprite_base_idx + 1, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user