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)//<<< 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; } } } }