inertialrush-game-test
Version:
This package enables the integration of the Inertial Rush game into any React application, making it easy to showcase the game.
773 lines (656 loc) • 21.2 kB
JavaScript
/*
* HexGL
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
*/
var bkcore = bkcore || {};
bkcore.hexgl = bkcore.hexgl || {};
bkcore.hexgl.ShipControls = function(ctx)
{
this.dt = 1;
this.name = "";
this.sounds = 1;
var self = this;
var domElement = ctx.document;
this.active = true;
this.destroyed = false;
this.falling = false;
this.isGarage = false;
this.dom = domElement;
this.mesh = null;
this.epsilon = 0.00000001;
this.zero = new THREE.Vector3(0,0,0);
this.airResist = 0.02;
this.airDrift = 0.1;
this.thrust = 0.02;
this.airBrake = 0.02;
this.maxSpeed = 7.0;
this.boosterSpeed = this.maxSpeed * 0.2;
this.boosterDecay = 0.01;
this.angularSpeed = 0.005;
this.airAngularSpeed = 0.0065;
this.repulsionRatio = 0.5;
this.repulsionCap = 2.5;
this.repulsionLerp = 0.1;
this.collisionSpeedDecrease = 0.8;
this.collisionSpeedDecreaseCoef = 0.8;
this.maxShield = 0.5;
this.shieldDelay = 60;
this.shieldTiming = 0;
this.shieldDamage = 0.25;
this.driftLerp = 0.35;
this.angularLerp = 0.35;
this.movement = new THREE.Vector3(0,0,0);
this.rotation = new THREE.Vector3(0,0,0);
this.roll = 0.0;
this.rollAxis = new THREE.Vector3();
this.drift = 0.0;
this.speed = 0.0;
this.speedRatio = 0.0;
this.boost = 0.0;
this.shield = 0.5;
this.angular = 0.0;
this.currentVelocity = new THREE.Vector3();
this.quaternion = new THREE.Quaternion();
this.dummy = new THREE.Object3D();
this.collisionMap = null;
this.collisionPixelRatio = 1.0;
this.collisionDetection = false;
this.collisionPreviousPosition = new THREE.Vector3();
this.heightMap = null;
this.heightPixelRatio = 1.0;
this.heightBias = 0.0;
this.heightLerp = 0.4;
this.heightScale = 1.0;
this.rollAngle = 0.6;
this.rollLerp = 0.08;
this.rollDirection = new THREE.Vector3(0,0,1);
this.gradient = 0.0;
this.gradientTarget = 0.0;
this.gradientLerp = 0.05;
this.gradientScale = 4.0;
this.gradientVector = new THREE.Vector3(0,0,5);
this.gradientAxis = new THREE.Vector3(1,0,0);
this.tilt = 0.0;
this.tiltTarget = 0.0;
this.tiltLerp = 0.05;
this.tiltScale = 4.0;
this.tiltVector = new THREE.Vector3(5,0,0);
this.tiltAxis = new THREE.Vector3(0,0,1);
this.repulsionVLeft = new THREE.Vector3(1,0,0);
this.repulsionVRight = new THREE.Vector3(-1,0,0);
this.repulsionVFront = new THREE.Vector3(0,0,1);
this.repulsionVScale = 4.0;
this.repulsionAmount = 0.0;
this.repulsionForce = new THREE.Vector3();
this.fallVector = new THREE.Vector3(0,-20,0);
this.resetPos = null;
this.resetRot = null;
this.key = {
forward: false,
backward: false,
left: false,
right: false,
ltrigger: false,
rtrigger: false,
use: false
};
this.collision = {
front: false,
left: false,
right: false
};
this.touchController = null;
this.orientationController = null;
this.gamepadController = null
if(ctx.controlType == 1 && bkcore.controllers.TouchController.isCompatible())
{
this.touchController = new bkcore.controllers.TouchController(
domElement, ctx.width/2,
function(state, touch, event){
if(event.touches.length >= 4)
window.location.reload(false);
else if(event.touches.length == 3)
ctx.restart();
// touch was on the right-hand side of the screen
else if (touch.clientX > (ctx.width / 2)) {
if (event.type === 'touchend')
self.key.forward = false;
else
self.key.forward = true;
}
});
}
else if(ctx.controlType == 4 && bkcore.controllers.OrientationController.isCompatible())
{
this.orientationController = new bkcore.controllers.OrientationController(
domElement, true,
function(state, touch, event){
if(event.touches.length >= 4)
window.location.reload(false);
else if(event.touches.length == 3)
ctx.restart();
else if(event.touches.length < 1)
self.key.forward = false;
else
self.key.forward = true;
});
}
else if(ctx.controlType == 3 && bkcore.controllers.GamepadController.isCompatible())
{
this.gamepadController = new bkcore.controllers.GamepadController(
function(controller){
if (controller.select)
ctx.restart();
else
self.key.forward = controller.acceleration > 0;
self.key.ltrigger = controller.ltrigger > 0;
self.key.rtrigger = controller.rtrigger > 0;
self.key.left = controller.lstickx < -0.1;
self.key.right = controller.lstickx > 0.1;
});
}
else if(ctx.controlType == 2)
{
if(Leap == null)
throw new Error("Unable to reach LeapJS!");
var leapInfo = this.leapInfo = document.getElementById('leapinfo');
isServerConnected = false;
var lb = this.leapBridge = {
isConnected: true,
hasHands: false,
palmNormal: [0, 0, 0]
};
function updateInfo()
{
if(!isServerConnected)
{
leapInfo.innerHTML = 'Waiting for the Leap Motion Controller server...'
leapInfo.style.display = 'block';
}
else if(lb.isConnected && lb.hasHands)
{
leapInfo.style.display = 'none';
}
else if(!lb.isConnected)
{
leapInfo.innerHTML = 'Please connect your Leap Motion Controller.'
leapInfo.style.display = 'block';
}
else if(!lb.hasHands)
{
leapInfo.innerHTML = 'Put your hand over the Leap Motion Controller to play.'
leapInfo.style.display = 'block';
}
}
updateInfo();
var lc = this.leapController = new Leap.Controller({enableGestures: false});
lc.on('connect', function()
{
isServerConnected = true;
updateInfo();
});
lc.on('deviceConnected', function()
{
lb.isConnected = true;
updateInfo();
});
lc.on('deviceDisconnected', function()
{
lb.isConnected = false;
updateInfo();
});
lc.on('frame', function(frame)
{
if(!lb.isConnected) return;
hand = frame.hands[0];
if(typeof hand === 'undefined')
{
if(lb.hasHands)
{
lb.hasHands = false;
updateInfo();
}
lb.palmNormal = [0, 0, 0];
}
else
{
if(!lb.hasHands)
{
lb.hasHands = true;
updateInfo();
}
lb.palmNormal = hand.palmNormal;
}
});
lc.connect();
}
function onKeyDown(event) {
switch (event.keyCode) {
case 38: /*up*/
self.key.forward = true;
break;
case 40: /*down*/
self.key.backward = true;
break;
case 37: /*left*/
self.key.left = true;
break;
case 39: /*right*/
self.key.right = true;
break;
case 81: /*Q*/
self.key.ltrigger = true;
break;
case 65: /*A*/
self.key.ltrigger = true;
break;
case 68: /*D*/
self.key.rtrigger = true;
break;
case 69: /*E*/
self.key.rtrigger = true;
break;
}
}
function onKeyUp(event) {
switch (event.keyCode) {
case 38: /*up*/
self.key.forward = false;
break;
case 40: /*down*/
self.key.backward = false;
break;
case 37: /*left*/
self.key.left = false;
break;
case 39: /*right*/
self.key.right = false;
break;
case 81: /*Q*/
self.key.ltrigger = false;
break;
case 65: /*A*/
self.key.ltrigger = false;
break;
case 68: /*D*/
self.key.rtrigger = false;
break;
case 69: /*E*/
self.key.rtrigger = false;
break;
}
}
domElement.addEventListener('keydown', onKeyDown, false);
domElement.addEventListener('keyup', onKeyUp, false);
};
bkcore.hexgl.ShipControls.prototype.control = function(threeMesh)
{
this.mesh = threeMesh;
this.mesh.martixAutoUpdate = false;
this.mesh.matrixAutoUpdate = false;
this.dummy.position.copy(this.mesh.position);
};
bkcore.hexgl.ShipControls.prototype.reset = function(position)
{
this.movement.set(0,0,0);
this.roll = 0.0;
this.drift = 0.0;
this.speed = 0.0;
this.speedRatio = 0.0;
this.boost = 0.0;
this.shield = this.maxShield;
this.destroyed = false;
this.dummy.position.copy(position);
this.quaternion.set(0, -1, 0, 1).normalize();
this.dummy.quaternion.set(0,0,0,1);
this.dummy.quaternion.multiply(this.quaternion);
this.dummy.matrix.makeRotationFromQuaternion(this.dummy.quaternion);
this.dummy.matrix.setPosition(this.dummy.position);
this.mesh.matrix.identity();
this.mesh.applyMatrix4(this.dummy.matrix);
}
bkcore.hexgl.ShipControls.prototype.terminate = function()
{
this.destroy();
if(this.leapController != null)
{
this.leapController.disconnect();
this.leapInfo.style.display = 'none';
}
}
bkcore.hexgl.ShipControls.prototype.destroy = function(otherShip)
{
if (this.sounds && !otherShip) {
bkcore.Audio.play('destroyed');
bkcore.Audio.stop('bg');
bkcore.Audio.stop('wind');
}
this.active = false;
this.destroyed = true;
this.collision.front = false;
this.collision.left = false;
this.collision.right = false;
}
bkcore.hexgl.ShipControls.prototype.fall = function()
{
this.active = false;
this.collision.front = false;
this.collision.left = false;
this.collision.right = false;
this.falling = true;
_this = this;
setTimeout(function(){
_this.destroyed = true;
}, 1500);
}
bkcore.hexgl.ShipControls.prototype.requestUpdate = function (dt) {
this.dt = dt;
const dataToSendArr = [];
dataToSendArr[0] = dt.toFixed(4)
dataToSendArr[1] = this.key.forward ? 1 : undefined
dataToSendArr[2] = this.key.left ? 1 : undefined
dataToSendArr[3] = this.key.right ? 1 : undefined
dataToSendArr[4] = this.key.ltrigger ? 1 : undefined
dataToSendArr[5] = this.key.rtrigger ? 1 : undefined
if (this.touchController != null) {
dataToSendArr[6] = this.touchController;
} else if (this.orientationController != null) {
dataToSendArr[7] = this.orientationController;
} else if (this.gamepadController != null && this.gamepadController.updateAvailable()) {
dataToSendArr[8] = this.gamepadController;
dataToSendArr[9] = this.gamepadController.updateAvailable();
} else if (this.leapBridge != null && this.leapBridge.hasHands) {
dataToSendArr[10] = this.leapBridge;
}
for (let i = 0; i < dataToSendArr.length; i++) {
if (dataToSendArr[i] === 0 || dataToSendArr[i] === -0 || !dataToSendArr[i]) {
delete dataToSendArr[i];
}
}
const dataToSendStr = dataToSendArr.join();
sendMessage(bkcore.hexgl.connectionToSocket, "u", dataToSendStr);
};
bkcore.hexgl.ShipControls.prototype.update = function(message, otherShip)
{
const {
rollAmount,
shield,
dummyX,
dummyY,
dummyZ,
quaternionX,
quaternionY,
quaternionZ,
quaternionW,
} = message
this.shield = shield
this.dummy.position.set(dummyX, dummyY, dummyZ)
this.dummy.quaternion.set(quaternionX, quaternionY, quaternionZ, quaternionW).normalize()
this.boosterCheck(otherShip);
this.heightCheck();
this.collisionCheck(otherShip);
this.dummy.matrix.makeRotationFromQuaternion(this.dummy.quaternion);
this.dummy.matrix.setPosition(this.dummy.position);
if(this.shield <= 0.0)
{
this.destroy(otherShip);
}
var yawLeap = 0.0;
if (this.active) {
if (this.leapBridge != null && this.leapBridge.hasHands) {
yawLeap = -this.leapBridge.palmNormal[2] * 0.6;
this.speed += Math.max(0.0, 0.5 + this.leapBridge.palmNormal[2]) * 3 * this.thrust * this.dt;
}
if (this.key.forward) {
this.speed += this.thrust * this.dt;
} else {
this.speed -= this.airResist * this.dt;
}
if (this.key.ltrigger) {
this.speed -= this.airBrake * this.dt;
}
if (this.key.rtrigger) {
this.speed -= this.airBrake * this.dt;
}
}
this.speed = Math.max(0.0, Math.min(this.speed, this.maxSpeed));
if(this.mesh != null)
{
this.mesh.matrix.identity();
var tempMatrixRotation = new THREE.Matrix4();
// Gradient (Mesh only, no dummy physics impact)
var gradientDelta = (this.gradientTarget - (yawLeap + this.gradient)) * this.gradientLerp;
if(Math.abs(gradientDelta) > this.epsilon) this.gradient += gradientDelta;
if(Math.abs(this.gradient) > this.epsilon)
{
this.gradientAxis.set(1,0,0);
/*this.mesh.matrix.rotateByAxis(this.gradientAxis, this.gradient);*/
tempMatrixRotation.makeRotationAxis(this.gradientAxis, this.gradient);
this.mesh.matrix.multiply( tempMatrixRotation );
}
// Tilting (Idem)
var tiltDelta = (this.tiltTarget - this.tilt) * this.tiltLerp;
if(Math.abs(tiltDelta) > this.epsilon) this.tilt += tiltDelta;
if(Math.abs(this.tilt) > this.epsilon)
{
this.tiltAxis.set(0,0,1);
/*this.mesh.matrix.rotateByAxis(this.tiltAxis, this.tilt);*/
tempMatrixRotation.makeRotationAxis(this.tiltAxis, this.tilt);
this.mesh.matrix.multiply( tempMatrixRotation );
}
// Rolling (Idem)
var rollDelta = (rollAmount - this.roll) * this.rollLerp;
if(Math.abs(rollDelta) > this.epsilon) this.roll += rollDelta;
if(Math.abs(this.roll) > this.epsilon)
{
this.rollAxis.copy(this.rollDirection);
/*this.mesh.matrix.rotateByAxis(this.rollAxis, this.roll);*/
tempMatrixRotation.makeRotationAxis(this.rollAxis, this.roll);
this.mesh.matrix.multiply( tempMatrixRotation );
}
this.mesh.applyMatrix4(this.dummy.matrix);
this.mesh.updateMatrixWorld(true);
}
if(this.isGarage) this.reset(new THREE.Vector3( -782, 399, 1399 ));
//Update listener position
if(!otherShip) {
bkcore.Audio.setListenerPos(this.movement);
bkcore.Audio.setListenerVelocity(this.currentVelocity);
}
};
bkcore.hexgl.ShipControls.prototype.teleport = function(pos, quat)
{
this.quaternion.copy(quat);
this.dummy.quaternion.copy(this.quaternion);
this.dummy.position.copy(pos);
this.dummy.matrix.makeRotationFromQuaternion(this.dummy.quaternion);
this.dummy.matrix.setPosition(this.dummy.position);
if(this.mesh != null)
{
this.mesh.matrix.identity();
var tempMatrixRotation = new THREE.Matrix4();
// Gradient (Mesh only, no dummy physics impact)
var gradientDelta = (this.gradientTarget - this.gradient) * this.gradientLerp;
if(Math.abs(gradientDelta) > this.epsilon) this.gradient += gradientDelta;
if(Math.abs(this.gradient) > this.epsilon)
{
this.gradientAxis.set(1,0,0);
/*this.mesh.matrix.rotateByAxis(this.gradientAxis, this.gradient);*/
tempMatrixRotation.makeRotationAxis(this.gradientAxis, this.gradient);
this.mesh.matrix.multiply( tempMatrixRotation );
}
// Tilting (Idem)
var tiltDelta = (this.tiltTarget - this.tilt) * this.tiltLerp;
if(Math.abs(tiltDelta) > this.epsilon) this.tilt += tiltDelta;
if(Math.abs(this.tilt) > this.epsilon)
{
this.tiltAxis.set(0,0,1);
/*this.mesh.matrix.rotateByAxis(this.tiltAxis, this.tilt);*/
tempMatrixRotation.makeRotationAxis(this.tiltAxis, this.tilt);
this.mesh.matrix.multiply( tempMatrixRotation );
}
this.mesh.applyMatrix4(this.dummy.matrix);
this.mesh.updateMatrixWorld(true);
}
}
bkcore.hexgl.ShipControls.prototype.boosterCheck = function(otherShip)
{
if(!this.collisionMap || !this.collisionMap.loaded)
return false;
this.boost -= this.boosterDecay * this.dt;
if(this.boost < 0){
this.boost = 0.0;
if(this.sounds && !otherShip) bkcore.Audio.stop('boost');
}
var x = Math.round(this.collisionMap.pixels.width/2 + this.dummy.position.x * this.collisionPixelRatio);
var z = Math.round(this.collisionMap.pixels.height/2 + this.dummy.position.z * this.collisionPixelRatio);
var color = this.collisionMap.getPixel(x, z);
if(color.r == 255 && color.g < 127 && color.b < 127) {
if(this.sounds && !otherShip) bkcore.Audio.play('boost');
this.boost = this.boosterSpeed;
}
}
bkcore.hexgl.ShipControls.prototype.collisionCheck = function(otherShip)
{
if(!this.collisionDetection || !this.collisionMap || !this.collisionMap.loaded)
return false;
this.collision.left = false;
this.collision.right = false;
this.collision.front = false;
var x = Math.round(this.collisionMap.pixels.width/2 + this.dummy.position.x * this.collisionPixelRatio);
var z = Math.round(this.collisionMap.pixels.height/2 + this.dummy.position.z * this.collisionPixelRatio);
var pos = new THREE.Vector3(x, 0, z);
var collision = this.collisionMap.getPixelBilinear(x, z);
// Repulsion
this.repulsionVLeft.set(1,0,0);
this.repulsionVRight.set(-1,0,0);
this.repulsionVLeft.transformDirection(this.dummy.matrix);
this.repulsionVRight.transformDirection(this.dummy.matrix);
this.repulsionVLeft.multiplyScalar(this.repulsionVScale);
this.repulsionVRight.multiplyScalar(this.repulsionVScale);
var lPos = this.repulsionVLeft.add(pos);
var rPos = this.repulsionVRight.add(pos);
var lCol = this.collisionMap.getPixel(Math.round(lPos.x), Math.round(lPos.z)).r;
var rCol = this.collisionMap.getPixel(Math.round(rPos.x), Math.round(rPos.z)).r;
if(collision.r < 255)
{
if(this.sounds && !otherShip) bkcore.Audio.play('crash');
if(rCol > lCol)
{// Repulse right
this.collision.left = true;
}
else if(rCol < lCol)
{// Repulse left
this.collision.right = true;
}
else
{
this.collision.front = true;
this.speed = 0;
}
this.speed *= this.collisionSpeedDecrease;
this.speed *= (1-this.collisionSpeedDecreaseCoef*(1-collision.r/255));
this.boost = 0;
return true;
}
}
bkcore.hexgl.ShipControls.prototype.heightCheck = function()
{
if(!this.heightMap || !this.heightMap.loaded)
return false;
var x = this.heightMap.pixels.width/2 + this.dummy.position.x * this.heightPixelRatio;
var z = this.heightMap.pixels.height/2 + this.dummy.position.z * this.heightPixelRatio;
var height = this.heightMap.getPixelFBilinear(x, z) / this.heightScale + this.heightBias;
if(height < 16777)
{
var delta = (height - this.dummy.position.y);
if(delta > 0)
{
this.movement.y += delta;
}
else
{
this.movement.y += delta * this.heightLerp;
}
}
// gradient
this.gradientVector.set(0,0,5);
this.gradientVector.transformDirection( this.dummy.matrix );
this.gradientVector.add(this.dummy.position);
x = this.heightMap.pixels.width/2 + this.gradientVector.x * this.heightPixelRatio;
z = this.heightMap.pixels.height/2 + this.gradientVector.z * this.heightPixelRatio;
var nheight = this.heightMap.getPixelFBilinear(x, z) / this.heightScale + this.heightBias;
if(nheight < 16777)
this.gradientTarget = -Math.atan2(nheight-height, 5.0)*this.gradientScale;
// tilt
this.tiltVector.set(5,0,0);
this.tiltVector.transformDirection(this.dummy.matrix);
this.tiltVector.add(this.dummy.position);
x = this.heightMap.pixels.width/2 + this.tiltVector.x * this.heightPixelRatio;
z = this.heightMap.pixels.height/2 + this.tiltVector.z * this.heightPixelRatio;
nheight = this.heightMap.getPixelFBilinear(x, z) / this.heightScale + this.heightBias;
if(nheight >= 16777) // If right project out of bounds, try left projection
{
this.tiltVector.sub(this.dummy.position).multiplyScalar(-1).add(this.dummy.position);
x = this.heightMap.pixels.width/2 + this.tiltVector.x * this.heightPixelRatio;
z = this.heightMap.pixels.height/2 + this.tiltVector.z * this.heightPixelRatio;
nheight = this.heightMap.getPixelFBilinear(x, z) / this.heightScale + this.heightBias;
}
if(nheight < 16777)
this.tiltTarget = Math.atan2(nheight-height, 5.0)*this.tiltScale;
};
bkcore.hexgl.ShipControls.prototype.inGarage = function() {
this.active = false;
this.isGarage = true;
const garage = this.dom.querySelector('#garage')
garage.style.display = 'block'
garage.querySelector('#garage_close').addEventListener('click', () => {
garage.style.display = 'none'
sendMessage(bkcore.hexgl.connectionToSocket, "g", '');
this.active = true;
this.isGarage = false;
})
}
bkcore.hexgl.ShipControls.prototype.getRealSpeed = function(scale)
{
return Math.round(
(this.speed+this.boost)
* (scale == undefined ? 1 : scale)
);
};
bkcore.hexgl.ShipControls.prototype.getRealSpeedRatio = function()
{
return Math.min(
this.maxSpeed,
this.speed+this.boost
) / this.maxSpeed;
};
bkcore.hexgl.ShipControls.prototype.getSpeedRatio = function()
{
return (this.speed+this.boost)/ this.maxSpeed;
};
bkcore.hexgl.ShipControls.prototype.getBoostRatio = function()
{
return this.boost / this.boosterSpeed;
};
bkcore.hexgl.ShipControls.prototype.getShieldRatio = function()
{
return this.shield / this.maxShield;
};
bkcore.hexgl.ShipControls.prototype.getShield = function(scale)
{
return Math.round(
this.shield
* (scale == undefined ? 1 : scale)
);
};
bkcore.hexgl.ShipControls.prototype.getPosition = function()
{
return this.dummy.position;
}
bkcore.hexgl.ShipControls.prototype.getQuaternion = function()
{
return this.dummy.quaternion;
}