From afa0c12084d7c51e8e103ee8cc2adbd535226c8f Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Mon, 7 Jun 2021 16:29:37 +0530 Subject: [PATCH] Add powerups --- src/DtsObject.hx | 36 ++++++----- src/InstanceManager.hx | 15 +++++ src/Main.hx | 29 ++++++--- src/Marble.hx | 110 +++++++++++++++++++++++++++++--- src/MarbleWorld.hx | 26 +++++++- src/collision/CollisionWorld.hx | 5 ++ src/octree/OctreeNode.hx | 2 +- src/shapes/AntiGravity.hx | 13 ++++ src/shapes/Helicopter.hx | 28 ++++++++ src/shapes/PowerUp.hx | 57 ++++++++++++++++- src/shapes/ShockAbsorber.hx | 27 ++++++++ src/shapes/SuperBounce.hx | 27 ++++++++ src/shapes/SuperJump.hx | 14 ++++ src/shapes/SuperSpeed.hx | 29 +++++++++ 14 files changed, 382 insertions(+), 36 deletions(-) create mode 100644 src/shapes/Helicopter.hx create mode 100644 src/shapes/ShockAbsorber.hx create mode 100644 src/shapes/SuperBounce.hx diff --git a/src/DtsObject.hx b/src/DtsObject.hx index 4712632c..8b2465c1 100644 --- a/src/DtsObject.hx +++ b/src/DtsObject.hx @@ -300,7 +300,8 @@ class DtsObject extends GameObject { rootObject.scaleX = -1; - this.boundingCollider = new BoxCollisionEntity(this.getBounds().clone(), cast this); + this.boundingCollider = new BoxCollisionEntity(this.level.instanceManager.getObjectBounds(cast this), cast this); + this.boundingCollider.setTransform(this.getTransform()); } function computeMaterials() { @@ -331,16 +332,18 @@ class DtsObject extends GameObject { var texture:Texture = ResourceLoader.getTexture(fullName); texture.wrap = Wrap.Repeat; material.texture = texture; + // if (this.useInstancing) { var dtsshader = new DtsTexture(); dtsshader.texture = texture; dtsshader.currentOpacity = 1; material.mainPass.removeShader(material.textureShader); material.mainPass.addShader(dtsshader); + // } // TODO TRANSLUENCY SHIT } if (flags & 4 > 0) { material.blendMode = BlendMode.Alpha; - material.mainPass.culling = h3d.mat.Data.Face.Front; + // material.mainPass.culling = h3d.mat.Data.Face.Front; } // TODO TRANSPARENCY SHIT if (flags & 8 > 0) @@ -540,6 +543,7 @@ class DtsObject extends GameObject { public override function setTransform(mat:Matrix) { super.setTransform(mat); this.boundingCollider.setTransform(mat); + this.level.collisionWorld.updateTransform(this.boundingCollider); } public function update(currentTime:Float, dt:Float) { @@ -774,19 +778,21 @@ class DtsObject extends GameObject { return; this.currentOpacity = opacity; - for (material in this.materials) { - if (this.currentOpacity != 1) { - material.blendMode = BlendMode.Alpha; - if (this.alphaShader == null) { - this.alphaShader = new AlphaMult(); - } - if (material.mainPass.getShader(AlphaMult) == null) { - material.mainPass.addShader(this.alphaShader); - } - this.alphaShader.alpha = this.currentOpacity; - } else { - if (alphaShader != null) { - alphaShader.alpha = this.currentOpacity; + if (!this.useInstancing) { + for (material in this.materials) { + if (this.currentOpacity != 1) { + // material.blendMode = BlendMode.Alpha; + // if (this.alphaShader == null) { + // this.alphaShader = new AlphaMult(); + // } + // if (material.mainPass.getShader(AlphaMult) == null) { + // material.mainPass.addShader(this.alphaShader); + // } + // this.alphaShader.alpha = this.currentOpacity; + // } else { + // if (alphaShader != null) { + // alphaShader.alpha = this.currentOpacity; + // } } } } diff --git a/src/InstanceManager.hx b/src/InstanceManager.hx index 8801eaf8..63e0d406 100644 --- a/src/InstanceManager.hx +++ b/src/InstanceManager.hx @@ -106,6 +106,21 @@ class InstanceManager { } } + public function getObjectBounds(object:GameObject) { + if (isInstanced(object)) { + var minfos = objects.get(object.identifier); + var invmat = minfos[0].instances[0].gameObject.getInvPos(); + var b = minfos[0].instances[0].gameObject.getBounds().clone(); + b.transform(invmat); + return b; + } else { + var invmat = object.getInvPos(); + var b = object.getBounds().clone(); + b.transform(invmat); + return b; + } + } + public function isInstanced(object:GameObject) { if (objects.exists(object.identifier)) return true; diff --git a/src/Main.hx b/src/Main.hx index c056bc98..f01f4670 100644 --- a/src/Main.hx +++ b/src/Main.hx @@ -1,5 +1,8 @@ package; +import shapes.Helicopter; +import shapes.ShockAbsorber; +import shapes.SuperBounce; import shapes.SuperSpeed; import shapes.SignFinish; import shapes.Trapdoor; @@ -35,8 +38,8 @@ class Main extends hxd.App { override function init() { super.init(); - dtsObj = new SuperSpeed(); - // dtsObj.z = 5; + // dtsObj = new SuperSpeed(); + // dtsObj.x = -3; world = new MarbleWorld(s3d); @@ -86,13 +89,23 @@ class Main extends hxd.App { // world.addPathedInterior(pi); - world.addDtsObject(dtsObj); - dtsObj.setOpacity(0.5); + // world.addDtsObject(dtsObj); - var dto = new SuperSpeed(); - world.addDtsObject(dto); - dto.setOpacity(1); - dto.z = 1; + // var sj = new SuperJump(); + // sj.x = 3; + // world.addDtsObject(sj); + + var sb = new Helicopter(); + sb.y = 3; + world.addDtsObject(sb); + + // var sh = new ShockAbsorber(); + // sh.y = -3; + // world.addDtsObject(sh); + + // var he = new Helicopter(); + // world.addDtsObject(he); + // sj.setTransform(sj.getTransform()); // for (i in 0...10) { // for (j in 0...10) { diff --git a/src/Marble.hx b/src/Marble.hx index 2db337f4..6c3a6b60 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -1,5 +1,9 @@ package src; +import src.DtsObject; +import sdl.Cursor; +import hxd.Cursor; +import shapes.PowerUp; import src.GameObject; import src.ForceObject; import src.MarbleWorld; @@ -44,7 +48,7 @@ class Marble extends GameObject { public var level:MarbleWorld; - var gravityDir:Vector = new Vector(0, 0, -1); + public var gravityDir:Vector = new Vector(0, 0, -1); public var _radius = 0.2; @@ -55,7 +59,7 @@ class Marble extends GameObject { var _staticFriction = 1.1; var _brakingAcceleration = 30; var _gravity = 20; - var _airAccel = 5; + var _airAccel:Float = 5; var _maxDotSlide = 0.5; var _minBounceVel = 0.1; var _bounceKineticFriction = 0.2; @@ -75,6 +79,15 @@ class Marble extends GameObject { var contacts:Array = []; var queuedContacts:Array = []; + public var heldPowerup:PowerUp; + public var lastContactNormal:Vector; + + var forcefield:DtsObject; + var helicopter:DtsObject; + var superBounceEnableTime:Float = -1e8; + var shockAbsorberEnableTime:Float = -1e8; + var helicopterEnableTime:Float = -1e8; + public function new() { super(); var geom = Sphere.defaultUnitSphere(); @@ -91,6 +104,31 @@ class Marble extends GameObject { this.collider = new SphereCollisionEntity(cast this); } + public function init(level:MarbleWorld) { + this.level = level; + this.forcefield = new DtsObject(); + this.forcefield.dtsPath = "data/shapes/images/glow_bounce.dts"; + this.forcefield.useInstancing = true; + this.forcefield.identifier = "GlowBounce"; + this.forcefield.showSequences = false; + this.addChild(this.forcefield); + this.forcefield.x = 1e8; + this.forcefield.y = 1e8; + this.forcefield.z = 1e8; + level.addDtsObject(this.forcefield); + + this.helicopter = new DtsObject(); + this.helicopter.dtsPath = "data/shapes/images/helicopter.dts"; + this.helicopter.useInstancing = true; + this.helicopter.identifier = "Helicopter"; + this.helicopter.showSequences = true; + // this.addChild(this.helicopter); + this.helicopter.x = 1e8; + this.helicopter.y = 1e8; + this.helicopter.z = 1e8; + level.addDtsObject(this.helicopter); + } + function findContacts(collisiomWorld:CollisionWorld, dt:Float) { this.contacts = queuedContacts; var c = collisiomWorld.sphereIntersection(this.collider, dt); @@ -101,7 +139,7 @@ class Marble extends GameObject { this.queuedContacts.push(collisionInfo); } - function getMarbleAxis() { + public function getMarbleAxis() { var cammat = Matrix.I(); var xrot = new Matrix(); xrot.initRotationX(this.camera.CameraPitch); @@ -117,9 +155,12 @@ class Marble extends GameObject { return [sidedir, motiondir, updir]; } - function getExternalForces(m:Move, dt:Float) { + function getExternalForces(currentTime:Float, m:Move, dt:Float) { var gWorkGravityDir = gravityDir; var A = gWorkGravityDir.multiply(this._gravity); + if (currentTime - this.helicopterEnableTime < 5) { + A = A.multiply(0.25); + } for (obj in level.dtsObjects) { if (obj is ForceObject) { var force = cast(obj, ForceObject).getForce(this.getAbsPos().getPosition()); @@ -157,7 +198,11 @@ class Marble extends GameObject { var sideDir = axes[0]; var motionDir = axes[1]; var upDir = axes[2]; - A = A.add(sideDir.multiply(m.d.x).add(motionDir.multiply(m.d.y)).multiply(this._airAccel)); + var airAccel = this._airAccel; + if (currentTime - this.helicopterEnableTime < 5) { + airAccel *= 2; + } + A = A.add(sideDir.multiply(m.d.x).add(motionDir.multiply(m.d.y)).multiply(airAccel)); } return A; } @@ -206,7 +251,7 @@ class Marble extends GameObject { return {result: true, aControl: aControl, desiredOmega: desiredOmega}; } - function velocityCancel(surfaceSlide:Bool, noBounce:Bool, stoppedPaths:Bool, pi:Array) { + function velocityCancel(currentTime:Float, dt:Float, surfaceSlide:Bool, noBounce:Bool, stoppedPaths:Bool, pi:Array) { var SurfaceDotThreshold = 0.001; var looped = false; var itersIn = 0; @@ -253,6 +298,12 @@ class Marble extends GameObject { this.velocity = vel; } else { var restitution = this._bounceRestitution; + if (currentTime - this.superBounceEnableTime < 5) { + restitution = 0.9; + } + if (currentTime - this.shockAbsorberEnableTime < 5) { + restitution = 0; + } restitution *= contacts[i].restitution; var velocityAdd = surfaceVel.multiply(-(1 + restitution)); var vAtC = sVel.add(this.omega.cross(contacts[i].normal.multiply(-this._radius))); @@ -416,6 +467,8 @@ class Marble extends GameObject { } A = A.add(AFriction); a = a.add(aFriction); + + lastContactNormal = bestContact.normal; } a = a.add(aControl); return [A, a]; @@ -530,14 +583,14 @@ class Marble extends GameObject { var aControl = cmf.aControl; var desiredOmega = cmf.desiredOmega; var stoppedPaths = false; - stoppedPaths = this.velocityCancel(isCentered, false, stoppedPaths, pathedInteriors); - var A = this.getExternalForces(m, timeStep); + stoppedPaths = this.velocityCancel(currentTime, dt, isCentered, false, stoppedPaths, pathedInteriors); + var A = this.getExternalForces(currentTime, m, timeStep); var retf = this.applyContactForces(timeStep, m, isCentered, aControl, desiredOmega, A); A = retf[0]; var a = retf[1]; this.velocity = this.velocity.add(A.multiply(timeStep)); this.omega = this.omega.add(a.multiply(timeStep)); - stoppedPaths = this.velocityCancel(isCentered, true, stoppedPaths, pathedInteriors); + stoppedPaths = this.velocityCancel(currentTime, dt, isCentered, true, stoppedPaths, pathedInteriors); this._totalTime += timeStep; if (contacts.length != 0) { this._contactTime += timeStep; @@ -577,6 +630,11 @@ class Marble extends GameObject { this.collider.setTransform(tform); this.collider.velocity = this.velocity; + if (this.heldPowerup != null && m.powerup) { + this.heldPowerup.use(currentTime); + this.heldPowerup = null; + } + timeRemaining -= timeStep; it++; } while (it <= 10); @@ -602,6 +660,9 @@ class Marble extends GameObject { if (Key.isDown(Key.SPACE)) { move.jump = true; } + if (Key.isDown(Key.MOUSE_LEFT)) { + move.powerup = true; + } } advancePhysics(currentTime, dt, move, collisionWorld, pathedInteriors); @@ -610,6 +671,37 @@ class Marble extends GameObject { this.camera.update(dt); } + updatePowerupStates(currentTime, dt); + // this.camera.target.load(this.getAbsPos().getPosition().toPoint()); } + + public function updatePowerupStates(currentTime:Float, dt:Float) { + if (currentTime - this.shockAbsorberEnableTime < 5) { + this.forcefield.setPosition(0, 0, 0); + } else if (currentTime - this.superBounceEnableTime < 5) { + this.forcefield.setPosition(0, 0, 0); + } else { + this.forcefield.x = 1e8; + this.forcefield.y = 1e8; + this.forcefield.z = 1e8; + } + if (currentTime - this.helicopterEnableTime < 5) { + this.helicopter.setPosition(x, y, z); + } else { + this.helicopter.setPosition(1e8, 1e8, 1e8); + } + } + + public function enableSuperBounce(time:Float) { + this.superBounceEnableTime = time; + } + + public function enableShockAbsorber(time:Float) { + this.shockAbsorberEnableTime = time; + } + + public function enableHelicopter(time:Float) { + this.helicopterEnableTime = time; + } } diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 71a4debc..663a595a 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -1,5 +1,6 @@ package src; +import shapes.PowerUp; import collision.SphereCollisionEntity; import src.Sky; import h3d.scene.Mesh; @@ -32,7 +33,7 @@ class MarbleWorld { public var scene:Scene; - var marble:Marble; + public var marble:Marble; public function new(scene:Scene) { this.collisionWorld = new CollisionWorld(); @@ -83,6 +84,7 @@ class MarbleWorld { marble.level = cast this; if (marble.controllable) { marble.camera.init(cast this); + marble.init(cast this); this.scene.addChild(marble.camera); this.marble = marble; // Ugly hack @@ -151,4 +153,26 @@ class MarbleWorld { this.shapeImmunity = newImmunity; } + + public function pickUpPowerUp(powerUp:PowerUp) { + if (this.marble.heldPowerup != null) + return false; + this.marble.heldPowerup = powerUp; + // for (let overlayShape + // of + // this.overlayShapes + // ) + // { + // if (overlayShape.dtsPath.includes("gem")) + // continue; + // // Show the corresponding icon in the HUD + // if (overlayShape.dtsPath == = powerUp.dtsPath) + // this.overlayScene.add(overlayShape.group); + // else + // this.overlayScene.remove(overlayShape.group); + // } + // if (!this.rewinding) + // AudioManager.play(powerUp.sounds[0]); + return true; + } } diff --git a/src/collision/CollisionWorld.hx b/src/collision/CollisionWorld.hx index e8de221a..e4b14a05 100644 --- a/src/collision/CollisionWorld.hx +++ b/src/collision/CollisionWorld.hx @@ -81,4 +81,9 @@ class CollisionWorld { public function addMovingEntity(entity:CollisionEntity) { this.dynamicEntities.push(entity); } + + public function updateTransform(entity:CollisionEntity) { + this.octree.remove(entity); + this.octree.insert(entity); + } } diff --git a/src/octree/OctreeNode.hx b/src/octree/OctreeNode.hx index d7d1f3d6..16680f45 100644 --- a/src/octree/OctreeNode.hx +++ b/src/octree/OctreeNode.hx @@ -111,7 +111,7 @@ class OctreeNode implements IOctreeElement { } public function merge() { - if (this.count > 8 || !(this.octants == null)) + if (this.count > 8 || (this.octants == null)) return; // Add all objects in the octants back to this node for (i in 0...8) { diff --git a/src/shapes/AntiGravity.hx b/src/shapes/AntiGravity.hx index ef70458a..888bcb2c 100644 --- a/src/shapes/AntiGravity.hx +++ b/src/shapes/AntiGravity.hx @@ -10,4 +10,17 @@ class AntiGravity extends PowerUp { this.isTSStatic = false; this.identifier = "AntiGravity"; } + + public function pickUp():Bool { + return this.level.pickUpPowerUp(this); + } + + public function use(time:Float) { + var marble = this.level.marble; + // marble.body.addLinearVelocity(this.level.currentUp.scale(20)); // Simply add to vertical velocity + // if (!this.level.rewinding) + // AudioManager.play(this.sounds[1]); + // this.level.particles.createEmitter(superJumpParticleOptions, null, () => Util.vecOimoToThree(marble.body.getPosition())); + // this.level.deselectPowerUp(); + } } diff --git a/src/shapes/Helicopter.hx b/src/shapes/Helicopter.hx new file mode 100644 index 00000000..9dc934fa --- /dev/null +++ b/src/shapes/Helicopter.hx @@ -0,0 +1,28 @@ +package shapes; + +import src.DtsObject; + +class Helicopter extends PowerUp { + public function new() { + super(); + this.dtsPath = "data/shapes/images/helicopter.dts"; + this.isCollideable = false; + this.isTSStatic = false; + this.showSequences = false; + this.identifier = "Helicopter"; + } + + public function pickUp():Bool { + return this.level.pickUpPowerUp(this); + } + + public function use(time:Float) { + var marble = this.level.marble; + marble.enableHelicopter(time); + // marble.body.addLinearVelocity(this.level.currentUp.scale(20)); // Simply add to vertical velocity + // if (!this.level.rewinding) + // AudioManager.play(this.sounds[1]); + // this.level.particles.createEmitter(superJumpParticleOptions, null, () => Util.vecOimoToThree(marble.body.getPosition())); + // this.level.deselectPowerUp(); + } +} diff --git a/src/shapes/PowerUp.hx b/src/shapes/PowerUp.hx index 661eb68c..7b881e53 100644 --- a/src/shapes/PowerUp.hx +++ b/src/shapes/PowerUp.hx @@ -1,15 +1,68 @@ package shapes; +import src.Util; +import h3d.Vector; import src.DtsObject; -class PowerUp extends DtsObject { - public var lastPickupTime:Float = -1; +class PowerupParams { + public var duration:Float = 5; + public var airAccel = 1.0; + public var activateTime:Float = 0; + public var bounce = -1.0; + public var sizeScale = 1.0; + public var massScale = 1.0; + public var gravityMod = 1.0; + public var repulseDist = 0.0; + public var repulseMax = 0.0; + public var boostDir = new Vector(); + public var timeFreeze:Float = 0; + public var boostAmount = 0.0; + public var boostMassless = 0.0; + + public function new() {}; +} + +abstract class PowerUp extends DtsObject { + public var lastPickUpTime:Float = -1; public var cooldownDuration:Float = 7; public var autoUse:Bool = false; + public var powerupParams:PowerupParams = new PowerupParams(); public function new() { super(); this.isCollideable = false; this.ambientRotate = true; } + + public override function onMarbleInside(time:Float) { + var pickupable = this.lastPickUpTime == -1 || (time - this.lastPickUpTime) >= this.cooldownDuration; + if (!pickupable) + return; + + if (this.pickUp()) { + // this.level.replay.recordMarbleInside(this); + + this.lastPickUpTime = time; + if (this.autoUse) + this.use(time); + + // displayAlert(`You picked up a ${this.pickUpName}!`); + // if (this.element.showhelponpickup === "1" && !this.autoUse) displayHelp(`Press to use the ${this.pickUpName}!`); + } + } + + public override function update(currentTime:Float, dt:Float) { + super.update(currentTime, dt); + var opacity = 1.0; + if (this.lastPickUpTime > 0 && this.cooldownDuration > 0) { + var availableTime = this.lastPickUpTime + this.cooldownDuration; + opacity = Util.clamp((currentTime - availableTime), 0, 1); + } + + this.setOpacity(opacity); + } + + public abstract function pickUp():Bool; + + public abstract function use(time:Float):Void; } diff --git a/src/shapes/ShockAbsorber.hx b/src/shapes/ShockAbsorber.hx new file mode 100644 index 00000000..cf31af2f --- /dev/null +++ b/src/shapes/ShockAbsorber.hx @@ -0,0 +1,27 @@ +package shapes; + +import src.DtsObject; + +class ShockAbsorber extends PowerUp { + public function new() { + super(); + this.dtsPath = "data/shapes/items/shockabsorber.dts"; + this.isCollideable = false; + this.isTSStatic = false; + this.identifier = "ShockAbsorber"; + } + + public function pickUp():Bool { + return this.level.pickUpPowerUp(this); + } + + public function use(time:Float) { + var marble = this.level.marble; + marble.enableShockAbsorber(time); + // marble.body.addLinearVelocity(this.level.currentUp.scale(20)); // Simply add to vertical velocity + // if (!this.level.rewinding) + // AudioManager.play(this.sounds[1]); + // this.level.particles.createEmitter(superJumpParticleOptions, null, () => Util.vecOimoToThree(marble.body.getPosition())); + // this.level.deselectPowerUp(); + } +} diff --git a/src/shapes/SuperBounce.hx b/src/shapes/SuperBounce.hx new file mode 100644 index 00000000..163cef06 --- /dev/null +++ b/src/shapes/SuperBounce.hx @@ -0,0 +1,27 @@ +package shapes; + +import src.DtsObject; + +class SuperBounce extends PowerUp { + public function new() { + super(); + this.dtsPath = "data/shapes/items/superbounce.dts"; + this.isCollideable = false; + this.isTSStatic = false; + this.identifier = "SuperBounce"; + } + + public function pickUp():Bool { + return this.level.pickUpPowerUp(this); + } + + public function use(time:Float) { + var marble = this.level.marble; + marble.enableSuperBounce(time); + // marble.body.addLinearVelocity(this.level.currentUp.scale(20)); // Simply add to vertical velocity + // if (!this.level.rewinding) + // AudioManager.play(this.sounds[1]); + // this.level.particles.createEmitter(superJumpParticleOptions, null, () => Util.vecOimoToThree(marble.body.getPosition())); + // this.level.deselectPowerUp(); + } +} diff --git a/src/shapes/SuperJump.hx b/src/shapes/SuperJump.hx index 8d0d81b4..4cafe508 100644 --- a/src/shapes/SuperJump.hx +++ b/src/shapes/SuperJump.hx @@ -10,4 +10,18 @@ class SuperJump extends PowerUp { this.isTSStatic = false; this.identifier = "SuperJump"; } + + public function pickUp():Bool { + return this.level.pickUpPowerUp(this); + } + + public function use(time:Float) { + var marble = this.level.marble; + marble.velocity = marble.velocity.add(marble.gravityDir.multiply(-20)); + // marble.body.addLinearVelocity(this.level.currentUp.scale(20)); // Simply add to vertical velocity + // if (!this.level.rewinding) + // AudioManager.play(this.sounds[1]); + // this.level.particles.createEmitter(superJumpParticleOptions, null, () => Util.vecOimoToThree(marble.body.getPosition())); + // this.level.deselectPowerUp(); + } } diff --git a/src/shapes/SuperSpeed.hx b/src/shapes/SuperSpeed.hx index e2488d40..0aab72b2 100644 --- a/src/shapes/SuperSpeed.hx +++ b/src/shapes/SuperSpeed.hx @@ -1,5 +1,7 @@ package shapes; +import h3d.Quat; +import h3d.Vector; import src.DtsObject; class SuperSpeed extends PowerUp { @@ -11,4 +13,31 @@ class SuperSpeed extends PowerUp { this.identifier = "SuperSpeed"; this.useInstancing = true; } + + public function pickUp():Bool { + return this.level.pickUpPowerUp(this); + } + + public function use(time:Float) { + var marble = this.level.marble; + var movementVector = marble.getMarbleAxis()[0]; + + // Okay, so super speed directionality is a bit strange. In general, the direction is based on the normal vector of the last surface you had contact with. + + // var quat = level.newOrientationQuat; + // movementVector.applyQuaternion(quat); + + var quat2 = new Quat(); + // Determine the necessary rotation to rotate the up vector to the contact normal. + quat2.initMoveTo(marble.gravityDir.multiply(-1), marble.lastContactNormal); + movementVector.transform(quat2.toMatrix()); + marble.velocity = marble.velocity.add(movementVector.multiply(-24.7)); + + // marble.body.addLinearVelocity(Util.vecThreeToOimo(movementVector).scale(24.7)); // Whirligig's determined value + // marble.body.addLinearVelocity(this.level.currentUp.scale(20)); // Simply add to vertical velocity + // if (!this.level.rewinding) + // AudioManager.play(this.sounds[1]); + // this.level.particles.createEmitter(superJumpParticleOptions, null, () => Util.vecOimoToThree(marble.body.getPosition())); + // this.level.deselectPowerUp(); + } }