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:
parent
508feea4c9
commit
6a0e8bfc47
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.
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue