159 lines
4.1 KiB
TypeScript
159 lines
4.1 KiB
TypeScript
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils';
|
|
|
|
import {
|
|
Mesh,
|
|
MeshStandardMaterial,
|
|
Color,
|
|
AnimationAction,
|
|
AnimationMixer,
|
|
Object3D,
|
|
Vector3,
|
|
ShaderMaterial,
|
|
} from 'three';
|
|
import { FullStatePacket, CharacterPacket } from '../../../common/types/packet';
|
|
import { CanvasUtils } from '../canvas-utils';
|
|
import { NameTag } from '../nametag';
|
|
import { PonyModelLoader } from '../resource/pony-loader';
|
|
import { ClientWorld } from '../world/client-world';
|
|
import { PonyEyes } from './eyes';
|
|
|
|
const nameTagBuilder = new CanvasUtils({
|
|
fill: false,
|
|
textBorderColor: '#000',
|
|
foregroundColor: '#fff',
|
|
textShadowBlur: 2,
|
|
textBorderSize: 1,
|
|
});
|
|
|
|
export class PonyEntity {
|
|
public velocity = new Vector3(0, 0, 0);
|
|
public angularVelocity = new Vector3(0, 0, 0);
|
|
public onFloor = true;
|
|
public remote = false;
|
|
public gravity = -50;
|
|
public jumpPower = 16;
|
|
public mixer!: AnimationMixer;
|
|
public container!: Object3D;
|
|
public model!: Object3D;
|
|
public material!: MeshStandardMaterial;
|
|
public walkAnimationState = 0;
|
|
public idleAction: AnimationAction;
|
|
public walkAction: AnimationAction;
|
|
public nameTag?: NameTag;
|
|
public changes: FullStatePacket = {};
|
|
public heightSource?: ClientWorld;
|
|
|
|
initialize() {
|
|
const loader = PonyModelLoader.getInstance();
|
|
this.model = (SkeletonUtils as any).clone(loader.ponyModel);
|
|
this.material = (
|
|
(this.model.children[0].children[1] as Mesh)
|
|
.material as MeshStandardMaterial
|
|
).clone();
|
|
(this.model.children[0].children[1] as Mesh).material = this.material;
|
|
(this.model.children[0].children[2] as Mesh).material =
|
|
PonyEyes.getInstance().getShader();
|
|
this.mixer = new AnimationMixer(this.model);
|
|
this.idleAction = this.mixer.clipAction(loader.animations[0]);
|
|
this.walkAction = this.mixer.clipAction(loader.animations[2]);
|
|
this.idleAction.play();
|
|
this.container = new Object3D();
|
|
this.container.add(this.model);
|
|
}
|
|
|
|
update(dt: number) {
|
|
this.mixer.update(dt);
|
|
|
|
if (this.remote) {
|
|
return;
|
|
}
|
|
|
|
this.velocity.y += this.gravity * dt;
|
|
|
|
this.container.position.add(this.velocity.clone().multiplyScalar(dt));
|
|
this.container.rotation.setFromVector3(
|
|
new Vector3(
|
|
this.container.rotation.x,
|
|
this.container.rotation.y,
|
|
this.container.rotation.z,
|
|
).add(this.angularVelocity.clone().multiplyScalar(dt)),
|
|
);
|
|
|
|
// Put pony on the terrain
|
|
const terrainFloorHeight =
|
|
this.heightSource?.getHeight(
|
|
this.container.position.x,
|
|
this.container.position.z,
|
|
) || 0;
|
|
|
|
if (this.container.position.y <= terrainFloorHeight) {
|
|
this.onFloor = true;
|
|
this.velocity.y = 0;
|
|
this.container.position.y = terrainFloorHeight;
|
|
} else {
|
|
this.onFloor = false;
|
|
}
|
|
}
|
|
|
|
dispose() {
|
|
this.model = null;
|
|
this.material.dispose();
|
|
this.nameTag?.dispose();
|
|
}
|
|
|
|
public addNameTag(name: string) {
|
|
this.nameTag = new NameTag(nameTagBuilder, name);
|
|
this.nameTag.tag.position.set(0, 1.8, 0.5);
|
|
this.container.add(this.nameTag.tag);
|
|
}
|
|
|
|
public setWalkAnimationState(index: number) {
|
|
const previousState = this.walkAnimationState;
|
|
this.walkAnimationState = index;
|
|
if (previousState === this.walkAnimationState) {
|
|
return;
|
|
}
|
|
|
|
this.changes.animState = index;
|
|
|
|
if (index === 1) {
|
|
this.walkAction.reset().crossFadeFrom(this.idleAction, 0.5, false).play();
|
|
} else {
|
|
this.walkAction.crossFadeTo(this.idleAction.reset(), 0.5, false).play();
|
|
}
|
|
}
|
|
|
|
public jump() {
|
|
if (!this.onFloor) {
|
|
return;
|
|
}
|
|
|
|
this.velocity.y = 12;
|
|
}
|
|
|
|
public setColor(color: number | string) {
|
|
this.material.color = new Color(color);
|
|
}
|
|
|
|
public setEyeColor(color: number | string) {
|
|
PonyEyes.getInstance().setColor(
|
|
(this.model.children[0].children[2] as Mesh).material as ShaderMaterial,
|
|
color,
|
|
);
|
|
}
|
|
|
|
public setCharacter(packet: CharacterPacket) {
|
|
if (packet.color) {
|
|
this.setColor(packet.color);
|
|
}
|
|
|
|
if (packet.eyeColor) {
|
|
this.setEyeColor(packet.eyeColor);
|
|
}
|
|
}
|
|
|
|
public setHeightSource(source: ClientWorld) {
|
|
this.heightSource = source;
|
|
}
|
|
}
|