From 75f6c7d8dc1f359610e8bd32136b4414c9148488 Mon Sep 17 00:00:00 2001 From: Trevor Boddy Date: Mon, 16 Feb 2026 09:24:19 -0500 Subject: [PATCH] sfx, explozion --- res/pbullet.png | Bin 1994 -> 2489 bytes src/bullets.h | 42 ++++++++++++++++++++----- src/enemytypes.h | 3 +- src/global.h | 30 +++++++++++++++--- src/main.c | 2 ++ src/player.h | 1 + src/sfx.h | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 146 insertions(+), 12 deletions(-) create mode 100644 src/sfx.h diff --git a/res/pbullet.png b/res/pbullet.png index 50372314410c2a62926d878712ced4acb3660703..7e26b48ae6394f91c216c13c0bb91976eb9bb0ba 100644 GIT binary patch delta 864 zcmX@bzf)MTGr-TCmrII^fq{Y7)59eQNG||l2M%T+xhk}0?ncF@Ok8Fm1{PMvhE}Gg zlLeTSk-4_a0V+o3<|YP-21&YRNft@ECT6CIx|Rl}X}YOK$)*M-Mn>jI29}#QGG{Rn zrE+ost2nX^6InwhZ()n9*N?ed#lXNc!PCVtB%|?eq;GMH0uL|W-UA2!|2M9laN5XO z{YXZ`i(7G0-(+`jv-b8+*B5tiWU!7nu%q?ep*<{Ryga4*R93UG&AWGCNu#4rzSvxq zg{8BM&Q=uOdi$9{&_{0LVgCO5O^wcRzc`i8Rg16iewcsnfTI3kpF_s$)a!GYP8$ff z=!f{W*Y4_Z~ zHK*g+P1fs`@n*$uKmF14Pw;1>8pZ?lQTrcS*qIq>ZC_{@+bq9b*Y=~|ed8&A{@t8Z zV{knBS8ri@LXZC*A=N__p&u{Tcg+%ek@wo&;0IIq&BCefMdDW$FS}f{M}Bh8gMF6@ zX1~%})jm1k4(F};_DzmAem*|>^TLJ38=uu1KPOkb+PbP-e0D8cto0Qq12wzr0lso- zR@3SaXr=Z=AN{y>ckHRVZo21|9*n4bQOr_xXZPBr4{tahv&}mB%-SuwV9ngg2X{Pg zx>Q*4cS)efirB}q_c&^}yFC4PBD}gxLNG1qL#*C2f7Z^>Q?FHiOmEuw%aJeoee6Tk zCEfSak_v8zzPOd%dq#RySCPS0Gu@)EvHN27g&H_oS=Og7Gh;iH!sGO`;DXml=OxbT zGW?WQZ}mREGVD*jdF;Cwo~CQ*Dy#fcSd=?zr0)bu?#~ySS%0(pi{%fQ^T!tOJz<+a z*{JcD-^$H1v=<~tm&qH2O(<`Fe8z8o{KM!Y?w@&fsdwMXdiF%UG`l2Th4;JYqpDzY zFZusGY^7%N_b=o&Je76ReZBd9^%?0GniGwgmfV;AF+F_!t$EAykJm9Q{CITo{o>Ew Qz)Zv7>FVdQ&MBb@0EYy4Gynhq delta 359 zcmdlfe2QPOGr-TCmrII^fq{Y7)59eQNGpIa2Q!d#S<-cEqvBI0F5?g*11m#ID+80s z0?f+DTwCS<6+@$B3v**LQ(e=<#6(?_q*OCqi&QfMT@%BU#54m_LrX(Ti_IIEvzUld zIk|vUmIZ9pMAneWTi7D&XKBpZ3v|swPZ!4!i{81x7x|7TaA= -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); + } + } +}