590 lines
22 KiB
JavaScript
590 lines
22 KiB
JavaScript
import { playMusic, stopMusic } from '../../audio.js';
|
|
|
|
const PLATFORMS = [
|
|
{ y: 820, xMin: 50, xMax: 1550 }, // 0 = floor
|
|
{ y: 660, xMin: 50, xMax: 1550 }, // 1
|
|
{ y: 495, xMin: 50, xMax: 1550 }, // 2
|
|
{ y: 330, xMin: 50, xMax: 1550 }, // 3
|
|
{ y: 165, xMin: 50, xMax: 1550 }, // 4 = Kong platform (WIN)
|
|
];
|
|
|
|
// Ladders: bottom connects lower platform, top connects upper platform
|
|
// Zone: player can grab if within ±20px horizontally of center
|
|
const LADDERS = [
|
|
{ x: 1150, fromPlatform: 0, yBottom: 820, yTop: 660 }, // Floor → P1
|
|
{ x: 380, fromPlatform: 1, yBottom: 660, yTop: 495 }, // P1 → P2
|
|
{ x: 1050, fromPlatform: 2, yBottom: 495, yTop: 330 }, // P2 → P3
|
|
{ x: 680, fromPlatform: 3, yBottom: 330, yTop: 165 }, // P3 → Kong (WIN lane)
|
|
];
|
|
|
|
const PLATFORM_H = 15;
|
|
const PLAYER_W = 28;
|
|
const PLAYER_H = 40;
|
|
const BARREL_R = 14;
|
|
const LADDER_W = 36;
|
|
const LADDER_GRAB_RANGE = 28;
|
|
|
|
// Initial direction for barrels per platform index
|
|
const BARREL_DIR = [1, -1, 1, -1, 1]; // index = platformIndex
|
|
|
|
export default class BurliKong extends Phaser.Scene {
|
|
constructor() {
|
|
super({ key: 'BurliKong' });
|
|
}
|
|
|
|
preload() {
|
|
this.load.json('bkConfig', 'src/games/burli-kong/config.json');
|
|
this.load.spritesheet('burliSprite', 'assets/images/burli-sprite.png', { frameWidth: 135, frameHeight: 135 });
|
|
this.load.audio('bkMusic', 'assets/music/06-burli-kong.mp3');
|
|
this.load.audio('bkComplete', 'assets/fx/complete.mp3');
|
|
this.load.audio('bkJump', 'assets/fx/launch.mp3');
|
|
this.load.audio('bkStomp', 'assets/fx/destroy.mp3');
|
|
this.load.audio('bkHit', 'assets/fx/short_death.mp3');
|
|
this.load.audio('bkBarrel', 'assets/fx/fireball.mp3');
|
|
}
|
|
|
|
init(data) {
|
|
this.lives = data.lives ?? 3;
|
|
this.level = String(data.level ?? 1);
|
|
}
|
|
|
|
create() {
|
|
const all = this.cache.json.get('bkConfig');
|
|
this.cfg = all.levels[this.level] ?? all.levels['1'];
|
|
|
|
this.gameActive = true;
|
|
this.barrelsCleared = 0;
|
|
this.spawnTimer = 0;
|
|
this.barrels = [];
|
|
this.kongArmRaise = 0;
|
|
|
|
// Idle animation state
|
|
this.kongIdleTimer = 0;
|
|
this.kongIdleInterval = 3.5;
|
|
this.kongIsIdling = false;
|
|
this.kongIdleSeq = 0; // incremented to invalidate stale delayed callbacks
|
|
|
|
this.player = {
|
|
x: 200,
|
|
y: PLATFORMS[0].y - PLAYER_H,
|
|
vx: 0,
|
|
vy: 0,
|
|
state: 'ground', // 'ground' | 'jumping' | 'ladder'
|
|
platformIndex: 0,
|
|
facingDir: 1,
|
|
ladderIndex: -1,
|
|
jumpedOverBarrels: new Set(),
|
|
};
|
|
|
|
// Background drawn once at depth 0
|
|
const bgGfx = this.add.graphics().setDepth(0);
|
|
this._drawBackground(bgGfx);
|
|
|
|
// Kong sprite at depth 1, bottom-anchored to platform surface
|
|
this.kongSprite = this.add.sprite(95, PLATFORMS[4].y - PLATFORM_H, 'burliSprite', 0)
|
|
.setOrigin(0.5, 1)
|
|
.setDepth(1);
|
|
|
|
// Sprite 5: static, 20px to the right of Kong
|
|
this.add.image(250, PLATFORMS[4].y - PLATFORM_H, 'burliSprite', 5)
|
|
.setOrigin(0.5, 1)
|
|
.setDepth(1);
|
|
|
|
// Game elements (platforms, ladders, barrels, player) at depth 2
|
|
this.mainGfx = this.add.graphics().setDepth(2);
|
|
|
|
this.cursors = this.input.keyboard.createCursorKeys();
|
|
this.keyA = this.input.keyboard.addKey('A');
|
|
this.keyAPressed = false;
|
|
|
|
this._buildHUD();
|
|
playMusic(this, 'bkMusic');
|
|
}
|
|
|
|
update(time, delta) {
|
|
if (!this.gameActive) return;
|
|
const dt = delta / 1000;
|
|
|
|
this._handleInput(dt);
|
|
this._spawnBarrels(dt);
|
|
this._updateBarrels(dt);
|
|
this._checkCollisions();
|
|
this._updateKongSprite(dt);
|
|
this._draw();
|
|
this._updateHUD();
|
|
}
|
|
|
|
// ─── Input ────────────────────────────────────────────────────────────────
|
|
|
|
_handleInput(dt) {
|
|
const p = this.player;
|
|
const cfg = this.cfg;
|
|
|
|
// Jump (A key, edge-triggered, ground only)
|
|
if (this.keyA.isDown && !this.keyAPressed) {
|
|
this.keyAPressed = true;
|
|
if (p.state === 'ground') {
|
|
p.state = 'jumping';
|
|
p.vy = -cfg.jumpVelocity;
|
|
this._playFx('bkJump', 0.5);
|
|
}
|
|
}
|
|
if (!this.keyA.isDown) this.keyAPressed = false;
|
|
|
|
if (p.state === 'ground') {
|
|
p.vx = 0;
|
|
if (this.cursors.left.isDown) { p.vx = -cfg.playerSpeed; p.facingDir = -1; }
|
|
if (this.cursors.right.isDown) { p.vx = cfg.playerSpeed; p.facingDir = 1; }
|
|
|
|
p.x += p.vx * dt;
|
|
p.x = Phaser.Math.Clamp(p.x, PLATFORMS[p.platformIndex].xMin + PLAYER_W / 2,
|
|
PLATFORMS[p.platformIndex].xMax - PLAYER_W / 2);
|
|
|
|
// Snap y to current platform surface
|
|
p.y = PLATFORMS[p.platformIndex].y - PLAYER_H;
|
|
|
|
// Start climbing: up arrow near ladder bottom on current platform
|
|
if (this.cursors.up.isDown) {
|
|
const li = this._nearLadderBottom(p);
|
|
if (li >= 0) {
|
|
p.state = 'ladder';
|
|
p.ladderIndex = li;
|
|
p.x = LADDERS[li].x;
|
|
p.vx = 0;
|
|
}
|
|
}
|
|
} else if (p.state === 'jumping') {
|
|
p.vy += cfg.gravity * dt;
|
|
p.x += p.vx * dt;
|
|
p.y += p.vy * dt;
|
|
p.x = Phaser.Math.Clamp(p.x, 55, 1545);
|
|
|
|
// Land on current platform (only if moving downward and crossing platform top)
|
|
const plat = PLATFORMS[p.platformIndex];
|
|
const platTop = plat.y - PLATFORM_H;
|
|
if (p.vy > 0 && p.y + PLAYER_H >= platTop) {
|
|
p.y = plat.y - PLAYER_H;
|
|
p.vy = 0;
|
|
p.state = 'ground';
|
|
}
|
|
} else if (p.state === 'ladder') {
|
|
const ladder = LADDERS[p.ladderIndex];
|
|
|
|
if (this.cursors.up.isDown) {
|
|
p.y -= cfg.climbSpeed * dt;
|
|
} else if (this.cursors.down.isDown) {
|
|
p.y += cfg.climbSpeed * dt;
|
|
}
|
|
|
|
// Dismount at top: reached upper platform
|
|
if (p.y <= ladder.yTop - PLAYER_H) {
|
|
const newPlatformIndex = ladder.fromPlatform + 1;
|
|
p.y = PLATFORMS[newPlatformIndex].y - PLAYER_H;
|
|
p.platformIndex = newPlatformIndex;
|
|
p.state = 'ground';
|
|
p.ladderIndex = -1;
|
|
|
|
// Win: reached Kong platform
|
|
if (p.platformIndex === 4) {
|
|
this._endGame(true, 'MADE IT!');
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Dismount at bottom: dropped below ladder bottom
|
|
if (p.y + PLAYER_H >= ladder.yBottom) {
|
|
p.y = PLATFORMS[ladder.fromPlatform].y - PLAYER_H;
|
|
p.platformIndex = ladder.fromPlatform;
|
|
p.state = 'ground';
|
|
p.ladderIndex = -1;
|
|
}
|
|
|
|
// Dismount sideways: left/right while on ladder (onto current platform level)
|
|
if (this.cursors.left.isDown || this.cursors.right.isDown) {
|
|
// Find which platform the player's midpoint is closest to
|
|
const midY = p.y + PLAYER_H / 2;
|
|
let bestPlat = ladder.fromPlatform;
|
|
let bestDist = Infinity;
|
|
for (let i = ladder.fromPlatform; i <= ladder.fromPlatform + 1; i++) {
|
|
const d = Math.abs(PLATFORMS[i].y - PLATFORM_H / 2 - midY);
|
|
if (d < bestDist) { bestDist = d; bestPlat = i; }
|
|
}
|
|
p.platformIndex = bestPlat;
|
|
p.y = PLATFORMS[bestPlat].y - PLAYER_H;
|
|
p.state = 'ground';
|
|
p.facingDir = this.cursors.left.isDown ? -1 : 1;
|
|
p.ladderIndex = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
_nearLadderBottom(p) {
|
|
for (let i = 0; i < LADDERS.length; i++) {
|
|
const l = LADDERS[i];
|
|
if (l.fromPlatform !== p.platformIndex) continue;
|
|
if (Math.abs(p.x - l.x) <= LADDER_GRAB_RANGE) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// ─── Spawn ────────────────────────────────────────────────────────────────
|
|
|
|
_spawnBarrels(dt) {
|
|
this.spawnTimer += dt;
|
|
if (this.spawnTimer < this.cfg.barrelSpawnInterval) return;
|
|
if (this.barrels.filter(b => b.alive).length >= this.cfg.maxBarrels) return;
|
|
this.spawnTimer = 0;
|
|
|
|
this.barrels.push({
|
|
x: 200,
|
|
y: PLATFORMS[4].y - BARREL_R - PLATFORM_H,
|
|
platformIndex: 4,
|
|
dir: BARREL_DIR[4],
|
|
falling: false,
|
|
vy: 0,
|
|
alive: true,
|
|
cleared: false,
|
|
ladderRollsDone: new Set(),
|
|
});
|
|
|
|
this.kongArmRaise = 0.6;
|
|
this._playFx('bkBarrel', 0.5);
|
|
}
|
|
|
|
// ─── Barrel update ────────────────────────────────────────────────────────
|
|
|
|
_updateBarrels(dt) {
|
|
const cfg = this.cfg;
|
|
|
|
for (const b of this.barrels) {
|
|
if (!b.alive) continue;
|
|
|
|
if (b.falling) {
|
|
b.vy += cfg.gravity * dt;
|
|
b.y += b.vy * dt;
|
|
|
|
// Land on next platform down
|
|
const nextIdx = b.platformIndex - 1;
|
|
if (nextIdx < 0) {
|
|
b.alive = false;
|
|
continue;
|
|
}
|
|
const nextPlat = PLATFORMS[nextIdx];
|
|
const landY = nextPlat.y - BARREL_R - PLATFORM_H;
|
|
if (b.y >= landY) {
|
|
b.y = landY;
|
|
b.falling = false;
|
|
b.vy = 0;
|
|
b.platformIndex = nextIdx;
|
|
b.dir = BARREL_DIR[nextIdx];
|
|
b.ladderRollsDone = new Set();
|
|
}
|
|
} else {
|
|
b.x += b.dir * cfg.barrelSpeed * dt;
|
|
|
|
// 50% chance to fall down a ladder when rolling over one
|
|
for (let li = 0; li < LADDERS.length; li++) {
|
|
const l = LADDERS[li];
|
|
if (l.fromPlatform + 1 !== b.platformIndex) continue;
|
|
if (b.ladderRollsDone.has(li)) continue;
|
|
if (Math.abs(b.x - l.x) < 32) {
|
|
b.ladderRollsDone.add(li);
|
|
if (Math.random() < 0.5) {
|
|
b.x = l.x;
|
|
b.falling = true;
|
|
b.vy = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
const plat = PLATFORMS[b.platformIndex];
|
|
// Fall off edge
|
|
if (b.dir > 0 && b.x > plat.xMax - BARREL_R) {
|
|
if (b.platformIndex === 0) {
|
|
b.alive = false; // off the floor
|
|
} else {
|
|
b.falling = true;
|
|
b.vy = 0;
|
|
b.x = plat.xMax - BARREL_R;
|
|
}
|
|
} else if (b.dir < 0 && b.x < plat.xMin + BARREL_R) {
|
|
if (b.platformIndex === 0) {
|
|
b.alive = false;
|
|
} else {
|
|
b.falling = true;
|
|
b.vy = 0;
|
|
b.x = plat.xMin + BARREL_R;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.barrels = this.barrels.filter(b => b.alive);
|
|
if (this.kongArmRaise > 0) this.kongArmRaise -= dt;
|
|
}
|
|
|
|
// ─── Collision ────────────────────────────────────────────────────────────
|
|
|
|
_checkCollisions() {
|
|
if (!this.gameActive) return;
|
|
const p = this.player;
|
|
const pLeft = p.x - PLAYER_W / 2;
|
|
const pRight = p.x + PLAYER_W / 2;
|
|
const pTop = p.y;
|
|
const pBottom = p.y + PLAYER_H;
|
|
const pCenterX = p.x;
|
|
|
|
for (const b of this.barrels) {
|
|
if (!b.alive || b.falling) continue;
|
|
// Only check barrels on same or adjacent platform
|
|
if (Math.abs(b.platformIndex - p.platformIndex) > 0) continue;
|
|
if (b.platformIndex !== p.platformIndex) continue;
|
|
|
|
const dx = pCenterX - b.x;
|
|
const dy = (p.y + PLAYER_H / 2) - b.y;
|
|
const dist = Math.hypot(dx, dy);
|
|
|
|
// Stomp: player falling, feet crossing top of barrel
|
|
if (p.state === 'jumping' && p.vy > 0 &&
|
|
pBottom >= b.y - BARREL_R && pBottom <= b.y + BARREL_R &&
|
|
Math.abs(dx) < BARREL_R + PLAYER_W * 0.5) {
|
|
b.alive = false;
|
|
if (!b.cleared) {
|
|
b.cleared = true;
|
|
this.barrelsCleared++;
|
|
}
|
|
p.vy = -this.cfg.stompBounce;
|
|
this._playFx('bkStomp', 0.7);
|
|
this._checkWin();
|
|
continue;
|
|
}
|
|
|
|
// Jump-over: player jumping, feet above barrel center, laterally overlapping
|
|
if (p.state === 'jumping' && !b.cleared &&
|
|
pBottom < b.y &&
|
|
Math.abs(dx) < BARREL_R + PLAYER_W * 0.6 &&
|
|
!p.jumpedOverBarrels.has(b)) {
|
|
p.jumpedOverBarrels.add(b);
|
|
b.cleared = true;
|
|
this.barrelsCleared++;
|
|
this._checkWin();
|
|
continue;
|
|
}
|
|
|
|
// Side hit: AABB vs circle overlap (not a stomp or jump-over already processed)
|
|
if (dist < BARREL_R + Math.min(PLAYER_W, PLAYER_H) * 0.45) {
|
|
// Don't penalize if player is clearly above (already scored)
|
|
if (p.state === 'jumping' && pBottom < b.y - BARREL_R * 0.5) continue;
|
|
this._endGame(false, "BARREL'D!");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Clean up jump-over tracking for dead/cleared barrels
|
|
for (const b of p.jumpedOverBarrels) {
|
|
if (!b.alive || b.cleared) continue; // keep cleared ones out naturally
|
|
}
|
|
}
|
|
|
|
_checkWin() {
|
|
if (this.barrelsCleared >= this.cfg.barrelsToPass) {
|
|
this._endGame(true, 'CLEARED!');
|
|
}
|
|
}
|
|
|
|
// ─── Drawing ──────────────────────────────────────────────────────────────
|
|
|
|
_draw() {
|
|
const g = this.mainGfx;
|
|
g.clear();
|
|
|
|
this._drawPlatforms(g);
|
|
this._drawLadders(g);
|
|
this._drawBarrels(g);
|
|
this._drawPlayer(g);
|
|
}
|
|
|
|
_drawBackground(g) {
|
|
g.fillStyle(0x00060f);
|
|
g.fillRect(0, 0, 1600, 900);
|
|
g.lineStyle(1, 0x0a1a2a, 0.5);
|
|
for (let x = 0; x < 1600; x += 80) g.lineBetween(x, 0, x, 900);
|
|
for (let y = 0; y < 900; y += 60) g.lineBetween(0, y, 1600, y);
|
|
}
|
|
|
|
// ─── Kong sprite ──────────────────────────────────────────────────────────
|
|
|
|
_updateKongSprite(dt) {
|
|
if (this.kongArmRaise > 0) {
|
|
// Throwing — invalidate any in-flight idle sequence
|
|
this.kongIdleSeq++;
|
|
this.kongIsIdling = false;
|
|
this.kongIdleTimer = 0;
|
|
this.kongSprite.setFrame(1);
|
|
} else {
|
|
if (!this.kongIsIdling) {
|
|
this.kongSprite.setFrame(0);
|
|
this.kongIdleTimer += dt;
|
|
if (this.kongIdleTimer >= this.kongIdleInterval) {
|
|
this._playKongIdleAnimation();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_playKongIdleAnimation() {
|
|
this.kongIsIdling = true;
|
|
this.kongIdleTimer = 0;
|
|
const seq = ++this.kongIdleSeq;
|
|
|
|
this.kongSprite.setFrame(2);
|
|
this.time.delayedCall(450, () => {
|
|
if (!this.gameActive || this.kongIdleSeq !== seq) return;
|
|
this.kongSprite.setFrame(3);
|
|
this.time.delayedCall(450, () => {
|
|
if (!this.gameActive || this.kongIdleSeq !== seq) return;
|
|
this.kongSprite.setFrame(0);
|
|
this.kongIsIdling = false;
|
|
});
|
|
});
|
|
}
|
|
|
|
_drawPlatforms(g) {
|
|
for (const plat of PLATFORMS) {
|
|
const w = plat.xMax - plat.xMin;
|
|
// Platform body
|
|
g.fillStyle(0x2255bb);
|
|
g.fillRect(plat.xMin, plat.y - PLATFORM_H, w, PLATFORM_H);
|
|
// Bright top edge
|
|
g.lineStyle(3, 0x44aaff, 1.0);
|
|
g.lineBetween(plat.xMin, plat.y - PLATFORM_H, plat.xMax, plat.y - PLATFORM_H);
|
|
}
|
|
}
|
|
|
|
_drawLadders(g) {
|
|
for (const l of LADDERS) {
|
|
const lx = l.x - LADDER_W / 2;
|
|
const rx = l.x + LADDER_W / 2;
|
|
g.lineStyle(3, 0xffcc44, 0.9);
|
|
g.lineBetween(lx, l.yBottom - PLATFORM_H, lx, l.yTop);
|
|
g.lineBetween(rx, l.yBottom - PLATFORM_H, rx, l.yTop);
|
|
// Rungs
|
|
g.lineStyle(2, 0xffcc44, 0.7);
|
|
const rungCount = Math.floor((l.yBottom - l.yTop) / 20);
|
|
for (let r = 0; r <= rungCount; r++) {
|
|
const ry = l.yTop + r * ((l.yBottom - PLATFORM_H - l.yTop) / rungCount);
|
|
g.lineBetween(lx, ry, rx, ry);
|
|
}
|
|
}
|
|
}
|
|
|
|
_drawBarrels(g) {
|
|
for (const b of this.barrels) {
|
|
if (!b.alive) continue;
|
|
const r = BARREL_R;
|
|
// Barrel body
|
|
g.fillStyle(0xaa5500);
|
|
g.fillCircle(b.x, b.y, r);
|
|
// Cross-lines
|
|
g.lineStyle(2, 0xffaa44, 0.9);
|
|
g.lineBetween(b.x - r + 3, b.y, b.x + r - 3, b.y);
|
|
g.lineBetween(b.x, b.y - r + 3, b.x, b.y + r - 3);
|
|
// Outline
|
|
g.lineStyle(1.5, 0xff8800, 0.7);
|
|
g.strokeCircle(b.x, b.y, r);
|
|
}
|
|
}
|
|
|
|
_drawPlayer(g) {
|
|
const p = this.player;
|
|
const x = p.x, y = p.y;
|
|
|
|
// Body
|
|
g.fillStyle(0xdd4411);
|
|
g.fillRect(x - PLAYER_W / 2, y, PLAYER_W, PLAYER_H * 0.65);
|
|
|
|
// Head
|
|
g.fillStyle(0xffaa77);
|
|
g.fillCircle(x, y - 2, PLAYER_W * 0.42);
|
|
|
|
// Facing direction indicator (small triangle on chest)
|
|
g.fillStyle(0xffff00);
|
|
const tx = x + p.facingDir * (PLAYER_W * 0.35);
|
|
const ty = y + PLAYER_H * 0.3;
|
|
g.fillTriangle(
|
|
tx, ty,
|
|
tx - p.facingDir * 8, ty - 6,
|
|
tx - p.facingDir * 8, ty + 6
|
|
);
|
|
|
|
// Legs
|
|
g.fillStyle(0x994400);
|
|
g.fillRect(x - PLAYER_W / 2, y + PLAYER_H * 0.65, PLAYER_W * 0.4, PLAYER_H * 0.35);
|
|
g.fillRect(x + PLAYER_W * 0.1, y + PLAYER_H * 0.65, PLAYER_W * 0.4, PLAYER_H * 0.35);
|
|
}
|
|
|
|
// ─── HUD ──────────────────────────────────────────────────────────────────
|
|
|
|
_buildHUD() {
|
|
this.livesText = this.add.text(340, 16, '', {
|
|
fontSize: '26px', fontFamily: 'ArcadeClassic, monospace',
|
|
color: '#ff4444', stroke: '#000000', strokeThickness: 4,
|
|
}).setDepth(10);
|
|
|
|
this.barrelsText = this.add.text(800, 16, '', {
|
|
fontSize: '26px', fontFamily: 'ArcadeClassic, monospace',
|
|
color: '#ffcc44', stroke: '#000000', strokeThickness: 4,
|
|
}).setOrigin(0.5, 0).setDepth(10);
|
|
|
|
this.levelText = this.add.text(1580, 16, `LEVEL ${this.level}`, {
|
|
fontSize: '26px', fontFamily: 'ArcadeClassic, monospace',
|
|
color: '#00ccff', stroke: '#000000', strokeThickness: 4,
|
|
}).setOrigin(1, 0).setDepth(10);
|
|
|
|
this.hintText = this.add.text(800, 875, 'A: Jump ↑↓: Climb Reach the top or clear barrels!', {
|
|
fontSize: '18px', fontFamily: 'ArcadeClassic, monospace',
|
|
color: '#446688', stroke: '#000000', strokeThickness: 3,
|
|
}).setOrigin(0.5, 1).setDepth(10);
|
|
}
|
|
|
|
_updateHUD() {
|
|
this.livesText.setText('♥ '.repeat(this.lives).trim());
|
|
this.barrelsText.setText(`BARRELS ${this.barrelsCleared} / ${this.cfg.barrelsToPass}`);
|
|
}
|
|
|
|
// ─── End game ─────────────────────────────────────────────────────────────
|
|
|
|
_endGame(success, msg) {
|
|
if (!this.gameActive) return;
|
|
this.gameActive = false;
|
|
|
|
if (success) {
|
|
this._playFx('bkComplete', 0.8);
|
|
this.kongSprite.setFrame(4);
|
|
} else {
|
|
this._playFx('bkHit', 0.7);
|
|
}
|
|
|
|
const color = success ? '#00ff44' : '#ff2222';
|
|
this.add.text(800, 440, msg, {
|
|
fontSize: '80px', fontFamily: 'ArcadeClassic, monospace',
|
|
color, stroke: '#000000', strokeThickness: 6,
|
|
}).setOrigin(0.5).setDepth(20);
|
|
|
|
this.time.delayedCall(2200, () => {
|
|
this.game.events.emit('miniGameResult', { success });
|
|
});
|
|
}
|
|
|
|
shutdown() {
|
|
stopMusic(this);
|
|
}
|
|
|
|
_playFx(key, volume = 0.6) {
|
|
const snd = this.sound.add(key, { volume });
|
|
snd.once('complete', () => snd.destroy());
|
|
snd.play();
|
|
}
|
|
}
|