@@ 293,7 293,7 @@ int Ball_Disruption() {
float spawnX = firstBall.x;
float spawnY = firstBall.y;
float spawnAngle = firstBall.getAngle();
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < 5; i++) {
float newAngle = spawnAngle + Random_Range(-45, 45);
balls.add(Ball(ballTextures[ballMode - POWER_BALL]->texture, spawnX, spawnY, newAngle));
}
@@ 41,6 41,10 @@ typedef enum {
STATE_GAME_PLAY,
STATE_GAME_PAUSE,
STATE_GAME_LOSS,
+ STATE_GAME_CENTERSHIP,
+ STATE_GAME_FLYUP,
+ STATE_GAME_FLYDOWN,
+ STATE_GAME_FLYOUT,
STATE_GAME_OVER,
} GAME_STATE;
@@ 52,7 56,8 @@ static float frames = 0;
int score = 0;
-#define START_LIVES (3)
+// extra lives, not total lives (you can have 0 lives)
+#define START_LIVES (4)
static int lives = START_LIVES;
#define NUM_POWERUPS (P_BARRIER)
@@ 113,7 118,6 @@ float shipLeft;
float shipRight;
int shipState;
-float shipSpeed;
//ship's y pos during normal gameplay
#define SHIP_POS (220)
@@ 122,11 126,24 @@ float shipSpeed;
#define SHIP_TIMING (6)
static float shipFrames;
//where ship starts a new life
-#define SHIP_STARTX (((RIGHT_WALL - LEFT_WALL) / 2) - (SHIP_WIDTH / 2))
+#define SHIP_STARTX (LEFT_WALL + ((RIGHT_WALL - LEFT_WALL) / 2) - (SHIP_WIDTH / 2))
#define SHIP_STARTY (WINDOW_LOHEIGHT)
+
+// where ship flies to at the end of each level batch
+#define SHIP_FLY1 (150)
+#define SHIP_FLY2 (120)
+#define SHIP_FLY3 (180)
+#define SHIP_FLY4 (200)
+
#define SHIP_SPRITESHEET_FIRST (512)
#define SHIP_SPRITESHEET_LAST (992)
+#define COLLAPSE_TIMING (9)
+#define SHIP_COLLAPSE_FIRST (0)
+#define SHIP_COLLAPSE_LAST (480)
+
+static float shipSpeed;
+
SpriteInfo barrelSprite;
#define BARREL_SIZE (8)
// number of barrel frames
@@ 134,6 151,17 @@ SpriteInfo barrelSprite;
#define BARREL_XOFFSET (24)
#define BARREL_YOFFSET (8)
+static SpriteInfo flameSprite;
+static int flameFrame;
+#define FLAME_SIZE (48)
+#define FLAME_XOFFSET (-8)
+#define FLAME_YOFFSET (24)
+#define FLAME_SMALL_START (0)
+#define FLAME_SMALL_END (144)
+#define FLAME_LARGE_START (144)
+#define FLAME_LARGE_END (336)
+
+
// reset powerup state
void Game_PowerUpReset() {
// reset powerup meter
@@ 153,6 181,12 @@ void Game_PowerUpReset() {
barrierLife = 0;
}
+void Game_StateReset() {
+ score = 0;
+ lives = START_LIVES;
+ Game_PowerUpReset();
+}
+
void Game_Init(int level, int numLevels) {
Fade_Start(0xFF, 0x00, 30);
Global_SetLoRes();
@@ 166,16 200,15 @@ void Game_Init(int level, int numLevels) {
bitSprite = SpriteInfo("bit.png");
bitSprite.source.h = BIT_HEIGHT;
+ flameSprite = SpriteInfo("shipflame.png");
+ flameSprite.source.h = FLAME_SIZE;
+
Sound_StopMusic();
Sound_PlayVGM("12 Stage 1.vgz");
Hud_Init();
Hud_ChipSet(STATE_CHIP_NONE);
frames = 0;
- //init lives
- lives = START_LIVES;
- //init score
- score = 0;
//init the ship sprite
shipSprite.source.y = SHIP_SPRITESHEET_FIRST;
shipSprite.x = SHIP_STARTX;
@@ 194,8 227,6 @@ void Game_Init(int level, int numLevels) {
Enemy_Init();
//add first ball
Ball_Add(0, 0, 45);
- //init powerup state
- Game_PowerUpReset();
gameLevelNum = level;
gameLevelMax = level + numLevels;
@@ 204,6 235,8 @@ void Game_Init(int level, int numLevels) {
state = STATE_GAME_FADEIN;
}
+
+// ship flies in from bottom of the screen and transforms into a paddle
static void Game_ShipAnim() {
// ship animation stuff (keeping it stateless helps simplify things)
// move ship when it spawns
@@ 220,7 253,7 @@ static void Game_ShipAnim() {
// if we're still doing the ship transformation animation
if (shipSprite.source.y < SHIP_SPRITESHEET_LAST) {
- shipSprite.source.y += 32;
+ shipSprite.source.y += SHIP_HEIGHT;
}
// otherwise, animate the barrels
@@ 234,6 267,17 @@ static void Game_ShipAnim() {
}
}
+static void Game_ShipCollapseAnim() {
+ shipFrames += Speed_Multiplier();
+ if (shipFrames >= COLLAPSE_TIMING) {
+ shipFrames = 0;
+
+ if (shipSprite.source.y < SHIP_COLLAPSE_LAST) {
+ shipSprite.source.y += SHIP_HEIGHT;
+ }
+ }
+}
+
static void Game_BitAnim() {
bitFrames += Speed_Multiplier();
if (bitFrames >= BIT_TIMING) {
@@ 245,6 289,26 @@ static void Game_BitAnim() {
}
}
+static void Game_FlameRun(int start, int end) {
+ static uint32_t frameCnt = 0;
+
+ frameCnt++;
+ if (frameCnt & 1) {
+ flameFrame += FLAME_SIZE;
+ if (flameFrame >= end) {
+ flameFrame = start + FLAME_SIZE;
+ }
+ flameSprite.source.y = flameFrame;
+ }
+ else {
+ flameSprite.source.y = start;
+ }
+
+ flameSprite.x = shipSprite.x + FLAME_XOFFSET;
+ flameSprite.y = shipSprite.y + FLAME_YOFFSET;
+ flameSprite.draw();
+}
+
void Game_IncPowerUp() {
// sound_play(SOUND_CAPSULE);
powerupCursor++;
@@ 383,9 447,9 @@ int Game_Run() {
Enemy_RemoveAll();
gameLevelNum++;
- // TODO show the "ship flying off the screen" animation instead of just returning
+ // show the "ship flying off the screen" animation
if (gameLevelNum >= gameLevelMax) {
- return 1;
+ state = STATE_GAME_CENTERSHIP;
}
// load new level
@@ 436,6 500,69 @@ int Game_Run() {
}
break;
+ case STATE_GAME_CENTERSHIP:
+ if (shipSprite.x < SHIP_STARTX) {
+ shipSprite.x += 3;
+ if (shipSprite.x > SHIP_STARTX) {
+ shipSprite.x = SHIP_STARTX;
+ }
+ }
+ if (shipSprite.x > SHIP_STARTX) {
+ shipSprite.x -= 3;
+ if (shipSprite.x < SHIP_STARTX) {
+ shipSprite.x = SHIP_STARTX;
+ }
+ }
+
+ if (shipSprite.x == SHIP_STARTX) {
+ state = STATE_GAME_FLYUP;
+ }
+
+ break;
+
+ case STATE_GAME_FLYUP:
+ if (shipSprite.y > SHIP_FLY1) {
+ shipSprite.y--;
+ // get the ship ready for animation
+ if (shipSprite.y > SHIP_FLY2) {
+ shipSprite.source.y = SHIP_COLLAPSE_FIRST;
+ }
+ }
+ else if (shipSprite.y > SHIP_FLY2) {
+ shipSprite.y -= 0.5;
+ Game_ShipCollapseAnim();
+ }
+ else {
+ state = STATE_GAME_FLYDOWN;
+ }
+ break;
+
+ case STATE_GAME_FLYDOWN:
+ if (shipSprite.y < SHIP_FLY3) {
+ shipSprite.y += 0.5;
+ }
+ else if (shipSprite.y < SHIP_FLY4) {
+ shipSprite.y += 0.25;
+ Game_FlameRun(FLAME_SMALL_START, FLAME_SMALL_END);
+ }
+ else {
+ shipSpeed = 0;
+ Game_FlameRun(FLAME_SMALL_START, FLAME_SMALL_END);
+ state = STATE_GAME_FLYOUT;
+ }
+ Game_ShipCollapseAnim();
+ break;
+
+ case STATE_GAME_FLYOUT:
+ shipSpeed += 0.2;
+ shipSprite.y -= shipSpeed;
+
+ if (shipSprite.y < -128) {
+ return 1;
+ }
+ Game_FlameRun(FLAME_LARGE_START, FLAME_LARGE_END);
+ break;
+
case STATE_GAME_OVER:
frames += Speed_Multiplier();
if (frames >= 360) {
@@ 71,6 71,10 @@ extern std::unique_ptr<Level> gameLevel;
// current level number
extern int gameLevelNum;
+// resets the player's score, lives, and power-ups. should be run when
+// starting a new game
+void Game_StateReset();
+
// inits a game running a set of levels
void Game_Init(int level, int numLevels);
@@ 26,7 26,7 @@
#include "chip.h"
#include "fade.h"
#include "font.h"
#include "game.h"
#include "globals.h"
#include "menu.h"
#include "menu_text.h"
@@ 149,6 149,7 @@ void Menu_StartGame() {
timer = 0;
state = STATE_MENU_ANIMOUT;
Chip_AnimOut();
Game_StateReset();
}
}