enemy spawning etc

This commit is contained in:
t. boddy 2026-02-14 22:44:21 -05:00
parent b2c0eaf30b
commit 11547e9d13
6 changed files with 109 additions and 54 deletions

View file

@ -57,36 +57,47 @@ static void doBulletRotation(u8 i){
} }
void spawnBullet(struct bulletSpawner spawner, void(*updater)){ 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; s16 i = -1;
for(s16 j = 0; j < BULLET_COUNT; j++) if(!bullets[j].active && i == -1) i = j; for(s16 j = 0; j < BULLET_COUNT; j++) if(!bullets[j].active) { i = j; break; }
if(i > -1){ if(i == -1) return;
bullets[i].active = TRUE;
bullets[i].pos.x = spawner.x; bullets[i].active = TRUE;
bullets[i].pos.y = spawner.y; bullets[i].pos.x = spawner.x;
bullets[i].angle = spawner.angle; bullets[i].pos.y = spawner.y;
bullets[i].player = spawner.player; bullets[i].angle = spawner.angle;
bullets[i].clock = 0; bullets[i].player = spawner.player;
if(spawner.vel.x || spawner.vel.y){ bullets[i].clock = 0;
bullets[i].vel.x = spawner.vel.x; if(spawner.vel.x || spawner.vel.y){
bullets[i].vel.y = spawner.vel.y; bullets[i].vel.x = spawner.vel.x;
} else { bullets[i].vel.y = spawner.vel.y;
bullets[i].vel.x = fix32Mul(fix16ToFix32(cosFix16(spawner.angle)), spawner.speed); } else {
bullets[i].vel.y = fix32Mul(fix16ToFix32(sinFix16(spawner.angle)), spawner.speed); 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);
} }
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; s32 bulletDist;

View file

@ -1,20 +1,53 @@
void spawnEnemy(u8 type){ #define ENEMY_MIN_DIST FIX32(64)
(void)type; // Unused parameter, kept for API compatibility
s16 i = -1; static bool isValidEnemyPosition(fix32 x, fix32 y) {
for(s16 j = 0; j < ENEMY_COUNT; j++) if(!enemies[j].active && i == -1) i = j; for(s16 j = 0; j < ENEMY_COUNT; j++) {
if(i > -1){ if(enemies[j].active) {
enemies[i].active = TRUE; fix32 dx = getWrappedDelta(x, enemies[j].pos.x);
enemies[i].type = type; fix32 dy = y - enemies[j].pos.y;
enemies[i].pos.x = FIX32(64); // Check if within 64px in both X and Y
enemies[i].pos.y = FIX32(64); if(dx >= -ENEMY_MIN_DIST && dx <= ENEMY_MIN_DIST &&
enemies[i].off = 16; dy >= -ENEMY_MIN_DIST && dy <= ENEMY_MIN_DIST) {
enemies[i].image = SPR_addSprite(&butterflySprite, return FALSE; // Too close to existing enemy
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);
} }
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){ 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); 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 = { struct bulletSpawner spawner = {
.x = enemies[i].pos.x, .x = enemies[i].pos.x,
.y = enemies[i].pos.y, .y = enemies[i].pos.y,
.anim = 7, .anim = 7,
// .frame = 1, // .frame = 1,
.speed = FIX32(2), .speed = FIX32(4),
.angle = random() % 128, .angle = random() % 128,
}; };
for(u8 j = 0; j < 8; j++){ for(u8 j = 0; j < 8; j++){

View file

@ -1,5 +1,6 @@
u32 clock; u32 clock;
#define CLOCK_LIMIT 32000 #define CLOCK_LIMIT 32000
#define PROP_COUNT 4
#define GAME_H_F FIX32(224) #define GAME_H_F FIX32(224)
@ -70,7 +71,7 @@ struct bullet bullets[BULLET_COUNT];
// enemies // enemies
#define ENEMY_COUNT 16 #define ENEMY_COUNT 24
struct enemy { struct enemy {
bool active; bool active;
@ -80,6 +81,7 @@ struct enemy {
fix32 speed; fix32 speed;
Vect2D_f32 vel, pos; Vect2D_f32 vel, pos;
Sprite* image; Sprite* image;
s16 ints[PROP_COUNT];
}; };
struct enemy enemies[ENEMY_COUNT]; struct enemy enemies[ENEMY_COUNT];

View file

@ -8,6 +8,7 @@
#include "player.h" #include "player.h"
#include "stage.h" #include "stage.h"
#include "chrome.h" #include "chrome.h"
#include "start.h"
static void loadInternals(){ static void loadInternals(){
JOY_init(); JOY_init();
@ -29,10 +30,13 @@ void loadGame(){
static void updateGame(){ static void updateGame(){
updateChrome(); updateChrome();
updateBackground();
updateEnemies();
updatePlayer(); updatePlayer();
updateBullets(); if(clock % 2 == 0){
updateEnemies();
} else {
updateBackground();
updateBullets();
}
} }
int main(bool hardReset){ int main(bool hardReset){

View file

@ -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 PLAYER_SPEED >> 3
#define PLAYER_ACCEL_FOCUS PLAYER_SPEED_FOCUS >> 3 #define PLAYER_ACCEL_FOCUS PLAYER_SPEED_FOCUS >> 3
@ -100,7 +100,7 @@ static void shootPlayer(){
.x = player.pos.x, .x = player.pos.x,
.y = player.pos.y, .y = player.pos.y,
.anim = 0, .anim = 0,
.speed = FIX32(12), .speed = FIX32(24),
.angle = player.shotAngle, .angle = player.shotAngle,
.player = TRUE .player = TRUE
}; };

View file

@ -1,3 +1,8 @@
void loadStage(){ 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);
}
}
} }