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": {
|
"worldBackgrounds": {
|
||||||
"terran": { "key": "vega-world-terran", "path": "assets/images/vega/world-terran-01.png" },
|
"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" },
|
"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" },
|
"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" },
|
"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" },
|
"desert": { "key": "vega-world-desert", "path": "assets/images/vega/world-desert-01.png" },
|
||||||
|
|
@ -52,10 +52,10 @@
|
||||||
"sheets": {
|
"sheets": {
|
||||||
"ships": {
|
"ships": {
|
||||||
"key": "vega-ships",
|
"key": "vega-ships",
|
||||||
"path": null,
|
"path": "assets/images/vega/ships.png",
|
||||||
"kind": "ship",
|
"kind": "ship",
|
||||||
"frameWidth": 96,
|
"frameWidth": 192,
|
||||||
"frameHeight": 96,
|
"frameHeight": 192,
|
||||||
"cols": 8,
|
"cols": 8,
|
||||||
"rows": 10,
|
"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."
|
"_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;
|
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
|
// --------------------------------------------------------------- landing
|
||||||
|
|
||||||
showLanding() {
|
showLanding() {
|
||||||
|
|
@ -123,8 +172,20 @@ export default class MasterOfVegaGame extends Phaser.Scene {
|
||||||
|
|
||||||
this.paintBackdrop(layer, 0.34);
|
this.paintBackdrop(layer, 0.34);
|
||||||
|
|
||||||
// Logo large on the left.
|
// Logo large on the left, breathing gently.
|
||||||
this.paintTitle(layer, 580, 430, 900, 560, 76);
|
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.
|
// Buttons well below it, over on the right.
|
||||||
const bx = 1420;
|
const bx = 1420;
|
||||||
|
|
@ -327,7 +388,7 @@ export default class MasterOfVegaGame extends Phaser.Scene {
|
||||||
enqueueSpeech(UI_SPEECH.chooseSpecies, null, { force: true });
|
enqueueSpeech(UI_SPEECH.chooseSpecies, null, { force: true });
|
||||||
|
|
||||||
const choice = {
|
const choice = {
|
||||||
speciesId: 'human',
|
speciesId: null,
|
||||||
sizeId: 'medium',
|
sizeId: 'medium',
|
||||||
shapeId: 'spiral',
|
shapeId: 'spiral',
|
||||||
difficultyId: 'normal',
|
difficultyId: 'normal',
|
||||||
|
|
@ -372,13 +433,13 @@ export default class MasterOfVegaGame extends Phaser.Scene {
|
||||||
choice.speciesId = spec.id;
|
choice.speciesId = spec.id;
|
||||||
for (const c of cards) c.bg.setStrokeStyle(1.5, 0x24405f, 1);
|
for (const c of cards) c.bg.setStrokeStyle(1.5, 0x24405f, 1);
|
||||||
bg.setStrokeStyle(2.5, 0x6fc4ff, 1);
|
bg.setStrokeStyle(2.5, 0x6fc4ff, 1);
|
||||||
|
start.setEnabled(true);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
card.add(zone);
|
card.add(zone);
|
||||||
layer.add(card);
|
layer.add(card);
|
||||||
cards.push({ bg, spec });
|
cards.push({ bg, spec });
|
||||||
});
|
});
|
||||||
cards[0].bg.setStrokeStyle(2.5, 0x6fc4ff, 1);
|
|
||||||
|
|
||||||
// --- option rows
|
// --- option rows
|
||||||
const optY = 600;
|
const optY = 600;
|
||||||
|
|
@ -418,10 +479,11 @@ export default class MasterOfVegaGame extends Phaser.Scene {
|
||||||
layer.add(b);
|
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();
|
layer.destroy();
|
||||||
this.beginGame(choice);
|
this.beginGame(choice);
|
||||||
}), { width: 260, height: 64, fontSize: 30 });
|
}), { width: 260, height: 64, fontSize: 30 });
|
||||||
|
start.setEnabled(false);
|
||||||
layer.add(start);
|
layer.add(start);
|
||||||
|
|
||||||
// Resuming lives on the landing screen now, so this only steps back to it.
|
// Resuming lives on the landing screen now, so this only steps back to it.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue