now its a different game

This commit is contained in:
t. boddy 2022-09-23 10:21:36 -04:00
parent 4211296f3b
commit 4946dd8b92
48 changed files with 457 additions and 364 deletions

BIN
res/bg/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

BIN
res/bullets/big.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

BIN
res/bullets/huge.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
res/bullets/player.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
res/bullets/small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

BIN
res/enemies/fairyblue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
res/enemies/fairygreen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
res/enemies/fairyred.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
res/enemies/fairyyellow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
res/player/hitbox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

BIN
res/player/sunny.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -8,40 +8,20 @@ IMAGE frame "chrome/frame.png" FAST
// background
IMAGE wall1 "bg/wall1.png" FAST
// foreground
IMAGE rock1Bottom "fg/rock1bottom.png" FAST
IMAGE rock1Top "fg/rock1top.png" FAST
IMAGE obstacle1LeftBottom "fg/obstacle1leftbottom.png" FAST
IMAGE obstacle1RightBottom "fg/obstacle1rightbottom.png" FAST
IMAGE obstacle1MiddleBottom "fg/obstacle1middlebottom.png" FAST
IMAGE obstacle1LeftTop "fg/obstacle1lefttop.png" FAST
IMAGE obstacle1RightTop "fg/obstacle1righttop.png" FAST
IMAGE obstacle1MiddleTop "fg/obstacle1middletop.png" FAST
IMAGE rock2Bottom "fg/rock2bottom.png" FAST
IMAGE rock2Top "fg/rock2top.png" FAST
IMAGE bg1 "bg/1.png" FAST
// player and enemies
SPRITE nitori "player/nitori.png" 4 4 FAST
SPRITE fairy1 "enemies/fairy1.png" 5 4 FAST
SPRITE sunny "player/sunny.png" 6 5 FAST 10
SPRITE hitbox "player/hitbox.png" 1 1 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
SPRITE fairyRed "enemies/fairyred.png" 4 4 FAST 10
SPRITE fairyBlue "enemies/fairyblue.png" 4 4 FAST 10
SPRITE fairyYellow "enemies/fairyyellow.png" 4 4 FAST 10
SPRITE fairyGreen "enemies/fairygreen.png" 4 4 FAST 10
SPRITE smallBullet "bullets/small.png" 1 1 FAST 5
SPRITE bigBullet "bullets/big.png" 2 2 FAST 5
SPRITE hugeBullet "bullets/huge.png" 4 4 FAST 5
SPRITE playerBullet "bullets/player.png" 4 3 FAST 5

View File

@ -2,48 +2,46 @@
#define BG_I 512
#define BG_W GAME_W_T + 8
#define BG_H GAME_H_T
#define BG_W 38
#define BG_H 32
// draw
static void drawBg(){
for(u16 x = 0; x < BG_W; x++) for(u16 y = 0; y < BG_H; y++){
if(x % 8 == 0 && y % 8 == 0)
VDP_drawImageEx(BG_A, &wall1, TILE_ATTR_FULL(PAL2, 0, 0, 0, BG_I), x, y, 0, DMA);
if(x % 8 == 0 && y % 8 == 0){
VDP_drawImageEx(BG_B, &bg1, TILE_ATTR_FULL(PAL1, 0, 0, 0, BG_I + 1), x - 4, y, 0, DMA);
}
}
}
// update
#define BG_SPEED FIX16(0.5)
#define BG_SPEED_NORM FIX16(0.354)
#define BG_SPEED FIX16(2)
#define BG_SPEED_NORM FIX16(0.5 * NORM)
#define BG_SIZE 64
#define BG_LIMIT FIX16(-256)
#define BG_SIZE_F FIX16(BG_SIZE)
s16 bgPosX[GAME_H_T];
fix16 bgPosXF[GAME_H_T];
s16 bgPos;
fix16 bgPosF;
static void scrollBg(){
for(u8 y = 0; y < GAME_H_T; y++){
if(y > 2) bgPosXF[y] = fix16Sub(bgPosXF[y], BG_SPEED);
if(bgPosXF[y] <= -BG_SIZE_F) bgPosXF[y] = fix16Add(bgPosXF[y], BG_SIZE_F);
bgPosX[y] = fix16ToInt(bgPosXF[y]);
}
bgPosF = fix16Sub(bgPosF, BG_SPEED);
if(bgPosF <= BG_LIMIT) bgPosF = fix16Sub(bgPosF, BG_LIMIT);
bgPos = fix16ToInt(bgPosF);
}
// loop
void loadBg(){
VDP_setScrollingMode(HSCROLL_TILE, VSCROLL_PLANE);
drawBg();
}
void updateBg(){
VDP_setHorizontalScrollTile(BG_A, 0, bgPosX, GAME_H_T, DMA);
VDP_setVerticalScroll(BG_B, bgPos);
scrollBg();
}

View File

@ -2,9 +2,13 @@
#define BULLET_OFF 4
#define BULLET_OFF_BIG 8
#define BULLET_OFF_HUGE 16
#define BULLET_OFF_P_X 16
#define BULLET_OFF_P_Y 12
#define BULLET_DIST FIX32(4)
#define BULLET_DIST_BIG FIX32(8)
#define BULLET_DIST_HUGE FIX32(16)
// lifecycle
@ -16,13 +20,14 @@ void spawnBullet(struct bulletSpawner spawner, void(*updater)){
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].dist = fix16ToFix32(spawner.huge ? BULLET_DIST_HUGE : (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;
bullets[i].huge = spawner.huge;
for(u8 j = 0; j < COUNT_INT; j++){
bullets[i].bools[j] = spawner.bools[j];
bullets[i].ints[j] = spawner.ints[j];
@ -31,17 +36,18 @@ void spawnBullet(struct bulletSpawner spawner, void(*updater)){
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;
if(bullets[i].vel.y < 0 && !bullets[i].player && bullets[i].pos.y < player.pos.y) bullets[i].vel.y = -bullets[i].vel.y;
} 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)),
fix16ToInt(fix16Sub(bullets[i].pos.x, FIX16(spawner.player ? BULLET_OFF_P_X : (spawner.huge ? BULLET_OFF_HUGE : (spawner.big ? BULLET_OFF_BIG : BULLET_OFF))))),
fix16ToInt(fix16Sub(bullets[i].pos.y, FIX16(spawner.player ? BULLET_OFF_P_Y : (spawner.huge ? BULLET_OFF_HUGE : (spawner.big ? BULLET_OFF_BIG : BULLET_OFF))))),
TILE_ATTR(PAL1, 0, 0, 0));
// SPR_setDepth(bullets[i].image, 4);
if(spawner.light) SPR_setAnim(bullets[i].image, 1);
SPR_setDepth(bullets[i].image, spawner.top ? 3 : 4);
}
}
@ -62,19 +68,23 @@ void updateBulletVel(s16 i){
// collision
#define BULLET_LIMIT FIX16(-BULLET_OFF)
#define BULLET_LIMIT FIX16(0 - 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_BIG FIX16(0 - 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)
#define BULLET_LIMIT_HUGE FIX16(0 - BULLET_OFF_HUGE)
#define BULLET_LIMIT_W_HUGE FIX16(GAME_W + BULLET_OFF_HUGE)
#define BULLET_LIMIT_H_HUGE FIX16(GAME_H + BULLET_OFF_HUGE)
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)){
if(bullets[i].pos.x < (bullets[i].huge ? BULLET_LIMIT_HUGE : (bullets[i].big ? BULLET_LIMIT_BIG : BULLET_LIMIT)) ||
bullets[i].pos.x > (bullets[i].huge ? BULLET_LIMIT_W_HUGE : (bullets[i].big ? BULLET_LIMIT_W_BIG : BULLET_LIMIT_W)) ||
bullets[i].pos.y < (bullets[i].huge ? BULLET_LIMIT_HUGE : (bullets[i].big ? BULLET_LIMIT_BIG : BULLET_LIMIT)) ||
bullets[i].pos.y > (bullets[i].huge ? BULLET_LIMIT_H_HUGE : (bullets[i].big ? BULLET_LIMIT_H_BIG : BULLET_LIMIT_H))){
killBullet(i);
}
}
@ -89,8 +99,8 @@ static void updateBullet(s16 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)));
fix16ToInt(fix16Sub(bullets[i].pos.x, FIX16(bullets[i].player ? BULLET_OFF_P_X : (bullets[i].huge ? BULLET_OFF_HUGE : (bullets[i].big ? BULLET_OFF_BIG : BULLET_OFF))))),
fix16ToInt(fix16Sub(bullets[i].pos.y, FIX16(bullets[i].player ? BULLET_OFF_P_Y : (bullets[i].huge ? BULLET_OFF_HUGE : (bullets[i].big ? BULLET_OFF_BIG : BULLET_OFF))))));
bullets[i].clock++;
}

View File

