UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

364 lines (320 loc) 11 kB
var Vehicle = pc.createScript('vehicle'); Vehicle.attributes.add('wheels', { type: 'entity', array: true, title: 'Wheels' }); Vehicle.attributes.add('maxEngineForce', { type: 'number', default: 2000, title: 'Max Engine Force' }); Vehicle.attributes.add('maxBrakingForce', { type: 'number', default: 100, title: 'Max Braking Force' }); Vehicle.attributes.add('maxSteering', { type: 'number', default: 0.3, title: 'Max Steering' }); Object.defineProperty(Vehicle.prototype, 'speed', { get: function () { return this.vehicle ? this.vehicle.getCurrentSpeedKmHour() : 0; } }); // initialize code called once per entity Vehicle.prototype.initialize = function () { var body = this.entity.rigidbody.body; var dynamicsWorld = this.app.systems.rigidbody.dynamicsWorld; // Create vehicle var tuning = new Ammo.btVehicleTuning(); var vehicleRayCaster = new Ammo.btDefaultVehicleRaycaster(dynamicsWorld); var vehicle = new Ammo.btRaycastVehicle(tuning, body, vehicleRayCaster); vehicle.setCoordinateSystem(0, 1, 2); // Never deactivate the vehicle var DISABLE_DEACTIVATION = 4; body.setActivationState(DISABLE_DEACTIVATION); // Add wheels to the vehicle var wheelAxle = new Ammo.btVector3(-1, 0, 0); var wheelDirection = new Ammo.btVector3(0, -1, 0); var connectionPoint = new Ammo.btVector3(0, 0, 0); this.wheels.forEach((wheelEntity) => { var wheelScript = wheelEntity.script.vehicleWheel; var frictionSlip = wheelScript.frictionSlip; var isFront = wheelScript.isFront; var radius = wheelScript.radius; var rollInfluence = wheelScript.rollInfluence; var suspensionCompression = wheelScript.suspensionCompression; var suspensionDamping = wheelScript.suspensionDamping; var suspensionRestLength = wheelScript.suspensionRestLength; var suspensionStiffness = wheelScript.suspensionStiffness; var wheelPos = wheelEntity.getLocalPosition(); connectionPoint.setValue(wheelPos.x, wheelPos.y, wheelPos.z); var wheelInfo = vehicle.addWheel(connectionPoint, wheelDirection, wheelAxle, suspensionRestLength, radius, tuning, isFront); wheelInfo.set_m_suspensionStiffness(suspensionStiffness); wheelInfo.set_m_wheelsDampingRelaxation(suspensionDamping); wheelInfo.set_m_wheelsDampingCompression(suspensionCompression); wheelInfo.set_m_frictionSlip(frictionSlip); wheelInfo.set_m_rollInfluence(rollInfluence); }, this); Ammo.destroy(wheelAxle); Ammo.destroy(wheelDirection); Ammo.destroy(connectionPoint); // Add the vehicle to the dynamics world dynamicsWorld.addAction(vehicle); this.vehicle = vehicle; this.engineForce = 0; this.brakingForce = 0; this.steering = 0; // Event handling this.on('enable', () => { dynamicsWorld.addAction(vehicle); }); this.on('disable', () => { dynamicsWorld.removeAction(vehicle); }); this.on('destroy', () => { dynamicsWorld.removeAction(vehicle); Ammo.destroy(vehicleRayCaster); Ammo.destroy(vehicle); }); this.on('vehicle:controls', function (steering, throttle) { this.steering = pc.math.lerp(this.steering, steering * this.maxSteering, 0.3); if (throttle > 0) { this.brakingForce = 0; this.engineForce = this.maxEngineForce; } else if (throttle < 0) { this.brakingForce = 0; this.engineForce = -this.maxEngineForce; } else { this.brakingForce = this.maxBrakingForce; this.engineForce = 0; } }); }; // update code called every frame Vehicle.prototype.update = function (dt) { var vehicle = this.vehicle; var i; var body = this.entity.rigidbody.body; var DISABLE_DEACTIVATION = 4; body.setActivationState(DISABLE_DEACTIVATION); // Apply steering to the front wheels vehicle.setSteeringValue(this.steering, 0); vehicle.setSteeringValue(this.steering, 1); // Apply engine and braking force to the back wheels vehicle.applyEngineForce(this.engineForce, 2); vehicle.setBrake(this.brakingForce, 2); vehicle.applyEngineForce(this.engineForce, 3); vehicle.setBrake(this.brakingForce, 3); var numWheels = vehicle.getNumWheels(); for (i = 0; i < numWheels; i++) { // synchronize the wheels with the (interpolated) chassis worldtransform vehicle.updateWheelTransform(i, true); var t = this.vehicle.getWheelTransformWS(i); var p = t.getOrigin(); var q = t.getRotation(); var wheel = this.wheels[i]; wheel.setPosition(p.x(), p.y(), p.z()); wheel.setRotation(q.x(), q.y(), q.z(), q.w()); } }; var VehicleWheel = pc.createScript('vehicleWheel'); VehicleWheel.attributes.add('isFront', { type: 'boolean', default: true, title: 'Front Wheel' }); VehicleWheel.attributes.add('radius', { type: 'number', default: 0.4, title: 'Radius' }); VehicleWheel.attributes.add('width', { type: 'number', default: 0.4, title: 'Width' }); VehicleWheel.attributes.add('suspensionStiffness', { type: 'number', default: 10, title: 'Suspension Stiffness' }); VehicleWheel.attributes.add('suspensionDamping', { type: 'number', default: 2.3, title: 'Suspension Damping' }); VehicleWheel.attributes.add('suspensionCompression', { type: 'number', default: 4.4, title: 'Suspension Compression' }); VehicleWheel.attributes.add('suspensionRestLength', { type: 'number', default: 0.4, title: 'Suspension Rest Length' }); VehicleWheel.attributes.add('rollInfluence', { type: 'number', default: 0.2, title: 'Roll Influence' }); VehicleWheel.attributes.add('frictionSlip', { type: 'number', default: 1000, title: 'Friction Slip' }); VehicleWheel.attributes.add('debugRender', { type: 'boolean', default: false, title: 'Debug Render' }); VehicleWheel.prototype.initialize = function () { var createDebugWheel = function (radius, width) { var debugWheel = new pc.Entity(); debugWheel.addComponent('model', { type: 'cylinder', castShadows: true }); debugWheel.setLocalEulerAngles(0, 0, 90); debugWheel.setLocalScale(radius * 2, width, radius * 2); return debugWheel; }; if (this.debugRender) { this.debugWheel = createDebugWheel(this.radius, this.width); this.entity.addChild(this.debugWheel); } this.on('attr:debugRender', function (value, prev) { if (value) { this.debugWheel = createDebugWheel(this.radius, this.width); this.entity.addChild(this.debugWheel); } else { if (this.debugWheel) { this.debugWheel.destroy(); this.debugWheel = null; } } }); }; var VehicleControls = pc.createScript('vehicleControls'); VehicleControls.attributes.add('targetVehicle', { type: 'entity', title: 'Target Vehicle' }); VehicleControls.attributes.add('leftButton', { type: 'entity', title: 'Left Button' }); VehicleControls.attributes.add('rightButton', { type: 'entity', title: 'Right Button' }); VehicleControls.attributes.add('forwardButton', { type: 'entity', title: 'Forward Button' }); VehicleControls.attributes.add('reverseButton', { type: 'entity', title: 'Reverse Button' }); VehicleControls.prototype.initialize = function () { this.leftButtonPressed = false; this.rightButtonPressed = false; this.upButtonPressed = false; this.downButtonPressed = false; this.leftKeyPressed = false; this.rightKeyPressed = false; this.upKeyPressed = false; this.downKeyPressed = false; if (this.leftButton) { this.leftButton.enabled = pc.platform.mobile; this.leftButton.button.on('pressedstart', function () { this.leftButtonPressed = true; }, this); this.leftButton.button.on('pressedend', function () { this.leftButtonPressed = false; }, this); } if (this.rightButton) { this.rightButton.enabled = pc.platform.mobile; this.rightButton.button.on('pressedstart', function () { this.rightButtonPressed = true; }, this); this.rightButton.button.on('pressedend', function () { this.rightButtonPressed = false; }, this); } if (this.forwardButton) { this.forwardButton.enabled = pc.platform.mobile; this.forwardButton.button.on('pressedstart', function () { this.upButtonPressed = true; }, this); this.forwardButton.button.on('pressedend', function () { this.upButtonPressed = false; }, this); } if (this.reverseButton) { this.reverseButton.enabled = pc.platform.mobile; this.reverseButton.button.on('pressedstart', function () { this.downButtonPressed = true; }, this); this.reverseButton.button.on('pressedend', function () { this.downButtonPressed = false; }, this); } this.app.keyboard.on('keydown', function (e) { switch (e.key) { case pc.KEY_A: case pc.KEY_LEFT: this.leftKeyPressed = true; break; case pc.KEY_D: case pc.KEY_RIGHT: this.rightKeyPressed = true; break; case pc.KEY_W: case pc.KEY_UP: this.upKeyPressed = true; break; case pc.KEY_S: case pc.KEY_DOWN: this.downKeyPressed = true; break; } }, this); this.app.keyboard.on('keyup', function (e) { switch (e.key) { case pc.KEY_A: case pc.KEY_LEFT: this.leftKeyPressed = false; break; case pc.KEY_D: case pc.KEY_RIGHT: this.rightKeyPressed = false; break; case pc.KEY_W: case pc.KEY_UP: this.upKeyPressed = false; break; case pc.KEY_S: case pc.KEY_DOWN: this.downKeyPressed = false; break; } }, this); }; VehicleControls.prototype.update = function (dt) { var targetVehicle = this.targetVehicle ? this.targetVehicle : this.entity; if (targetVehicle) { var steering = 0; var throttle = 0; if (this.leftButtonPressed || this.leftKeyPressed) steering++; if (this.rightButtonPressed || this.rightKeyPressed) steering--; if (this.upButtonPressed || this.upKeyPressed) throttle++; if (this.downButtonPressed || this.downKeyPressed) throttle--; targetVehicle.script.vehicle.fire('vehicle:controls', steering, throttle); } };