feedback2 WA: a knocked-out operator facing UP falls and lies with its Front model, the Back model holds still meanwhile (GitHub issue #25)

131 of the 135 Back skeletons have no Die clip, so SpineActor.die() changed nothing and the
attack / skill / idle loop went on under the redeploy ring. UnitView._wantsBack() now wants the
Back model only while the unit stands (or when its Back skeleton has a Die clip of its own);
die() / revive() mark the view and its update swaps the model in place after the frame's events
(a death and a redeploy in one frame load nothing). The Front model replays the fall (held end
for a unit already down), gets the knocked-down grey, and the redeploy brings the Back model back
with the deploy clip carried over. A skeleton without a Die clip holds its idle's first frame.
This commit is contained in:
sganggs committed 2026-10-03 22:58:19 +08:00
1 parent 2a03467897
commit 072e1231ae
3 files changed
+396 -12

No files matched your search

+26 -4
View File
@@ -12,7 +12,8 @@
// clip plays once at its own speed, then base
// setSkill(on) skill begin→loop while active (skill idle replaces idle), end on stop
// deploy() 'Start' once, then base
// die() die clip once (callers fade out afterwards)
// die() die clip once (callers fade out afterwards); a skeleton without one holds its
// idle clip's first frame (GitHub issue #25: the attack loop went on)
// stunned (setBase('stun')) stun clip, or the current track frozen at timeScale 0
// setForm(roles, change, end) another clip set of the skeleton (an enemy's mode), after a change clip
// (no attack cuts the change clip short); `end` = { clip, in, roles? }: a
@@ -341,24 +342,45 @@ export class SpineActor {
if (this.has(d) && d !== this.roles.idle) {
this.mode = 'deploy';
this._play(d, false, { mix: 0 });
this.deployAt = this.clock;
this.deployUntil = this.clock + this.dur(d);
}
}
/** Play the death clip; returns its duration (0 when there is none). */
/** Seconds into the deploy clip while it plays, else null (a model swapped mid-deploy carries it over: units.js). */
deployElapsed() {
return this.mode === 'deploy' ? Math.max(0, this.clock - (this.deployAt || 0)) : null;
}
/** The skeleton's death clip, or null. */
dieClip() {
const d = this.roles.die || (this.has('Die') ? 'Die' : null);
return d && this.has(d) ? d : null;
}
/**
* Play the death clip; returns its duration (0 when there is none). A skeleton without one (131 of the 135 Back
* models, GitHub issue #25; a few idle-only summons and enemies) stops whatever looped — an attack, a skill or the idle —
* and holds the first frame of its idle clip (frozen when it has none either): a dead unit never goes on attacking. A
* knocked-out operator shows its fall with the Front model instead (render/units.js _wantsBack).
*/
die() {
if (this.dead) return 0;
this.dead = true;
this.frozen = false;
this.mode = 'die';
const d = this.roles.die || (this.has('Die') ? 'Die' : null);
if (d && this.has(d)) { this._play(d, false, { mix: 0.05 }); return this.dur(d); }
const d = this.dieClip();
if (d) { this._play(d, false, { mix: 0.05 }); return this.dur(d); }
const idle = this.has(this.roles.idle) ? this.roles.idle : this.has('Idle') ? 'Idle' : null;
if (idle) this._play(idle, false, { mix: 0.1, timeScale: 0 });
else this.frozen = true;
return 0;
}
/** Revive (redeploy after death). */
revive() {
this.dead = false;
this.frozen = false;
this.mode = 'base';
this.skillOn = false;
this._play(this._baseName(), true);