@ -5,25 +5,21 @@
// frame
static void loadFrame(){
VDP_loadTileSet(frame.tileset, CHROME_I, DMA);
VDP_fillTileMapRect(BG_A, TILE_ATTR_FULL(PAL2, 1, 0, 0, CHROME_I), 0, 0, GAME_W_T, 3);
// VDP_loadTileSet(frame.tileset, CHROME_I, DMA);
// VDP_fillTileMapRect(BG_A, TILE_ATTR_FULL(PAL2, 1, 0, 0, CHROME_I), 0, 0, GAME_W_T, 4);
}
// score
#define SCORE_X 4
#define SCORE_Y 2
#define SCORE_LENGTH 8
#define SCORE_X 1
#define SCORE_Y 1
#define SCORE_LENGTH 9
u32 lastScore;
char scoreStr[SCORE_LENGTH];
static void loadScore(){
VDP_drawText("HI", 1, 1);
VDP_drawText("00000000", SCORE_X, 1);
VDP_drawText("sc", 1, 2);
intToStr(score, scoreStr, SCORE_LENGTH);
VDP_drawText(scoreStr, SCORE_X, SCORE_Y);
VDP_drawText("00000000", SCORE_X, SCORE_Y);
}
// static void updateScore(){
@ -36,37 +32,35 @@ static void loadScore(){
// }
// zone
// time
#define ZONE_X 28
#define ZONE_Y 1
#define ZONE_LABEL_X 23
#define TIME_Y 1
#define TIME_X 27
static void loadZone(){
VDP_drawText("ZONE", ZONE_LABEL_X, ZONE_Y);
VDP_drawText("001", ZONE_X, ZONE_Y);
static void loadTime(){
VDP_drawText("1:58", TIME_X, TIME_Y);
}
// heat
#define HEAT_X 28
#define HEAT_Y 2
#define HEAT_LABEL_X 23
#define RANK_X 28
#define RANK_Y 2
#define RANK_LABEL_X 25
static void loadHeat(){
VDP_drawText("heat", HEAT_LABEL_X, HEAT_Y);
VDP_drawText("100", HEAT_X, HEAT_Y);
static void loadRank(){
// VDP_drawText("RANK 1", RANK_LABEL_X, RANK_Y);
// VDP_drawText("100", RANK_X, HEAT_Y);
}
// loop
void loadChrome(){
loadFrame();
// loadFrame();
loadScore();
loadZone();
loadHeat();
loadTime();
// loadRank();
}
void updateChrome(){

View File

@ -68,7 +68,7 @@ static void updateEnemy(s16 i){
killEnemy(i);
enemies[i].suicide(i);
} else {
if(!enemies[i].seen && enemies[i].pos.x <= fix16Add(FIX16(GAME_W), enemies[i].off.x)){
if(!enemies[i].seen && enemies[i].pos.y >= fix16Sub(0, enemies[i].off.y)){
enemies[i].seen = TRUE;
SPR_setVisibility(enemies[i].image, VISIBLE);
}

View File

@ -1,159 +0,0 @@
// foreground
#define FG_I 576
#define FG_W 64
#define OBSTACLE_COUNT 24
#define FG_SPEED FIX16(1.75)
#define FG_SPEED_NORM FIX16(1.75 * 0.707)
struct obstacle {
bool active, top;
Vect2D_f16 pos, size;
s16 startX;
};
struct obstacle obstacles[OBSTACLE_COUNT];
s16 currentFg;
SpriteDefinition* currentTopImage;
SpriteDefinition* currentBottomImage;
// draw
#define CEIL_Y 3
#define FLOOR_Y 24
static void drawFg(){
switch(currentFg){
case 0:
VDP_loadTileSet(rock1Top.tileset, FG_I, DMA);
VDP_loadTileSet(rock1Bottom.tileset, FG_I + 16, DMA);
break;
case 1:
VDP_loadTileSet(rock2Top.tileset, FG_I, DMA);
VDP_loadTileSet(rock2Bottom.tileset, FG_I + 16, DMA);
break;
}
for(u16 x = 0; x < FG_W; x++){
if(x % 4 == 0){
for(s16 i = 0; i < 4; i++){
for(s16 j = 0; j < 4; j++){
VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I + i + 4 * j), x + i, CEIL_Y + j);
VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I + 16 + i + 4 * j), x + i, FLOOR_Y + j);
}
}
}
}
}
// obstacle
#define OBS_CEIL_Y 3
#define OBS_FLOOR_Y 20
#define OBS_X 32
#define OBS_TOP_Y FIX16(56)
#define OBS_BOTTOM_Y FIX16(160)
s16 fgPos, obsX;
#define OBS_I FG_I + 32
SpriteDefinition* obstacleImage;
s16 obstacleI;
static void spawnObstacle(bool top, s16 offset, u8 type){
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(32);
obstacles[i].size.y = FIX16(32);
if(offset){
obstacles[i].pos.x = fix16Sub(obstacles[i].pos.x, FIX16(offset));
obsX -= offset / 8;
}
obstacles[i].startX = obsX;
switch(type){
case 0: obstacleImage = top ? &obstacle1LeftTop : &obstacle1LeftBottom; break;
case 1: obstacleImage = top ? &obstacle1MiddleTop : &obstacle1MiddleBottom; break;
case 2: obstacleImage = top ? &obstacle1RightTop : &obstacle1RightBottom; break;
}
obstacleI = type * 32;
if(top) obstacleI += 128;
VDP_drawImageEx(BG_B, obstacleImage,
TILE_ATTR_FULL(PAL2, 1, 0, 0, OBS_I + obstacleI),
obsX, top ? OBS_CEIL_Y : OBS_FLOOR_Y, 0, DMA);
}
}
#define OBSTACLE_MOD FIX16(8)
#define OBSTACLE_LIMIT_X FIX16(-64)
static void killObstacle(s16 i){
obstacles[i].active = FALSE;
VDP_clearTileMapRect(BG_B, obstacles[i].startX, obstacles[i].top ? OBS_CEIL_Y + 4 : OBS_FLOOR_Y, 4, 4);
for(s16 h = 0; h < 4; h++){
for(s16 j = 0; j < 4; j++){
if(obstacles[i].top) VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I + h + 4 * j), obstacles[i].startX + h, CEIL_Y + j);
else VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I + 16 + h + 4 * j), obstacles[i].startX + h, FLOOR_Y + j);
}
}
}
static void collideObstacle(s16 i){
collideObstacleWithPlayer(i);
}
static void updateObstacle(s16 i){
obstacles[i].pos.x = fix16Sub(obstacles[i].pos.x, FG_SPEED);
obstacles[i].pos.x <= OBSTACLE_LIMIT_X ? killObstacle(i) : collideObstacle(i);
}
// update
#define FG_SIZE 32
#define FG_LIMIT FIX16(-512)
#define FG_SIZE_F 40
s16 fgPosX[GAME_H_T];
fix16 fgPosXF[GAME_H_T];
static void scrollFg(){
for(u8 y = 0; y < GAME_H_T; y++){
if(y > 2){
fgPosXF[y] = fix16Sub(fgPosXF[y], FG_SPEED);
if(fgPosXF[y] <= FG_LIMIT) fgPosXF[y] = 0;
fgPosX[y] = fix16ToInt(fgPosXF[y]);
}
}
fgPos = fgPosX[3];
}
void nextFg(){
VDP_clearTileMapRect(BG_B, 0, OBS_CEIL_Y + 4, FG_W, 17);
currentFg++;
drawFg();
}
// loop
void loadFg(){
drawFg();
}
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);
}

