feat: add timed pose transitions to host portrait reactions
Introduce temporary emotional reactions for the host portrait that hold for a duration before reverting to a resting pose. The setPose method now accepts an optional holdMs parameter; when provided, the pose is applied temporarily and transitions back to the base (danger-driven) pose once the timer elapses. This prevents the host from remaining in a reaction pose indefinitely after events like scoring or opponent clears.
This commit is contained in:
parent
ecfdf4c59b
commit
962466a0a3
|
|
@ -20,6 +20,7 @@ const BOARD_LEFT = 744;
|
|||
const BOARD_TOP = 116;
|
||||
|
||||
const STEP_MS = 1000 / 60; // logic tick rate
|
||||
const POSE_HOLD_MS = 5000; // how long a reaction pose holds before resting
|
||||
|
||||
export const D = { bg: -10, boardBg: 0, panels: 5, incoming: 4, cursor: 12, fx: 16, hud: 24, portrait: 20, overlay: 60, overlayUI: 62 };
|
||||
|
||||
|
|
@ -288,8 +289,8 @@ export default class TetrisAttackGame extends Phaser.Scene {
|
|||
fontFamily: FONT, fontSize: '34px', color, stroke: '#101018', strokeThickness: 6,
|
||||
}).setOrigin(0.5).setDepth(D.fx);
|
||||
this.tweens.add({ targets: t, y: t.y - 70, alpha: 0, duration: 900, ease: 'Cubic.easeOut', onComplete: () => t.destroy() });
|
||||
// host reacts: player doing well → worried
|
||||
this.hostPortrait?.setPose('worried');
|
||||
// host reacts: player doing well → worried for a beat, then back to rest
|
||||
this.hostPortrait?.setPose('worried', POSE_HOLD_MS);
|
||||
}
|
||||
// floating score
|
||||
if (n && e.score) {
|
||||
|
|
@ -419,7 +420,7 @@ export default class TetrisAttackGame extends Phaser.Scene {
|
|||
stroke: '#3a2a00', strokeThickness: 9, lineSpacing: 10,
|
||||
}).setOrigin(0.5).setDepth(D.fx);
|
||||
this.tweens.add({ targets: banner, scale: { from: 0.4, to: 1 }, duration: 340, ease: 'Back.easeOut' });
|
||||
this.hostPortrait?.setPose('worried');
|
||||
this.hostPortrait?.setPose('worried', POSE_HOLD_MS);
|
||||
|
||||
this.time.delayedCall(1400, () => {
|
||||
this.tweens.add({
|
||||
|
|
|
|||
|
|
@ -288,19 +288,37 @@ export function createHostPortrait(scene, x, y, round, index = scene.roundIndex)
|
|||
const frameBg = scene.add.rectangle(x, y, 300, 380, 0x0e1526, 0.5).setStrokeStyle(5, 0x4a6ea8).setDepth(20);
|
||||
const img = buildPortraitImage(scene, round, index, 'neutral', x, y, 1.0);
|
||||
img.setDepth(21);
|
||||
|
||||
const apply = (pose) => {
|
||||
if (scene.textures.exists('tetrisattack-characters')) {
|
||||
img.setFrame(index * 3 + (POSE_OFFSET[pose] ?? 0));
|
||||
} else {
|
||||
// opponents fallback has no poses — pulse instead
|
||||
const tint = pose === 'happy' ? 0xffd0d0 : pose === 'worried' ? 0xd0ffe0 : 0xffffff;
|
||||
img.setTint(tint);
|
||||
scene.tweens.add({ targets: img, scale: img.scaleX * 1.06, duration: 120, yoyo: true });
|
||||
}
|
||||
};
|
||||
|
||||
// basePose is the pose the host rests in (driven by the danger flag); a held
|
||||
// pose is a momentary reaction that reverts to it once holdMs elapses.
|
||||
let basePose = 'neutral';
|
||||
let holdTimer = null;
|
||||
const clearHold = () => { if (holdTimer) { holdTimer.remove(false); holdTimer = null; } };
|
||||
|
||||
return {
|
||||
sprite: img,
|
||||
setPose(pose) {
|
||||
if (scene.textures.exists('tetrisattack-characters')) {
|
||||
img.setFrame(index * 3 + (POSE_OFFSET[pose] ?? 0));
|
||||
setPose(pose, holdMs = 0) {
|
||||
clearHold();
|
||||
if (holdMs > 0) {
|
||||
apply(pose);
|
||||
holdTimer = scene.time.delayedCall(holdMs, () => { holdTimer = null; apply(basePose); });
|
||||
} else {
|
||||
// opponents fallback has no poses — pulse instead
|
||||
const tint = pose === 'happy' ? 0xffd0d0 : pose === 'worried' ? 0xd0ffe0 : 0xffffff;
|
||||
img.setTint(tint);
|
||||
scene.tweens.add({ targets: img, scale: img.scaleX * 1.06, duration: 120, yoyo: true });
|
||||
basePose = pose;
|
||||
apply(pose);
|
||||
}
|
||||
},
|
||||
destroy() { frameBg.destroy(); img.destroy(); },
|
||||
destroy() { clearHold(); frameBg.destroy(); img.destroy(); },
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue