diff --git a/marblegame.hl b/marblegame.hl index 879be063..d8054867 100644 Binary files a/marblegame.hl and b/marblegame.hl differ diff --git a/src/DtsObject.hx b/src/DtsObject.hx index 93a3ba0f..6cdd5510 100644 --- a/src/DtsObject.hx +++ b/src/DtsObject.hx @@ -620,11 +620,13 @@ class DtsObject extends GameObject { var rot = sequence.rotationMatters.length > 0 ? sequence.rotationMatters[0] : 0; var trans = sequence.translationMatters.length > 0 ? sequence.translationMatters[0] : 0; + var scale = sequence.scaleMatters.length > 0 ? sequence.scaleMatters[0] : 0; var affectedCount = 0; var completion = timeState.timeSinceLoad / sequence.duration; var quaternions:Array = null; var translations:Array = null; + var scales:Array = null; var actualKeyframe = this.sequenceKeyframeOverride.exists(sequence) ? this.sequenceKeyframeOverride.get(sequence) : ((completion * sequence.numKeyFrames) % sequence.numKeyFrames); if (this.lastSequenceKeyframes.get(sequence) == actualKeyframe) @@ -698,6 +700,33 @@ class DtsObject extends GameObject { } } } + + if (scale > 0) { + scales = []; + + for (i in 0...this.dts.nodes.length) { + var affected = ((1 << i) & scale) != 0; + + if (affected) { + var scale1 = this.dts.nodeAlignedScales[sequence.numKeyFrames * affectedCount + keyframeLow]; + var scale2 = this.dts.nodeAlignedScales[sequence.numKeyFrames * affectedCount + keyframeHigh]; + + var v1 = new Vector(scale1.x, scale1.y, scale1.z); + var v2 = new Vector(scale2.x, scale2.y, scale2.z); + + var scaleVec = Util.lerpThreeVectors(v1, v2, t); + this.graphNodes[i].scaleX = scaleVec.x; + this.graphNodes[i].scaleY = scaleVec.y; + this.graphNodes[i].scaleZ = scaleVec.z; + + this.dirtyTransforms[i] = true; + } else { + this.graphNodes[i].scaleX = 1; + this.graphNodes[i].scaleY = 1; + this.graphNodes[i].scaleZ = 1; + } + } + } } if (this.skinMeshData != null && !isInstanced) { diff --git a/src/Marble.hx b/src/Marble.hx index 117ee100..1cddd7dc 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -171,6 +171,7 @@ class Marble extends GameObject { var superbounceSound:Channel; var shockabsorberSound:Channel; var helicopterSound:Channel; + var playedSounds = []; public var mode:Mode = Play; @@ -283,10 +284,16 @@ class Marble extends GameObject { for (contact in contacts) { if (contact.force != 0 && !forceObjects.contains(contact.otherObject)) { if (contact.otherObject is RoundBumper) { - AudioManager.playSound(ResourceLoader.getAudio("data/sound/bumperding1.wav")); + if (!playedSounds.contains("data/sound/bumperding1.wav")) { + AudioManager.playSound(ResourceLoader.getAudio("data/sound/bumperding1.wav")); + playedSounds.push("data/sound/bumperding1.wav"); + } } if (contact.otherObject is TriangleBumper) { - AudioManager.playSound(ResourceLoader.getAudio("data/sound/bumper1.wav")); + if (!playedSounds.contains("data/sound/bumper1.wav")) { + AudioManager.playSound(ResourceLoader.getAudio("data/sound/bumper1.wav")); + playedSounds.push("data/sound/bumper1.wav"); + } } forceObjectCount++; contactNormal = contactNormal.add(contact.normal); @@ -485,7 +492,7 @@ class Marble extends GameObject { var soFar = 0.0; for (k in 0...contacts.length) { var dist = this._radius - contacts[k].contactDistance; - var timeToSeparate = 0.016; + var timeToSeparate = 0.1; if (dist >= 0) { var f1 = this.velocity.sub(contacts[k].velocity).add(dir.multiply(soFar)).dot(contacts[k].normal); var f2 = timeToSeparate * f1; @@ -531,7 +538,10 @@ class Marble extends GameObject { } if (sv < this._jumpImpulse) { this.velocity = this.velocity.add(bestContact.normal.multiply((this._jumpImpulse - sv))); - AudioManager.playSound(ResourceLoader.getAudio("data/sound/jump.wav")); + if (!playedSounds.contains("data/sound/jump.wav")) { + AudioManager.playSound(ResourceLoader.getAudio("data/sound/jump.wav")); + playedSounds.push("data/sound/jump.wav"); + } } } for (j in 0...contacts.length) { @@ -951,6 +961,7 @@ class Marble extends GameObject { } } + playedSounds = []; advancePhysics(timeState, move, collisionWorld, pathedInteriors); if (this.controllable) { diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index f8ff7880..17ab3f6e 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -943,14 +943,16 @@ class MarbleWorld extends Scheduler { } public function pickUpPowerUp(powerUp:PowerUp) { - if (this.marble.heldPowerup == powerUp) - return false; + if (this.marble.heldPowerup != null) + if (this.marble.heldPowerup.identifier == powerUp.identifier) + return false; this.marble.heldPowerup = powerUp; this.playGui.setPowerupImage(powerUp.identifier); return true; } public function deselectPowerUp() { + this.marble.heldPowerup = null; this.playGui.setPowerupImage(""); } @@ -979,7 +981,7 @@ class MarbleWorld extends Scheduler { var u = v1.normalized(); var v = v2.normalized(); - if (u.multiply(-1).equals(v)) { + if (u.dot(v) == -1) { var q = new Quat(); var o = orthogonal(u).normalized(); q.x = o.x; @@ -998,8 +1000,7 @@ class MarbleWorld extends Scheduler { return q; } - var quatChange = new Quat(); - quatChange.initMoveTo(oldUp, vec); + var quatChange = getRotQuat(oldUp, vec); // Instead of calculating the new quat from nothing, calculate it from the last one to guarantee the shortest possible rotation. // quatChange.initMoveTo(oldUp, vec); quatChange.multiply(quatChange, currentQuat); diff --git a/src/gui/EndGameGui.hx b/src/gui/EndGameGui.hx index d14eec53..8f0f80ea 100644 --- a/src/gui/EndGameGui.hx +++ b/src/gui/EndGameGui.hx @@ -127,10 +127,10 @@ class EndGameGui extends GuiControl { var rightColumn = new GuiMLText(domcasual32, mlFontLoader); rightColumn.text.textColor = 0x000000; - rightColumn.text.text = '${Util.formatTime(mission.qualifyTime == Math.POSITIVE_INFINITY ? 5999.999 : mission.qualifyTime)}
${Util.formatTime(mission.goldTime)}
${Util.formatTime(elapsedTime)}
${Util.formatTime(bonusTime)}


'; + rightColumn.text.text = '${Util.formatTime(mission.qualifyTime == Math.POSITIVE_INFINITY ? 5999.999 : mission.qualifyTime)}

${Util.formatTime(elapsedTime)}
${Util.formatTime(bonusTime)}


'; for (i in 0...3) { if (scoreData[i].time < mission.goldTime) - rightColumn.text.text += '${Util.formatTime(scoreData[i].time)}
'; + rightColumn.text.text += '
'; else rightColumn.text.text += '${Util.formatTime(scoreData[i].time)}
'; } @@ -139,6 +139,20 @@ class EndGameGui extends GuiControl { rightColumn.extent = new Vector(208, 50); pg.addChild(rightColumn); + var rightColumnGold = new GuiMLText(domcasual32, mlFontLoader); + rightColumnGold.text.textColor = 0xFFFF00; + rightColumnGold.text.text = '
${Util.formatTime(mission.goldTime)}




'; + for (i in 0...3) { + if (scoreData[i].time < mission.goldTime) + rightColumnGold.text.text += '${Util.formatTime(scoreData[i].time)}
'; + else + rightColumnGold.text.text += '
'; + } + rightColumnGold.text.filter = new DropShadow(1.414, 0.785, 0x00000, 1, 0, 0.4, 1, true); + rightColumnGold.position = new Vector(274, 103); + rightColumnGold.extent = new Vector(208, 50); + pg.addChild(rightColumnGold); + pg.addChild(continueButton); pg.addChild(restartButton); @@ -168,14 +182,22 @@ class EndGameGui extends GuiControl { leftColumn.text.text += '${i + 1}. ${scoreData[i].name}
'; } - rightColumn.text.text = '${Util.formatTime(mission.qualifyTime == Math.POSITIVE_INFINITY ? 5999.999 : mission.qualifyTime)}
${Util.formatTime(mission.goldTime)}
${Util.formatTime(elapsedTime)}
${Util.formatTime(bonusTime)}


'; + rightColumn.text.text = '${Util.formatTime(mission.qualifyTime == Math.POSITIVE_INFINITY ? 5999.999 : mission.qualifyTime)}

${Util.formatTime(elapsedTime)}
${Util.formatTime(bonusTime)}


'; for (i in 0...3) { if (scoreData[i].time < mission.goldTime) - rightColumn.text.text += '${Util.formatTime(scoreData[i].time)}
'; + rightColumn.text.text += '
'; else rightColumn.text.text += '${Util.formatTime(scoreData[i].time)}
'; } + rightColumnGold.text.text = '
${Util.formatTime(mission.goldTime)}




'; + for (i in 0...3) { + if (scoreData[i].time < mission.goldTime) + rightColumnGold.text.text += '${Util.formatTime(scoreData[i].time)}
'; + else + rightColumnGold.text.text += '
'; + } + Settings.saveScore(mission.path, myScore); scoreSubmitted = true; diff --git a/src/gui/GuiControl.hx b/src/gui/GuiControl.hx index 04c89305..6567f8aa 100644 --- a/src/gui/GuiControl.hx +++ b/src/gui/GuiControl.hx @@ -41,6 +41,7 @@ class GuiControl { var parent:GuiControl; var _entered:Bool = false; + var _skipNextEvent:Bool = false; public function new() {} @@ -48,45 +49,50 @@ class GuiControl { for (c in children) { c.render(scene2d); } + this._skipNextEvent = true; } public function update(dt:Float, mouseState:MouseState) { - var hitTestRect = getHitTestRect(); - if (hitTestRect.inRect(mouseState.position)) { - if (Key.isPressed(Key.MOUSE_LEFT)) { - mouseState.button = Key.MOUSE_LEFT; - this.onMousePress(mouseState); - } - if (Key.isPressed(Key.MOUSE_RIGHT)) { - mouseState.button = Key.MOUSE_RIGHT; - this.onMousePress(mouseState); - } - if (Key.isReleased(Key.MOUSE_LEFT)) { - mouseState.button = Key.MOUSE_LEFT; - this.onMouseRelease(mouseState); - } - if (Key.isReleased(Key.MOUSE_RIGHT)) { - mouseState.button = Key.MOUSE_RIGHT; - this.onMouseRelease(mouseState); - } - if (Key.isDown(Key.MOUSE_LEFT)) { - mouseState.button = Key.MOUSE_LEFT; - this.onMouseDown(mouseState); - } - if (Key.isDown(Key.MOUSE_RIGHT)) { - mouseState.button = Key.MOUSE_RIGHT; - this.onMouseDown(mouseState); - } + if (!_skipNextEvent) { + var hitTestRect = getHitTestRect(); + if (hitTestRect.inRect(mouseState.position)) { + if (Key.isPressed(Key.MOUSE_LEFT)) { + mouseState.button = Key.MOUSE_LEFT; + this.onMousePress(mouseState); + } + if (Key.isPressed(Key.MOUSE_RIGHT)) { + mouseState.button = Key.MOUSE_RIGHT; + this.onMousePress(mouseState); + } + if (Key.isReleased(Key.MOUSE_LEFT)) { + mouseState.button = Key.MOUSE_LEFT; + this.onMouseRelease(mouseState); + } + if (Key.isReleased(Key.MOUSE_RIGHT)) { + mouseState.button = Key.MOUSE_RIGHT; + this.onMouseRelease(mouseState); + } + if (Key.isDown(Key.MOUSE_LEFT)) { + mouseState.button = Key.MOUSE_LEFT; + this.onMouseDown(mouseState); + } + if (Key.isDown(Key.MOUSE_RIGHT)) { + mouseState.button = Key.MOUSE_RIGHT; + this.onMouseDown(mouseState); + } - if (!_entered) { - _entered = true; - this.onMouseEnter(mouseState); + if (!_entered) { + _entered = true; + this.onMouseEnter(mouseState); + } + } else { + if (_entered) { + _entered = false; + this.onMouseLeave(mouseState); + } } } else { - if (_entered) { - _entered = false; - this.onMouseLeave(mouseState); - } + _skipNextEvent = false; } for (c in children) { c.update(dt, mouseState); diff --git a/src/shapes/RoundBumper.hx b/src/shapes/RoundBumper.hx index e2a59d80..be4e1b1e 100644 --- a/src/shapes/RoundBumper.hx +++ b/src/shapes/RoundBumper.hx @@ -1,12 +1,43 @@ package shapes; +import collision.CollisionInfo; import src.DtsObject; +import src.TimeState; +import src.Util; class RoundBumper extends DtsObject { + var lastContactTime = Math.NEGATIVE_INFINITY; + public function new() { super(); dtsPath = "data/shapes/bumpers/pball_round.dts"; isCollideable = true; identifier = "RoundBumper"; } + + override function update(timeState:src.TimeState) { + // Override the keyframe + var currentCompletion = getCurrentCompletion(timeState); + this.sequenceKeyframeOverride.set(this.dts.sequences[0], currentCompletion * (this.dts.sequences[0].numKeyFrames - 1)); + + super.update(timeState); + } + + function getCurrentCompletion(timeState:TimeState) { + var elapsed = timeState.timeSinceLoad - this.lastContactTime; + var completion = Util.clamp(elapsed / this.dts.sequences[0].duration, 0, 1); + return completion; + } + + override function onMarbleContact(time:TimeState, ?contact:CollisionInfo) { + super.onMarbleContact(time, contact); + if (time.timeSinceLoad - this.lastContactTime <= 0) + return; + var currentCompletion = this.getCurrentCompletion(time); + if (currentCompletion == 0 || currentCompletion == 1) { + this.lastContactTime = time.timeSinceLoad; + } + + // this.level.replay.recordMarbleContact(this); + } }