View File

@ -1,5 +1,7 @@
// globals
#define NORM 0.707
#define GAME_W_T 32
#define GAME_H_T 28

View File

@ -8,7 +8,7 @@
#include "controls.h"
#include "start.h"
#include "background.h"
#include "foreground.h"
// #include "foreground.h"
#include "bullets.h"
#include "player.h"
#include "enemies.h"
@ -22,18 +22,15 @@ static void loadInternals(){
JOY_init();
JOY_setEventHandler(&updateControls);
SPR_init(127, 0, 0);
VDP_setPalette(PAL1, nitori.palette -> data);
VDP_setPalette(PAL2, wall1.palette -> data);
VDP_setPalette(PAL3, font.palette -> data);
VDP_loadFont(font.tileset, DMA);
VDP_setTextPalette(3);
VDP_setPalette(PAL1, fairyYellow.palette -> data);
VDP_setTextPalette(1);
}
void loadGame(){
started = TRUE;
loadBg();
loadChrome();
loadFg();
loadPlayer();
}
@ -43,7 +40,6 @@ static void updateGame(){
updateStage();
updateBullets();
updateBg();
updateFg();
updateChrome();
clock++;
if(clock >= CLOCK_LIMIT) clock -= CLOCK_LIMIT;

View File

@ -1,10 +1,13 @@
// player
#define PLAYER_OFF FIX16(16)
#define PLAYER_INIT_X FIX16(32)
#define PLAYER_INIT_Y FIX16(124)
#define PLAYER_OFF_X FIX16(24)
#define PLAYER_OFF_Y FIX16(20)
#define PLAYER_INIT_X FIX16(GAME_W / 2)
#define PLAYER_INIT_Y FIX16(GAME_H - 40)
#define SHOT_INTERVAL 15
#define HITBOX_OFF FIX16(4)
#define SHOT_INTERVAL 12
// spawn
@ -13,60 +16,43 @@ 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)),
player.image = SPR_addSprite(&sunny,
fix16ToInt(fix16Sub(player.pos.x, PLAYER_OFF_X)),
fix16ToInt(fix16Sub(player.pos.y, PLAYER_OFF_Y)),
TILE_ATTR(PAL1, 0, 0, 0));
player.hitboxImage = SPR_addSprite(&hitbox,
fix16ToInt(fix16Sub(player.pos.x, HITBOX_OFF)),
fix16ToInt(fix16Sub(player.pos.y, HITBOX_OFF)),
TILE_ATTR(PAL1, 0, 0, 0));
SPR_setDepth(player.image, 6);
SPR_setDepth(player.hitboxImage, 1);
}
#define PLAYER_SPEED FIX16(2.5)
#define PLAYER_SPEED_NORM FIX16(1.768)
#define PLAYER_SPEED FIX16(3)
#define PLAYER_SPEED_NORM FIX16(3 * NORM)
// collision
#define PLAYER_LIMIT_X FIX16(16)
#define PLAYER_LIMIT_W FIX16(240)
#define PLAYER_LIMIT_Y FIX16(16)
#define PLAYER_LIMIT_H FIX16(208)
#define PLAYER_LIMIT_Y_HORI FIX16(72)
#define PLAYER_LIMIT_H_HORI FIX16(176)
#define PLAYER_LIMIT_X FIX16(0)
#define PLAYER_LIMIT_W FIX16(GAME_W)
#define PLAYER_LIMIT_Y FIX16(0)
#define PLAYER_LIMIT_H FIX16(GAME_H)
static void checkPlayerBounds(){
if(player.pos.x < PLAYER_LIMIT_X) player.pos.x = PLAYER_LIMIT_X;
else if(player.pos.x > PLAYER_LIMIT_W) player.pos.x = PLAYER_LIMIT_W;
if(player.pos.y < PLAYER_LIMIT_Y_HORI) player.pos.y = PLAYER_LIMIT_Y_HORI;
else if(player.pos.y > PLAYER_LIMIT_H_HORI) player.pos.y = PLAYER_LIMIT_H_HORI;
}
void collideObstacleWithPlayer(s16 i){
if(
obstacles[i].pos.x < fix16Add(player.pos.x, PLAYER_OFF) &&
fix16Add(obstacles[i].pos.x, obstacles[i].size.x) > fix16Sub(player.pos.x, PLAYER_OFF) &&
obstacles[i].pos.y < fix16Add(player.pos.y, PLAYER_OFF) &&
fix16Add(obstacles[i].pos.y, obstacles[i].size.y) > fix16Sub(player.pos.y, PLAYER_OFF)
){
if(obstacles[i].pos.x > player.pos.x) player.pos.x = fix16Sub(fix16Sub(obstacles[i].pos.x, FG_SPEED), PLAYER_OFF);
// else if(fix16Add(obstacles[i].pos.x, obstacles[i].size.x) > fix16Sub(player.pos.x, PLAYER_OFF)) player.pos.x = fix16Add(fix16Add(obstacles[i].pos.x, obstacles[i].size.x), PLAYER_OFF);
else if(obstacles[i].pos.y > player.pos.y) player.pos.y = fix16Sub(obstacles[i].pos.y, PLAYER_OFF);
else if(fix16Add(obstacles[i].pos.y, obstacles[i].size.y) > fix16Sub(player.pos.y, PLAYER_OFF)) player.pos.y = fix16Add(fix16Add(obstacles[i].pos.y, obstacles[i].size.y), PLAYER_OFF);
checkPlayerBounds();
}
if(player.pos.y < PLAYER_LIMIT_Y) player.pos.y = PLAYER_LIMIT_Y;
else if(player.pos.y > PLAYER_LIMIT_H) player.pos.y = PLAYER_LIMIT_H;
}
// movement
s16 playerFrame;
static void movePlayer(){
playerFrame = 0;
if(ctrl.left || ctrl.right || ctrl.up || ctrl.down){
if(ctrl.left || ctrl.right){
if(ctrl.up || ctrl.down){
player.vel.x = ctrl.left ? -PLAYER_SPEED_NORM : PLAYER_SPEED_NORM;
player.vel.y = ctrl.up ? -PLAYER_SPEED_NORM : PLAYER_SPEED_NORM;
playerFrame = ctrl.up ? 2 : 1;
} else {
player.vel.x = ctrl.left ? -PLAYER_SPEED : PLAYER_SPEED;
player.vel.y = 0;
@ -74,17 +60,14 @@ static void movePlayer(){
} else if(ctrl.up){
player.vel.x = 0;
player.vel.y = -PLAYER_SPEED;
playerFrame = 2;
} else if(ctrl.down){
player.vel.x = 0;
player.vel.y = PLAYER_SPEED;
playerFrame = 1;
}
if(player.vel.x != 0) player.pos.x = fix16Add(player.pos.x, player.vel.x);
if(player.vel.y != 0) player.pos.y = fix16Add(player.pos.y, player.vel.y);
checkPlayerBounds();
}
SPR_setFrame(player.image, playerFrame);
}
@ -93,13 +76,14 @@ static void movePlayer(){
// shoot
#define PLAYER_BULLET_SPEED FIX16(16)
#define PLAYER_BULLET_ANGLE 0
#define PLAYER_BULLET_ANGLE 768
#define PLAYER_BULLET_OFF FIX16(8)
static void spawnPlayerBullet(){
struct bulletSpawner spawner = {
.x = player.pos.x,
.y = player.pos.y,
.image = &smallWhiteBullet,
.y = fix16Sub(player.pos.y, PLAYER_BULLET_OFF),
.image = &playerBullet,
.speed = PLAYER_BULLET_SPEED,
.angle = PLAYER_BULLET_ANGLE,
.player = TRUE
@ -126,8 +110,11 @@ void updatePlayer(){
movePlayer();
shotPlayer();
SPR_setPosition(player.image,
fix16ToInt(fix16Sub(player.pos.x, PLAYER_OFF)),
fix16ToInt(fix16Sub(player.pos.y, PLAYER_OFF)));
fix16ToInt(fix16Sub(player.pos.x, PLAYER_OFF_X)),
fix16ToInt(fix16Sub(player.pos.y, PLAYER_OFF_Y)));
SPR_setPosition(player.hitboxImage,
fix16ToInt(fix16Sub(player.pos.x, HITBOX_OFF)),
fix16ToInt(fix16Sub(player.pos.y, HITBOX_OFF)));
player.clock++;
if(player.clock >= CLOCK_LIMIT) player.clock -= CLOCK_LIMIT;
}

View File

@ -1,94 +1,379 @@
// stage
#define SPAWN_MID 124
/*
sine from left
sine from right
big middle
sine from left, big right
sine from right, big left
big middle
swarm
big from left and right
swarm, big right
swarm, big left
midboss
big from left and right
big from right and left
big from left, small formation
big from right, small formation
big from left, small formation
big from right, small formation
midboss
final boss at 30 seconds left
*/
#define SPAWN_MID 128
// groups
static void groupOne(s16 off, bool firesAll){
static void waveSine(bool right){
struct enemySpawner spawner = {
.angle = 512,
.speed = FIX16(1),
.x = GAME_W + 20,
.y = SPAWN_MID + off,
.image = &fairy1,
.offX = 20,
.angle = 256,
.speed = FIX16(0.8),
.x = GAME_W / 5 * (right ? 3 : 2),
.y = -16,
.image = right ? &fairyRed : &fairyBlue,
.offX = 16,
.offY = 16
};
spawner.fixes[0] = FIX16(spawner.y);
spawner.fixes[1] = FIX16(8);
spawner.fixes[2] = FIX16(8);
spawner.fixes[3] = FIX16(0.25);
spawner.fixes[0] = FIX16(spawner.x);
spawner.fixes[1] = FIX16(32);
spawner.fixes[2] = FIX16(64);
spawner.fixes[3] = FIX16(0.08);
spawner.bools[0] = right;
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 && enemies[i].bools[0]){
enemies[i].pos.x = fix16Sub(enemies[i].fixes[0], fix16Mul(sinFix16(enemies[i].fixes[1]), enemies[i].fixes[2]));
enemies[i].fixes[1] = enemies[i].bools[0] ? fix16Add(enemies[i].fixes[1], enemies[i].fixes[3]) : fix16Sub(enemies[i].fixes[1], enemies[i].fixes[3]);
}
spawnEnemy(spawner, updater, EMPTY);
}
static void waveBig1(){
struct enemySpawner spawner = {
.angle = 256,
.speed = FIX16(0.6),
.x = GAME_W / 2,
.y = -16,
.image = &fairyGreen,
.offX = 16,
.offY = 16
};
void updater(s16 i){
if(enemies[i].clock == 60){
struct bulletSpawner spawner = {
.x = enemies[i].pos.x,
.y = enemies[i].pos.y,
.image = &bigBullet,
.angle = 128,
.speed = FIX16(1.5),
.big = TRUE
};
for(u8 j = 0; j < 5; j++){
spawnBullet(spawner, EMPTY);
spawner.angle += 64;
}
}
}
spawnEnemy(spawner, updater, EMPTY);
}
static void waveBig2(bool left){
struct enemySpawner spawner = {
.angle = 256,
.speed = FIX16(0.6),
.x = left ? GAME_W / 5 - 16 : GAME_W / 5 * 4 + 16,
.y = -16,
.image = left ? &fairyGreen : &fairyYellow,
.offX = 16,
.offY = 16
};
spawner.bools[0] = left;
void updater(s16 i){
if(enemies[i].clock >= 60 && enemies[i].clock < 180 && enemies[i].clock % 15 == 0){
if(enemies[i].clock == 60){
velPos.x = player.pos.x;
velPos.y = player.pos.y;
}
struct bulletSpawner spawner = {
.x = enemies[i].pos.x,
.y = enemies[i].pos.y,
.speed = FIX16(1.5),
.image = &smallBullet,
.light = enemies[i].clock % 30 == 0,
.top = TRUE
};
spawner.vel = hone(enemies[i].pos, velPos, spawner.speed, 48);
spawnBullet(spawner, EMPTY);
} else if(enemies[i].bools[0] && enemies[i].clock == 61){
struct bulletSpawner spawner = {
.x = enemies[i].pos.x,
.y = enemies[i].pos.y,
.image = &bigBullet,
.angle = 64,
.speed = FIX16(1.25),
.big = TRUE
};
for(u8 j = 0; j < 4; j++){
spawnBullet(spawner, EMPTY);
spawner.angle += 64;
}
}
}
spawnEnemy(spawner, updater, EMPTY);
}
static void waveBig3(){
struct enemySpawner spawner = {
.angle = 256,
.speed = FIX16(0.6),
.x = GAME_W / 2,
.y = -16,
.image = &fairyGreen,
.offX = 16,
.offY = 16
};
void updater(s16 i){
if(enemies[i].clock >= 30 && enemies[i].clock <= 90 && enemies[i].clock % 30 == 0){
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);
if(enemies[i].clock == 60){
spawner.image = &smallBullet;
spawner.angle = 96;
} else {
spawner.image = &bigBullet;
spawner.big = TRUE;
spawner.angle = 128;
}
for(u8 j = 0; j < (enemies[i].clock == 60 ? 6 : 5); j++){
spawnBullet(spawner, EMPTY);
spawner.angle += 64;
}
}
}
spawnEnemy(spawner, updater, EMPTY);
}
static void waveSwarm(bool right, bool color){
struct enemySpawner spawner = {
.angle = 256,
.speed = FIX16(1.25),
.x = random() % (GAME_W / 2 - 64),
.y = -16,
.image = color ? &fairyRed : &fairyBlue,
.offX = 16,
.offY = 16
};
spawner.x += right ? (GAME_W / 2) : 64;
spawnEnemy(spawner, EMPTY, EMPTY);
}
static void waveBig4(bool right, bool second){
struct enemySpawner spawner = {
.angle = 256,
.speed = FIX16(0.6),
.x = right ? (GAME_W / 4 * 3 + 24) : (GAME_W / 4 - 24),
.y = -16,
.image = right ? &fairyYellow : &fairyGreen,
.offX = 16,
.offY = 16
};
spawner.bools[0] = right;
spawner.bools[1] = second;
void updater(s16 i){
if(enemies[i].clock == 40){
struct bulletSpawner spawner = {
.x = enemies[i].pos.x,
.y = enemies[i].pos.y,
.image = &bigBullet,
.big = TRUE,
.speed = FIX16(1.25),
.angle = 32,
.light = enemies[i].bools[0]
};
if(enemies[i].bools[0]) spawner.angle = 512 - spawner.angle;
for(u8 j = 0; j < 5; j++){
spawnBullet(spawner, EMPTY);
spawner.angle += enemies[i].bools[0] ? -64 : 64;
}
} else if(enemies[i].clock >= 60 && enemies[i].clock < 150 && enemies[i].clock % 10 == 0 && enemies[i].bools[1]){
struct bulletSpawner spawner = {
.x = enemies[i].pos.x,
.y = enemies[i].pos.y,
.image = &smallBullet,
.speed = FIX16(2),
.light = !enemies[i].bools[0]
};
if(enemies[i].clock == 60){
velPos = hone(enemies[i].pos, player.pos, spawner.speed, 0);
enemies[i].fixes[0] = velPos.x;
enemies[i].fixes[1] = velPos.y;
}
spawner.vel.x = enemies[i].fixes[0];
spawner.vel.y = enemies[i].fixes[1];
// spawner.vel = velPos;
spawnBullet(spawner, EMPTY);
}
}
for(u8 j = 0; j < 3; j++){
spawner.bools[0] = j == 2 || firesAll;
spawnEnemy(spawner, updater, EMPTY);
spawner.x += 44;
}
spawnEnemy(spawner, updater, EMPTY);
}
// bosses
static void waveMidboss1(){
struct enemySpawner spawner = {
.angle = 256,
.speed = FIX16(1),
.x = GAME_W / 2,
.y = -16,
.image = &fairyGreen,
.offX = 16,
.offY = 16
};
void updater(s16 i){
if(enemies[i].bools[0]){
// ring
if(enemies[i].clock % 90 == 0){
struct bulletSpawner spawner = {
.x = enemies[i].pos.x,
.y = enemies[i].pos.y,
.image = &bigBullet,
.big = TRUE,
.speed = FIX16(1),
.angle = 80 + random() % 32,
.light = TRUE
};
for(u8 j = 3; j < 15; j++){
if(j % 3 < 2) spawnBullet(spawner, EMPTY);
spawner.angle += 32;
}
}
// puke
else if(enemies[i].clock % 20 == 0){
struct bulletSpawner spawner = {
.x = FIX16(enemies[i].clock % 180 < 90 ? 32 : GAME_W - 32),
.y = FIX16(40),
.image = &bigBullet,
.big = TRUE,
.speed = FIX16(1.75)
};
velPos.x = spawner.x;
velPos.y = spawner.y;
spawner.vel = hone(velPos, player.pos, spawner.speed, 32);
spawnBullet(spawner, EMPTY);
}
} else if(!enemies[i].bools[0] && enemies[i].clock > 0 && enemies[i].clock % 30 == 0) {
enemies[i].speed = fix16Sub(enemies[i].speed, FIX16(0.25));
if(enemies[i].speed <= 0){
enemies[i].speed = 0;
enemies[i].bools[0] = TRUE;
enemies[i].clock = -1;
}
updateEnemyVel(i);
}
}
spawnEnemy(spawner, updater, EMPTY);
}
// loop
#define OBS_INTERVAL 15
s16 stageClock,
nextClock,
currentWave;
nextClock;
s16 currentWave = 42;
static void updateWaves(){
if(stageClock == nextClock){
switch(currentWave){
case 0:
for(s16 i = 0; i < 6; i++)
for(s16 j = 0; j < 2; j++) spawnObstacle(j == 0 ? TRUE : FALSE, 256 - i * 32, i == 5 ? 2 : 1);
groupOne(0, FALSE);
nextClock += 180;
break;
case 1:
for(s16 i = 0; i < 6; i++)
spawnObstacle(FALSE, 0 - i * 32, i == 0 ? 0 : (i == 5 ? 2 : 1));
groupOne(-24, FALSE);
nextClock += 180;
break;
case 2:
for(s16 i = 0; i < 6; i++)
spawnObstacle(TRUE, 0 - i * 32, i == 0 ? 0 : (i == 5 ? 2 : 1));
groupOne(24, FALSE);
nextClock += 180;
break;
case 3:
groupOne(0, FALSE);
nextClock += 180;
break;
case 4:
nextFg();
break;
// sine from left
if(currentWave < 6){
waveSine(FALSE);
nextClock += currentWave == 5 ? 90 : 40;
}
// sine from right
else if(currentWave < 12){
waveSine(TRUE);
nextClock += currentWave == 11 ? 90 : 40;
}
// big middle
else if(currentWave == 12){
waveBig1();
nextClock += 120;
}
// sine from left, big right
else if(currentWave < 18){
waveSine(FALSE);
if(currentWave == 14) waveBig2(FALSE);
nextClock += currentWave == 17 ? 90 : 40;
}
// sine from right, big left
else if(currentWave < 24){
waveSine(TRUE);
if(currentWave == 20) waveBig2(TRUE);
nextClock += currentWave == 23 ? 90 : 40;
}
// big middle
else if(currentWave == 24){
waveBig3();
nextClock += 180;
}
// swarm (8)
else if(currentWave < 32){
waveSwarm(currentWave % 2 == 0, currentWave % 4 < 2);
nextClock += 30;
}
// big left and right
else if(currentWave < 34){
waveBig4(currentWave == 32, FALSE);
nextClock += currentWave == 32 ? 60 : 120;
}
// swarm (4), big right
else if(currentWave < 38){
waveSwarm(FALSE, currentWave % 2 < 1);
if(currentWave == 35) waveBig4(TRUE, TRUE);
nextClock += currentWave == 37 ? 60 : 30;
}
// swarm (4), big left
else if(currentWave < 42){
waveSwarm(TRUE, currentWave % 2 < 1);
if(currentWave == 39) waveBig4(FALSE, TRUE);
nextClock += currentWave == 41 ? 60 : 30;
}
else if(currentWave == 42){
waveMidboss1();
}
currentWave++;
}
}
// case 0: groupOne(-32, FALSE); break;
// case 180: groupOne(32, FALSE); break;
// case 360: groupOne(0, TRUE); break;
void updateStage(){
updateWaves();
stageClock++;

View File

@ -9,19 +9,18 @@ struct bulletSpawner {
Vect2D_f16 vel;
s16 angle;
SpriteDefinition* image;
bool big, player;
bool big, player, huge, light, top;
bool bools[COUNT_INT];
s16 ints[COUNT_INT];
fix16 fixes[COUNT_INT];
};
struct bullet {
bool active, player;
bool active, player, dead, big, huge;
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];
@ -35,6 +34,7 @@ struct bullet bullets[BULLET_COUNT];
struct playerStruct {
Vect2D_f16 pos, vel;
Sprite* image;
Sprite* hitboxImage;
s16 clock, invincibleClock, shotClock;
};
struct playerStruct player;