gfx, shit

This commit is contained in:
t. boddy 2026-02-17 15:10:28 -05:00
parent 364a34ce33
commit 0151304d05
8 changed files with 140 additions and 33 deletions

View file

@ -95,7 +95,8 @@ static void updateMap(){
// compute new enemy positions // compute new enemy positions
for(s16 i = 0; i < ENEMY_COUNT; i++){ for(s16 i = 0; i < ENEMY_COUNT; i++){
if(!enemies[i].active || enemies[i].image == NULL){ if(!enemies[i].active || enemies[i].image == NULL
|| enemies[i].pos.y < FIX32(0) || enemies[i].pos.y > GAME_H_F){
mapNewCol[i] = -1; mapNewCol[i] = -1;
mapNewRow[i] = -1; mapNewRow[i] = -1;
continue; continue;
@ -113,7 +114,7 @@ static void updateMap(){
// compute new human positions // compute new human positions
for(s16 i = 0; i < HUMAN_COUNT; i++){ for(s16 i = 0; i < HUMAN_COUNT; i++){
if(!humans[i].active || humans[i].image == NULL){ if(!humans[i].active || humans[i].image == NULL || humans[i].state == HUMAN_COLLECTED){
mapNewHumanCol[i] = -1; mapNewHumanCol[i] = -1;
mapNewHumanRow[i] = -1; mapNewHumanRow[i] = -1;
continue; continue;
@ -185,6 +186,7 @@ void loadChrome(){
} }
bool didGameOver; bool didGameOver;
u32 gameOverClock;
static void doGameOver(){ static void doGameOver(){
didGameOver = TRUE; didGameOver = TRUE;
for(s16 i = 0; i < BULLET_COUNT; i++) if(bullets[i].active) SPR_setPalette(bullets[i].image, PAL1); for(s16 i = 0; i < BULLET_COUNT; i++) if(bullets[i].active) SPR_setPalette(bullets[i].image, PAL1);
@ -203,9 +205,59 @@ static void doGameOver(){
VDP_drawText("PRESS ANY BUTTON", 12, 14); VDP_drawText("PRESS ANY BUTTON", 12, 14);
} }
static void showPause(){
for(s16 i = 0; i < BULLET_COUNT; i++) if(bullets[i].active) SPR_setPalette(bullets[i].image, PAL1);
for(s16 i = 0; i < ENEMY_COUNT; i++) if(enemies[i].active) SPR_setPalette(enemies[i].image, PAL1);
for(s16 i = 0; i < HUMAN_COUNT; i++) if(humans[i].active) SPR_setPalette(humans[i].image, PAL1);
SPR_setPalette(player.image, PAL1);
VDP_drawText("PAUSE", 17, 13);
}
static void clearPause(){
for(s16 i = 0; i < BULLET_COUNT; i++) if(bullets[i].active) SPR_setPalette(bullets[i].image, PAL0);
for(s16 i = 0; i < ENEMY_COUNT; i++) if(enemies[i].active) SPR_setPalette(enemies[i].image, PAL0);
for(s16 i = 0; i < HUMAN_COUNT; i++) if(humans[i].active) SPR_setPalette(humans[i].image, PAL0);
SPR_setPalette(player.image, PAL0);
VDP_clearText(17, 13, 5);
}
u32 pauseClock;
static void updatePause(){
if(gameOver) return;
if(ctrl.start){
if(!isPausing){
isPausing = TRUE;
if(!paused){
pauseClock = 0;
paused = TRUE;
showPause();
} else {
paused = FALSE;
clearPause();
}
}
} else {
isPausing = FALSE;
}
if(paused){
if(pauseClock % 60 < 30)
VDP_drawText("PAUSE", 17, 13);
else
VDP_clearText(17, 13, 5);
pauseClock++;
if(pauseClock >= 240) pauseClock = 0;
}
}
void updateChrome(){ void updateChrome(){
updatePause();
if(gameOver && !didGameOver) doGameOver(); if(gameOver && !didGameOver) doGameOver();
if(didGameOver) return; if(didGameOver){
gameOverClock++;
if((gameOverClock > 120 && (ctrl.a || ctrl.b || ctrl.c || ctrl.start)) || gameOverClock > 900)
SYS_hardReset();
return;
}
if(lastScore != score){ if(lastScore != score){
lastScore = score; lastScore = score;
drawScore(); drawScore();

View file

@ -62,9 +62,16 @@ void spawnEnemy(u8 type, u8 zone){
static void boundsEnemy(u8 i){ static void boundsEnemy(u8 i){
if(enemies[i].ints[3] >= 0){ if(enemies[i].ints[3] >= 0){
s16 h = enemies[i].ints[3];
// if the human was collected by player or gone, kill this enemy
if(!humans[h].active || humans[h].state == HUMAN_COLLECTED){
enemies[i].ints[3] = -1;
humanBeingCarried = FALSE;
killEnemy(i);
return;
}
// carrying: only check for reaching the top // carrying: only check for reaching the top
if(enemies[i].pos.y <= FIX32(0)){ else if(enemies[i].pos.y <= FIX32(0)){
s16 h = enemies[i].ints[3];
if(humans[h].active) killHuman(h); if(humans[h].active) killHuman(h);
enemies[i].ints[3] = -1; enemies[i].ints[3] = -1;
humanBeingCarried = FALSE; humanBeingCarried = FALSE;
@ -90,19 +97,20 @@ static void updateEnemy(u8 i){
enemies[i].pos.x += enemies[i].vel.x; enemies[i].pos.x += enemies[i].vel.x;
enemies[i].pos.y += enemies[i].vel.y; enemies[i].pos.y += enemies[i].vel.y;
boundsEnemy(i);
if(!enemies[i].active) return;
fix32 dx = getWrappedDelta(enemies[i].pos.x, player.pos.x);
enemies[i].onScreen = (dx >= -CULL_LIMIT && dx <= CULL_LIMIT);
switch(enemies[i].type){ switch(enemies[i].type){
case 0: case 0:
updateEnemyOne(i); updateEnemyOne(i);
break; break;
} }
boundsEnemy(i);
if(!enemies[i].active) return;
s16 sx = getScreenX(enemies[i].pos.x, player.camera); s16 sx = getScreenX(enemies[i].pos.x, player.camera);
s16 sy = fix32ToInt(enemies[i].pos.y); s16 sy = fix32ToInt(enemies[i].pos.y);
fix32 dx = getWrappedDelta(enemies[i].pos.x, player.pos.x);
enemies[i].onScreen = (dx >= -CULL_LIMIT && dx <= CULL_LIMIT);
SPR_setVisibility(enemies[i].image, enemies[i].onScreen ? VISIBLE : HIDDEN); SPR_setVisibility(enemies[i].image, enemies[i].onScreen ? VISIBLE : HIDDEN);
SPR_setPosition(enemies[i].image, sx - enemies[i].off, sy - enemies[i].off); SPR_setPosition(enemies[i].image, sx - enemies[i].off, sy - enemies[i].off);

View file

@ -70,13 +70,13 @@ void updateEnemyOne(u8 i){
} }
// normal shooting // normal shooting
if(enemies[i].clock % 60 == enemies[i].ints[0] && enemies[i].onScreen){ if(enemies[i].clock % 20 == enemies[i].ints[0] && enemies[i].onScreen){
enemies[i].clock % 120 == enemies[i].ints[0] ? sfxEnemyShotB() : sfxEnemyShotA(); enemies[i].clock % 40 == enemies[i].ints[0] ? sfxEnemyShotB() : sfxEnemyShotA();
struct bulletSpawner spawner = { struct bulletSpawner spawner = {
.x = enemies[i].pos.x, .x = enemies[i].pos.x,
.y = enemies[i].pos.y, .y = enemies[i].pos.y,
.anim = 3 + (random() % 3), .anim = 3 + (random() % 3),
.speed = FIX32(2) + FIX16(random() % 4), .speed = FIX32(4) + FIX32(random() % 4),
.angle = random() % 128, .angle = random() % 128,
}; };
switch(random() % 3){ switch(random() % 3){

View file

@ -23,7 +23,9 @@ u32 score;
char debugStr[8]; char debugStr[8];
void EMPTY(s16 i){(void)i;} void EMPTY(s16 i){(void)i;}
bool started;
bool gameOver; bool gameOver;
bool paused, isPausing;
s16 enemyCount, bulletCount; s16 enemyCount, bulletCount;
// controls // controls
@ -98,16 +100,19 @@ struct enemy enemies[ENEMY_COUNT];
#define HUMAN_WALKING 0 #define HUMAN_WALKING 0
#define HUMAN_CARRIED 1 #define HUMAN_CARRIED 1
#define HUMAN_FALLING 2 #define HUMAN_FALLING 2
#define HUMAN_COLLECTED 3
struct human { struct human {
bool active; bool active;
u8 state; u8 state;
s16 carriedBy; s16 carriedBy;
s16 trailIndex;
Vect2D_f32 pos, vel; Vect2D_f32 pos, vel;
Sprite* image; Sprite* image;
}; };
struct human humans[HUMAN_COUNT]; struct human humans[HUMAN_COUNT];
bool humanBeingCarried; bool humanBeingCarried;
s16 collectedCount;
void killHuman(u8 i){ void killHuman(u8 i){
if(humans[i].state == HUMAN_CARRIED && humans[i].carriedBy >= 0){ if(humans[i].state == HUMAN_CARRIED && humans[i].carriedBy >= 0){
@ -152,7 +157,7 @@ void killEnemy(u8 i){
humans[h].state = HUMAN_FALLING; humans[h].state = HUMAN_FALLING;
humans[h].carriedBy = -1; humans[h].carriedBy = -1;
humans[h].vel.x = 0; humans[h].vel.x = 0;
humans[h].vel.y = FIX32(2); humans[h].vel.y = FIX32(3);
} }
humanBeingCarried = FALSE; humanBeingCarried = FALSE;
} }

View file

@ -1,3 +1,5 @@
#define HUMAN_OFF 16
void spawnHuman(u8 zone){ void spawnHuman(u8 zone){
s16 i = -1; s16 i = -1;
@ -16,8 +18,8 @@ void spawnHuman(u8 zone){
humans[i].vel.x = (random() % 2 == 0) ? speeds[random() % 3] : -speeds[random() % 3]; humans[i].vel.x = (random() % 2 == 0) ? speeds[random() % 3] : -speeds[random() % 3];
humans[i].vel.y = (random() % 2 == 0) ? FIX32(0.1) : FIX32(-0.1); humans[i].vel.y = (random() % 2 == 0) ? FIX32(0.1) : FIX32(-0.1);
humans[i].image = SPR_addSprite(&humanSprite, humans[i].image = SPR_addSprite(&koaSprite,
getScreenX(humans[i].pos.x, player.camera), fix32ToInt(humans[i].pos.y), getScreenX(humans[i].pos.x, player.camera) - HUMAN_OFF, fix32ToInt(humans[i].pos.y) - HUMAN_OFF,
TILE_ATTR(PAL0, 0, 0, 0)); TILE_ATTR(PAL0, 0, 0, 0));
if(!humans[i].image){ if(!humans[i].image){
humans[i].active = FALSE; humans[i].active = FALSE;
@ -52,7 +54,7 @@ static void updateHuman(u8 i){
humans[i].state = HUMAN_FALLING; humans[i].state = HUMAN_FALLING;
humans[i].carriedBy = -1; humans[i].carriedBy = -1;
humans[i].vel.x = 0; humans[i].vel.x = 0;
humans[i].vel.y = FIX32(2); humans[i].vel.y = FIX32(3);
humanBeingCarried = FALSE; humanBeingCarried = FALSE;
} }
break; break;
@ -68,16 +70,46 @@ static void updateHuman(u8 i){
humans[i].vel.y = (random() % 2 == 0) ? FIX32(0.1) : FIX32(-0.1); humans[i].vel.y = (random() % 2 == 0) ? FIX32(0.1) : FIX32(-0.1);
} }
break; break;
case HUMAN_COLLECTED: {
fix32 targetX, targetY;
if(humans[i].trailIndex == 0){
targetX = player.pos.x;
targetY = player.pos.y + FIX32(24);
} else {
// find the human ahead in the chain
targetX = player.pos.x;
targetY = player.pos.y + FIX32(24);
for(s16 j = 0; j < HUMAN_COUNT; j++){
if(humans[j].active && humans[j].state == HUMAN_COLLECTED
&& humans[j].trailIndex == humans[i].trailIndex - 1){
targetX = humans[j].pos.x;
targetY = humans[j].pos.y + FIX32(8);
break;
}
}
}
fix32 deltaX = getWrappedDelta(targetX, humans[i].pos.x);
humans[i].pos.x += deltaX >> 2;
humans[i].pos.y += (targetY - humans[i].pos.y) >> 2;
// X wrap
if(humans[i].pos.x >= GAME_WRAP)
humans[i].pos.x -= GAME_WRAP;
if(humans[i].pos.x < 0)
humans[i].pos.x += GAME_WRAP;
break;
}
} }
// collect: check overlap with player (walking or falling only) // collect: check overlap with player (walking or falling only)
fix32 dx = getWrappedDelta(humans[i].pos.x, player.pos.x); fix32 dx = getWrappedDelta(humans[i].pos.x, player.pos.x);
if(humans[i].state != HUMAN_CARRIED){ if(humans[i].state != HUMAN_CARRIED && humans[i].state != HUMAN_COLLECTED){
fix32 dy = humans[i].pos.y - player.pos.y; fix32 dy = humans[i].pos.y - player.pos.y;
if(dx >= FIX32(-24) && dx <= FIX32(24) && dy >= FIX32(-24) && dy <= FIX32(24)){ if(dx >= FIX32(-24) && dx <= FIX32(24) && dy >= FIX32(-24) && dy <= FIX32(24)){
score += (humans[i].state == HUMAN_FALLING) ? 2000 : 1000; score += (humans[i].state == HUMAN_FALLING) ? 2000 : 1000;
sfxPickup(); sfxPickup();
killHuman(i); humans[i].state = HUMAN_COLLECTED;
humans[i].trailIndex = collectedCount++;
return; return;
} }
} }
@ -86,7 +118,7 @@ static void updateHuman(u8 i){
s16 sy = fix32ToInt(humans[i].pos.y); s16 sy = fix32ToInt(humans[i].pos.y);
bool visible = (dx >= -CULL_LIMIT && dx <= CULL_LIMIT); bool visible = (dx >= -CULL_LIMIT && dx <= CULL_LIMIT);
SPR_setVisibility(humans[i].image, visible ? VISIBLE : HIDDEN); SPR_setVisibility(humans[i].image, visible ? VISIBLE : HIDDEN);
SPR_setPosition(humans[i].image, sx, sy); SPR_setPosition(humans[i].image, sx - HUMAN_OFF, sy - HUMAN_OFF);
} }
void updateHumans(){ void updateHumans(){

View file

@ -28,28 +28,31 @@ void loadGame(){
loadPlayer(); loadPlayer();
loadChrome(); loadChrome();
loadStage(); loadStage();
started = TRUE;
} }
static void updateGame(){ static void updateGame(){
updateChrome(); updateChrome();
updatePlayer();
updateSfx(); updateSfx();
if(clock % 2 == 0){ if(!paused){
updateEnemies(); updatePlayer();
if(!gameOver && enemyCount == 0) gameOver = TRUE; if(clock % 2 == 0){
updateHumans(); updateEnemies();
} else { if(!gameOver && enemyCount == 0) gameOver = TRUE;
updateBackground(); updateHumans();
updateBullets(); } else {
updateBackground();
updateBullets();
}
} }
} }
int main(bool hardReset){ int main(bool hardReset){
loadInternals(); loadInternals();
loadGame(); loadStart();
// loadStart();
while(1){ while(1){
updateGame(); if(started) updateGame();
else updateStart();
clock++; clock++;
if(clock >= CLOCK_LIMIT) clock = 600; if(clock >= CLOCK_LIMIT) clock = 600;
SPR_update(); SPR_update();

View file

@ -1,6 +1,6 @@
#define PLAYER_SPEED FIX32(4) #define PLAYER_SPEED FIX32(5)
#define PLAYER_SPEED_FOCUS FIX32(2.5) #define PLAYER_SPEED_FOCUS FIX32(3)
#define PLAYER_ACCEL PLAYER_SPEED >> 3 #define PLAYER_ACCEL PLAYER_SPEED >> 3
#define PLAYER_ACCEL_FOCUS PLAYER_SPEED_FOCUS >> 3 #define PLAYER_ACCEL_FOCUS PLAYER_SPEED_FOCUS >> 3

View file

@ -5,3 +5,10 @@ void loadStart(){
VDP_drawText("press any button", 12, 16); VDP_drawText("press any button", 12, 16);
VDP_drawText(" 2026 T.BODDY ", 12, 18); VDP_drawText(" 2026 T.BODDY ", 12, 18);
} }
void updateStart(){
if(ctrl.a || ctrl.b || ctrl.c || ctrl.start){
VDP_clearTileMapRect(BG_A, 0, 0, 40, 28);
loadGame();
}
}