lerp approach
This commit is contained in:
parent
e075590734
commit
c198306717
@ -118,14 +118,18 @@ export class Game {
|
||||
});
|
||||
|
||||
this.socket.on('playerupdate', (data) => {
|
||||
const player = this.players.find((player) => player.user.id === data.id);
|
||||
if (
|
||||
player &&
|
||||
player instanceof PlayerEntity &&
|
||||
player.user.id !== this.me.id
|
||||
) {
|
||||
player.addUncommittedChanges(data);
|
||||
}
|
||||
data.forEach((item) => {
|
||||
const player = this.players.find(
|
||||
(player) => player.user.id === item.id,
|
||||
);
|
||||
if (
|
||||
player &&
|
||||
player instanceof PlayerEntity &&
|
||||
player.user.id !== this.me.id
|
||||
) {
|
||||
player.addUncommittedChanges(item);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.socket.on('chat', (event) => {
|
||||
|
@ -1,16 +1,29 @@
|
||||
import { IcyNetUser } from '../../common/types/user';
|
||||
import * as THREE from 'three';
|
||||
import { PonyEntity } from './pony';
|
||||
import { Packet } from '../../common/types/packet';
|
||||
import {
|
||||
FullStatePacket,
|
||||
PositionUpdatePacket,
|
||||
} from '../../common/types/packet';
|
||||
import { CanvasUtils } from './canvas-utils';
|
||||
import { ChatBubble } from './chat-bubble';
|
||||
|
||||
const chatBuilder = new CanvasUtils();
|
||||
|
||||
export class PlayerEntity extends PonyEntity {
|
||||
private uncommittedPacket: Packet = {};
|
||||
private _updateQueue: PositionUpdatePacket[] = [];
|
||||
private _targetFrame: any = null;
|
||||
private _lastFrame: any = null;
|
||||
private _chats: ChatBubble[] = [];
|
||||
|
||||
private _p1 = new THREE.Vector3();
|
||||
private _p2 = new THREE.Vector3();
|
||||
private _q1 = new THREE.Vector3();
|
||||
private _q2 = new THREE.Vector3();
|
||||
|
||||
private _pf = new THREE.Vector3();
|
||||
private _qf = new THREE.Vector3();
|
||||
|
||||
constructor(public user: IcyNetUser) {
|
||||
super();
|
||||
}
|
||||
@ -84,18 +97,31 @@ export class PlayerEntity extends PonyEntity {
|
||||
);
|
||||
}
|
||||
|
||||
public addUncommittedChanges(packet: Packet) {
|
||||
this.uncommittedPacket = { ...this.uncommittedPacket, ...packet };
|
||||
public addUncommittedChanges(packet: PositionUpdatePacket) {
|
||||
const appendix = { ...packet, time: 0.1 };
|
||||
this._updateQueue.push(appendix);
|
||||
if (!this._targetFrame) {
|
||||
this.setFromPacket(packet);
|
||||
this._targetFrame = appendix;
|
||||
}
|
||||
}
|
||||
|
||||
public update(dt: number) {
|
||||
this.commitServerUpdate();
|
||||
this.commitServerUpdate(dt);
|
||||
super.update(dt);
|
||||
}
|
||||
|
||||
private setFromPacket(packet: Packet) {
|
||||
if (packet.velocity) {
|
||||
this.setVelocity(new THREE.Vector3().fromArray(packet.velocity));
|
||||
private setFromPacket(packet: FullStatePacket | PositionUpdatePacket) {
|
||||
if ((packet as FullStatePacket).velocity) {
|
||||
this.setVelocity(
|
||||
new THREE.Vector3().fromArray((packet as FullStatePacket).velocity),
|
||||
);
|
||||
}
|
||||
|
||||
if ((packet as FullStatePacket).angular) {
|
||||
this.setAngularVelocity(
|
||||
new THREE.Vector3().fromArray((packet as FullStatePacket).angular),
|
||||
);
|
||||
}
|
||||
|
||||
if (packet.position) {
|
||||
@ -106,17 +132,47 @@ export class PlayerEntity extends PonyEntity {
|
||||
this.setRotation(new THREE.Euler().fromArray(packet.rotation));
|
||||
}
|
||||
|
||||
if (packet.angular) {
|
||||
this.setAngularVelocity(new THREE.Vector3().fromArray(packet.angular));
|
||||
}
|
||||
|
||||
if (packet.animState) {
|
||||
this.setWalkAnimationState(packet.animState);
|
||||
}
|
||||
}
|
||||
|
||||
private commitServerUpdate() {
|
||||
this.setFromPacket(this.uncommittedPacket);
|
||||
this.uncommittedPacket = {};
|
||||
private commitServerUpdate(dt: number) {
|
||||
if (this._updateQueue.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._updateQueue.length; ++i) {
|
||||
this._updateQueue[i].time -= dt;
|
||||
}
|
||||
|
||||
while (this._updateQueue.length > 0 && this._updateQueue[0].time <= 0.0) {
|
||||
this._lastFrame = {
|
||||
animState: this._targetFrame.animState,
|
||||
position: this.container.position.toArray(),
|
||||
rotation: this.container.rotation.toArray(),
|
||||
};
|
||||
this._targetFrame = this._updateQueue.shift();
|
||||
this._targetFrame.time = 0.0;
|
||||
}
|
||||
|
||||
// Lerp the position and rotation
|
||||
if (this._targetFrame && this._lastFrame) {
|
||||
this._targetFrame.time += dt;
|
||||
this._p1.fromArray(this._lastFrame.position);
|
||||
this._p2.fromArray(this._targetFrame.position);
|
||||
this._q1.fromArray(this._lastFrame.rotation);
|
||||
this._q2.fromArray(this._targetFrame.rotation);
|
||||
this._pf.copy(this._p1);
|
||||
this._qf.copy(this._q1);
|
||||
|
||||
const t = Math.max(Math.min(this._targetFrame.time / 0.1, 1.0), 0.0);
|
||||
this._pf.lerp(this._p2, t);
|
||||
this._qf.lerp(this._q2, t);
|
||||
|
||||
this.setPosition(this._pf);
|
||||
this.setRotation(this._qf);
|
||||
this.setWalkAnimationState(this._lastFrame.animState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,20 +92,24 @@ export class Player extends PonyEntity {
|
||||
} else if (this._wasTurning && !wasExternalForce) {
|
||||
this._wasTurning = false;
|
||||
this.angularVelocity.set(0, 0, 0);
|
||||
this.changes.rotation = this.container.rotation.toArray();
|
||||
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.position = this.container.position.toArray();
|
||||
this.changes.velocity = this.velocity.toArray();
|
||||
this.setWalkAnimationState(0);
|
||||
}
|
||||
|
||||
this.changes.position = this.container.position.toArray();
|
||||
}
|
||||
|
||||
update(dt: number): void {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils';
|
||||
import * as THREE from 'three';
|
||||
import modelLoaderInstance from './pony-loader';
|
||||
import { Packet } from '../../common/types/packet';
|
||||
import { FullStatePacket } from '../../common/types/packet';
|
||||
import { NameTag } from './nametag';
|
||||
import { CanvasUtils } from './canvas-utils';
|
||||
|
||||
@ -17,7 +17,7 @@ export class PonyEntity {
|
||||
public idleAction: THREE.AnimationAction;
|
||||
public walkAction: THREE.AnimationAction;
|
||||
public nameTag?: NameTag;
|
||||
public changes: Packet = {};
|
||||
public changes: FullStatePacket = {};
|
||||
|
||||
initialize() {
|
||||
this.model = (SkeletonUtils as any).clone(modelLoaderInstance.ponyModel);
|
||||
@ -39,12 +39,6 @@ export class PonyEntity {
|
||||
).add(this.angularVelocity.clone().multiplyScalar(dt)),
|
||||
);
|
||||
this.mixer.update(dt);
|
||||
|
||||
if (this.velocity.length() > 0) {
|
||||
this.setWalkAnimationState(1);
|
||||
} else {
|
||||
this.setWalkAnimationState(0);
|
||||
}
|
||||
}
|
||||
|
||||
public addNameTag(name: string) {
|
||||
|
@ -1,6 +1,14 @@
|
||||
import { IcyNetUser } from './user';
|
||||
|
||||
export interface Packet {
|
||||
export interface PositionUpdatePacket {
|
||||
id?: number;
|
||||
position?: number[];
|
||||
rotation?: (number | string)[];
|
||||
animState?: number;
|
||||
time?: number;
|
||||
}
|
||||
|
||||
export interface FullStatePacket {
|
||||
velocity?: number[];
|
||||
angular?: number[];
|
||||
position?: number[];
|
||||
@ -8,4 +16,4 @@ export interface Packet {
|
||||
animState?: number;
|
||||
}
|
||||
|
||||
export interface CompositePacket extends IcyNetUser, Packet {}
|
||||
export interface CompositePacket extends IcyNetUser, FullStatePacket {}
|
||||
|
@ -1,7 +1,10 @@
|
||||
import { Server, Socket } from 'socket.io';
|
||||
import { config } from '../config';
|
||||
import { RequestHandler } from 'express';
|
||||
import { IcyNetUser } from '../../common/types/user';
|
||||
import {
|
||||
CompositePacket,
|
||||
PositionUpdatePacket,
|
||||
} from '../../common/types/packet';
|
||||
|
||||
const PLACEHOLDER_USER = (socket: Socket): IcyNetUser => {
|
||||
const randomName = `player-${socket.id.substring(0, 8)}`;
|
||||
@ -16,6 +19,7 @@ const PLACEHOLDER_USER = (socket: Socket): IcyNetUser => {
|
||||
|
||||
export class Game {
|
||||
private _connections: Socket[] = [];
|
||||
private _changedPlayers: number[] = [];
|
||||
|
||||
constructor(private io: Server, private session: RequestHandler) {}
|
||||
|
||||
@ -50,9 +54,9 @@ export class Game {
|
||||
socket.data.user = user;
|
||||
socket.data.playerinfo = {
|
||||
velocity: [0, 0, 0],
|
||||
angular: [0, 0, 0],
|
||||
angular: [0, 0, 0, 'XYZ'],
|
||||
position: [0, 0, 0],
|
||||
rotation: [0, 0, 0],
|
||||
rotation: [0, 0, 0, 'XYZ'],
|
||||
animState: 0,
|
||||
};
|
||||
|
||||
@ -71,10 +75,10 @@ export class Game {
|
||||
...socket.data.playerinfo,
|
||||
...packet,
|
||||
};
|
||||
socket.broadcast.emit('playerupdate', {
|
||||
id: user.id,
|
||||
...packet,
|
||||
});
|
||||
|
||||
if (!this._changedPlayers.includes(socket.data.user.id)) {
|
||||
this._changedPlayers.push(socket.data.user.id);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('chat-send', (raw) => {
|
||||
@ -91,5 +95,24 @@ export class Game {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
const playerInfo: PositionUpdatePacket[] = [];
|
||||
this._connections
|
||||
.filter(
|
||||
(conn) =>
|
||||
conn.data.user && this._changedPlayers.includes(conn.data.user.id),
|
||||
)
|
||||
.forEach((conn) =>
|
||||
playerInfo.push({
|
||||
position: conn.data.playerinfo.position,
|
||||
rotation: conn.data.playerinfo.rotation,
|
||||
animState: conn.data.playerinfo.animState,
|
||||
id: conn.data.user.id,
|
||||
}),
|
||||
);
|
||||
this.io.emit('playerupdate', playerInfo);
|
||||
this._changedPlayers.length = 0;
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user