skinview3d/src/animation.ts

150 lines
3.8 KiB
TypeScript
Raw Normal View History

2018-07-17 20:49:00 +02:00
import { PlayerObject } from "./model"
2018-01-06 15:01:12 +01:00
function invokeAnimation(animation, player, time) {
if (animation instanceof CompositeAnimation) {
animation.play(player, time);
} else if (animation instanceof Function) {
animation(player, time);
} else {
throw `Not an animation: ${animation}`;
}
}
2018-07-17 20:49:00 +02:00
interface IAnimation {
play(player: PlayerObject, time: number): void;
}
class AnimationHandle implements IAnimation {
animation: Animation;
paused = false;
speed: number = 1.0;
private _paused = false;
private _lastChange: number = null;
private _speed: number = 1.0;
private _lastChangeX: number = null;
2018-01-06 15:01:12 +01:00
constructor(animation) {
2018-07-17 20:49:00 +02:00
2018-01-06 15:01:12 +01:00
}
2018-07-17 20:49:00 +02:00
2018-01-06 15:01:12 +01:00
play(player, time) {
if (this._lastChange === null) {
this._lastChange = time;
this._lastChangeX = 0;
} else if (this.paused !== this._paused || this.speed !== this._speed) {
let dt = time - this._lastChange;
if (this._paused === false) {
this._lastChangeX += dt * this._speed;
}
this._paused = this.paused;
this._speed = this.speed;
this._lastChange = time;
}
if (this.paused === false) {
let dt = time - this._lastChange;
let x = this._lastChangeX + this.speed * dt;
2018-01-06 15:01:12 +01:00
invokeAnimation(this.animation, player, x);
}
}
2018-07-17 20:49:00 +02:00
reset() {
2018-01-06 15:01:12 +01:00
this._lastChange = null;
}
2018-07-17 20:49:00 +02:00
remove(animHandle: AnimationHandle) {
// stub get's overriden
}
2018-01-06 15:01:12 +01:00
}
class CompositeAnimation {
2018-07-17 20:49:00 +02:00
handle: AnimationHandle;
handles: Set<AnimationHandle>;
2018-01-06 15:01:12 +01:00
constructor() {
this.handles = new Set();
}
add(animation) {
2018-07-17 20:49:00 +02:00
this.handle = new AnimationHandle(animation);
this.handle
this.handle.remove = () => this.handles.delete(this.handle);
this.handles.add(this.handle);
return this.handle;
2018-01-06 15:01:12 +01:00
}
play(player, time) {
this.handles.forEach(handle => handle.play(player, time));
}
}
let WalkingAnimation = (player, time) => {
2017-10-01 14:00:45 +02:00
let skin = player.skin;
// Multiply by animation's natural speed
time *= 8;
// Leg swing
2018-07-17 20:49:00 +02:00
skin.leftLeg.rotation.x = Math.sin(time) * 0.5;
skin.rightLeg.rotation.x = Math.sin(time + Math.PI) * 0.5;
2017-10-01 14:00:45 +02:00
// Arm swing
2018-07-17 20:49:00 +02:00
skin.leftArm.rotation.x = Math.sin(time + Math.PI) * 0.5;
skin.rightArm.rotation.x = Math.sin(time) * 0.5;
2018-07-17 20:49:00 +02:00
let basicArmRotationZ = Math.PI * 0.02;
skin.leftArm.rotation.z = Math.cos(time) * 0.03 + basicArmRotationZ;
skin.rightArm.rotation.z = Math.cos(time + Math.PI) * 0.03 - basicArmRotationZ;
// Head shaking with different frequency & amplitude
skin.head.rotation.y = Math.sin(time / 4) * 0.2;
skin.head.rotation.x = Math.sin(time / 5) * 0.1;
// Always add an angle for cape around the x axis
let basicCapeRotationX = Math.PI * 0.06;
player.cape.rotation.x = Math.sin(time / 1.5) * 0.06 + basicCapeRotationX;
};
let RunningAnimation = (player, time) => {
let skin = player.skin;
time *= 15;
// Leg swing with larger amplitude
2018-07-17 20:49:00 +02:00
skin.leftLeg.rotation.x = Math.cos(time + Math.PI) * 1.3;
skin.rightLeg.rotation.x = Math.cos(time) * 1.3;
// Arm swing
2018-07-17 20:49:00 +02:00
skin.leftArm.rotation.x = Math.cos(time) * 1.5;
skin.rightArm.rotation.x = Math.cos(time + Math.PI) * 1.5;
2018-07-17 20:49:00 +02:00
let basicArmRotationZ = Math.PI * 0.1;
skin.leftArm.rotation.z = Math.cos(time) * 0.1 + basicArmRotationZ;
skin.rightArm.rotation.z = Math.cos(time + Math.PI) * 0.1 - basicArmRotationZ;
// Jumping
player.position.y = Math.cos(time * 2);
// Dodging when running
player.position.x = Math.cos(time) * 0.15;
// Slightly tilting when running
player.rotation.z = Math.cos(time + Math.PI) * 0.01;
// Apply higher swing frequency, lower amplitude,
// and greater basic rotation around x axis,
// to cape when running.
let basicCapeRotationX = Math.PI * 0.3;
player.cape.rotation.x = Math.sin(time * 2) * 0.1 + basicCapeRotationX;
// What about head shaking?
// You shouldn't glance right and left when running dude :P
};
let RotatingAnimation = (player, time) => {
player.rotation.y = time;
2017-10-01 14:00:45 +02:00
};
export {
CompositeAnimation,
invokeAnimation,
WalkingAnimation,
RunningAnimation,
RotatingAnimation
};