#define PLAYER_SPEED FIX32(5) #define PLAYER_SPEED_NORM fix32Mul(PLAYER_SPEED, FIX32(0.707)) #define PLAYER_SPEED_FOCUS FIX32(3) #define PLAYER_SPEED_FOCUS_NORM fix32Mul(PLAYER_SPEED_FOCUS, FIX32(0.707)) #define PLAYER_ACCEL PLAYER_SPEED >> 3 #define PLAYER_ACCEL_FOCUS PLAYER_SPEED_FOCUS >> 3 #define PLAYER_OFF 16 #define PLAYER_BOUND_Y FIX32(PLAYER_OFF) #define PLAYER_BOUND_H FIX32(224 - PLAYER_OFF) #define CAMERA_X FIX32(80) #define CAMERA_W FIX32(240) #define SHOT_INTERVAL 15 s16 shotClock; fix32 screenX; fix32 playerSpeed, playerSpeedNorm; fix32 playerVelX; // Track actual X velocity for momentum static void movePlayer(){ // Y-axis stays instant player.vel.y = 0; // Determine target X speed based on input fix32 targetVelX = 0; if(ctrl.left || ctrl.right || ctrl.up || ctrl.down){ if(ctrl.b){ playerSpeed = PLAYER_SPEED_FOCUS; playerSpeedNorm = PLAYER_SPEED_FOCUS_NORM; } else { playerSpeed = PLAYER_SPEED; playerSpeedNorm = PLAYER_SPEED_NORM; } player.last.x = player.pos.x; if(ctrl.left || ctrl.right){ if(!ctrl.a) player.shotAngle = ctrl.left ? 512 : 0; targetVelX = ctrl.left ? -playerSpeed : playerSpeed; } // Y velocity (instant) if(ctrl.up) player.vel.y = -playerSpeed; else if(ctrl.down) player.vel.y = playerSpeed; } // Apply acceleration toward target X velocity if(playerVelX < targetVelX){ playerVelX += ctrl.b ? PLAYER_ACCEL_FOCUS : PLAYER_ACCEL; if(playerVelX > targetVelX) playerVelX = targetVelX; } else if(playerVelX > targetVelX){ playerVelX -= ctrl.b ? PLAYER_ACCEL_FOCUS : PLAYER_ACCEL; if(playerVelX < targetVelX) playerVelX = targetVelX; } player.vel.x = playerVelX; // Normalize if diagonal if(player.vel.x != 0 && player.vel.y != 0){ player.vel.x = fix32Mul(player.vel.x, FIX32(0.707)); player.vel.y = fix32Mul(player.vel.y, FIX32(0.707)); } // Apply movement (always, for momentum to work during deceleration) player.pos.x += player.vel.x; player.pos.y += player.vel.y; // Update facing direction when moving horizontally if(ctrl.a){ SPR_setHFlip(player.image, player.shotAngle != 0); } else { if(player.vel.x < 0){ SPR_setHFlip(player.image, TRUE); } else if(player.vel.x > 0){ SPR_setHFlip(player.image, FALSE); } } } static void boundsPlayer(){ if(player.pos.y < PLAYER_BOUND_Y) player.pos.y = PLAYER_BOUND_Y; else if(player.pos.y > PLAYER_BOUND_H) player.pos.y = PLAYER_BOUND_H; if(player.pos.x >= GAME_WRAP){ player.pos.x -= GAME_WRAP; player.camera -= GAME_WRAP; } if(player.pos.x <= 0){ player.pos.x += GAME_WRAP; player.camera += GAME_WRAP; } } static void cameraPlayer(){ screenX = player.pos.x - player.camera; if(screenX < CAMERA_X && player.vel.x < 0) player.camera += player.vel.x; else if(screenX > CAMERA_W && player.vel.x > 0) player.camera += player.vel.x; } static void shootPlayer(){ if(ctrl.a && shotClock == 0){ struct bulletSpawner spawner = { .x = player.pos.x, .y = player.pos.y, .anim = 0, .speed = FIX32(12), .angle = player.shotAngle, .player = TRUE }; void updater(u8 i){ if(bullets[i].clock >= 16) killBullet(i); } spawnBullet(spawner, updater); shotClock = SHOT_INTERVAL; } else if(shotClock > 0) shotClock--; } void loadPlayer(){ player.shotAngle = 0; player.camera = 0; player.pos.x = FIX32(128); player.pos.y = FIX32(112); playerVelX = 0; player.lives = 3; player.image = SPR_addSprite(&sakuyaSprite, fix32ToInt(player.pos.x) - PLAYER_OFF, fix32ToInt(player.pos.y) - PLAYER_OFF, TILE_ATTR(PAL0, 0, 0, 0)); } void updatePlayer(){ movePlayer(); boundsPlayer(); cameraPlayer(); shootPlayer(); s16 sx = getScreenX(player.pos.x, player.camera); s16 sy = fix32ToInt(player.pos.y); SPR_setPosition(player.image, sx - PLAYER_OFF, sy - PLAYER_OFF); intToStr(fix32ToInt(player.pos.x), debugStr, 1); }