diff --git a/res/pbullet.png b/res/pbullet.png index 5037231..7e26b48 100644 Binary files a/res/pbullet.png and b/res/pbullet.png differ diff --git a/src/bullets.h b/src/bullets.h index e9259f6..d72147d 100644 --- a/src/bullets.h +++ b/src/bullets.h @@ -82,6 +82,7 @@ void spawnBullet(struct bulletSpawner spawner, void(*updater)){ bullets[i].vel.y = fix32Mul(fix16ToFix32(sinFix16(spawner.angle)), spawner.speed); } bullets[i].updater = updater; + bullets[i].explosion = FALSE; bullets[i].dist = bullets[i].player ? 16 : (spawner.anim == 0 ? 4 : 7); u8 off = bullets[i].player ? P_BULLET_OFF : BULLET_OFF; @@ -116,8 +117,9 @@ static void collideWithEnemy(u8 i){ deltaX >= -BULLET_CHECK && deltaX <= BULLET_CHECK){ bulletDist = getApproximatedDistance(fix32ToInt(deltaX), fix32ToInt(deltaY)); if(bulletDist <= bullets[i].dist){ - killBullet(i); + killBullet(i, TRUE); killEnemy(j); + sfxExplosion(); } } } @@ -131,14 +133,35 @@ static void collideWithPlayer(u8 i){ s32 dist = getApproximatedDistance( fix32ToInt(deltaX), fix32ToInt(deltaY)); - if(dist <= 4){ - killBullet(i); + if(dist <= 4){ + killBullet(i, TRUE); + sfxExplosion(); // player.lives--; // if(player.lives <= 0) gameOver = TRUE; } } +static void updateBulletExplosion(u8 i){ + bullets[i].clock++; + if(bullets[i].clock & 1){ + bullets[i].frame++; + if(bullets[i].frame >= 5){ + killBullet(i, FALSE); + return; + } + SPR_setFrame(bullets[i].image, bullets[i].frame); + } + s16 sx = getScreenX(bullets[i].pos.x, player.camera); + s16 sy = fix32ToInt(bullets[i].pos.y); + u8 off = bullets[i].player ? P_BULLET_OFF : BULLET_OFF; + SPR_setPosition(bullets[i].image, sx - off, sy); +} + static void updateBullet(u8 i){ + if(bullets[i].explosion){ + updateBulletExplosion(i); + return; + } bullets[i].pos.x += bullets[i].vel.x; bullets[i].pos.y += bullets[i].vel.y; @@ -152,11 +175,16 @@ static void updateBullet(u8 i){ fix32 dx = getWrappedDelta(bullets[i].pos.x, player.pos.x); bool offScreenX = (dx < -CULL_LIMIT || dx > CULL_LIMIT); - bool offScreenY = (bullets[i].pos.y < FIX32(-16) || bullets[i].pos.y > GAME_H_F + FIX32(16)); + bool offScreenTop = (bullets[i].pos.y < FIX32(-16)); + bool offScreenBottom = (bullets[i].pos.y > GAME_H_F - FIX32(8)); - if(offScreenX || offScreenY){ - killBullet(i); - return; + if(offScreenX || offScreenTop){ + killBullet(i, FALSE); + return; + } + if(offScreenBottom){ + killBullet(i, TRUE); + return; } if(bullets[i].clock > 0) bullets[i].updater(i); if(bullets[i].player) collideWithEnemy(i); diff --git a/src/enemytypes.h b/src/enemytypes.h index 0203f93..2b02d36 100644 --- a/src/enemytypes.h +++ b/src/enemytypes.h @@ -5,7 +5,8 @@ void loadEnemyOne(u8 i){ } void updateEnemyOne(u8 i){ - if(enemies[i].clock % 60 == enemies[i].ints[0]){ + if(enemies[i].clock % 60 == enemies[i].ints[0] && enemies[i].onScreen){ + enemies[i].clock % 120 == enemies[i].ints[0] ? sfxEnemyShotB() : sfxEnemyShotA(); struct bulletSpawner spawner = { .x = enemies[i].pos.x, .y = enemies[i].pos.y, diff --git a/src/global.h b/src/global.h index 06e280d..dcc009d 100644 --- a/src/global.h +++ b/src/global.h @@ -62,7 +62,7 @@ struct bulletSpawner { bool top, player; }; struct bullet { - bool active, player, vFlip, hFlip; + bool active, player, vFlip, hFlip, explosion; Vect2D_f32 pos, vel; Sprite* image; s16 clock, angle, anim, frame; @@ -87,9 +87,31 @@ struct enemy { }; struct enemy enemies[ENEMY_COUNT]; -void killBullet(u8 i){ - bullets[i].active = FALSE; - SPR_releaseSprite(bullets[i].image); +void killBullet(u8 i, bool explode){ + if(explode){ + if(bullets[i].player){ + SPR_setAnim(bullets[i].image, 1); + } else { + s16 a = bullets[i].anim; + s16 explosionAnim; + if(a < FIRST_ROTATING_BULLET){ + explosionAnim = 13 + bullets[i].frame; + } else { + s16 mod = a % 3; + explosionAnim = 13 + mod; + } + SPR_setAnim(bullets[i].image, explosionAnim); + } + bullets[i].clock = 0; + bullets[i].frame = 0; + bullets[i].explosion = TRUE; + SPR_setFrame(bullets[i].image, 0); + SPR_setHFlip(bullets[i].image, random() & 1); + // SPR_setVFlip(bullets[i].image, random() & 1); + } else { + bullets[i].active = FALSE; + SPR_releaseSprite(bullets[i].image); + } } void killEnemy(u8 i){ diff --git a/src/main.c b/src/main.c index f8f8be2..73be5eb 100644 --- a/src/main.c +++ b/src/main.c @@ -9,6 +9,7 @@ #include "stage.h" #include "chrome.h" #include "start.h" +#include "sfx.h" static void loadInternals(){ JOY_init(); @@ -31,6 +32,7 @@ void loadGame(){ static void updateGame(){ updateChrome(); updatePlayer(); + updateSfx(); if(clock % 2 == 0){ updateEnemies(); } else { diff --git a/src/player.h b/src/player.h index b5844f3..08b55b4 100644 --- a/src/player.h +++ b/src/player.h @@ -107,6 +107,7 @@ static void shootPlayer(){ .player = TRUE }; spawnBullet(spawner, EMPTY); + sfxPlayerShot(); shotClock = SHOT_INTERVAL; } else if(shotClock > 0) shotClock--; } diff --git a/src/sfx.h b/src/sfx.h new file mode 100644 index 0000000..2bb4574 --- /dev/null +++ b/src/sfx.h @@ -0,0 +1,80 @@ +static s16 sfxShotClock; +static u16 sfxShotFreq; + +void sfxPlayerShot(){ + sfxShotClock = 4; + sfxShotFreq = 150; + PSG_setEnvelope(2, 2); + PSG_setFrequency(2, sfxShotFreq); +} + +static s16 sfxEnemyShotClock; +static u16 sfxEnemyShotFreq; +static u8 sfxEnemyShotType; + +// high sharp zap - quick descending chirp +void sfxEnemyShotA(){ + sfxEnemyShotClock = 3; + sfxEnemyShotFreq = 1200; + sfxEnemyShotType = 0; + PSG_setEnvelope(1, 3); + PSG_setFrequency(1, sfxEnemyShotFreq); +} + +// mid buzzy pulse - sits in the midrange +void sfxEnemyShotB(){ + sfxEnemyShotClock = 5; + sfxEnemyShotFreq = 400; + sfxEnemyShotType = 1; + PSG_setEnvelope(1, 3); + PSG_setFrequency(1, sfxEnemyShotFreq); +} + +// quick rising ping - sweeps upward +void sfxEnemyShotC(){ + sfxEnemyShotClock = 4; + sfxEnemyShotFreq = 300; + sfxEnemyShotType = 2; + PSG_setEnvelope(1, 3); + PSG_setFrequency(1, sfxEnemyShotFreq); +} + +static s16 sfxExpClock; + +void sfxExplosion(){ + sfxExpClock = 18; + PSG_setNoise(PSG_NOISE_TYPE_WHITE, PSG_NOISE_FREQ_CLOCK2); + PSG_setEnvelope(3, 0); +} + +void updateSfx(){ + if(sfxExpClock > 0){ + sfxExpClock--; + PSG_setEnvelope(3, (18 - sfxExpClock) * 15 / 18); + if(sfxExpClock == 0){ + PSG_setEnvelope(3, 15); + } + } + if(sfxEnemyShotClock > 0){ + sfxEnemyShotClock--; + if(sfxEnemyShotType == 0) sfxEnemyShotFreq -= 300; + else if(sfxEnemyShotType == 1) sfxEnemyShotFreq -= 50; + else sfxEnemyShotFreq += 150; + PSG_setFrequency(1, sfxEnemyShotFreq); + PSG_setEnvelope(1, 3 + (sfxEnemyShotType == 0 ? (3 - sfxEnemyShotClock) * 4 : + sfxEnemyShotType == 1 ? (5 - sfxEnemyShotClock) * 2 : + (4 - sfxEnemyShotClock) * 3)); + if(sfxEnemyShotClock == 0){ + PSG_setEnvelope(1, 15); + } + } + if(sfxShotClock > 0){ + sfxShotClock--; + sfxShotFreq -= 30; + PSG_setFrequency(2, sfxShotFreq); + PSG_setEnvelope(2, 2 + (4 - sfxShotClock) * 3); + if(sfxShotClock == 0){ + PSG_setEnvelope(2, 15); + } + } +}