From 11547e9d13b414542a39f70fa9c9947dcb449908 Mon Sep 17 00:00:00 2001 From: Trevor Boddy Date: Sat, 14 Feb 2026 22:44:21 -0500 Subject: [PATCH] enemy spawning etc --- src/bullets.h | 67 ++++++++++++++++++++++++++++--------------------- src/enemies.h | 69 +++++++++++++++++++++++++++++++++++++-------------- src/global.h | 4 ++- src/main.c | 10 +++++--- src/player.h | 6 ++--- src/stage.h | 7 +++++- 6 files changed, 109 insertions(+), 54 deletions(-) diff --git a/src/bullets.h b/src/bullets.h index 85b2b40..3d00548 100644 --- a/src/bullets.h +++ b/src/bullets.h @@ -57,36 +57,47 @@ static void doBulletRotation(u8 i){ } void spawnBullet(struct bulletSpawner spawner, void(*updater)){ + // Don't spawn if offscreen + fix32 dx = getWrappedDelta(spawner.x, player.pos.x); + bool offScreenX = (dx < FIX32(-256) || dx > FIX32(256)); + bool offScreenY = (spawner.y < FIX32(-16) || spawner.y > GAME_H_F + FIX32(16)); + if(offScreenX || offScreenY) return; + + // Find available slot, return if none s16 i = -1; - for(s16 j = 0; j < BULLET_COUNT; j++) if(!bullets[j].active && i == -1) i = j; - if(i > -1){ - bullets[i].active = TRUE; - bullets[i].pos.x = spawner.x; - bullets[i].pos.y = spawner.y; - bullets[i].angle = spawner.angle; - bullets[i].player = spawner.player; - bullets[i].clock = 0; - if(spawner.vel.x || spawner.vel.y){ - bullets[i].vel.x = spawner.vel.x; - bullets[i].vel.y = spawner.vel.y; - } else { - bullets[i].vel.x = fix32Mul(fix16ToFix32(cosFix16(spawner.angle)), spawner.speed); - bullets[i].vel.y = fix32Mul(fix16ToFix32(sinFix16(spawner.angle)), spawner.speed); - } - bullets[i].updater = updater; - bullets[i].dist = bullets[i].player ? 16 : (spawner.anim == 0 ? 4 : 7); - bullets[i].image = SPR_addSprite(spawner.player ? &pBulletSprite : &bulletsSprite, - getScreenX(bullets[i].pos.x, player.camera) - (spawner.player ? P_BULLET_OFF : BULLET_OFF), - fix32ToInt(bullets[i].pos.y) - (spawner.player ? P_BULLET_OFF : BULLET_OFF), - TILE_ATTR(gameOver ? PAL1 : PAL0, 0, 0, spawner.player && spawner.angle == 512 ? 1 : 0)); - if(spawner.anim) SPR_setAnim(bullets[i].image, spawner.anim); - bullets[i].anim = spawner.anim; - bullets[i].frame = spawner.frame; - SPR_setFrame(bullets[i].image, spawner.frame); - SPR_setAnim(bullets[i].image, spawner.anim); - SPR_setDepth(bullets[i].image, spawner.player ? 7 : (spawner.top ? 3 : 4)); - doBulletRotation(i); + for(s16 j = 0; j < BULLET_COUNT; j++) if(!bullets[j].active) { i = j; break; } + if(i == -1) return; + + bullets[i].active = TRUE; + bullets[i].pos.x = spawner.x; + bullets[i].pos.y = spawner.y; + bullets[i].angle = spawner.angle; + bullets[i].player = spawner.player; + bullets[i].clock = 0; + if(spawner.vel.x || spawner.vel.y){ + bullets[i].vel.x = spawner.vel.x; + bullets[i].vel.y = spawner.vel.y; + } else { + bullets[i].vel.x = fix32Mul(fix16ToFix32(cosFix16(spawner.angle)), spawner.speed); + bullets[i].vel.y = fix32Mul(fix16ToFix32(sinFix16(spawner.angle)), spawner.speed); } + bullets[i].updater = updater; + bullets[i].dist = bullets[i].player ? 16 : (spawner.anim == 0 ? 4 : 7); + + u8 off = bullets[i].player ? P_BULLET_OFF : BULLET_OFF; + s16 sx = getScreenX(bullets[i].pos.x, player.camera); + s16 sy = fix32ToInt(bullets[i].pos.y); + bullets[i].image = SPR_addSprite(spawner.player ? &pBulletSprite : &bulletsSprite, + -32, -32, + TILE_ATTR(gameOver ? PAL1 : PAL0, 0, 0, spawner.player && spawner.angle == 512 ? 1 : 0)); + + if(spawner.anim) SPR_setAnim(bullets[i].image, spawner.anim); + bullets[i].anim = spawner.anim; + bullets[i].frame = spawner.frame; + SPR_setFrame(bullets[i].image, spawner.frame); + SPR_setAnim(bullets[i].image, spawner.anim); + SPR_setDepth(bullets[i].image, spawner.player ? 7 : (spawner.top ? 3 : 4)); + doBulletRotation(i); } s32 bulletDist; diff --git a/src/enemies.h b/src/enemies.h index 3b5237d..a954095 100644 --- a/src/enemies.h +++ b/src/enemies.h @@ -1,20 +1,53 @@ -void spawnEnemy(u8 type){ - (void)type; // Unused parameter, kept for API compatibility - s16 i = -1; - for(s16 j = 0; j < ENEMY_COUNT; j++) if(!enemies[j].active && i == -1) i = j; - if(i > -1){ - enemies[i].active = TRUE; - enemies[i].type = type; - enemies[i].pos.x = FIX32(64); - enemies[i].pos.y = FIX32(64); - enemies[i].off = 16; - enemies[i].image = SPR_addSprite(&butterflySprite, - getScreenX(enemies[i].pos.x, player.camera) - enemies[i].off, fix32ToInt(enemies[i].pos.y) - enemies[i].off, TILE_ATTR(gameOver ? PAL1 : PAL0, 0, 0, 0)); - enemies[i].angle = 128; - enemies[i].speed = FIX32(1); - enemies[i].vel.x = fix32Mul(fix16ToFix32(cosFix16(enemies[i].angle)), enemies[i].speed); - enemies[i].vel.y = fix32Mul(fix16ToFix32(sinFix16(enemies[i].angle)), enemies[i].speed); +#define ENEMY_MIN_DIST FIX32(64) + +static bool isValidEnemyPosition(fix32 x, fix32 y) { + for(s16 j = 0; j < ENEMY_COUNT; j++) { + if(enemies[j].active) { + fix32 dx = getWrappedDelta(x, enemies[j].pos.x); + fix32 dy = y - enemies[j].pos.y; + // Check if within 64px in both X and Y + if(dx >= -ENEMY_MIN_DIST && dx <= ENEMY_MIN_DIST && + dy >= -ENEMY_MIN_DIST && dy <= ENEMY_MIN_DIST) { + return FALSE; // Too close to existing enemy + } + } } + return TRUE; // Position is valid +} + +void spawnEnemy(u8 type, u8 zone){ + // Find available slot, return if none + s16 i = -1; + for(s16 j = 0; j < ENEMY_COUNT; j++) if(!enemies[j].active) { i = j; break; } + if(i == -1) return; + + enemies[i].active = TRUE; + enemies[i].type = type; + + // Calculate zone bounds (each zone is 512px) + fix32 zoneStart = FIX32(zone * 512); + fix32 randX, randY; + u16 attempts = 0; + do { + // Random X within zone: zoneStart + random(0-511) + randX = zoneStart + FIX32(random() % 512); + randY = FIX32(16 + (random() % 192)); + attempts++; + } while(!isValidEnemyPosition(randX, randY) && attempts < 100); + + enemies[i].pos.x = randX; + enemies[i].pos.y = randY; + enemies[i].off = 16; + enemies[i].image = SPR_addSprite(&butterflySprite, + getScreenX(enemies[i].pos.x, player.camera) - enemies[i].off, fix32ToInt(enemies[i].pos.y) - enemies[i].off, TILE_ATTR(gameOver ? PAL1 : PAL0, 0, 0, 0)); + enemies[i].angle = random() % 2 < 1 ? 128 : 384; + enemies[i].speed = FIX32(1); + enemies[i].vel.x = fix32Mul(fix16ToFix32(cosFix16(enemies[i].angle)), enemies[i].speed); + enemies[i].vel.y = fix32Mul(fix16ToFix32(sinFix16(enemies[i].angle)), enemies[i].speed); + for(u8 j = 0; j < PROP_COUNT; j++){ + enemies[i].ints[j] = 0; + } + enemies[i].ints[0] = random() % 45; } static void boundsEnemy(u8 i){ @@ -43,13 +76,13 @@ static void updateEnemy(u8 i){ SPR_setPosition(enemies[i].image, sx - enemies[i].off, sy - enemies[i].off); - if(enemies[i].clock % 45 == 0){ + if(enemies[i].clock % 45 == enemies[i].ints[0]){ struct bulletSpawner spawner = { .x = enemies[i].pos.x, .y = enemies[i].pos.y, .anim = 7, // .frame = 1, - .speed = FIX32(2), + .speed = FIX32(4), .angle = random() % 128, }; for(u8 j = 0; j < 8; j++){ diff --git a/src/global.h b/src/global.h index b34668d..2267466 100644 --- a/src/global.h +++ b/src/global.h @@ -1,5 +1,6 @@ u32 clock; #define CLOCK_LIMIT 32000 +#define PROP_COUNT 4 #define GAME_H_F FIX32(224) @@ -70,7 +71,7 @@ struct bullet bullets[BULLET_COUNT]; // enemies -#define ENEMY_COUNT 16 +#define ENEMY_COUNT 24 struct enemy { bool active; @@ -80,6 +81,7 @@ struct enemy { fix32 speed; Vect2D_f32 vel, pos; Sprite* image; + s16 ints[PROP_COUNT]; }; struct enemy enemies[ENEMY_COUNT]; diff --git a/src/main.c b/src/main.c index 9d33b31..f8f8be2 100644 --- a/src/main.c +++ b/src/main.c @@ -8,6 +8,7 @@ #include "player.h" #include "stage.h" #include "chrome.h" +#include "start.h" static void loadInternals(){ JOY_init(); @@ -29,10 +30,13 @@ void loadGame(){ static void updateGame(){ updateChrome(); - updateBackground(); - updateEnemies(); updatePlayer(); - updateBullets(); + if(clock % 2 == 0){ + updateEnemies(); + } else { + updateBackground(); + updateBullets(); + } } int main(bool hardReset){ diff --git a/src/player.h b/src/player.h index 42fda40..775d51c 100644 --- a/src/player.h +++ b/src/player.h @@ -1,6 +1,6 @@ -#define PLAYER_SPEED FIX32(5) +#define PLAYER_SPEED FIX32(4) -#define PLAYER_SPEED_FOCUS FIX32(3) +#define PLAYER_SPEED_FOCUS FIX32(2.5) #define PLAYER_ACCEL PLAYER_SPEED >> 3 #define PLAYER_ACCEL_FOCUS PLAYER_SPEED_FOCUS >> 3 @@ -100,7 +100,7 @@ static void shootPlayer(){ .x = player.pos.x, .y = player.pos.y, .anim = 0, - .speed = FIX32(12), + .speed = FIX32(24), .angle = player.shotAngle, .player = TRUE }; diff --git a/src/stage.h b/src/stage.h index 4ce724a..be60f12 100644 --- a/src/stage.h +++ b/src/stage.h @@ -1,3 +1,8 @@ void loadStage(){ - spawnEnemy(0); + // Spawn 2 enemies per zone (4 zones = 8 total) + for(u8 zone = 0; zone < 4; zone++){ + for(u8 i = 0; i < 2; i++){ + spawnEnemy(0, zone); + } + } } \ No newline at end of file