icy3dw/src/client/object/player.ts

142 lines
3.6 KiB
TypeScript

import { IcyNetUser } from '../../common/types/user';
import { Socket } from 'socket.io-client';
import { PonyEntity } from './pony';
import { Scene, Vector2, Vector3 } from 'three';
export class Player extends PonyEntity {
public keydownMap: { [x: string]: boolean } = {};
private _prevKeydownMap: { [x: string]: boolean } = {};
/**
* Normal vector of the currently faced direction
*/
private _lookVector = new Vector3();
/**
* Direction of the current movement.
* X axis controls angular velocity, Y axis controls linear velocity direction by world coordinates.
*/
private _direction = new Vector2();
/**
* Joystick or other external movement usage.
*/
private _externalDirection = new Vector2();
/**
* Was external movement used this tick
*/
private _externalForce = false;
/**
* Was moving last tick
*/
private _wasMoving = false;
/**
* Was turning last tick
*/
private _wasTurning = false;
constructor(public user: IcyNetUser) {
super();
}
public static fromUser(user: IcyNetUser, scene: Scene): Player {
const entity = new Player(user);
entity.initialize();
scene.add(entity.container);
return entity;
}
initialize(): void {
super.initialize();
window.addEventListener('keydown', (e) => {
this.keydownMap[e.key.toLowerCase()] = true;
});
window.addEventListener('keyup', (e) => {
this.keydownMap[e.key.toLowerCase()] = false;
});
}
public createPacket(socket: Socket): void {
if (Object.keys(this.changes).length) {
socket.emit('move', this.changes);
this.changes = {};
}
}
public applyForce(vec: Vector2) {
this._externalDirection.copy(vec);
this._externalForce = true;
}
public moveCharacter(dt: number) {
const vector = new Vector2();
const wasExternalForce = this._externalForce;
this._externalForce = false;
if (wasExternalForce) {
vector.copy(this._externalDirection);
} else {
vector.copy(this._direction);
}
if (vector.x !== 0) {
this.angularVelocity.set(0, Math.PI * vector.x, 0);
this.changes.angular = this.angularVelocity.toArray();
this._wasTurning = true;
} else if (this._wasTurning && !wasExternalForce) {
this._wasTurning = false;
this.angularVelocity.set(0, 0, 0);
this.changes.angular = this.angularVelocity.toArray();
this.changes.rotation = this.container.rotation.toArray();
}
if (vector.y !== 0) {
this.velocity.copy(this._lookVector.clone().multiplyScalar(vector.y));
this.changes.velocity = this.velocity.toArray();
this._wasMoving = true;
this.setWalkAnimationState(1);
} else if (this._wasMoving && !wasExternalForce) {
this._wasMoving = false;
this.velocity.set(0, 0, 0);
this.changes.velocity = this.velocity.toArray();
this.changes.position = this.container.position.toArray();
this.setWalkAnimationState(0);
}
this.changes.rotation = this.container.rotation.toArray();
this.changes.position = this.container.position.toArray();
}
update(dt: number): void {
this.container.getWorldDirection(this._lookVector);
if (this.keydownMap['w']) {
this._direction.y = 1;
} else if (this.keydownMap['s']) {
this._direction.y = -1;
} else {
this._direction.y = 0;
}
if (this.keydownMap['a']) {
this._direction.x = 1;
} else if (this.keydownMap['d']) {
this._direction.x = -1;
} else {
this._direction.x = 0;
}
this.moveCharacter(dt);
super.update(dt);
this._prevKeydownMap = { ...this.keydownMap };
}
}