diff --git a/res/bullets/bigblue.png b/res/bullets/bigblue.png new file mode 100644 index 0000000..013a853 Binary files /dev/null and b/res/bullets/bigblue.png differ diff --git a/res/bullets/biggreen.png b/res/bullets/biggreen.png new file mode 100644 index 0000000..1fb50a0 Binary files /dev/null and b/res/bullets/biggreen.png differ diff --git a/res/bullets/bigpink.png b/res/bullets/bigpink.png new file mode 100644 index 0000000..b27c394 Binary files /dev/null and b/res/bullets/bigpink.png differ diff --git a/res/bullets/bigred.png b/res/bullets/bigred.png new file mode 100644 index 0000000..12a43c6 Binary files /dev/null and b/res/bullets/bigred.png differ diff --git a/res/bullets/bigwhite.png b/res/bullets/bigwhite.png new file mode 100644 index 0000000..98d353a Binary files /dev/null and b/res/bullets/bigwhite.png differ diff --git a/res/bullets/bigyellow.png b/res/bullets/bigyellow.png new file mode 100644 index 0000000..9960eb1 Binary files /dev/null and b/res/bullets/bigyellow.png differ diff --git a/res/bullets/smallblue.png b/res/bullets/smallblue.png new file mode 100644 index 0000000..6bfb075 Binary files /dev/null and b/res/bullets/smallblue.png differ diff --git a/res/bullets/smallgreen.png b/res/bullets/smallgreen.png new file mode 100644 index 0000000..d00ebc2 Binary files /dev/null and b/res/bullets/smallgreen.png differ diff --git a/res/bullets/smallpink.png b/res/bullets/smallpink.png new file mode 100644 index 0000000..bce9ff9 Binary files /dev/null and b/res/bullets/smallpink.png differ diff --git a/res/bullets/smallred.png b/res/bullets/smallred.png new file mode 100644 index 0000000..32d447f Binary files /dev/null and b/res/bullets/smallred.png differ diff --git a/res/bullets/smallwhite.png b/res/bullets/smallwhite.png new file mode 100644 index 0000000..63e9ee7 Binary files /dev/null and b/res/bullets/smallwhite.png differ diff --git a/res/bullets/smallyellow.png b/res/bullets/smallyellow.png new file mode 100644 index 0000000..1e8731b Binary files /dev/null and b/res/bullets/smallyellow.png differ diff --git a/res/resources.res b/res/resources.res index 0723128..37eda00 100644 --- a/res/resources.res +++ b/res/resources.res @@ -4,4 +4,17 @@ IMAGE bgWall1 "bg/wall1.png" FAST IMAGE bgCeil1 "bg/ceil1.png" FAST IMAGE bgFloor1 "bg/floor1.png" FAST -SPRITE nitori "player/nitori.png" 4 4 FAST \ No newline at end of file +SPRITE nitori "player/nitori.png" 4 4 FAST + +SPRITE smallRedBullet "bullets/smallred.png" 1 1 FAST 5 +SPRITE smallBlueBullet "bullets/smallblue.png" 1 1 FAST 5 +SPRITE smallGreenBullet "bullets/smallgreen.png" 1 1 FAST 5 +SPRITE smallPinkBullet "bullets/smallpink.png" 1 1 FAST 5 +SPRITE smallYellowBullet "bullets/smallyellow.png" 1 1 FAST 5 +SPRITE smallWhiteBullet "bullets/smallwhite.png" 1 1 FAST 5 +SPRITE bigRedBullet "bullets/bigred.png" 2 2 FAST 5 +SPRITE bigBlueBullet "bullets/bigblue.png" 2 2 FAST 5 +SPRITE bigGreenBullet "bullets/biggreen.png" 2 2 FAST 5 +SPRITE bigPinkBullet "bullets/bigpink.png" 2 2 FAST 5 +SPRITE bigYellowBullet "bullets/bigyellow.png" 2 2 FAST 5 +SPRITE bigWhiteBullet "bullets/bigwhite.png" 2 2 FAST 5 \ No newline at end of file diff --git a/src/bullets.h b/src/bullets.h new file mode 100644 index 0000000..daf58d1 --- /dev/null +++ b/src/bullets.h @@ -0,0 +1,124 @@ +// bullets + +#define BULLET_COUNT 64 + +struct bullet { + bool active, player; + fix16 speed; + fix32 dist; + Vect2D_f16 pos, vel; + s16 angle, clock; + Sprite* image; + bool dead, big; + void (*updater)(s16); + bool bools[COUNT_INT]; + s16 ints[COUNT_INT]; + fix16 fixes[COUNT_INT]; +}; +struct bullet bullets[BULLET_COUNT]; + + +// lifecycle + +#define BULLET_OFF 4 +#define BULLET_OFF_BIG 8 + +#define BULLET_DIST FIX32(4) +#define BULLET_DIST_BIG FIX32(8) + +void spawnBullet(struct bulletSpawner spawner, void(*updater)){ + s16 i = -1; + for(s16 j = 0; j < BULLET_COUNT; j++) if(!bullets[j].active && i == -1) i = j; + if(i > -1 && (spawner.player || (player.invincibleClock < INVINCIBLE_LIMIT))){ + bullets[i].active = TRUE; + bullets[i].pos.x = spawner.x; + bullets[i].pos.y = spawner.y; + bullets[i].dist = fix16ToFix32(spawner.big ? BULLET_DIST_BIG : BULLET_DIST); + bullets[i].speed = spawner.speed; + bullets[i].angle = spawner.angle; + bullets[i].player = spawner.player; + bullets[i].clock = 0; + bullets[i].dead = FALSE; + bullets[i].big = spawner.big; + for(u8 j = 0; j < COUNT_INT; j++){ + bullets[i].bools[j] = spawner.bools[j]; + bullets[i].ints[j] = spawner.ints[j]; + bullets[i].fixes[j] = spawner.fixes[j]; + } + if(spawner.vel.x && spawner.vel.y){ + bullets[i].vel.x = spawner.vel.x; + bullets[i].vel.y = spawner.vel.y; + if(bullets[i].vel.x > 0 && !bullets[i].player) bullets[i].vel.x = -bullets[i].vel.x; + } else { + bullets[i].vel.x = fix16Mul(cosFix16(spawner.angle), spawner.speed); + bullets[i].vel.y = fix16Mul(sinFix16(spawner.angle), spawner.speed); + } + bullets[i].updater = updater; + bullets[i].image = SPR_addSprite(spawner.image, + fix16ToInt(fix16Sub(bullets[i].pos.x, spawner.big ? BULLET_OFF_BIG : BULLET_OFF)), + fix16ToInt(fix16Sub(bullets[i].pos.y,spawner.big ? BULLET_OFF_BIG : BULLET_OFF)), + TILE_ATTR(PAL1, 0, 0, 0)); + // SPR_setDepth(bullets[i].image, 4); + } +} + +static void killBullet(s16 i){ + bullets[i].active = FALSE; + SPR_releaseSprite(bullets[i].image); + if(bullets[i].dead){ + // spawnExplosion(bullets[i].pos.x, bullets[i].pos.y, 0); + bullets[i].dead = FALSE; + } +} + +void updateBulletVel(s16 i){ + bullets[i].vel.x = fix16Mul(cosFix16(bullets[i].angle), bullets[i].speed); + bullets[i].vel.y = fix16Mul(sinFix16(bullets[i].angle), bullets[i].speed); +} + + +// collision + +#define BULLET_LIMIT FIX16(-BULLET_OFF) +#define BULLET_LIMIT_W FIX16(GAME_W + BULLET_OFF) +#define BULLET_LIMIT_H FIX16(GAME_H + BULLET_OFF) + +#define BULLET_LIMIT_BIG FIX16(-BULLET_OFF_BIG) +#define BULLET_LIMIT_W_BIG FIX16(GAME_W + BULLET_OFF_BIG) +#define BULLET_LIMIT_H_BIG FIX16(GAME_H + BULLET_OFF_BIG) + +static void collideBullet(s16 i){ + if(bullets[i].pos.x < (bullets[i].big ? BULLET_LIMIT_BIG : BULLET_LIMIT) || + bullets[i].pos.x > (bullets[i].big ? BULLET_LIMIT_W_BIG : BULLET_LIMIT_W) || + bullets[i].pos.y < (bullets[i].big ? BULLET_LIMIT_BIG : BULLET_LIMIT) || + bullets[i].pos.y > (bullets[i].big ? BULLET_LIMIT_H_BIG : BULLET_LIMIT_H)){ + killBullet(i); + } +} + + +// loop + +static void updateBullet(s16 i){ + bullets[i].pos.x = fix16Add(bullets[i].pos.x, bullets[i].vel.x); + bullets[i].pos.y = fix16Add(bullets[i].pos.y, bullets[i].vel.y); + bullets[i].updater(i); + collideBullet(i); + SPR_setPosition( + bullets[i].image, + fix16ToInt(fix16Sub(bullets[i].pos.x, bullets[i].big ? BULLET_OFF_BIG : BULLET_OFF)), + fix16ToInt(fix16Sub(bullets[i].pos.y, bullets[i].big ? BULLET_OFF_BIG : BULLET_OFF))); + bullets[i].clock++; +} + +void updateBullets(){ + if(killBullets){ + for(s16 i = 0; i < BULLET_COUNT; i++) if(bullets[i].active){ + if(i % 4 == 0) bullets[i].dead = TRUE; + killBullet(i); + } + killBullets = FALSE; + } else { + for(s16 i = 0; i < BULLET_COUNT; i++) if(bullets[i].active) updateBullet(i); + } +} \ No newline at end of file diff --git a/src/global.h b/src/global.h index e7fe089..2ec5d97 100644 --- a/src/global.h +++ b/src/global.h @@ -19,8 +19,27 @@ #define GAME_Y 0 #define CLOCK_LIMIT 32000 +#define COUNT_INT 8 + +bool killBullets; s16 clock; u32 score, - highScore; \ No newline at end of file + highScore; + +void EMPTY(s16 i){} + + +// structs + +struct bulletSpawner { + fix16 x, y, speed; + Vect2D_f16 vel; + s16 angle; + Sprite* image; + bool big, player; + bool bools[COUNT_INT]; + s16 ints[COUNT_INT]; + fix16 fixes[COUNT_INT]; +}; \ No newline at end of file diff --git a/src/main.c b/src/main.c index 4e65260..f77ef09 100644 --- a/src/main.c +++ b/src/main.c @@ -7,6 +7,7 @@ #include "controls.h" #include "background.h" #include "player.h" +#include "bullets.h" #include "chrome.h" // game loop @@ -30,6 +31,7 @@ static void loadGame(){ static void updateGame(){ updatePlayer(); + updateBullets(); updateBg(); updateChrome(); clock++; diff --git a/src/player.h b/src/player.h index ba16521..dffd0d6 100644 --- a/src/player.h +++ b/src/player.h @@ -4,10 +4,13 @@ #define PLAYER_INIT_X FIX16(40) #define PLAYER_INIT_Y FIX16(GAME_H / 2) +#define INVINCIBLE_LIMIT 60 * 4 +#define SHOT_INTERVAL 15 + struct playerStruct { Vect2D_f16 pos, vel; Sprite* image; - s16 clock; + s16 clock, invincibleClock, shotClock; }; struct playerStruct player; @@ -17,6 +20,7 @@ struct playerStruct player; static void spawnPlayer(){ player.pos.x = PLAYER_INIT_X; player.pos.y = PLAYER_INIT_Y; + player.shotClock = SHOT_INTERVAL; player.image = SPR_addSprite(&nitori, fix16ToInt(fix16Sub(player.pos.x, PLAYER_OFF)), fix16ToInt(fix16Sub(player.pos.y, PLAYER_OFF)), @@ -40,8 +44,8 @@ static void checkPlayerBounds(){ // movement -#define PLAYER_SPEED FIX16(2.25) -#define PLAYER_SPEED_NORM FIX16(2.25 * 0.707) +#define PLAYER_SPEED FIX16(2.5) +#define PLAYER_SPEED_NORM FIX16(2.5 * 0.707) s16 playerFrame; @@ -74,6 +78,34 @@ static void movePlayer(){ } +// shooting + +// shoot + +#define PLAYER_BULLET_SPEED FIX16(16) +#define PLAYER_BULLET_ANGLE 0 + +static void spawnPlayerBullet(){ + struct bulletSpawner spawner = { + .x = player.pos.x, + .y = player.pos.y, + .image = &smallWhiteBullet, + .speed = PLAYER_BULLET_SPEED, + .angle = PLAYER_BULLET_ANGLE, + .player = TRUE + }; + spawnBullet(spawner, EMPTY); +} + + +static void shotPlayer(){ + if(player.shotClock >= SHOT_INTERVAL && ctrl.a) player.shotClock = 0; + if(player.shotClock == 0) spawnPlayerBullet(); + player.shotClock++; + if(player.shotClock >= CLOCK_LIMIT) player.shotClock = SHOT_INTERVAL; +} + + // loop void loadPlayer(){ @@ -82,6 +114,7 @@ void loadPlayer(){ void updatePlayer(){ movePlayer(); + shotPlayer(); SPR_setPosition(player.image, fix16ToInt(fix16Sub(player.pos.x, PLAYER_OFF)), fix16ToInt(fix16Sub(player.pos.y, PLAYER_OFF)));