forked from sent/waves
172 lines
5.2 KiB
JavaScript
172 lines
5.2 KiB
JavaScript
/**
|
|
* @file manyfaces.class.js
|
|
* @version 1.0.0
|
|
*/
|
|
|
|
import Entity from '../framework/entity.class.js';
|
|
import ModelManager from '../framework/modelmanager.class.js';
|
|
|
|
import Utility from '../game/utility.class.js';
|
|
|
|
import * as THREE from '../lib/three.js/three.module.js';
|
|
|
|
export default class Manyfaces extends Entity {
|
|
constructor(context, scene, options = Object.create(null)) {
|
|
options.updatePriority = 2;
|
|
|
|
super(context, scene, options);
|
|
|
|
const tScene = scene.getThreeScene();
|
|
|
|
const gltf = ModelManager.getModel('characters');
|
|
|
|
this._bikes = [];
|
|
|
|
const bikeOriginal = gltf.scene.getObjectByName('BikeFlesh');
|
|
bikeOriginal.traverse(obj => {
|
|
obj.matrixAutoUpdate = true;
|
|
obj.material = Utility.replaceMaterial(obj.material);
|
|
});
|
|
|
|
for (let i = 0; i < 12; i++) {
|
|
const bike = bikeOriginal.clone();
|
|
bike.name = `Manyfaces${i}`;
|
|
tScene.add(bike);
|
|
|
|
this._bikes.push({
|
|
mesh: bike,
|
|
roadPosition: new THREE.Vector2(),
|
|
});
|
|
}
|
|
|
|
this._player = scene.findEntityOfType('Player');
|
|
this._road = scene.findEntityOfType('Road');
|
|
|
|
this._sceneName = null;
|
|
this._sceneSeconds = null;
|
|
|
|
this._stopping = null;
|
|
}
|
|
|
|
reset(context) {
|
|
this._sceneName = null;
|
|
|
|
this._stopping = false;
|
|
|
|
this._bikes.forEach(bike => {
|
|
bike.mesh.removeFromParent();
|
|
|
|
bike.stunned = null;
|
|
});
|
|
}
|
|
|
|
update(context) {
|
|
super.update(context);
|
|
|
|
if (this._sceneName === null) {
|
|
return;
|
|
}
|
|
|
|
const dt = context.time.elapsedSeconds;
|
|
|
|
this._sceneSeconds += dt;
|
|
|
|
const distanceMax = this._road.getRoadDistanceMax();
|
|
const playerRoadPosition = this._road.getPlayerRoadPosition();
|
|
const inFront = this._sceneName === 'in_front';
|
|
const driveBy = this._sceneName === 'drive_by';
|
|
|
|
this._bikes.forEach((bike, i) => {
|
|
if (bike.mesh.parent === undefined) {
|
|
return;
|
|
}
|
|
|
|
const pdx = bike.roadPosition.x - playerRoadPosition.x;
|
|
const pdd = this._road.getRoadDistanceBetween(playerRoadPosition.y, bike.roadPosition.y);
|
|
const distanceToPlayer = Math.sqrt(pdx * pdx + pdd * pdd);
|
|
const playerColliding = this._player.getBiking() && distanceToPlayer < 0.65;
|
|
|
|
if (playerColliding && !bike.stunned) {
|
|
this._player.stun(context);
|
|
|
|
bike.stunned = true;
|
|
}
|
|
|
|
const roadType = this._road.getRoadType(bike.roadPosition.y);
|
|
const bikeAngle = this._sceneSeconds * 0.5 + i * 4.5 + Math.PI;
|
|
const targetX = roadType.laneCenter + (inFront ? roadType.laneOffset : Math.sin(bikeAngle) * (roadType.laneOffset - roadType.laneCenter) * 2);
|
|
const velocity = inFront ? Math.max(0, (20 - pdd) * 0.05) : driveBy ? 0.8 : 0.05 + 0.02 * i;
|
|
const steerT = 1 - 0.6 ** dt;
|
|
|
|
const lastX = bike.roadPosition.x;
|
|
|
|
if (!this._stopping) {
|
|
bike.roadPosition.set(
|
|
bike.roadPosition.x * (1 - steerT) + targetX * steerT,
|
|
Math.min(distanceMax, bike.roadPosition.y + dt * velocity));
|
|
}
|
|
|
|
const dx = dt === 0 ? 0 : (bike.roadPosition.x - lastX) / dt;
|
|
|
|
if (driveBy) {
|
|
if (bike.roadPosition.y === distanceMax) {
|
|
this.reset(context);
|
|
}
|
|
} else if (bike.roadPosition.y < this._road.getPlayerRoadPosition().y - 2
|
|
|| bike.roadPosition.y >= distanceMax) {
|
|
if (this._stopping) {
|
|
bike.mesh.removeFromParent();
|
|
} else {
|
|
bike.roadPosition.y = this._road.getPlayerRoadPosition().y + 2 + Math.random() * 4;
|
|
bike.stunned = false;
|
|
}
|
|
}
|
|
|
|
this._road.roadToWorldPosition(bike.roadPosition, bike.mesh.position);
|
|
|
|
bike.mesh.rotation.set(0, 0, 0);
|
|
bike.mesh.rotateY(-this._road.getRoadAngle(bike.roadPosition.y) - dx * 0.3);
|
|
bike.mesh.rotateX(-this._road.getForwardSlopeAngle(bike.mesh));
|
|
});
|
|
}
|
|
|
|
playScene(context, sceneName) {
|
|
this.reset(context);
|
|
|
|
const tScene = this.getScene().getThreeScene();
|
|
const playerRoadPosition = this._road.getPlayerRoadPosition();
|
|
|
|
this._sceneName = sceneName;
|
|
this._sceneSeconds = 0;
|
|
|
|
switch (sceneName) {
|
|
case 'drive_by':
|
|
case 'in_front':
|
|
const bike = this._bikes[0];
|
|
tScene.add(bike.mesh);
|
|
bike.roadPosition.set(0, playerRoadPosition.y + (sceneName === 'drive_by' ? -1 : 1));
|
|
|
|
break;
|
|
|
|
case 'crowding':
|
|
this._bikes.forEach(bike => {
|
|
tScene.add(bike.mesh);
|
|
|
|
bike.roadPosition.set(0, -1);
|
|
bike.stunned = false;
|
|
});
|
|
|
|
break;
|
|
|
|
default:
|
|
throw new Error(`Manyfaces scene "${sceneName}" does not exist`);
|
|
}
|
|
}
|
|
|
|
stop() {
|
|
this._stopping = true;
|
|
}
|
|
}
|
|
|
|
Manyfaces.p_register();
|