feat(master-vega): add ship assets, jungle world, and species selection flow

- Add human ship spritesheet (ships.png) and increase frame size to 192x192
- Add jungle world background texture (world-jungle-01.png)
- Add human ship animation videos (scout, frigate, destroyer, cruiser,
  battleship, transport, colony)
- Enable species card selection with required choice before starting game
- Disable "Begin" button until a species is selected
- Add title logo breathing animation and light sweep effect on landing screen
- Reposition title and start button on landing layout
This commit is contained in:
Brian Fertig 2026-08-02 14:07:53 -06:00
parent 508feea4c9
commit 6a0e8bfc47
12 changed files with 71 additions and 9 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -34,7 +34,7 @@
"worldBackgrounds": {
"terran": { "key": "vega-world-terran", "path": "assets/images/vega/world-terran-01.png" },
"ocean": { "key": "vega-world-ocean", "path": "assets/images/vega/world-ocean-01.png" },
"jungle": { "key": "vega-world-jungle", "path": null },
"jungle": { "key": "vega-world-jungle", "path": "assets/images/vega/world-jungle-01.png" },
"steppe": { "key": "vega-world-steppe", "path": "assets/images/vega/world-steppe-01.png" },
"arid": { "key": "vega-world-arid", "path": "assets/images/vega/world-arid-01.png" },
"desert": { "key": "vega-world-desert", "path": "assets/images/vega/world-desert-01.png" },
@ -52,10 +52,10 @@
"sheets": {
"ships": {
"key": "vega-ships",
"path": null,
"path": "assets/images/vega/ships.png",
"kind": "ship",
"frameWidth": 96,
"frameHeight": 96,
"frameWidth": 192,
"frameHeight": 192,
"cols": 8,
"rows": 10,
"_layout": "One row per species (species.shipFrame), one column per hull (hull.frame). Frame = shipFrame * 8 + hull.frame. Ships face UP at frame rest."

View File

@ -115,6 +115,55 @@ export default class MasterOfVegaGame extends Phaser.Scene {
return t;
}
// A periodic light sweep over the title logo. A soft white band is masked to
// the title's own alpha (so it only lights the lettering, never the backdrop)
// and travels left → right on a loop. Returns the shine object so the caller
// can stop it if the landing layer is torn down.
paintTitleShine(layer, title) {
if (!this.textures.exists('vega-menu-title')) return null;
const w = title.displayWidth;
const h = title.displayHeight;
if (!w || !h) return null;
const bandW = Math.max(140, Math.round(w * 0.3));
const bandH = Math.ceil(h);
// A horizontal gradient: transparent → bright white → transparent.
if (!this.textures.exists('vega-title-shine')) {
const g = this.make.graphics({ add: false });
const steps = 48;
for (let i = 0; i < steps; i += 1) {
const t = i / (steps - 1);
const a = Math.sin(t * Math.PI);
g.fillStyle(0xffffff, a * 0.5);
g.fillRect(i * (bandW / steps), 0, Math.ceil(bandW / steps) + 1, bandH);
}
g.generateTexture('vega-title-shine', bandW, bandH);
g.destroy();
}
const shine = this.add.image(title.x, title.y, 'vega-title-shine')
.setBlendMode(Phaser.BlendModes.ADD);
shine.setMask(title.createBitmapMask());
layer.add(shine);
// Start fully off the left edge, sweep across, then loop after a pause.
const travel = w + bandW * 2;
const startX = title.x - travel / 2;
const endX = title.x + travel / 2;
shine.x = startX;
this.tweens.add({
targets: shine,
x: endX,
duration: 1500,
ease: 'Sine.easeInOut',
delay: 2200,
repeat: -1,
});
return shine;
}
// --------------------------------------------------------------- landing
showLanding() {
@ -123,8 +172,20 @@ export default class MasterOfVegaGame extends Phaser.Scene {
this.paintBackdrop(layer, 0.34);
// Logo large on the left.
this.paintTitle(layer, 580, 430, 900, 560, 76);
// Logo large on the left, breathing gently.
const title = this.paintTitle(layer, 1400, 300, 900, 560, 76);
this.tweens.add({
targets: title,
scale: title.scaleX * 1.04,
duration: 2800,
ease: 'Sine.easeInOut',
yoyo: true,
repeat: -1,
});
// A light sweep over the logo, masked to the lettering, on a loop.
this.paintTitleShine(layer, title);
// Buttons well below it, over on the right.
const bx = 1420;
@ -327,7 +388,7 @@ export default class MasterOfVegaGame extends Phaser.Scene {
enqueueSpeech(UI_SPEECH.chooseSpecies, null, { force: true });
const choice = {
speciesId: 'human',
speciesId: null,
sizeId: 'medium',
shapeId: 'spiral',
difficultyId: 'normal',
@ -372,13 +433,13 @@ export default class MasterOfVegaGame extends Phaser.Scene {
choice.speciesId = spec.id;
for (const c of cards) c.bg.setStrokeStyle(1.5, 0x24405f, 1);
bg.setStrokeStyle(2.5, 0x6fc4ff, 1);
start.setEnabled(true);
});
}));
card.add(zone);
layer.add(card);
cards.push({ bg, spec });
});
cards[0].bg.setStrokeStyle(2.5, 0x6fc4ff, 1);
// --- option rows
const optY = 600;
@ -418,10 +479,11 @@ export default class MasterOfVegaGame extends Phaser.Scene {
layer.add(b);
});
const start = new Button(this, GAME_WIDTH / 2 + 430, optY + 124, 'Begin', this.uiClick(() => {
const start = new Button(this, GAME_WIDTH / 2, GAME_HEIGHT - 90, 'Begin', this.uiClick(() => {
layer.destroy();
this.beginGame(choice);
}), { width: 260, height: 64, fontSize: 30 });
start.setEnabled(false);
layer.add(start);
// Resuming lives on the landing screen now, so this only steps back to it.