From 127d2ee7a387782eb935c54ad4489b7019fcea78 Mon Sep 17 00:00:00 2001 From: yushijinhun Date: Sun, 22 Dec 2019 20:19:33 +0800 Subject: [PATCH] Full refactor of animation control --- README.md | 14 ++++---- examples/index.html | 4 +-- src/animation.ts | 81 ++++++++++++++++++++++++++++++++++++++++----- src/viewer.ts | 16 +++------ 4 files changed, 86 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 47fbc03..7983547 100644 --- a/README.md +++ b/README.md @@ -42,23 +42,23 @@ Three.js powered Minecraft skin viewer. control.enableZoom = false; control.enablePan = false; - skinViewer.animation = new skinview3d.CompositeAnimation(); - // Add an animation - let walk = skinViewer.animation.add(skinview3d.WalkingAnimation); + let walk = skinViewer.animations.add(skinview3d.WalkingAnimation); // Add another animation - let rotate = skinViewer.animation.add(skinview3d.RotatingAnimation); + let rotate = skinViewer.animations.add(skinview3d.RotatingAnimation); // Remove an animation, stop walking dude walk.remove(); + // Remove the rotating animation, and make the player face forward + rotate.resetAndRemove(); // And run for now! - let run = skinViewer.animation.add(skinview3d.RunningAnimation); + let run = skinViewer.animations.add(skinview3d.RunningAnimation); // Set the speed of an animation run.speed = 3; // Pause single animation - run.speed = 0; + run.paused = true; // Pause all animations! - skinViewer.animationSpeed = 0; + skinViewer.animations.paused = true; ``` diff --git a/examples/index.html b/examples/index.html index c8dbe0b..c0800a9 100644 --- a/examples/index.html +++ b/examples/index.html @@ -36,8 +36,8 @@ // skinViewer.playerObject.skin.slim = true; let control = new skinview3d.createOrbitControls(skinViewer); - skinViewer.animation = skinview3d.WalkingAnimation; - skinViewer.animationSpeed = 1.5; + skinViewer.animations.add(skinview3d.WalkingAnimation); + skinViewer.animations.speed = 1.5; diff --git a/src/animation.ts b/src/animation.ts index 47c1494..b9863f6 100644 --- a/src/animation.ts +++ b/src/animation.ts @@ -1,4 +1,5 @@ import { PlayerObject } from "./model"; +import * as THREE from "three"; export interface IAnimation { play(player: PlayerObject, time: number): void; @@ -20,26 +21,50 @@ export function invokeAnimation(animation: Animation, player: PlayerObject, time // This interface is used to control animations export interface AnimationHandle { speed: number; + paused: boolean; + progress: number; readonly animation: Animation; reset(): void; - remove(): void; } -class AnimationWrapper implements AnimationHandle, IAnimation { - public speed: number = 1.0; - public readonly animation: Animation; +export interface SubAnimationHandle extends AnimationHandle { + remove(): void; + resetAndRemove(): void; +} - private lastTime = 0; - private progress = 0; +class AnimationWrapper implements SubAnimationHandle, IAnimation { + speed: number = 1.0; + paused: boolean = false; + progress: number = 0; + readonly animation: Animation; + + private lastTime: number = 0; + private started: boolean = false; + private toResetAndRemove: boolean = false; constructor(animation: Animation) { this.animation = animation; } play(player: PlayerObject, time: number) { - this.progress += (time - this.lastTime) * this.speed; + if (this.toResetAndRemove) { + invokeAnimation(this.animation, player, 0); + this.remove(); + return; + } + + let delta: number; + if (this.started) { + delta = time - this.lastTime; + } else { + delta = 0; + this.started = true; + } this.lastTime = time; + if (!this.paused) { + this.progress += delta * this.speed; + } invokeAnimation(this.animation, player, this.progress); } @@ -50,6 +75,10 @@ class AnimationWrapper implements AnimationHandle, IAnimation { remove() { // stub get's overriden } + + resetAndRemove() { + this.toResetAndRemove = true; + } } export class CompositeAnimation implements IAnimation { @@ -58,7 +87,9 @@ export class CompositeAnimation implements IAnimation { add(animation: Animation): AnimationHandle { const handle = new AnimationWrapper(animation); - handle.remove = () => this.handles.delete(handle); + handle.remove = () => { + this.handles.delete(handle); + }; this.handles.add(handle); return handle; } @@ -68,6 +99,40 @@ export class CompositeAnimation implements IAnimation { } } +export class RootAnimation extends CompositeAnimation implements AnimationHandle { + speed: number = 1.0; + progress: number = 0.0; + readonly clock: THREE.Clock = new THREE.Clock(true); + + get animation() { + return this; + } + + get paused() { + return !this.clock.running; + } + + set paused(value) { + if (value) { + this.clock.stop(); + } else { + this.clock.start(); + } + } + + runAnimationLoop(player: PlayerObject): void { + if (this.handles.size == 0) { + return; + } + this.progress += this.clock.getDelta() * this.speed; + this.play(player, this.progress); + } + + reset() { + this.progress = 0; + } +} + export const WalkingAnimation: Animation = (player, time) => { const skin = player.skin; diff --git a/src/viewer.ts b/src/viewer.ts index d8e02ab..16c78cd 100644 --- a/src/viewer.ts +++ b/src/viewer.ts @@ -1,6 +1,6 @@ import * as THREE from "three"; import { PlayerObject } from "./model"; -import { invokeAnimation } from "./animation"; +import { RootAnimation } from "./animation"; import { loadSkinToCanvas, loadCapeToCanvas, isSlimSkin } from "./utils"; export interface SkinViewerOptions { @@ -16,10 +16,8 @@ export interface SkinViewerOptions { export class SkinViewer { public readonly domElement: Node; - public animation: Animation | null; + public readonly animations: RootAnimation; public detectModel: boolean = true; - public animationSpeed: number = 1; - public animationTime: number = 0; public disposed: boolean = false; public readonly skinImg: HTMLImageElement; @@ -40,11 +38,8 @@ export class SkinViewer { public readonly playerObject: PlayerObject; - private readonly clock: THREE.Clock; - constructor(options: SkinViewerOptions) { this.domElement = options.domElement; - this.animation = options.animation || null; if (options.detectModel === false) { this.detectModel = false; } @@ -116,14 +111,11 @@ export class SkinViewer { if (options.width) this.width = options.width; if (options.height) this.height = options.height; - this.clock = new THREE.Clock(true); + this.animations = new RootAnimation(); const draw = () => { if (this.disposed) return; window.requestAnimationFrame(draw); - this.animationTime += this.clock.getDelta() * this.animationSpeed; - if (this.animation) { - invokeAnimation(this.animation, this.playerObject, this.animationTime); - } + this.animations.runAnimationLoop(this.playerObject); this.renderer.render(this.scene, this.camera); }; draw();