Play animation can blend into the new animation over a number of frames (#106)
game-maker / gate (push) Successful in 1m33s
game-maker / suite (push) Successful in 5m34s

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5 committed 2026-09-17 10:03:53 +02:00
1 parent beeea355d9
commit 04dc254b3d
4 files changed
+177 -14

No files matched your search

+25 -2
View File
@@ -388,6 +388,24 @@ export interface AnimationPlayer {
/** Start order across the whole run: of two players setting one property, the later start wins. */
order: number;
bases?: Record<string, PropertyValue>;
blend?: AnimationBlend;
}
/**
* A crossfade into a player that just took over (#106): over `frames` of its own, a row that blends
* mixes from what the property held into the player's value. `from` is taken on the first tick of the
* blend; a property an earlier player writes in the same tick is mixed from that value instead, live.
*/
export interface AnimationBlend {
frames: number;
elapsed: number;
from?: Record<string, PropertyValue>;
}
/** How far a blend has come, 0…1; an animation without a frame rate has nothing to blend over. */
export function blendShare(blend: AnimationBlend, fps: number): number {
if (!(blend.frames > 0) || !(fps > 0)) return 1;
return Math.min(1, (blend.elapsed * fps) / blend.frames);
}
interface PlayerHolder {
@@ -400,16 +418,21 @@ let startCount = 0;
* Starts the animation on the object, or lets a paused one run on. One already running keeps its
* frame, so a graph may ask for it every frame without holding it at its first frame – but it counts
* as started last again: turning back to a walk that still runs has to show that walk.
* `blendFrames` crossfades into it – but only when it takes over: asked for again while it already
* leads on the object, it keeps the blend it has, so a graph calling every frame does not restart it.
*/
export function playAnimation(holder: PlayerHolder, animationId: string): void {
export function playAnimation(holder: PlayerHolder, animationId: string, blendFrames = 0): void {
const players = (holder.animations ??= []);
const known = players.find((p) => p.animationId === animationId);
const blend = blendFrames > 0 ? { frames: blendFrames, elapsed: 0 } : undefined;
if (known) {
const leads = players.every((p) => p.order <= known.order);
known.playing = true;
known.order = ++startCount;
if (!leads) known.blend = blend;
return;
}
players.push({ animationId, time: 0, playing: true, order: ++startCount });
players.push({ animationId, time: 0, playing: true, order: ++startCount, ...(blend && { blend }) });
}
/** Ends it where it stands – the values stay; `''` ends every animation on the object. */