Files
ResistanceRacing2k97/src/3d/racing/shipManager.js
T
2026-10-23 00:24:27 +02:00

2049 lines
90 KiB
JavaScript

export default class ShipManager {
constructor(_scene, _level, _id, _isPlayer = true, _isAI = false, _modelFile = null) {
this.scene = _scene;
this.level = _level;
this.id = _id;
this.isPlayer = _isPlayer;
this.isAI = _isAI;
this.modelFile = _modelFile;
this.name = "Player";
this.character = null;
//
this.splineId = 0;
this.cameraSplineId = 0;
this.targetSplineId = 0;
this.referenceSplineId = 0;
this.bonusSplineId = 0;
this.temp = 0;
this.autopilot = false;
this.curveAmt = 0;
this.speedFactor = 0;
this.distToPerfectPitch = 0;
this.overSpeed = false;
this.scraping = false;
this.scrapingTime = 0;
this.overTemp = false;
this.position = -1;
this.raceProgress = 0; // = lap * trackleng + spline ID for position calculation
this.ignoreFinish = true;//ignore first finish line crossing and maybe also after the race when autppilot just drives you around
this.crossedFinish = true;
this.progressFinish = false;//add an offset to raceProgress when on the Start Finish Straight but not crossed the line yet
this.ignoreProgress = true;
//flightvars
this.flightRadius = 112;
this.flightRadiusLowerLimit = 32;//-112 + 32;
this.flightRadiusUpperLimit = 112;
this.speed = 0;
this.speedNormalized = 0;
this.speedMax = 16;
this.speedBonus = 0;
this.nearmissBoost = 1.5;
this.nearmissBoostCooldown = 0;
this.slipstreaming = false;
this.slipstreamBoost = 1.1;
this.slipstreamTarget = null;
this.slipstreamLasting = 0;
this.slipsteamTime = 0;
this.jumping = false;
this.jumpingLasting = 0;
this.crashPoints = 0;
this.wobble = {
pos: {
x: 0,
y: 0,
z: 0,
},
dir: {
yaw: 0,
pitch: 0,
roll: 0
}
}
this.acceleration = 0.1;
this.deceleration = -0.05;
this.brakes = -0.2;
this.rollSpeed = 0;
this.rollSpeedMax = 1;
this.rollSpeedMin = -1;
this.rollAcceleration = 0.05;
this.rollDeceleration = 0.2;
this.angleToTrack = 0;
this.angleToTrackMod = 1;
this.targetModel = null;
this.pitch = {
current: 0,
target: 0,
delta: 0,
acceleration: 0.1,
deceleration: 0.05,
min: -1,
max: 1
}
this.last = {
speedBonus: 0,
curveAmt: 0,
input: {
spd: 0,
roll: 0,
pitch: 0
},
keyInput: {
spd: 0,
roll: 0,
pitch: 0
},
fastestLap: 0
}
this.ai = {
prefRoll: 1,
flippedRoll: 0,
lastRollGood: false,
lastGoodPrefRoll: 1,
waitRoll: 0,
curveRec: -9999,
curveSample: 0,
navStates: {
seek: 0,
wait: 1,
dodge: 2,
follow: 3,
cooling: 4
},
navState: 0,
aggression: 0,
}
//camera
this.cameras = {
thirdPersonFollow: 0,
firstPersonCockpit: 1,
firstPersonBumper: 2,
thirdPersonOrbit: 3
}
this.camera = this.cameras.firstPersonCockpit;
this.cameraFovs = [2.5, 3, 3.5, 4.5, 5];
this.cameraFovEscalation = 0;
this.cameraSplineId = 0;
//input
this.input = {
spd: 0,
roll: 0,
rollSpd: 0.1,
pitch: 0,
previous: {
spd: 0,
roll: 0,
pitch: 0
}
}
this.keyInput = {
spd: 0,
roll: 0,
rollSpd: 0.1,
pitch: 0,
previous: {
spd: 0,
roll: 0,
pitch: 0
}
}
this.gondula = this.scene.geometryController.loadModel("hoverShip gondula " + String(this.id), "modDebugTile", { x: 0, y: 0, z: 0 }); //modDebugArrow
//this.gondula.flags.draw = true;
this.shipAnchor = this.scene.geometryController.loadModel("hoverShip anchor " + String(this.id), "modDebugTile", { x: 0, y: 96, z: 0 }); //modDebugArrow
//this.shipAnchor.flags.draw = true;
let models = ["modHoverCarWipeOutStyle", "modHoverCarF1", "modHoverCarTinnemann00", "modHoverCarHapton00"];
if (this.modelFile !== null) {
models = [this.modelFile]
}
this.ship = this.scene.geometryController.loadModel("hoverShip model " + String(this.id), models[Math.floor(Math.random() * models.length)], { x: 0, y: 96, z: 0 });//modHoverCarF1 modHoverCarWipeOutStyle
this.ship.flags.draw = true;
this.ship.depthMod = 48;
this.addCollisionBox();
this.shipAnchor.jumpToPosition({
x: (this.gondula.pos.x + (this.gondula.transform.up.x * -this.flightRadius)),
y: (this.gondula.pos.y + (this.gondula.transform.up.y * -this.flightRadius)),
z: (this.gondula.pos.z + (this.gondula.transform.up.z * -this.flightRadius))
});
//thrusters
this.thrusters = [];
for (let q of this.ship.quadData) {
if (q.frame === "texGlowSquareWhite00") {
this.thrusters.push(q);
}
}
//lensflare
this.lensflares = [];
this.lensflares.push(this.scene.geometryController.loadModel("hovership lensflare " + String(this.id), "modLensflare", { x: 0, y: 0, z: 0 }));
this.lensflares[this.lensflares.length - 1].flags.draw = true;
this.lensflares[this.lensflares.length - 1].setDrawMode(DRAWMODE.BILLBOARD3D);
this.lensflares[this.lensflares.length - 1].depthMod = 64;
this.lensflares[this.lensflares.length - 1].quadData[0].alpha = 0.2;
//trails
this.trails = [];
this.swooshOrigins = [];
this.shipSwooshOrigins = [];
this.trailLength = 10;
for (let q of this.ship.quadData) {
if (q.frame === "sprDebugTexture") {
this.shipSwooshOrigins.push(q);
this.swooshOrigins.push(this.scene.geometryController.loadModel("trail " + String(this.id) + " " + this.swooshOrigins.length, "modDebugTile", { x: 0, y: 0, z: 0 }));
this.swooshOrigins[this.swooshOrigins.length - 1].flags.draw = true;
this.swooshOrigins[this.swooshOrigins.length - 1].depthMod = 128;//todo: this causes issues
this.trails.push([this.swooshOrigins[this.swooshOrigins.length - 1].quadData[0]]);
this.trails[this.trails.length - 1][0].setTexture("atlasAll", "flatPal00White");
this.trails[this.trails.length - 1][0].alpha = 0.8;
//hide debug trail position on ship
this.shipSwooshOrigins[this.shipSwooshOrigins.length - 1].alpha = 0;
}
}
for (let j = 0; j < this.swooshOrigins.length; j++) {//<- number of swoosh Origins on ship (eg both wing tips)
let q = this.trails[j][0];
for (let i = 0; i < this.trailLength; i++) {
this.swooshOrigins[j].addQuadFromData({
type: q.type,
texture: q.texture,
frame: q.frame,
position: {
x: q.pos.x - this.swooshOrigins[j].pos.x,
y: q.pos.y - this.swooshOrigins[j].pos.y,
z: q.pos.z - this.swooshOrigins[j].pos.z,
},
points: [
{
x: q.points[0].x,
y: q.points[0].y,
z: q.points[0].z,
}, {
x: q.points[1].x,
y: q.points[1].y,
z: q.points[1].z,
}, {
x: q.points[2].x,
y: q.points[2].y,
z: q.points[2].z,
}, {
x: q.points[3].x,
y: q.points[3].y,
z: q.points[3].z,
}
]
});
this.trails[j].push(this.swooshOrigins[j].quadData[this.swooshOrigins[j].quadData.length - 1]);
this.swooshOrigins[j].quadData[this.swooshOrigins[j].quadData.length - 1].alpha = 1 - (i / (this.trailLength + 1));
}
}
//init trail history
this.shipTrailHistory = [];
for (let [j, t] of this.trails.entries()) {
this.shipTrailHistory.push([]);
for (let q of t) {
this.shipTrailHistory[j].push(this.ship.getWorldPositionOfQuad(this.shipSwooshOrigins[j]));
}
}
this.trailTicker = 0;
//times
this.startTime = Date.now();
this.elapsedTime = Date.now() - this.startTime;
this.lapTimes = [];
this.fastestLap = 0;
}
setShipColor(_color) {
for (let q of this.ship.quadData) {
if (q.texture === "atlasPlating") {
let frame = q.frame;
// t e x P l a t i n g R e d 0 0
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
let prStr = frame.substr(0, 10);
let nuStr = frame.substr(13, 2);
q.setTexture(q.texture, prStr + _color + nuStr);
}
}
}
setShipModel(_file, _color = "Red") {
this.scene.geometryController.destroyModelById(this.ship.id);
this.ship = this.scene.geometryController.loadModel("hoverShip model " + String(this.id), _file, { x: 0, y: 96, z: 0 });
this.ship.flags.draw = true;
this.ship.depthMod = 48;
this.addCollisionBox();
this.setShipColor(_color);
}
destroy() {
this.scene.geometryController.destroyModelById(this.ship.id);
}
addCollisionBox(_type = 0) {
switch (_type) {
case 0:
this.ship.addQuadFromData({
type: "collisionQuad",
position: {
x: 0, y: 0, z: 0
}, points: [{
x: -24, y: 0 + 0, z: -64
}, {
x: 24, y: 0 + 0, z: -64
}, {
x: 24, y: -32 - 0, z: -64
}, {
x: -24, y: -32 - 0, z: -64
}]
})
break;
default:
break;
}
}
update() {
this.elapsedTime = Date.now() - this.startTime;
//normalize transform
/*
this.gondula.transform.forward = gl_vec3.normalize(this.gondula.transform.forward, this.gondula.transform.forward);
this.gondula.transform.right = gl_vec3.normalize(this.gondula.transform.right, this.gondula.transform.right);
this.gondula.transform.up = gl_vec3.normalize(this.gondula.transform.up, this.gondula.transform.up);
this.shipAnchor.transform.forward = gl_vec3.normalize(this.shipAnchor.transform.forward, this.shipAnchor.transform.forward);
this.shipAnchor.transform.right = gl_vec3.normalize(this.shipAnchor.transform.right, this.shipAnchor.transform.right);
this.shipAnchor.transform.up = gl_vec3.normalize(this.shipAnchor.transform.up, this.shipAnchor.transform.up);
this.ship.transform.forward = gl_vec3.normalize(this.ship.transform.forward, this.ship.transform.forward);
this.ship.transform.right = gl_vec3.normalize(this.ship.transform.right, this.ship.transform.right);
this.ship.transform.up = gl_vec3.normalize(this.ship.transform.up, this.ship.transform.up);
*/
/*
for(let [i, t] of this.trails.entries()){
this.shipTrailHistory.push([]);
for(let q of t){
this.shipTrailHistory[i].push(this.ship.getWorldPositionOfQuad(q));
}
}
*/
//TODO breaks bc spline id 0-44 is not next lap yyet
this.raceProgress = (this.lapTimes.length * this.level.trackBuilder.spline.length) + this.splineId;
if (this.progressFinish === true) {
this.raceProgress += this.level.trackBuilder.spline.length;
}
}
updateFromHangar() {
//if(this.gondula.pos.y > 0){
//also change in lvlHangar if speed upwards changes
//this.gondula.jumpToPosition({x: this.gondula.pos.x, y: this.gondula.pos.y - (0.5 * this.scene.dt), z: this.gondula.pos.z}, true);
//this is also in racing
this.cameraSplineId = this.splineId - 5;
if (this.cameraSplineId < 0) {
this.cameraSplineId += this.level.trackBuilder.spline.length;
}
this.targetSplineId = this.splineId + 1;//INFO looking further down with higher speed?
while (this.targetSplineId >= this.level.trackBuilder.spline.length) {
this.targetSplineId -= this.level.trackBuilder.spline.length;
}
let splineRef = this.level.trackBuilder.spline[this.targetSplineId];
//until here in racing
//move gonudla and ship
//todo: why do the enemies fly further? is this not fuzzy enough?
let d = eud.distance([this.gondula.pos.x, this.gondula.pos.y, this.gondula.pos.z], [this.level.trackBuilder.spline[this.splineId].x, this.level.trackBuilder.spline[this.splineId].y, this.level.trackBuilder.spline[this.splineId].z]);
//if(this.isPlayer === true){
//console.log(d)
//}
if (d >= this.scene.dt) {
let spd = 0.5 * this.scene.dt;
this.gondula.jumpToPosition({ x: this.gondula.pos.x + (this.gondula.transform.up.x * spd), y: this.gondula.pos.y + (this.gondula.transform.up.y * spd), z: this.gondula.pos.z + (this.gondula.transform.up.z * spd) }, true);
this.shipAnchor.jumpToPosition({ x: this.gondula.pos.x + (this.gondula.transform.up.x * -96), y: this.gondula.pos.y + (this.gondula.transform.up.y * -96), z: this.gondula.pos.z + (this.gondula.transform.up.z * -96) }, true);
this.ship.jumpToPosition({ x: this.gondula.pos.x + (this.gondula.transform.up.x * -96), y: this.gondula.pos.y + (this.gondula.transform.up.y * -96), z: this.gondula.pos.z + (this.gondula.transform.up.z * -96) }, true);
}
//this is also in racing
let posFactor = 0.25 * this.scene.dt;// 0.5 //Math.max(0.01, ((this.speed + this.speedBonus) / (this.speedMax + this.speedBonus))) * 0.5;//todo: at max speed it still jitters
let rotFactor = 0.05 * this.scene.dt;
//rotate ship Anchor to Gondula
let targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.shipAnchor.transform.toVectorArray(this.shipAnchor.transform.forward),
this.shipAnchor.transform.toVectorArray(splineRef.transform.forward)
)
let rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.shipAnchor.transform.rotationQuat, targetRot, rotFactor);
this.shipAnchor.rotateByQuaternion(rot);
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.shipAnchor.transform.toVectorArray(this.shipAnchor.transform.right),
this.shipAnchor.transform.toVectorArray(this.gondula.transform.right)
)
rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.shipAnchor.transform.rotationQuat, targetRot, rotFactor);
this.shipAnchor.rotateByQuaternion(rot);
//move and rotate ship model to actual ship anchor point
this.ship.jumpToPosition({ x: this.shipAnchor.pos.x, y: this.shipAnchor.pos.y, z: this.shipAnchor.pos.z });
//rotate ship to Gondula
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.ship.transform.toVectorArray(this.ship.transform.forward),
this.ship.transform.toVectorArray(splineRef.transform.forward)
)
rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.ship.transform.rotationQuat, targetRot, rotFactor);
this.ship.rotateByQuaternion(rot);
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.ship.transform.toVectorArray(this.ship.transform.right),
this.ship.transform.toVectorArray(this.gondula.transform.right)
)
rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.ship.transform.rotationQuat, targetRot, rotFactor);
this.ship.rotateByQuaternion(rot);
//until here
//}
}
updateRacing() {
let invertedSpeedFactor = 1 - this.speedFactor;//(this.speed / (this.speedMax + this.speedBonus));
this.cameraSplineId = this.splineId - 5;
if (this.cameraSplineId < 0) {
this.cameraSplineId += this.level.trackBuilder.spline.length;
}
this.targetSplineId = this.splineId + 1;//INFO looking further down with higher speed?
while (this.targetSplineId >= this.level.trackBuilder.spline.length) {
this.targetSplineId -= this.level.trackBuilder.spline.length;
}
let splineRef = this.level.trackBuilder.spline[this.targetSplineId];
this.bonusSplineId = this.splineId + 5;
while (this.bonusSplineId >= this.level.trackBuilder.spline.length) {
this.bonusSplineId -= this.level.trackBuilder.spline.length;
}
let bonusRef = this.level.trackBuilder.spline[this.bonusSplineId];
this.input.spd = 0;
this.input.roll = 0;
this.input.pitch = 0;
if (this.level.state === this.level.states.race) {
if (this.autopilot === false) {
this.inputPlayer();
} else {
this.inputAI(bonusRef);
}
}
if (this.slipstreamLasting <= 0) {
this.slipstreaming = false;
} else {
this.slipstreamLasting -= this.scene.dt;
this.slipsteamTime += this.scene.dt;
}
this.slipstreamTarget = null;
if (this.jumpingLasting <= 0) {
this.jumping = false;
} else {
this.jumpingLasting -= this.scene.dt;
}
if (this.nearmissBoostCooldown >= 0) {
this.nearmissBoostCooldown -= this.scene.dt;
if (this.nearmissBoostCooldown <= 0) {
//console.log("COOLDOWNED")
}
}
this.last.speedBonus = this.speedBonus;
this.last.input.roll = this.input.roll;
this.last.curveAmt = this.curveAmt;
//check Collisions
let collCheckArr = [
{//check forward of ship
pos: {
x: this.ship.pos.x,
y: this.ship.pos.y,
z: this.ship.pos.z
},
dir: {
x: this.shipAnchor.transform.forward.x,
y: this.shipAnchor.transform.forward.y,
z: this.shipAnchor.transform.forward.z
},
hit: []
}, {//check forward right of ship for booster
pos: {
x: this.ship.pos.x + (this.shipAnchor.transform.right.x * 48),
y: this.ship.pos.y + (this.shipAnchor.transform.right.y * 48),
z: this.ship.pos.z + (this.shipAnchor.transform.right.z * 48)
},
dir: {
x: this.shipAnchor.transform.forward.x,
y: this.shipAnchor.transform.forward.y,
z: this.shipAnchor.transform.forward.z
},
hit: []
}, {//check forward left of ship for booster
pos: {
x: this.ship.pos.x + (this.shipAnchor.transform.right.x * -48),
y: this.ship.pos.y + (this.shipAnchor.transform.right.y * -48),
z: this.ship.pos.z + (this.shipAnchor.transform.right.z * -48)
},
dir: {
x: this.shipAnchor.transform.forward.x,
y: this.shipAnchor.transform.forward.y,
z: this.shipAnchor.transform.forward.z
},
hit: []
}, {//check slipstream with curve amt
pos: {
x: this.ship.pos.x,
y: this.ship.pos.y,
z: this.ship.pos.z
},
dir: {
x: this.shipAnchor.transform.forward.x + (this.shipAnchor.transform.up.x * this.curveAmt),
y: this.shipAnchor.transform.forward.y + (this.shipAnchor.transform.up.y * this.curveAmt),
z: this.shipAnchor.transform.forward.z + (this.shipAnchor.transform.up.z * this.curveAmt)
},
hit: []
}
];
//push stuff to collide with
let toCollideWith = [];
for (let o of this.level.trackBuilder.obstacles) {
if (o.data.id + 1 > this.splineId) {
toCollideWith.push(o);
}
//if (o.flags.update === true){
//o.update();
//}
}
for (let s of this.level.aiShips) {
if (s.id !== this.id) {
if (s.splineId > this.splineId) {
toCollideWith.push(s.ship);
}
}
}
if (this.isPlayer === false) {
if (this.level.playerShip.splineId > this.splineId) {
toCollideWith.push(this.level.playerShip.ship);
}
}
for (let m of toCollideWith) {
//if (m.flags.update === true){
// m.update();
//}
for (let q of m.collisionData) {
for (let c of collCheckArr) {
let hitData = this.scene.geometryController.collide(q, c);
if (hitData.pt !== null) {
hitData.model = m;
c.hit.push(hitData);
}
}
}
}
let alreadyColliding = false;
let distSpeed = this.speed * 2;
/*if (this.isPlayer === true) {
console.log(distSpeed)
}*/
//let avoids = [0, 0, 0];
let returnColl = collCheckArr;
//resolve collision with forward
if (returnColl[0].hit.length > 0) {
//filter relevant = nearest hit
let dist = 9999;
let nearestHit = returnColl[0].hit[0];
for (let [i, n] of returnColl[0].hit.entries()) {
let d = eud.distance([this.ship.pos.x, this.ship.pos.y, this.ship.pos.z], returnColl[0].hit[i].pt)
if (d < dist) {
dist = d;
nearestHit = returnColl[0].hit[i];
}
}
if (dist < 2048) {
//slipstreaming? //todo: set dist < slipstream wake / distance of that object (maybe additional check within 1024m)
if (nearestHit.model.data.slipstreamLength !== undefined) {
if (dist < nearestHit.model.data.slipstreamLength) {
//console.log(`slipstreaming: ${Math.floor(dist)}`);
this.slipstreaming = true;
this.slipstreamTarget = nearestHit.model;
this.slipstreamLasting = 60 * 3;
//TODO let the AI know you are slipstreaming
if (this.isPlayer === true) {
this.level.situation.actions.slipstream.who = nearestHit.model.data.name;
this.level.situation.actions.slipstream.priority += 1;
} else {
if (this.slipstreamTarget.data.name === "Player") {//"Player" // TODO does not work as of yet
this.level.situation.actions.slipstreamed.who = this.ship.data.name;
this.level.situation.actions.slipstream.priority += 1;
}
}
}
}
}
if (dist < 128 + distSpeed) {
alreadyColliding = true;
if (nearestHit.model.trigger.isTrigger === false) {
//console.log(returnColl[0]);
if (this.speed > 0 && this.isPlayer) {
this.scene.soundManager.playRandomSound(this.scene.soundManager.bumpSound);
}
this.crashPoints += 1;
this.speed *= 0.75;//= 0;
if (this.speed <= 1) {
this.speed = 0;
}
this.input.spd = 0;
if (nearestHit.model.data.roll !== undefined && nearestHit.model.data.roll !== 0) {
this.input.roll = nearestHit.model.data.roll * 2;
}
if (this.isPlayer) {
//console.log(nearestHit.model.data.name);
if (nearestHit.model.data.name !== undefined) {
//set ui.racerReaction to hitted pilot
this.level.situation.actions.hit.who = nearestHit.model.data.name;
this.level.situation.actions.hit.priority += 2;
//let character = this.level.aiShips.filter(el => el.name === nearestHit.model.data.name)[0].character;
//this.level.ui.addReaction("charSheetExpressions", character.reactions.hit[Math.floor(Math.random() * character.reactions.hit.length)]);
}
}
} else {
nearestHit.model.trigger.other = this;
nearestHit.model.updateTrigger();
}
}
}
//check booster only if collision free in front (0)
if (alreadyColliding === false) {
//resolve collision with forward right and then left of ship for boost
for (let j = 1; j < 3; j++) {
if (returnColl[j].hit.length > 0) {
//filter relevant = nearest hit
let dist = 9999;
let nearestHit = returnColl[j].hit[0];
for (let [i, n] of returnColl[j].hit.entries()) {
let d = eud.distance([returnColl[j].pos.x, returnColl[j].pos.y, returnColl[j].pos.z], returnColl[j].hit[i].pt)
if (d < dist) {
dist = d;
nearestHit = returnColl[j].hit[i];
}
}
/*if(dist < 1024){
avoids[j] = 1;
}*/
if (dist < 128) {
if (nearestHit.model.trigger.isTrigger === false) {
if (this.speed > (this.speedMax * 0.25) && this.input.spd >= 0 && this.nearmissBoostCooldown <= 0) {
this.input.spd = 1;
this.speed = this.speed * this.nearmissBoost;//this.speedMax * this.nearmissBoost;
this.speed = Math.min(this.speed, this.speedMax * this.nearmissBoost);
this.nearmissBoostCooldown = 60;
if (this.isPlayer === true) {
if (this.scene.cam.fov < 3.5) {//todo: find a good value for the boost effect
this.scene.cam.fov += 1 * this.scene.dt;
this.scene.cam.fov = Math.min(this.scene.cam.fov, 3.5);
}
//sound
this.scene.soundManager.playRandomSound(this.scene.soundManager.swooshSound);
}
}
} else {
//nearestHit.model.updateTrigger();
}
}
}
}
//check if slipstreaming with curve calculated
//filter relevant = nearest hit
let dist = 9999;
let nearestHit = returnColl[3].hit[0];
for (let [i, n] of returnColl[3].hit.entries()) {
let d = eud.distance([this.ship.pos.x, this.ship.pos.y, this.ship.pos.z], returnColl[3].hit[i].pt)
if (d < dist) {
dist = d;
nearestHit = returnColl[3].hit[i];
}
}
if (dist < 2048) {
//slipstreaming? //todo: set dist < slipstream wake / distance of that object (maybe additional check within 1024m)
if (nearestHit.model.data.slipstreamLength !== undefined) {
if (dist < nearestHit.model.data.slipstreamLength) {
//console.log(`slipstreaming: ${Math.floor(dist)}`);
this.slipstreaming = true;
this.slipstreamTarget = nearestHit.model;
this.slipstreamLasting = 60 * 3;
}
}
}
}
//find pitch to track to set bonus
let upVec = [//was gonudla before, but could work well with ship
bonusRef.x + (this.ship.transform.forward.x * 10) + (this.ship.transform.up.x * 10),
bonusRef.y + (this.ship.transform.forward.y * 10) + (this.ship.transform.up.y * 10),
bonusRef.z + (this.ship.transform.forward.z * 10) + (this.ship.transform.up.z * 10)
]
let doVec = [
bonusRef.x + (this.ship.transform.forward.x * 10) + (this.ship.transform.up.x * -10),
bonusRef.y + (this.ship.transform.forward.y * 10) + (this.ship.transform.up.y * -10),
bonusRef.z + (this.ship.transform.forward.z * 10) + (this.ship.transform.up.z * -10)
]
let upDist = eud.distance(upVec, [bonusRef.x + (bonusRef.transform.forward.x), bonusRef.y + (bonusRef.transform.forward.y), bonusRef.z + (bonusRef.transform.forward.z)]);
let doDist = eud.distance(doVec, [bonusRef.x + (bonusRef.transform.forward.x), bonusRef.y + (bonusRef.transform.forward.y), bonusRef.z + (bonusRef.transform.forward.z)]);
let bonusAmt = (doDist - upDist);
bonusAmt = Math.max(-1, Math.min(bonusAmt, 1));
let flingAmt = (doDist - upDist);
flingAmt = Math.max(-1, Math.min(flingAmt, 1));
if (this.jumping === true) {
flingAmt -= 1 * this.speedFactor;
if (this.isPlayer) {
}
}
//INFO reference : this.ui.pitchLimit.y = 64 - (32 * this.playerShip.curveAmt) - (32 * this.playerShip.pitch.current)
//bonusAmt = 64 - (32 * this.playerShip.curveAmt) - (32 * this.playerShip.pitch.current)//<<<<INFO original bonus amt
//32 is perfect < 0 is crash, > 32 is cooling in theory
this.distToPerfectPitch = 64 - (32 * this.curveAmt) - (32 * this.pitch.current) - (this.pitch.current * 32);
this.distToPerfectPitch = Math.max(-64, Math.min(this.distToPerfectPitch, 64));
//console.log(this.distToPerfectPitch) //todo: this might be stupid ^^^^
//this way <0 is heating >0 is cooling ~0 is speed gain zoon?
//bonusAmt = ((((this.distToPerfectPitch - 32) / 64) ) * -1);
bonusAmt = ((this.distToPerfectPitch / 64) * -1) + 0.5 + this.curveAmt;//INFO bot of these two lines dont quite work as intended - no jumping - too fast, too hot weird
//scraping?
if (this.distToPerfectPitch <= 0) {
if (this.speed > 0) {
this.scraping = true;
this.scrapingTime += this.scene.dt * 0.001;
}
bonusAmt = Math.max(-8, this.scrapingTime * -1);
} else {
this.scraping = false;
this.scrapingTime = 0;
}
if (this.slipstreaming === true) {
bonusAmt += this.slipstreamBoost;
}
//move away from ideal height
//this.flightRadius += (bonusAmt * (this.speed * 0.25)) * this.scene.dt;
this.flightRadius += (flingAmt * (this.speed * 0.25)) * this.scene.dt;
//if(this.temp > 500){
// this.flightRadius -= 10;
//}
let calmer = 1 * this.scene.dt;
this.flightRadius = Math.max(this.flightRadiusLowerLimit, Math.min(this.flightRadius + (calmer * Math.max(0.1, this.speedFactor)), this.flightRadiusUpperLimit));
if (this.flightRadius >= this.flightRadiusUpperLimit) {
this.jumping = false;
}
this.speedBonus = this.speedMax * bonusAmt;
//this.speedBonus += 8;//INFO neutral on a streaight is -8 atm, +8 and making the bonus less aggressive could be helpful in general for a less twitchy feel
//find pitch to track from gondula to set navigation
upVec = [
bonusRef.x + (this.gondula.transform.forward.x * 1) + (this.gondula.transform.up.x * 1),
bonusRef.y + (this.gondula.transform.forward.y * 1) + (this.gondula.transform.up.y * 1),
bonusRef.z + (this.gondula.transform.forward.z * 1) + (this.gondula.transform.up.z * 1)
]
doVec = [
bonusRef.x + (this.gondula.transform.forward.x * 1) + (this.gondula.transform.up.x * -1),
bonusRef.y + (this.gondula.transform.forward.y * 1) + (this.gondula.transform.up.y * -1),
bonusRef.z + (this.gondula.transform.forward.z * 1) + (this.gondula.transform.up.z * -1)
]
upDist = eud.distance(upVec, [bonusRef.x + (bonusRef.transform.forward.x * 320), bonusRef.y + (bonusRef.transform.forward.y * 320), bonusRef.z + (bonusRef.transform.forward.z * 320)]);
doDist = eud.distance(doVec, [bonusRef.x + (bonusRef.transform.forward.x * 320), bonusRef.y + (bonusRef.transform.forward.y * 320), bonusRef.z + (bonusRef.transform.forward.z * 320)]);
let curveAmt = (doDist - upDist);
//curveAmt = Math.max(-1, Math.min(curveAmt * 0.005, 1));
this.curveAmt = curveAmt;
//apply sppeed and move accordingly
if (this.input.spd !== 0) {
if (this.speed > this.speedMax + this.speedBonus) {
this.input.spd = (this.acceleration * -2);
}
this.speed += this.input.spd;
this.speed = Math.max(0, this.speed);
//this.speed = Math.max(0, Math.min(this.speed, this.speedMax + this.speedBonus));
//console.log(splineRef)
//use right axis if you need roll as well, but if using forward, you just follow the track as intended any you can roll on your own later
let targetVec = [splineRef.x - this.gondula.pos.x, splineRef.y - this.gondula.pos.y, splineRef.z - this.gondula.pos.z];
targetVec = gl_vec3.normalize(targetVec, targetVec);
let targetRot = [0, 0, 0, 0];
//console.log(targetVec)
targetRot = gl_quat.rotationTo(targetRot,
this.gondula.transform.toVectorArray(this.gondula.transform.forward),
//this.gondula.transform.toVectorArray( splineRef.transform.forward)
targetVec
)
let rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.gondula.transform.rotationQuat, targetRot, 0.5);
this.gondula.rotateByQuaternion(rot);
//this.gondula.rotateByQuaternion(targetRot);
//move gondula forward by spd
this.gondula.jumpToPosition({
x: this.gondula.pos.x + ((targetVec[0] * this.speed) * this.scene.dt),
y: this.gondula.pos.y + ((targetVec[1] * this.speed) * this.scene.dt),
z: this.gondula.pos.z + ((targetVec[2] * this.speed) * this.scene.dt)
});
let criticalSpeed = (1 * this.speed) * this.scene.dt;
/*if(this.isPlayer === true){
if(criticalSpeed >= 64){
console.log(criticalSpeed);
};
}*/
//check if reached target
let d = gl_vec3.distance(this.gondula.transform.toVectorArray(this.gondula.pos), [splineRef.x, splineRef.y, splineRef.z]);
//console.log(d)
if (d <= 64 /*this.speed * 1*/ /*64*/) {
let amt = Math.floor(criticalSpeed / 64) + 1; //jumjp further if speed exceeds the distance between splines
this.splineId += amt;
if (this.splineId >= this.level.trackBuilder.spline.length) {
this.splineId -= this.level.trackBuilder.spline.length;
this.crossedFinish = false;
}
if (this.splineId >= 0 && this.crossedFinish === false) {
//add length of track to raceProgress to prevent false positions
this.progressFinish = true;
}
if (this.splineId >= 44 && this.crossedFinish === false) {
if (this.ignoreFinish === false) {
this.crossedFinish = true;
this.progressFinish = false;
this.startNewLap();
} else {
this.ignoreFinish = false;
}
}
//console.log("next point: " + String(this.splineId) + " / " + String(this.level.trackBuilder.spline.length))
}
}
//INFO original temp calc
if (this.speed > this.speedMax && this.slipstreaming === false) {
this.temp += 0.5 * this.scene.dt;
if (this.speedBonus < 3) {
if (this.scraping === false) {
this.temp -= 0.75 * this.scene.dt;
}
}
} else {
if (this.scraping === false) {
this.temp -= 1.1 * this.scene.dt;
}
}
if (this.scraping === true) {
this.temp += (Math.max(0, Math.min(1, this.speed / this.speedMax)) * 1) * this.scene.dt;
}
this.temp = Math.max(0, Math.min(this.temp, 999));
if (this.temp >= 999) {
this.speedBonus = 0;
} else {
}
this.speedNormalized = this.speed / this.speedMax;
//roll the ship
if (this.input.roll !== 0) {
let kir = Math.abs(this.input.roll);
if (this.input.roll > 0) {
if (this.rollSpeed < this.rollSpeedMax) {
this.rollSpeed += this.rollAcceleration * this.scene.dt;
this.rollSpeed = Math.min(this.rollSpeed, this.rollSpeedMax * kir);
}
}
if (this.input.roll < 0) {
if (this.rollSpeed > this.rollSpeedMin) {
this.rollSpeed -= this.rollAcceleration * this.scene.dt;
this.rollSpeed = Math.max(this.rollSpeed, this.rollSpeedMin * kir);
}
}
} else {
if (this.rollSpeed < 0) {
this.rollSpeed += this.rollDeceleration * this.scene.dt;
this.rollSpeed = Math.min(this.rollSpeed, 0);
}
if (this.rollSpeed > 0) {
this.rollSpeed -= this.rollDeceleration * this.scene.dt;
this.rollSpeed = Math.max(this.rollSpeed, 0);
}
}
if (this.scene.numkeys.nine.isDown) {
if (this.flightRadius > this.flightRadiusLowerLimit) {
this.flightRadius -= 1 * this.scene.dt;
}
}
if (this.scene.numkeys.three.isDown) {
//if(this.flightRadius < this.flightRadiusUpperLimit){
this.flightRadius += 1 * this.scene.dt;
//}
}
this.speedFactor = Math.max(0, Math.min((this.speed + this.speedBonus) / (this.speedMax + this.speedBonus), 1));
if (this.speed > this.speedMax) {
this.overSpeed = true;
} else {
this.overSpeed = false;
}
//visual rotatons based on input
//INFO: ALERT //todo: rotateAroundAxis fucks up the heatzone indicator (distToPerfectPitch) and moving the ship (currently out commented and indented) is the crazy crashout
//todo: at least with pitchditch it might be broken maybe more
//INFO //todo: clamping pitch.current (and the visual heatzone indicator (pitchLimit) prevents hiccups, but might be a pflaster solution)
this.gondula.rotateAroundAxis(this.gondula.transform.toVectorArray(this.gondula.transform.forward), (Math.PI * 0.01) * (this.rollSpeed) * this.scene.dt);
//let ship look a bit ahead of corner on input
this.shipAnchor.rotateAroundAxis(this.gondula.transform.toVectorArray(this.gondula.transform.up), (Math.PI * 0.01) * (this.rollSpeed) * this.scene.dt);
this.ship.rotateAroundAxis(this.ship.transform.toVectorArray(this.ship.transform.forward), ((Math.PI * 0.005 * this.speedFactor)) * (this.rollSpeed) * this.scene.dt);
this.pitch.target = Math.max(this.pitch.min, Math.min(this.keyInput.pitch, this.pitch.max));
this.pitch.delta = this.pitch.target - this.pitch.current;
this.pitch.current += this.pitch.delta * this.scene.dt;
this.pitch.current = Math.max(-1, Math.min(this.pitch.current, 1));
let pitchditch = this.pitch.current * 0.01;
this.ship.rotateAroundAxis(this.ship.transform.toVectorArray(this.ship.transform.right), pitchditch);
//roll ship for cool drifting effect
this.ship.rotateAroundAxis(this.shipAnchor.transform.toVectorArray(this.shipAnchor.transform.forward), (Math.PI * -0.0075) * (this.rollSpeed) * this.scene.dt);
//experimentalthis.ship.rotateAroundAxis(this.shipAnchor.transform.toVectorArray(this.shipAnchor.transform.up), (Math.PI * 0.025) * (this.rollSpeed) * this.scene.dt);
//move Ship to gondula
let posFactor = 0.25 * this.scene.dt; // 0.5 //Math.max(0.01, ((this.speed + this.speedBonus) / (this.speedMax + this.speedBonus))) * 0.5;//todo: at max speed it still jitters
let rotFactor = 0.05 * this.scene.dt; //0.1 //Math.max(0.01, ((this.speed + this.speedBonus) / (this.speedMax + this.speedBonus)) * 0.1);
if (this.speed < 0.01) {
//posFactor = 0.5;
//rotFactor = 0.1;
}
let deltaPos = {
x: ((this.gondula.pos.x + (this.gondula.transform.up.x * -this.flightRadius))) - this.shipAnchor.pos.x,
y: ((this.gondula.pos.y + (this.gondula.transform.up.y * -this.flightRadius))) - this.shipAnchor.pos.y,
z: ((this.gondula.pos.z + (this.gondula.transform.up.z * -this.flightRadius))) - this.shipAnchor.pos.z
}
this.shipAnchor.jumpToPosition({
x: this.shipAnchor.pos.x + (deltaPos.x * posFactor),
y: this.shipAnchor.pos.y + (deltaPos.y * posFactor),
z: this.shipAnchor.pos.z + (deltaPos.z * posFactor)
});
//rotate ship Anchor to Gondula
let targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.shipAnchor.transform.toVectorArray(this.shipAnchor.transform.forward),
this.shipAnchor.transform.toVectorArray(splineRef.transform.forward)
)
let rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.shipAnchor.transform.rotationQuat, targetRot, rotFactor);
this.shipAnchor.rotateByQuaternion(rot);
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.shipAnchor.transform.toVectorArray(this.shipAnchor.transform.right),
this.shipAnchor.transform.toVectorArray(this.gondula.transform.right)
)
rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.shipAnchor.transform.rotationQuat, targetRot, rotFactor);
this.shipAnchor.rotateByQuaternion(rot);
//move and rotate ship model to actual ship anchor point
let jitterPos = { x: 0, y: 0, z: 0 }
if (this.scraping === true) {
//todo: play scrape audio of player
let jitterMod = (this.speed / this.speedMax);
//jitterMod *= jitterMod;
if (jitterMod < 0) {
jitterMod = 0;
}
if (jitterMod > 1) {
jitterMod = 1;
}
jitterPos = { x: -(1 + (Math.random() * 2)) * jitterMod, y: -(3 + (Math.random() * 6)) * jitterMod, z: (-1 + (Math.random() * 2)) * jitterMod }
//(Math.max(0, Math.min(1, this.speed / this.speedMax)) * 1) * this.scene.dt;
}
this.ship.jumpToPosition({ x: this.shipAnchor.pos.x + jitterPos.x, y: this.shipAnchor.pos.y + jitterPos.y, z: this.shipAnchor.pos.z + jitterPos.z });
//rotate ship to Gondula
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.ship.transform.toVectorArray(this.ship.transform.forward),
this.ship.transform.toVectorArray(splineRef.transform.forward)
)
rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.ship.transform.rotationQuat, targetRot, rotFactor);
this.ship.rotateByQuaternion(rot);
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.ship.transform.toVectorArray(this.ship.transform.right),
this.ship.transform.toVectorArray(this.gondula.transform.right)
)
rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.ship.transform.rotationQuat, targetRot, rotFactor);
this.ship.rotateByQuaternion(rot);
//show ship trail
/*let tipL = {
x: this.ship.quadData[this.ship.quadData.length - 1].points[0].x + ((this.gondula.transform.forward.x * (1 + (-56 * (this.speed / this.speedMax)))) + (this.gondula.transform.right.x * 0) + (this.gondula.transform.up.x * -2)),
y: this.ship.quadData[this.ship.quadData.length - 1].points[0].y + ((this.gondula.transform.forward.y * (1 + (-56 * (this.speed / this.speedMax)))) + (this.gondula.transform.right.y * 0) + (this.gondula.transform.up.y * -2)),
z: this.ship.quadData[this.ship.quadData.length - 1].points[0].z + ((this.gondula.transform.forward.z * (1 + (-56 * (this.speed / this.speedMax)))) + (this.gondula.transform.right.z * 0) + (this.gondula.transform.up.z * -2))
}
let tipR = {
x: this.ship.quadData[this.ship.quadData.length - 1].points[1].x + ((this.gondula.transform.forward.x * (1 + (-56 * (this.speed / this.speedMax)))) + (this.gondula.transform.right.x * 0) + (this.gondula.transform.up.x * -2)),
y: this.ship.quadData[this.ship.quadData.length - 1].points[1].y + ((this.gondula.transform.forward.y * (1 + (-56 * (this.speed / this.speedMax)))) + (this.gondula.transform.right.y * 0) + (this.gondula.transform.up.y * -2)),
z: this.ship.quadData[this.ship.quadData.length - 1].points[1].z + ((this.gondula.transform.forward.z * (1 + (-56 * (this.speed / this.speedMax)))) + (this.gondula.transform.right.z * 0) + (this.gondula.transform.up.z * -2))
}
this.ship.quadData[this.ship.quadData.length - 1].points[3] = tipL;
this.ship.quadData[this.ship.quadData.length - 1].points[2] = tipR;
this.ship.quadData[this.ship.quadData.length - 2].points[3] = tipL;
this.ship.quadData[this.ship.quadData.length - 2].points[2] = tipR;*/
for (let t of this.thrusters) {
//todo: get the saved original position of the vertex to move and add the move vector to keep the shape of the thruster to keep a cone shape
t.points[3].x = t.points[0].x + (this.gondula.transform.forward.x * (1 + (-56 * (this.speed / this.speedMax))));
t.points[3].y = t.points[0].y + (this.gondula.transform.forward.y * (1 + (-56 * (this.speed / this.speedMax))));
t.points[3].z = t.points[0].z + (this.gondula.transform.forward.z * (1 + (-56 * (this.speed / this.speedMax))));
t.points[2].x = t.points[1].x + (this.gondula.transform.forward.x * (1 + (-56 * (this.speed / this.speedMax))));
t.points[2].y = t.points[1].y + (this.gondula.transform.forward.y * (1 + (-56 * (this.speed / this.speedMax))));
t.points[2].z = t.points[1].z + (this.gondula.transform.forward.z * (1 + (-56 * (this.speed / this.speedMax))));
}
this.lensflares[this.lensflares.length - 1].jumpToPosition({
x: this.ship.pos.x + (this.ship.transform.forward.x * -66) + (this.ship.transform.up.x * 22),
y: this.ship.pos.y + (this.ship.transform.forward.y * -66) + (this.ship.transform.up.y * 22),
z: this.ship.pos.z + (this.ship.transform.forward.z * -66) + (this.ship.transform.up.z * 22),
}, true);
this.lensflares[this.lensflares.length - 1].quadData[0].alpha = 1 * this.speedFactor;//0.2
//todo: save an array of previous tip positions (part of the model) and let quads dynamically stretch over them to form a growing trail
/*for(let t of this.trails){
for(let i = t.length -1 ; i >= 0 ; i--){
let p = t[i];
p.points[3] = p.points[0];
p.points[2] = p.points[1];
}
}*/
/*//my origin points
this.trails[0][0].points[0]
this.trails[0][0].points[1]
this.trails[1][0].points[0]
this.trails[1][0].points[1]
*/
this.trailTicker -= this.scene.dt;
for (let [j, t] of this.trails.entries()) {
if (this.trailTicker <= 0) {
for (let i = t.length - 1; i > 0; i--) {
this.shipTrailHistory[j][i] = this.shipTrailHistory[j][i - 1]
}
}
this.shipTrailHistory[j][0] = this.ship.getWorldPositionOfQuad(this.shipSwooshOrigins[j]);
for (let p of this.shipTrailHistory[j][0]) {
p.x += this.ship.pos.x;
p.y += this.ship.pos.y;
p.z += this.ship.pos.z;
}
}
for (let [j, t] of this.trails.entries()) {//each trail
//this.swooshOrigins[j].jumpToPosition(this.ship.pos);
if (this.trailTicker <= 0) {
for (let i = t.length - 1; i > 0; i--) {//each trail quad / saved position
let q = t[i];//each quad
//jump end of trailpart to timesaved position
q.points[3].x = this.shipTrailHistory[j][i][0].x + this.shipTrailHistory[j][i][4].x;
q.points[3].y = this.shipTrailHistory[j][i][0].y + this.shipTrailHistory[j][i][4].y;
q.points[3].z = this.shipTrailHistory[j][i][0].z + this.shipTrailHistory[j][i][4].z;
q.points[2].x = this.shipTrailHistory[j][i][1].x + this.shipTrailHistory[j][i][4].x;
q.points[2].y = this.shipTrailHistory[j][i][1].y + this.shipTrailHistory[j][i][4].y;
q.points[2].z = this.shipTrailHistory[j][i][1].z + this.shipTrailHistory[j][i][4].z;
//jump start of trailpart to timesaved previous position
q.points[0].x = this.shipTrailHistory[j][i - 1][0].x + this.shipTrailHistory[j][i - 1][4].x;
q.points[0].y = this.shipTrailHistory[j][i - 1][0].y + this.shipTrailHistory[j][i - 1][4].y;
q.points[0].z = this.shipTrailHistory[j][i - 1][0].z + this.shipTrailHistory[j][i - 1][4].z;
q.points[1].x = this.shipTrailHistory[j][i - 1][1].x + this.shipTrailHistory[j][i - 1][4].x;
q.points[1].y = this.shipTrailHistory[j][i - 1][1].y + this.shipTrailHistory[j][i - 1][4].y;
q.points[1].z = this.shipTrailHistory[j][i - 1][1].z + this.shipTrailHistory[j][i - 1][4].z;
}
}
//correct first trail part that is connected to the ship
//jump end of trailpart to timesaved position
t[0].points[3].x = this.shipTrailHistory[j][1][0].x + this.shipTrailHistory[j][1][4].x;
t[0].points[3].y = this.shipTrailHistory[j][1][0].y + this.shipTrailHistory[j][1][4].y;
t[0].points[3].z = this.shipTrailHistory[j][1][0].z + this.shipTrailHistory[j][1][4].z;
t[0].points[2].x = this.shipTrailHistory[j][1][1].x + this.shipTrailHistory[j][1][4].x;
t[0].points[2].y = this.shipTrailHistory[j][1][1].y + this.shipTrailHistory[j][1][4].y;
t[0].points[2].z = this.shipTrailHistory[j][1][1].z + this.shipTrailHistory[j][1][4].z;
t[0].points[0].x = this.shipTrailHistory[j][0][0].x + this.shipTrailHistory[j][0][4].x;
t[0].points[0].y = this.shipTrailHistory[j][0][0].y + this.shipTrailHistory[j][0][4].y;
t[0].points[0].z = this.shipTrailHistory[j][0][0].z + this.shipTrailHistory[j][0][4].z;
t[0].points[1].x = this.shipTrailHistory[j][0][1].x + this.shipTrailHistory[j][0][4].x;
t[0].points[1].y = this.shipTrailHistory[j][0][1].y + this.shipTrailHistory[j][0][4].y;
t[0].points[1].z = this.shipTrailHistory[j][0][1].z + this.shipTrailHistory[j][0][4].z;
}
if (this.trailTicker <= 0) {
this.trailTicker = this.speed * 0.25;
}
//after moving setters
let ref = this.level.trackBuilder.spline[this.splineId];
if (ref.model !== null) {
//console.log(ref)
this.targetModel = ref.model;
//console.log(this.level.trackBuilder.spline[this.splineId]);//model.transfrom .roll .obstacles
//console.log(shipRight[0])
}
if (this.targetModel !== null) {
let trackRight = [this.targetModel.transform.right.x, this.targetModel.transform.right.y, this.targetModel.transform.right.z];
let shipRight = [this.gondula.transform.right.x, this.gondula.transform.right.y, this.gondula.transform.right.z];
this.angleToTrack = gl_vec3.dot(trackRight, shipRight);
//console.log(this.angleToTrack) gondula
let trackUp = [this.targetModel.transform.up.x, this.targetModel.transform.up.y, this.targetModel.transform.up.z];
let shipUp = [this.gondula.transform.up.x, this.gondula.transform.up.y, this.gondula.transform.up.z];
this.angleToTrackMod = gl_vec3.dot(trackUp, shipRight);
}
//todo: positional sound here
}
updateDream() {
let splineRef = this.level.trackBuilder.spline[0];
this.gondula.jumpToPosition({
x: this.gondula.pos.x,
y: this.gondula.pos.y,
z: this.gondula.pos.z + ((1 * this.speed) * this.scene.dt)
});
//move Ship to gondula
let posFactor = 0.25 * this.scene.dt;// 0.5 //Math.max(0.01, ((this.speed + this.speedBonus) / (this.speedMax + this.speedBonus))) * 0.5;//todo: at max speed it still jitters
let rotFactor = 0.05 * this.scene.dt;//0.1 //Math.max(0.01, ((this.speed + this.speedBonus) / (this.speedMax + this.speedBonus)) * 0.1);
if (this.speed < 0.01) {
//posFactor = 0.5;
//rotFactor = 0.1;
}
let deltaPos = {
x: ((this.gondula.pos.x + (this.gondula.transform.up.x * -this.flightRadius))) - this.shipAnchor.pos.x,
y: ((this.gondula.pos.y + (this.gondula.transform.up.y * -this.flightRadius))) - this.shipAnchor.pos.y,
z: ((this.gondula.pos.z + (this.gondula.transform.up.z * -this.flightRadius))) - this.shipAnchor.pos.z
}
this.shipAnchor.jumpToPosition({
x: this.shipAnchor.pos.x + (deltaPos.x * posFactor),
y: this.shipAnchor.pos.y + (deltaPos.y * posFactor),
z: this.shipAnchor.pos.z + (deltaPos.z * posFactor)
});
//rotate ship Anchor to Gondula
let targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.shipAnchor.transform.toVectorArray(this.shipAnchor.transform.forward),
this.shipAnchor.transform.toVectorArray(splineRef.transform.forward)
)
let rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.shipAnchor.transform.rotationQuat, targetRot, rotFactor);
this.shipAnchor.rotateByQuaternion(rot);
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.shipAnchor.transform.toVectorArray(this.shipAnchor.transform.right),
this.shipAnchor.transform.toVectorArray(this.gondula.transform.right)
)
rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.shipAnchor.transform.rotationQuat, targetRot, rotFactor);
this.shipAnchor.rotateByQuaternion(rot);
//move and rotate ship model to actual ship anchor point
this.ship.jumpToPosition({ x: this.shipAnchor.pos.x, y: this.shipAnchor.pos.y, z: this.shipAnchor.pos.z });
//rotate ship to Gondula
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.ship.transform.toVectorArray(this.ship.transform.forward),
this.ship.transform.toVectorArray(splineRef.transform.forward)
)
rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.ship.transform.rotationQuat, targetRot, rotFactor);
this.ship.rotateByQuaternion(rot);
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.ship.transform.toVectorArray(this.ship.transform.right),
this.ship.transform.toVectorArray(this.gondula.transform.right)
)
rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.ship.transform.rotationQuat, targetRot, rotFactor);
this.ship.rotateByQuaternion(rot);
for (let t of this.thrusters) {
//todo: get the saved original position of the vertex to move and add the move vector to keep the shape of the thruster to keep a cone shape
t.points[3].x = t.points[0].x + (this.gondula.transform.forward.x * (1 + (-56 * (this.speed / this.speedMax))));
t.points[3].y = t.points[0].y + (this.gondula.transform.forward.y * (1 + (-56 * (this.speed / this.speedMax))));
t.points[3].z = t.points[0].z + (this.gondula.transform.forward.z * (1 + (-56 * (this.speed / this.speedMax))));
t.points[2].x = t.points[1].x + (this.gondula.transform.forward.x * (1 + (-56 * (this.speed / this.speedMax))));
t.points[2].y = t.points[1].y + (this.gondula.transform.forward.y * (1 + (-56 * (this.speed / this.speedMax))));
t.points[2].z = t.points[1].z + (this.gondula.transform.forward.z * (1 + (-56 * (this.speed / this.speedMax))));
}
this.lensflares[this.lensflares.length - 1].jumpToPosition({
x: this.ship.pos.x + (this.ship.transform.forward.x * -66) + (this.ship.transform.up.x * 22),
y: this.ship.pos.y + (this.ship.transform.forward.y * -66) + (this.ship.transform.up.y * 22),
z: this.ship.pos.z + (this.ship.transform.forward.z * -66) + (this.ship.transform.up.z * 22),
}, true);
this.lensflares[this.lensflares.length - 1].quadData[0].alpha = 1 * this.speedFactor;//0.2
this.trailTicker -= this.scene.dt;
for (let [j, t] of this.trails.entries()) {
if (this.trailTicker <= 0) {
for (let i = t.length - 1; i > 0; i--) {
this.shipTrailHistory[j][i] = this.shipTrailHistory[j][i - 1]
}
}
this.shipTrailHistory[j][0] = this.ship.getWorldPositionOfQuad(this.shipSwooshOrigins[j]);
for (let p of this.shipTrailHistory[j][0]) {
p.x += this.ship.pos.x;
p.y += this.ship.pos.y;
p.z += this.ship.pos.z;
}
}
for (let [j, t] of this.trails.entries()) {//each trail
//this.swooshOrigins[j].jumpToPosition(this.ship.pos);
if (this.trailTicker <= 0) {
for (let i = t.length - 1; i > 0; i--) {//each trail quad / saved position
let q = t[i];//each quad
//jump end of trailpart to timesaved position
q.points[3].x = this.shipTrailHistory[j][i][0].x + this.shipTrailHistory[j][i][4].x;
q.points[3].y = this.shipTrailHistory[j][i][0].y + this.shipTrailHistory[j][i][4].y;
q.points[3].z = this.shipTrailHistory[j][i][0].z + this.shipTrailHistory[j][i][4].z;
q.points[2].x = this.shipTrailHistory[j][i][1].x + this.shipTrailHistory[j][i][4].x;
q.points[2].y = this.shipTrailHistory[j][i][1].y + this.shipTrailHistory[j][i][4].y;
q.points[2].z = this.shipTrailHistory[j][i][1].z + this.shipTrailHistory[j][i][4].z;
//jump start of trailpart to timesaved previous position
q.points[0].x = this.shipTrailHistory[j][i - 1][0].x + this.shipTrailHistory[j][i - 1][4].x;
q.points[0].y = this.shipTrailHistory[j][i - 1][0].y + this.shipTrailHistory[j][i - 1][4].y;
q.points[0].z = this.shipTrailHistory[j][i - 1][0].z + this.shipTrailHistory[j][i - 1][4].z;
q.points[1].x = this.shipTrailHistory[j][i - 1][1].x + this.shipTrailHistory[j][i - 1][4].x;
q.points[1].y = this.shipTrailHistory[j][i - 1][1].y + this.shipTrailHistory[j][i - 1][4].y;
q.points[1].z = this.shipTrailHistory[j][i - 1][1].z + this.shipTrailHistory[j][i - 1][4].z;
}
}
//correct first trail part that is connected to the ship
//jump end of trailpart to timesaved position
t[0].points[3].x = this.shipTrailHistory[j][1][0].x + this.shipTrailHistory[j][1][4].x;
t[0].points[3].y = this.shipTrailHistory[j][1][0].y + this.shipTrailHistory[j][1][4].y;
t[0].points[3].z = this.shipTrailHistory[j][1][0].z + this.shipTrailHistory[j][1][4].z;
t[0].points[2].x = this.shipTrailHistory[j][1][1].x + this.shipTrailHistory[j][1][4].x;
t[0].points[2].y = this.shipTrailHistory[j][1][1].y + this.shipTrailHistory[j][1][4].y;
t[0].points[2].z = this.shipTrailHistory[j][1][1].z + this.shipTrailHistory[j][1][4].z;
t[0].points[0].x = this.shipTrailHistory[j][0][0].x + this.shipTrailHistory[j][0][4].x;
t[0].points[0].y = this.shipTrailHistory[j][0][0].y + this.shipTrailHistory[j][0][4].y;
t[0].points[0].z = this.shipTrailHistory[j][0][0].z + this.shipTrailHistory[j][0][4].z;
t[0].points[1].x = this.shipTrailHistory[j][0][1].x + this.shipTrailHistory[j][0][4].x;
t[0].points[1].y = this.shipTrailHistory[j][0][1].y + this.shipTrailHistory[j][0][4].y;
t[0].points[1].z = this.shipTrailHistory[j][0][1].z + this.shipTrailHistory[j][0][4].z;
}
if (this.trailTicker <= 0) {
this.trailTicker = this.speed * 0.25;
}
}
updateSelection(_delta, _slerpAmt = -1) {
this.targetSplineId = this.splineId + 1;//INFO looking further down with higher speed?
while (this.targetSplineId >= this.level.trackBuilder.spline.length) {
this.targetSplineId -= this.level.trackBuilder.spline.length;
}
let splineRef = this.level.trackBuilder.spline[this.targetSplineId];
let targetVec = [splineRef.x - this.gondula.pos.x, splineRef.y - this.gondula.pos.y, splineRef.z - this.gondula.pos.z];
targetVec = gl_vec3.normalize(targetVec, targetVec);
let targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.gondula.transform.toVectorArray(this.gondula.transform.forward),
targetVec
)
this.gondula.rotateByQuaternion(targetRot);
//move gondula forward by spd
this.gondula.jumpToPosition({
x: this.gondula.pos.x + ((targetVec[0] * this.speed) * this.scene.dt),
y: this.gondula.pos.y + ((targetVec[1] * this.speed) * this.scene.dt),
z: this.gondula.pos.z + ((targetVec[2] * this.speed) * this.scene.dt)
});
//check if reached target
let d = gl_vec3.distance(this.gondula.transform.toVectorArray(this.gondula.pos), [splineRef.x, splineRef.y, splineRef.z]);
if (d <= 64) {
//let amt = Math.floor(criticalSpeed/64) + 1; //jumjp further if speed exceeds the distance between splines
this.splineId += 1//amt;
if (this.splineId >= this.level.trackBuilder.spline.length) {
this.splineId -= this.level.trackBuilder.spline.length;
}
}
//move Ship to gondula
let posFactor = 0.25 * this.scene.dt;// 0.5 //Math.max(0.01, ((this.speed + this.speedBonus) / (this.speedMax + this.speedBonus))) * 0.5;//todo: at max speed it still jitters
let rotFactor = 0.015 * this.scene.dt;//0.1 //Math.max(0.01, ((this.speed + this.speedBonus) / (this.speedMax + this.speedBonus)) * 0.1);
if (this.speed < 0.01) {
//posFactor = 0.5;
//rotFactor = 0.1;
}
if (_slerpAmt > 0) {
posFactor = 1;
rotFactor = 1;
}
let deltaPos = {
x: ((this.gondula.pos.x + (this.gondula.transform.up.x * -this.flightRadius))) - this.shipAnchor.pos.x,
y: ((this.gondula.pos.y + (this.gondula.transform.up.y * -this.flightRadius))) - this.shipAnchor.pos.y,
z: ((this.gondula.pos.z + (this.gondula.transform.up.z * -this.flightRadius))) - this.shipAnchor.pos.z
}
this.shipAnchor.jumpToPosition({
x: this.shipAnchor.pos.x + (deltaPos.x * posFactor),
y: this.shipAnchor.pos.y + (deltaPos.y * posFactor),
z: this.shipAnchor.pos.z + (deltaPos.z * posFactor)
});
//rotate ship Anchor to Gondula
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.shipAnchor.transform.toVectorArray(this.shipAnchor.transform.forward),
this.shipAnchor.transform.toVectorArray(splineRef.transform.forward)
)
let rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.shipAnchor.transform.rotationQuat, targetRot, rotFactor);
this.shipAnchor.rotateByQuaternion(rot);
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.shipAnchor.transform.toVectorArray(this.shipAnchor.transform.right),
this.shipAnchor.transform.toVectorArray(this.gondula.transform.right)
)
rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.shipAnchor.transform.rotationQuat, targetRot, rotFactor);
this.shipAnchor.rotateByQuaternion(rot);
//move and rotate ship model to actual ship anchor point
this.ship.jumpToPosition({ x: this.shipAnchor.pos.x, y: this.shipAnchor.pos.y, z: this.shipAnchor.pos.z });
//rotate ship to Gondula
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.ship.transform.toVectorArray(this.ship.transform.forward),
this.ship.transform.toVectorArray(splineRef.transform.forward)
)
rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.ship.transform.rotationQuat, targetRot, rotFactor);
this.ship.rotateByQuaternion(rot);
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.ship.transform.toVectorArray(this.ship.transform.right),
this.ship.transform.toVectorArray(this.gondula.transform.right)
)
rot = [0, 0, 0, 0];
rot = gl_quat.slerp(rot, this.ship.transform.rotationQuat, targetRot, rotFactor);
this.ship.rotateByQuaternion(rot);
for (let t of this.thrusters) {
//todo: get the saved original position of the vertex to move and add the move vector to keep the shape of the thruster to keep a cone shape
t.points[3].x = t.points[0].x + (this.gondula.transform.forward.x * (1 + (-56 * (this.speed / this.speedMax))));
t.points[3].y = t.points[0].y + (this.gondula.transform.forward.y * (1 + (-56 * (this.speed / this.speedMax))));
t.points[3].z = t.points[0].z + (this.gondula.transform.forward.z * (1 + (-56 * (this.speed / this.speedMax))));
t.points[2].x = t.points[1].x + (this.gondula.transform.forward.x * (1 + (-56 * (this.speed / this.speedMax))));
t.points[2].y = t.points[1].y + (this.gondula.transform.forward.y * (1 + (-56 * (this.speed / this.speedMax))));
t.points[2].z = t.points[1].z + (this.gondula.transform.forward.z * (1 + (-56 * (this.speed / this.speedMax))));
}
this.lensflares[this.lensflares.length - 1].jumpToPosition({
x: this.ship.pos.x + (this.ship.transform.forward.x * -66) + (this.ship.transform.up.x * 22),
y: this.ship.pos.y + (this.ship.transform.forward.y * -66) + (this.ship.transform.up.y * 22),
z: this.ship.pos.z + (this.ship.transform.forward.z * -66) + (this.ship.transform.up.z * 22),
}, true);
this.lensflares[this.lensflares.length - 1].quadData[0].alpha = 1 * this.speedFactor;//0.2
this.trailTicker -= this.scene.dt;
for (let [j, t] of this.trails.entries()) {
if (this.trailTicker <= 0) {
for (let i = t.length - 1; i > 0; i--) {
this.shipTrailHistory[j][i] = this.shipTrailHistory[j][i - 1]
}
}
this.shipTrailHistory[j][0] = this.ship.getWorldPositionOfQuad(this.shipSwooshOrigins[j]);
for (let p of this.shipTrailHistory[j][0]) {
p.x += this.ship.pos.x;
p.y += this.ship.pos.y;
p.z += this.ship.pos.z;
}
}
for (let [j, t] of this.trails.entries()) {//each trail
//this.swooshOrigins[j].jumpToPosition(this.ship.pos);
if (this.trailTicker <= 0) {
for (let i = t.length - 1; i > 0; i--) {//each trail quad / saved position
let q = t[i];//each quad
//jump end of trailpart to timesaved position
q.points[3].x = this.shipTrailHistory[j][i][0].x + this.shipTrailHistory[j][i][4].x;
q.points[3].y = this.shipTrailHistory[j][i][0].y + this.shipTrailHistory[j][i][4].y;
q.points[3].z = this.shipTrailHistory[j][i][0].z + this.shipTrailHistory[j][i][4].z;
q.points[2].x = this.shipTrailHistory[j][i][1].x + this.shipTrailHistory[j][i][4].x;
q.points[2].y = this.shipTrailHistory[j][i][1].y + this.shipTrailHistory[j][i][4].y;
q.points[2].z = this.shipTrailHistory[j][i][1].z + this.shipTrailHistory[j][i][4].z;
//jump start of trailpart to timesaved previous position
q.points[0].x = this.shipTrailHistory[j][i - 1][0].x + this.shipTrailHistory[j][i - 1][4].x;
q.points[0].y = this.shipTrailHistory[j][i - 1][0].y + this.shipTrailHistory[j][i - 1][4].y;
q.points[0].z = this.shipTrailHistory[j][i - 1][0].z + this.shipTrailHistory[j][i - 1][4].z;
q.points[1].x = this.shipTrailHistory[j][i - 1][1].x + this.shipTrailHistory[j][i - 1][4].x;
q.points[1].y = this.shipTrailHistory[j][i - 1][1].y + this.shipTrailHistory[j][i - 1][4].y;
q.points[1].z = this.shipTrailHistory[j][i - 1][1].z + this.shipTrailHistory[j][i - 1][4].z;
}
}
//correct first trail part that is connected to the ship
//jump end of trailpart to timesaved position
t[0].points[3].x = this.shipTrailHistory[j][1][0].x + this.shipTrailHistory[j][1][4].x;
t[0].points[3].y = this.shipTrailHistory[j][1][0].y + this.shipTrailHistory[j][1][4].y;
t[0].points[3].z = this.shipTrailHistory[j][1][0].z + this.shipTrailHistory[j][1][4].z;
t[0].points[2].x = this.shipTrailHistory[j][1][1].x + this.shipTrailHistory[j][1][4].x;
t[0].points[2].y = this.shipTrailHistory[j][1][1].y + this.shipTrailHistory[j][1][4].y;
t[0].points[2].z = this.shipTrailHistory[j][1][1].z + this.shipTrailHistory[j][1][4].z;
t[0].points[0].x = this.shipTrailHistory[j][0][0].x + this.shipTrailHistory[j][0][4].x;
t[0].points[0].y = this.shipTrailHistory[j][0][0].y + this.shipTrailHistory[j][0][4].y;
t[0].points[0].z = this.shipTrailHistory[j][0][0].z + this.shipTrailHistory[j][0][4].z;
t[0].points[1].x = this.shipTrailHistory[j][0][1].x + this.shipTrailHistory[j][0][4].x;
t[0].points[1].y = this.shipTrailHistory[j][0][1].y + this.shipTrailHistory[j][0][4].y;
t[0].points[1].z = this.shipTrailHistory[j][0][1].z + this.shipTrailHistory[j][0][4].z;
}
if (this.trailTicker <= 0) {
this.trailTicker = this.speed * 0.25;
}
}
setDraw(_bool) {
this.ship.flags.draw = _bool
for (let l of this.lensflares) {
l.flags.draw = _bool;
}
for (let s of this.swooshOrigins) {
s.flags.draw = _bool;
}
}
startNewLap() {
//save and show last laptime
this.lapTimes.push({
time: this.elapsedTime,
position: this.position
});
//this.last.lapTime = this.elapsedTime
//find fastest laptime
this.last.fastestLap = this.fastestLap;
let r = (60 * 60) * 1000;
for (let [i, l] of this.lapTimes.entries()) {
if (l.time < r) {
r = l.time;
this.fastestLap = i;
}
}
if (this.isPlayer === true) {
if (this.level.raceMode === this.level.raceModes.canyon) {
this.level.raceModeData.playerIsHunter = !this.level.raceModeData.playerIsHunter;
this.level.startNewCanyon();
} else {
this.level.startNewLap();
}
}
//start new lap time
this.startTime = Date.now();
this.elapsedTime = Date.now() - this.startTime;
}
restartOnFromSplineId(_splineId, _roll = 0) {
this.splineId = _splineId;
let splg = this.level.trackBuilder.spline[this.splineId];
this.gondula.jumpToPosition({ x: splg.x, y: splg.y, z: splg.z });
let targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.gondula.transform.toVectorArray(this.gondula.transform.forward),
[0, 0, 1]
)
this.gondula.rotateByQuaternion(targetRot);
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.gondula.transform.toVectorArray(this.gondula.transform.right),
[1, 0, 0]
)
this.gondula.rotateByQuaternion(targetRot);
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.gondula.transform.toVectorArray(this.gondula.transform.up),
[0, -1, 0]
)
this.gondula.rotateByQuaternion(targetRot);
this.gondula.rotateAroundAxis(this.gondula.transform.toVectorArray(this.gondula.transform.forward), _roll);
this.speed = 0;
//start from hangar?
if (this.level.startFromHangar === true) {
this.gondula.jumpToPosition({ x: this.gondula.pos.x + (this.gondula.transform.up.x * -244), y: this.gondula.pos.y + (this.gondula.transform.up.y * -244), z: this.gondula.pos.z + (this.gondula.transform.up.z * -244) });//y 468-128-96 init start
this.shipAnchor.jumpToPosition({ x: this.gondula.pos.x + (this.gondula.transform.up.x * -96), y: this.gondula.pos.y + (this.gondula.transform.up.y * -96), z: this.gondula.pos.z + (this.gondula.transform.up.z * -96) }, true);
this.ship.jumpToPosition({ x: this.gondula.pos.x + (this.gondula.transform.up.x * -96), y: this.gondula.pos.y + (this.gondula.transform.up.y * -96), z: this.gondula.pos.z + (this.gondula.transform.up.z * -96) }, true);
}
}
jumpToSplineId(_splineId, _roll = 0) {
this.splineId = _splineId;
let splg = this.level.trackBuilder.spline[this.splineId];
this.gondula.jumpToPosition({ x: splg.x, y: splg.y, z: splg.z });
let targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.gondula.transform.toVectorArray(this.gondula.transform.forward),
[0, 0, 1]
)
this.gondula.rotateByQuaternion(targetRot);
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.gondula.transform.toVectorArray(this.gondula.transform.right),
[1, 0, 0]
)
this.gondula.rotateByQuaternion(targetRot);
targetRot = [0, 0, 0, 0];
targetRot = gl_quat.rotationTo(targetRot,
this.gondula.transform.toVectorArray(this.gondula.transform.up),
[0, -1, 0]
)
this.gondula.rotateByQuaternion(targetRot);
this.gondula.rotateAroundAxis(this.gondula.transform.toVectorArray(this.gondula.transform.forward), _roll);
this.speed = 0;
//start from hangar?
if (this.level.startFromHangar === true) {
this.gondula.jumpToPosition({ x: this.gondula.pos.x + (this.gondula.transform.up.x * -244), y: this.gondula.pos.y + (this.gondula.transform.up.y * -244), z: this.gondula.pos.z + (this.gondula.transform.up.z * -244) });//y 468-128-96 init start
this.shipAnchor.jumpToPosition({ x: this.gondula.pos.x + (this.gondula.transform.up.x * -96), y: this.gondula.pos.y + (this.gondula.transform.up.y * -96), z: this.gondula.pos.z + (this.gondula.transform.up.z * -96) }, true);
this.ship.jumpToPosition({ x: this.gondula.pos.x + (this.gondula.transform.up.x * -96), y: this.gondula.pos.y + (this.gondula.transform.up.y * -96), z: this.gondula.pos.z + (this.gondula.transform.up.z * -96) }, true);
}
}
inputPlayer() {
let gamepad = null;
gamepad = navigator.getGamepads()[Math.max(0, gamepadsConnected - 1)];
if (gamepad === undefined) {
gamepad = null;
}
this.keyInput.spd = 0;
//this.keyInput.roll = 0;
this.keyInput.pitch = 0;
//acceleration
if (INPUTS.triggerRight.amount > 0.1) {
this.input.spd = this.acceleration;
this.keyInput.spd = 1;
} else {
this.input.spd = this.deceleration;
if (INPUTS.triggerLeft.amount > 0.1) {//redundant?
this.keyInput.spd = -1;
}
}
if (INPUTS.triggerLeft.amount > 0.1) {
this.input.spd = this.brakes;
this.keyInput.spd = -1;
}
//pitch with mouse //todo: pitch also with gamepad
if (this.scene.hand.useControllerMouse === false) {
this.keyInput.pitch = Math.max(-1, Math.min(this.scene.hand.pos.y * 0.01, 1));
} else {
//gamepad
//console.log(INPUTS.stickRight.vertical)
if (gamepad !== null) { //todo INFO + if options enabled gamepad control
let sra = Math.abs(INPUTS.stickRight.vertical);
let sla = Math.abs(INPUTS.stickLeft.vertical);
this.keyInput.pitch = (sra > sla ? (INPUTS.stickRight.vertical * -1) : (INPUTS.stickLeft.vertical * -1));
}
}
//if (this.keyInput.pitch <= -0.5 && this.jumping === false) {
if (this.jumping === false) {
if (this.keyInput.pitch - this.keyInput.previous.pitch < -0.5) {
this.jumping = true;
this.jumpingLasting = 30;
}
}
//instant acceleration with bonus
//todo: slipstreaming is the same, but without better acceleration
/*
if(this.scene.keys.space.isDown){
this.input.spd = 1;
this.speedBonus = 4;
this.speed += 4;
this.speed = Math.min(this.speedMax + this.speedBonus, this.speed);
this.speed = this.speedMax + this.speedBonus;
}else{
this.speedBonus = 0;
}
*/
//roll
if (this.scene.hand.useControllerMouse === false) {
if (INPUTS.stickLeft.horizontal !== 0) {
if (INPUTS.stickLeft.horizontal > 0) {
if (this.keyInput.roll < 1) {
this.keyInput.roll += 0.02 * this.scene.dt;
this.keyInput.roll = Math.min(this.keyInput.roll, 1);
}
}
if (INPUTS.stickLeft.horizontal < 0) {
if (this.keyInput.roll > -1) {
this.keyInput.roll -= 0.02 * this.scene.dt;
this.keyInput.roll = Math.max(this.keyInput.roll, -1);
}
}
} else {
if (this.keyInput.roll < 0) {
this.keyInput.roll += 0.1 * this.scene.dt;
this.keyInput.roll = Math.min(this.keyInput.roll, 0);
}
if (this.keyInput.roll > 0) {
this.keyInput.roll -= 0.1 * this.scene.dt;
this.keyInput.roll = Math.max(this.keyInput.roll, 0);
}
}
this.input.roll = this.keyInput.roll;
} else {
this.input.roll = Math.abs(INPUTS.stickLeft.horizontal) > 0.2 ? INPUTS.stickLeft.horizontal : 0;
}
if (this.scene.hand.pressed === true && isMobile === true) {
//todo: maybe only look around with touch when touching in upper area
let hAmt = (this.scene.hand.pos.x - this.scene.hand.start.x) * 0.005;
if (hAmt > 0.05 || hAmt < 0.05) {
this.input.roll += hAmt;
}
this.input.roll = Math.max(-1, Math.min(1, this.input.roll));
let vAmt = (this.scene.hand.pos.y - this.scene.hand.start.y) * 0.005;
if (vAmt > 0.05) {
this.input.spd = this.brakes;
this.keyInput.spd = -1;
this.keyInput.pitch = -1;
} else {
this.input.spd = this.acceleration;
this.keyInput.spd = 1;
this.keyInput.pitch = 1;
}
this.scene.hand.start.x = this.scene.hand.pos.x;
//this.scene.hand.start.y = this.scene.hand.pos.y;
}
if (this.scene.hand.pressed === false && isMobile === true) {
this.input.spd = this.deceleration;
this.keyInput.spd = -1;
}
//let curveDelta = Math.max(-1, Math.min((this.last.curveAmt - this.curveAmt), 1));
/*if(this.curveAmt > this.ai.curveRec){
this.ai.curveRec = this.curveAmt;
console.log("new rec");
}else if(this.curveAmt < this.ai.curveRec){
console.log("wrong dir")
this.ai.curveRec = -9999;
}*/
//if(Math.abs(curveDelta) > 0.12){
//console.log(curveDelta) //true is good
//}
//console.log(this.curveAmt)
//console.log(this.last.speedBonus - this.speedBonus)
//console.log(this.curveAmt > this.last.curveAmt)
//console.log(this.last.curveAmt - this.curveAmt)
//
this.keyInput.previous.pitch = this.keyInput.pitch;
this.keyInput.previous.spd = this.keyInput.spd;
this.keyInput.previous.roll = this.keyInput.roll;
}
inputAI(_bonusRef) {
//dumb forward
this.input.spd = this.acceleration;
this.keyInput.spd = 1;
//this.input.roll = 0;
//this.keyInput.pitch = 0;
let keyThink = {
spd: 0,
roll: 0,
pitch: 0
}
let avoid = [0, 0, 0]
//check Collisions
let collCheckArr = [
{//check forward of ship
pos: {
x: this.shipAnchor.pos.x,
y: this.shipAnchor.pos.y,
z: this.shipAnchor.pos.z
},
dir: {
x: this.shipAnchor.transform.forward.x,
y: this.shipAnchor.transform.forward.y,
z: this.shipAnchor.transform.forward.z
},
hit: []
}, {//check forward right of ship for booster
pos: {
x: this.shipAnchor.pos.x + (this.shipAnchor.transform.right.x * 48),
y: this.shipAnchor.pos.y + (this.shipAnchor.transform.right.y * 48),
z: this.shipAnchor.pos.z + (this.shipAnchor.transform.right.z * 48)
},
dir: {
x: this.shipAnchor.transform.forward.x,
y: this.shipAnchor.transform.forward.y,
z: this.shipAnchor.transform.forward.z
},
hit: []
}, {//check forward left of ship for booster
pos: {
x: this.shipAnchor.pos.x + (this.shipAnchor.transform.right.x * -48),
y: this.shipAnchor.pos.y + (this.shipAnchor.transform.right.y * -48),
z: this.shipAnchor.pos.z + (this.shipAnchor.transform.right.z * -48)
},
dir: {
x: this.shipAnchor.transform.forward.x,
y: this.shipAnchor.transform.forward.y,
z: this.shipAnchor.transform.forward.z
},
hit: []
}
];
let toCollideWith = [];
for (let o of this.level.trackBuilder.obstacles) {
if (o.data.id + 1 > this.splineId) {
if (o.trigger.isTrigger === false) {
toCollideWith.push(o);
}
}
}
for (let m of toCollideWith) {
if (m.flags.update === true) {
//m.update();
//INFOalready updated in the actual update
}
for (let q of m.collisionData) {
for (let c of collCheckArr) {
let hitData = this.scene.geometryController.collide(q, c);
if (hitData.pt !== null) {
hitData.model = m;
c.hit.push(hitData);
}
}
}
}
let alreadyColliding = false;
let returnColl = collCheckArr;
//resolve collision with forward
if (returnColl[0].hit.length > 0) {
//filter relevant = nearest hit
let dist = 9999;
let nearestHit = returnColl[0].hit[0];
for (let [i, n] of returnColl[0].hit.entries()) {
let d = eud.distance([this.shipAnchor.pos.x, this.shipAnchor.pos.y, this.shipAnchor.pos.z], returnColl[0].hit[i].pt)
if (d < dist) {
dist = d;
nearestHit = returnColl[0].hit[i];
}
}
if (dist < 2024) {
avoid[0] = dist;
}
if (dist < 128) {
alreadyColliding = true;
if (nearestHit.model.trigger.isTrigger === false) {
//console.log(returnColl[0]);
/*
if(this.speed > 0){
this.scene.soundManager.playRandomSound(this.scene.soundManager.bumpSound);
}
this.input.spd = 0;
this.speed = 0;
if(nearestHit.model.data.roll !== undefined){
this.input.roll = nearestHit.model.data.roll * 2;
}*/
} else {
//nearestHit.model.updateTrigger();
}
}
}
//check booster only if collision free
if (alreadyColliding === false) {
//resolve collision with forward right and then left of ship for boost
for (let j = 1; j < 3; j++) {
if (returnColl[j].hit.length > 0) {
//filter relevant = nearest hit
let dist = 9999;
let nearestHit = returnColl[j].hit[0];
for (let [i, n] of returnColl[j].hit.entries()) {
let d = eud.distance([returnColl[j].pos.x, returnColl[j].pos.y, returnColl[j].pos.z], returnColl[j].hit[i].pt)
if (d < dist) {
dist = d;
nearestHit = returnColl[j].hit[i];
}
}
if (dist < 2024) {
avoid[j] = dist;
}
if (dist < 128) {
if (nearestHit.model.trigger.isTrigger === false) {
/*if(this.speed > (this.speedMax * 0.25) && this.input.spd >= 0){
this.input.spd = 1;
this.speed = this.speedMax * this.nearmissBoost;
if(this.isPlayer === true){
if(this.scene.cam.fov < 3.5){//todo: find a good value for the boost effect
this.scene.cam.fov += 1 * this.scene.dt;
this.scene.cam.fov = Math.min(this.scene.cam.fov, 3.5);
}
//sound
this.scene.soundManager.playRandomSound(this.scene.soundManager.swooshSound);
}
}*/
} else {
//nearestHit.model.updateTrigger();
}
}
}
}
}
//switch to dodge mode if obstacle comes up
if (avoid[0] > 0 || avoid[1] > 0 || avoid[2] > 0) {
this.ai.navState = this.ai.navStates.dodge;
}
//smaller than 0 delta is good
let curveDelta = this.last.curveAmt - this.curveAmt;//Math.max(-1, Math.min((this.last.curveAmt - this.curveAmt) , 1));
let speedDelta = this.last.speedBonus - this.speedBonus;
//cooling strategy?
/*if(curveDelta > 0){
this.input.roll = -curveDelta;
}*/
/*
//todo: best one yet
this.input.roll = this.ai.prefRoll;
if(curveDelta > 0){
if(this.ai.waitRoll <= 0){
this.ai.prefRoll *= -1;
this.input.roll = 0;
//wait a bit until switching roll direction again
if(this.curveAmt > 0.01){
this.ai.waitRoll = 1;
}else{
this.ai.waitRoll = 15;
}
}else{
this.ai.waitRoll -= 1 * this.scene.dt;
}
}
*/
switch (this.ai.navState) {
case this.ai.navStates.seek:
//todo: works okay-ish but still gets overpowered by curveAmt delta fluctuations when already on right track or halfway between good or bad
//todo: because the fluctuation values are as small as a roll would be
if (this.curveAmt > this.ai.curveRec) {
this.ai.curveRec = this.curveAmt;
//this.input.roll = this.ai.prefRoll;
keyThink.roll = this.ai.prefRoll;
this.ai.lastGoodPrefRoll = this.ai.prefRoll;
//console.log(curveDelta)
}
if (curveDelta > 0 && curveDelta < 0.003) {
//console.log("flipping")
//this.ai.prefRoll *= -1;
this.ai.prefRoll = this.ai.lastGoodPrefRoll * -1;
}
if (this.curveAmt < 0) {
this.ai.curveRec = -9999;
//console.log("wrong side")
} else {
this.ai.waitRoll -= 1 * this.scene.dt;
if (this.ai.waitRoll <= 0) {
this.ai.waitRoll = 30;
this.ai.curveRec = -9999;
}
}
this.aiFindPitch();
break;
case this.ai.navStates.wait:
this.ai.waitRoll -= 1 * this.scene.dt;
if (this.ai.waitRoll <= 0 || curveDelta >= 2) {
if (curveDelta > 2) {
//console.log("curve changed > seek");
}
this.ai.navState = this.ai.navStates.seek;
this.ai.curveRec = -9999;
}
this.aiFindPitch();
break;
case this.ai.navStates.dodge:
//dodge
let finishedDodging = true;
if (avoid[0] > 0) {//middle
//this.input.roll = this.ai.prefRoll;
keyThink.roll = this.ai.prefRoll;
if (avoid[0] < 1024) {
this.input.spd = this.brakes;
} else {
this.input.spd = this.deceleration;
}
this.keyInput.spd = -1;
this.aiFindPitch(false);//this.keyInput.pitch = -1;
//console.log("collision happening or imminent")
finishedDodging = false;
}
else if (avoid[1] > 0) {//right
//this.input.roll = -1;
keyThink.roll = -1;
this.ai.prefRoll = -1;
this.input.spd = this.acceleration;
this.keyInput.spd = 1;
this.aiFindPitch();//this.keyInput.pitch = 1;
//console.log("left")
finishedDodging = false;
}
else if (avoid[2] > 0) {//left
//this.input.roll = 1;
keyThink.roll = 1;
this.ai.prefRoll = 1;
this.input.spd = this.acceleration;
this.keyInput.spd = 1;
this.aiFindPitch();//this.keyInput.pitch = 1;
//console.log("right")
finishedDodging = false;
}
if (finishedDodging === true) {
this.ai.navState = this.ai.navStates.seek;
}
break;
default:
break;
}
this.aiFindRoll(keyThink.roll);
}
aiFindRoll(_thinkRoll) {
if (_thinkRoll !== 0) {
if (_thinkRoll > 0) {
if (this.keyInput.roll < 1) {
this.keyInput.roll += 0.02 * this.scene.dt;
this.keyInput.roll = Math.min(this.keyInput.roll, 1);
}
}
if (_thinkRoll < 0) {
if (this.keyInput.roll > -1) {
this.keyInput.roll -= 0.02 * this.scene.dt;
this.keyInput.roll = Math.max(this.keyInput.roll, -1);
}
}
} else {
if (this.keyInput.roll < 0) {
this.keyInput.roll += 0.1 * this.scene.dt;
this.keyInput.roll = Math.min(this.keyInput.roll, 0);
}
if (this.keyInput.roll > 0) {
this.keyInput.roll -= 0.1 * this.scene.dt;
this.keyInput.roll = Math.max(this.keyInput.roll, 0);
}
}
this.input.roll = this.keyInput.roll;
}
aiFindPitch(_allowHeat = true) {
//let distToPerfectPitchPlanned = 64 - (32 * this.curveAmt) - (32 * this.pitch.current) - (this.pitch.current * 32);
//this.distToPerfectPitch = Math.max(-64, Math.min(distToPerfectPitchPlanned, 64));
if (_allowHeat === true) {
if (this.distToPerfectPitch > 1) {
this.keyInput.pitch += 0.001 * this.scene.dt;
} else {
this.keyInput.pitch -= 0.01 * this.scene.dt;
}
} else {
if (this.distToPerfectPitch > 32) {
this.keyInput.pitch += 0.001 * this.scene.dt;
} else {
this.keyInput.pitch -= 0.01 * this.scene.dt;
}
}
}
}