From 60aa78f3f1d7e1cb8409f312829d8170627568c1 Mon Sep 17 00:00:00 2001 From: Trevor Boddy Date: Wed, 17 Aug 2022 20:39:28 -0400 Subject: [PATCH] start enemy work --- res/enemies/fairy1.png | Bin 0 -> 4507 bytes res/resources.res | 2 + src/enemies.h | 96 +++++++++++++++++++++++++++++++++++++++++ src/foreground.h | 34 ++++++--------- src/global.h | 20 ++++++++- src/main.c | 4 ++ src/stage.h | 59 +++++++++++++++++++++++++ src/structs.h | 39 +++++++++++++++++ 8 files changed, 233 insertions(+), 21 deletions(-) create mode 100644 res/enemies/fairy1.png create mode 100644 src/enemies.h create mode 100644 src/stage.h diff --git a/res/enemies/fairy1.png b/res/enemies/fairy1.png new file mode 100644 index 0000000000000000000000000000000000000000..acb061665e785f2235db779882cc9189ccbfbaf1 GIT binary patch literal 4507 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 -1){ + enemies[i].active = TRUE; + enemies[i].off.x = FIX16(spawner.offX); + enemies[i].off.y = FIX16(spawner.offY); + enemies[i].pos.x = FIX16(spawner.x); + enemies[i].pos.y = FIX16(spawner.y); + enemies[i].dist = intToFix32(spawner.offX - 2); + enemies[i].speed = spawner.speed; + enemies[i].angle = spawner.angle; + enemies[i].boss = spawner.boss; + enemies[i].shotClock = 0; + enemies[i].dead = FALSE; + enemies[i].health = spawner.health ? spawner.health : 1; + if(spawner.vel.x && spawner.vel.y){ + enemies[i].vel.x = spawner.vel.x; + enemies[i].vel.y = spawner.vel.y; + } else { + enemies[i].vel.x = fix16Mul(cosFix16(spawner.angle), spawner.speed); + enemies[i].vel.y = fix16Mul(sinFix16(spawner.angle), spawner.speed); + } + for(s16 j = 0; j < COUNT_INT; j++){ + enemies[i].bools[j] = spawner.bools[j]; + enemies[i].ints[j] = spawner.ints[j]; + enemies[i].fixes[j] = spawner.fixes[j]; + } + enemies[i].updater = updater; + enemies[i].suicide = suicide; + enemies[i].clock = 0; + enemies[i].seen = FALSE; + enemies[i].image = SPR_addSprite(spawner.image, + fix16ToInt(fix16Sub(enemies[i].pos.x, enemies[i].off.x)), + fix16ToInt(fix16Sub(enemies[i].pos.y, enemies[i].off.y)), + TILE_ATTR(PAL1, 0, 0, 0)); + SPR_setAnim(enemies[i].image, spawner.anim ? spawner.anim : 0); + SPR_setFrame(enemies[i].image, spawner.frame ? spawner.frame : 0); + SPR_setDepth(enemies[i].image, 5); + SPR_setVisibility(enemies[i].image, HIDDEN); + } +} + +void killEnemy(s16 i){ + enemies[i].dead = TRUE; +} + + +// helpers + +void updateEnemyVel(s16 i){ + enemies[i].vel.x = fix16Mul(cosFix16(enemies[i].angle), enemies[i].speed); + enemies[i].vel.y = fix16Mul(sinFix16(enemies[i].angle), enemies[i].speed); +} + + +// loop + +static void updateEnemy(s16 i){ + if(enemies[i].seen && (enemies[i].pos.x < fix16Sub(0, enemies[i].off.x) || + enemies[i].pos.x > fix16Add(FIX16(GAME_W), enemies[i].off.x) || + enemies[i].pos.y < fix16Sub(0, enemies[i].off.y) || + enemies[i].pos.y > fix16Add(FIX16(GAME_H), enemies[i].off.y))){ + killEnemy(i); + enemies[i].suicide(i); + } else { + if(!enemies[i].seen && enemies[i].pos.x <= fix16Add(FIX16(GAME_W), enemies[i].off.x)){ + enemies[i].seen = TRUE; + SPR_setVisibility(enemies[i].image, VISIBLE); + } + enemies[i].pos.x = fix16Add(enemies[i].pos.x, enemies[i].vel.x); + enemies[i].pos.y = fix16Add(enemies[i].pos.y, enemies[i].vel.y); + if(enemies[i].seen){ + enemies[i].updater(i); + if(enemies[i].boss) bossHealth = enemies[i].health; + // collideEnemy(i); + enemies[i].clock++; + if(enemies[i].clock >= CLOCK_LIMIT) enemies[i].clock -= CLOCK_LIMIT; + SPR_setPosition(enemies[i].image, + fix16ToInt(fix16Sub(enemies[i].pos.x, enemies[i].off.x)), + fix16ToInt(fix16Sub(enemies[i].pos.y, enemies[i].off.y))); + } + } + if(enemies[i].dead){ + enemies[i].active = FALSE; + SPR_releaseSprite(enemies[i].image); + } +} + +void updateEnemies(){ + for(s16 i = 0; i < ENEMY_COUNT; i++) if(enemies[i].active) updateEnemy(i); +} \ No newline at end of file diff --git a/src/foreground.h b/src/foreground.h index 2753e82..f9532bf 100644 --- a/src/foreground.h +++ b/src/foreground.h @@ -1,7 +1,7 @@ // foreground #define FG_I 576 -#define FG_W GAME_W_T + 30 +#define FG_W 64 #define OBSTACLE_COUNT 8 #define FG_SPEED FIX16(2) @@ -38,33 +38,28 @@ static void drawFg(){ #define OBS_TOP_Y FIX16(56) #define OBS_BOTTOM_Y FIX16(160) -s16 fgPos; +s16 fgPos, obsX; static void spawnObstacle(bool top){ s16 i = -1; for(s16 j = 0; j < OBSTACLE_COUNT; j++) if(!obstacles[j].active && i == -1) i = j; if(i > -1){ + // obsX = OBS_X; + obsX = OBS_X + (fgPos != 0 ? (-fgPos / 8) : 0); obstacles[i].active = TRUE; obstacles[i].top = top; obstacles[i].pos.x = FIX16(256); obstacles[i].pos.y = top ? OBS_TOP_Y : OBS_BOTTOM_Y; obstacles[i].size.x = FIX16(64); obstacles[i].size.y = FIX16(32); - obstacles[i].startX = OBS_X; - if(top){ - for(u8 j = 0; j < 4; j++){ - VDP_drawImageEx(BG_B, - j == 0 ? &rock1lt : (j == 1 ? &rock1t : (j == 2 ? &rock1rt : &rock1b)), - TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I + (j == 0 ? 32 : (j == 1 ? 48 : (j == 2 ? 64 : 80)))), - OBS_X + (j == 1 || j == 3 ? 2 : (j == 2 ? 6 : 0)), - OBS_CEIL_Y - (j == 0 || j == 2 ? 2 : (j == 3 ? 4 : 0)), - 0, DMA_QUEUE); - } - } else { - VDP_drawImageEx(BG_B, &rock1l, TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I + 32 + 80), OBS_X, OBS_FLOOR_Y, 0, DMA_QUEUE); - VDP_drawImageEx(BG_B, &rock1, TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I + 48 + 80), OBS_X + 2, OBS_FLOOR_Y, 0, DMA_QUEUE); - VDP_drawImageEx(BG_B, &rock1r, TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I + 64 + 80), OBS_X + 2 + 4, OBS_FLOOR_Y, 0, DMA_QUEUE); - VDP_drawImageEx(BG_B, &rock1b, TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I + 80), OBS_X + 2, OBS_FLOOR_Y + 4, 0, DMA_QUEUE); + obstacles[i].startX = obsX; + for(u8 j = 0; j < 4; j++){ + VDP_drawImageEx(BG_B, + top ? (j == 0 ? &rock1lt : (j == 1 ? &rock1t : (j == 2 ? &rock1rt : &rock1b))) : (j == 0 ? &rock1l : (j == 1 ? &rock1 : (j == 2 ? &rock1r : &rock1b))), + TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I + (top ? (j == 0 ? 32 : (j == 1 ? 48 : (j == 2 ? 64 : 80))) : (j == 0 ? 112 : (j == 1 ? 128 : (j == 2 ? 144 : 80))))), + obsX + (top ? (j == 1 || j == 3 ? 2 : (j == 2 ? 6 : 0)) : ((j == 1 || j == 3 ? 2 : (j == 2 ? 6 : 0)))), + top ? (OBS_CEIL_Y - (j == 0 || j == 2 ? 2 : (j == 3 ? 4 : 0))) : (OBS_FLOOR_Y + (j == 3 ? 4 : 0)), + 0, DMA_QUEUE); } } } @@ -93,7 +88,7 @@ static void updateObstacle(s16 i){ // update #define FG_SIZE 32 -#define FG_LIMIT FIX16(-320) +#define FG_LIMIT FIX16(-512) #define FG_SIZE_F 40 @@ -117,12 +112,11 @@ static void scrollFg(){ void loadFg(){ drawFg(); - spawnObstacle(FALSE); - spawnObstacle(TRUE); } void updateFg(){ VDP_setHorizontalScrollTile(BG_B, 0, fgPosX, GAME_H_T, DMA); scrollFg(); for(s16 i = 0; i < OBSTACLE_COUNT; i++) if(obstacles[i].active) updateObstacle(i); + if(clock % 60 == 0) spawnObstacle(clock % 120 < 60); } \ No newline at end of file diff --git a/src/global.h b/src/global.h index 65e4cd7..3d95b75 100644 --- a/src/global.h +++ b/src/global.h @@ -19,7 +19,8 @@ bool killBullets, started; -s16 clock; +s16 clock, + bossHealth, bossMax; u32 score, highScore; @@ -30,3 +31,20 @@ void EMPTY(s16 i){emptyI = i;} void loadGame(); void collideObstacleWithPlayer(s16); + +fix16 honeSpeed; +Vect2D_f16 hPos, velPos; +Vect2D_f16 hone(Vect2D_f16 pos, Vect2D_f16 target, fix16 speed, s16 lerp){ + hPos.x = target.x; + hPos.y = target.y; + // if(lerp > 0){ + // hPos.x = fix16Add(fix16Sub(hPos.x, FIX16(lerp)), FIX16(random() % (lerp * 2))); + // hPos.y = fix16Add(fix16Sub(hPos.y, FIX16(lerp)), FIX16(random() % (lerp * 2))); + // } + honeSpeed = fix32ToFix16(getApproximatedDistance( + fix32Sub(fix16ToFix32(pos.x), fix16ToFix32(hPos.x)), + fix32Sub(fix16ToFix32(pos.y), fix16ToFix32(hPos.y)))); + hPos.x = fix16Mul(fix16Div(fix16Sub(hPos.x, pos.x), honeSpeed), speed); + hPos.y = fix16Mul(fix16Div(fix16Sub(hPos.y, pos.y), honeSpeed), speed); + return hPos; +} \ No newline at end of file diff --git a/src/main.c b/src/main.c index fb3a078..2184241 100644 --- a/src/main.c +++ b/src/main.c @@ -11,6 +11,8 @@ #include "foreground.h" #include "bullets.h" #include "player.h" +#include "enemies.h" +#include "stage.h" #include "chrome.h" // game loop @@ -36,6 +38,8 @@ void loadGame(){ static void updateGame(){ updatePlayer(); + updateEnemies(); + updateStage(); updateBullets(); updateBg(); updateFg(); diff --git a/src/stage.h b/src/stage.h new file mode 100644 index 0000000..7c746e7 --- /dev/null +++ b/src/stage.h @@ -0,0 +1,59 @@ +// stage + +#define SPAWN_MID 124 + + +// waves + +static void waveOne(){ + + struct enemySpawner spawner = { + .angle = 512, + .speed = FIX16(0.75), + .x = GAME_W + 24, + .y = SPAWN_MID, + .image = &fairy1, + .offX = 24, + .offY = 16 + }; + spawner.fixes[0] = FIX16(spawner.y); + spawner.fixes[1] = FIX16(8); + spawner.fixes[2] = FIX16(12); + spawner.fixes[3] = FIX16(0.1); + void updater(s16 i){ + enemies[i].pos.y = fix16Sub(enemies[i].fixes[0], fix16Mul(sinFix16(enemies[i].fixes[1]), enemies[i].fixes[2])); + enemies[i].fixes[1] = fix16Add(enemies[i].fixes[1], enemies[i].fixes[3]); + if(enemies[i].clock == 30){ + struct bulletSpawner spawner = { + .x = enemies[i].pos.x, + .y = enemies[i].pos.y, + .image = &smallRedBullet, + .angle = 512, + .speed = FIX16(1.5) + }; + spawner.vel = hone(enemies[i].pos, player.pos, spawner.speed, 0); + spawnBullet(spawner, EMPTY); + } + } + for(u8 j = 0; j < 3; j++){ + spawnEnemy(spawner, updater, EMPTY); + spawner.x += 50; + } +} + + +// loop + +s16 stageClock; + +static void updateWaves(){ + switch(stageClock){ + case 5: waveOne(); break; + } +} + +void updateStage(){ + updateWaves(); + stageClock++; + if(stageClock >= CLOCK_LIMIT) stageClock -= CLOCK_LIMIT; +} \ No newline at end of file diff --git a/src/structs.h b/src/structs.h index 4235cbc..deac91b 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1,5 +1,8 @@ // structs + +// bullets + #define BULLET_COUNT 64 struct bulletSpawner { fix16 x, y, speed; @@ -26,9 +29,45 @@ struct bullet { }; struct bullet bullets[BULLET_COUNT]; + +// player + struct playerStruct { Vect2D_f16 pos, vel; Sprite* image; s16 clock, invincibleClock, shotClock; }; struct playerStruct player; + + +// enemies + +#define ENEMY_COUNT 32 + +struct enemySpawner { + fix16 speed; + s16 angle, offX, offY, x, y, anim, health, frame; + Vect2D_f16 vel; + Sprite* image; + bool boss, seal; + bool bools[COUNT_INT]; + s16 ints[COUNT_INT]; + fix16 fixes[COUNT_INT]; +}; + +struct enemy { + bool active, boss, seen, seal, dead; + fix16 speed; + fix32 dist; + Vect2D_f16 pos, vel, off; + s16 angle, clock, health, shotClock; + Sprite* image; + Sprite* sealImage; + void (*updater)(s16); + void (*bossUpdater)(s16); + void (*suicide)(s16); + bool bools[COUNT_INT]; + s16 ints[COUNT_INT]; + fix16 fixes[COUNT_INT]; +}; +struct enemy enemies[ENEMY_COUNT]; \ No newline at end of file