make physics ticks match to mbu

This commit is contained in:
RandomityGuy 2023-07-11 00:09:14 +05:30
parent 774d15fd29
commit 2bae691c23
7 changed files with 146 additions and 33 deletions

View file

@ -305,7 +305,7 @@ class CameraController extends Object {
CameraYaw = this.level.replay.currentPlaybackFrame.cameraYaw; CameraYaw = this.level.replay.currentPlaybackFrame.cameraYaw;
} }
var marblePosition = level.marble.collider.transform.getPosition(); var marblePosition = this.finish ? level.marble.collider.transform.getPosition() : level.marble.getAbsPos().getPosition();
if (this.finish) { if (this.finish) {
// Move the target to the centre of the finish // Move the target to the centre of the finish
@ -341,6 +341,10 @@ class CameraController extends Object {
var closeness = 0.1; var closeness = 0.1;
var rayCastOrigin = marblePosition.add(level.currentUp.multiply(marble._radius)).add(cameraVerticalTranslation); var rayCastOrigin = marblePosition.add(level.currentUp.multiply(marble._radius)).add(cameraVerticalTranslation);
for (pi in level.pathedInteriors) {
pi.pushTickState();
}
var processedShapes = []; var processedShapes = [];
for (i in 0...3) { for (i in 0...3) {
var rayCastDirection = camera.pos.sub(rayCastOrigin); var rayCastDirection = camera.pos.sub(rayCastOrigin);
@ -388,6 +392,10 @@ class CameraController extends Object {
break; break;
} }
for (pi in level.pathedInteriors) {
pi.popTickState();
}
if (oob) { if (oob) {
camera.pos = lastCamPos; camera.pos = lastCamPos;
camera.target = marblePosition.add(lastVertTranslation); camera.target = marblePosition.add(lastVertTranslation);

View file

@ -230,6 +230,11 @@ class Marble extends GameObject {
public var _mass:Float = 1; public var _mass:Float = 1;
var physicsAccumulator:Float = 0;
var oldPos:Vector;
var newPos:Vector;
var prevRot:Quat;
public var contacts:Array<CollisionInfo> = []; public var contacts:Array<CollisionInfo> = [];
public var bestContact:CollisionInfo; public var bestContact:CollisionInfo;
public var contactEntities:Array<CollisionEntity> = []; public var contactEntities:Array<CollisionEntity> = [];
@ -1593,6 +1598,9 @@ class Marble extends GameObject {
var passedTime = timeState.currentAttemptTime; var passedTime = timeState.currentAttemptTime;
oldPos = this.collider.transform.getPosition();
prevRot = this.getRotationQuat().clone();
if (this.controllable) { if (this.controllable) {
for (interior in pathedInteriors) { for (interior in pathedInteriors) {
// interior.pushTickState(); // interior.pushTickState();
@ -1604,7 +1612,7 @@ class Marble extends GameObject {
if (timeRemaining <= 0) if (timeRemaining <= 0)
break; break;
var timeStep = 0.004; var timeStep = 0.008;
if (timeRemaining < timeStep) if (timeRemaining < timeStep)
timeStep = timeRemaining; timeStep = timeRemaining;
@ -1691,13 +1699,13 @@ class Marble extends GameObject {
var quat = new Quat(); var quat = new Quat();
quat.initRotation(omega.x * timeStep, omega.y * timeStep, omega.z * timeStep); quat.initRotation(omega.x * timeStep, omega.y * timeStep, omega.z * timeStep);
quat.multiply(quat, rot); quat.multiply(quat, rot);
this.setRotationQuat(quat); // this.setRotationQuat(quat);
var totMatrix = quat.toMatrix(); var totMatrix = quat.toMatrix();
newPos.w = 1; // Fix shit blowing up newPos.w = 1; // Fix shit blowing up
totMatrix.setPosition(newPos); totMatrix.setPosition(newPos);
this.setPosition(newPos.x, newPos.y, newPos.z); // this.setPosition(newPos.x, newPos.y, newPos.z);
this.collider.setTransform(totMatrix); this.collider.setTransform(totMatrix);
this.collider.velocity = this.velocity; this.collider.velocity = this.velocity;
@ -1746,6 +1754,7 @@ class Marble extends GameObject {
} }
this.queuedContacts = []; this.queuedContacts = [];
newPos = this.collider.transform.getPosition();
this.updateRollSound(timeState, contactTime / timeState.dt, this._slipAmount); this.updateRollSound(timeState, contactTime / timeState.dt, this._slipAmount);
} }
@ -1796,8 +1805,32 @@ class Marble extends GameObject {
} }
} }
physicsAccumulator += timeState.dt;
playedSounds = []; playedSounds = [];
advancePhysics(timeState, move, collisionWorld, pathedInteriors); while (physicsAccumulator > 0.032) {
var adt = timeState.clone();
adt.dt = 0.032;
advancePhysics(adt, move, collisionWorld, pathedInteriors);
physicsAccumulator -= 0.032;
}
if (oldPos != null && newPos != null) {
var deltaT = physicsAccumulator / 0.032;
var renderPos = Util.lerpThreeVectors(this.oldPos, this.newPos, deltaT);
this.setPosition(renderPos.x, renderPos.y, renderPos.z);
var rot = this.prevRot;
var quat = new Quat();
quat.initRotation(omega.x * physicsAccumulator, omega.y * physicsAccumulator, omega.z * physicsAccumulator);
quat.multiply(quat, rot);
this.setRotationQuat(quat);
var adt = timeState.clone();
adt.dt = physicsAccumulator;
for (pi in pathedInteriors) {
pi.update(adt);
}
}
if (this.controllable) { if (this.controllable) {
if (!this.level.isWatching) { if (!this.level.isWatching) {
@ -1983,13 +2016,14 @@ class Marble extends GameObject {
public function useBlast() { public function useBlast() {
if (this.level.blastAmount < 0.25 || this.level.game != "ultra") if (this.level.blastAmount < 0.25 || this.level.game != "ultra")
return; return false;
var impulse = this.level.currentUp.multiply(this.level.blastAmount * 8); var impulse = this.level.currentUp.multiply(this.level.blastAmount * 8);
this.applyImpulse(impulse); this.applyImpulse(impulse);
AudioManager.playSound(ResourceLoader.getResource('data/sound/use_blast.wav', ResourceLoader.getAudio, this.soundResources)); AudioManager.playSound(ResourceLoader.getResource('data/sound/use_blast.wav', ResourceLoader.getAudio, this.soundResources));
this.blastWave.doSequenceOnceBeginTime = this.level.timeState.timeSinceLoad; this.blastWave.doSequenceOnceBeginTime = this.level.timeState.timeSinceLoad;
this.blastUseTime = this.level.timeState.currentAttemptTime; this.blastUseTime = this.level.timeState.currentAttemptTime;
this.level.blastAmount = 0; this.level.blastAmount = 0;
return true;
} }
public function applyImpulse(impulse:Vector, contactImpulse:Bool = false) { public function applyImpulse(impulse:Vector, contactImpulse:Bool = false) {
@ -2071,6 +2105,10 @@ class Marble extends GameObject {
this.teleportDisableTime = null; this.teleportDisableTime = null;
this.teleportEnableTime = null; this.teleportEnableTime = null;
this.finishAnimTime = 0; this.finishAnimTime = 0;
this.physicsAccumulator = 0;
this.prevRot = this.getRotationQuat().clone();
this.oldPos = this.getAbsPos().getPosition();
this.newPos = this.getAbsPos().getPosition();
if (this._radius != this._prevRadius) { if (this._radius != this._prevRadius) {
this._radius = this._prevRadius; this._radius = this._prevRadius;
this._marbleScale = this._renderScale = this._defaultScale; this._marbleScale = this._renderScale = this._defaultScale;

View file

@ -1017,14 +1017,15 @@ class MarbleWorld extends Scheduler {
this.tickSchedule(timeState.currentAttemptTime); this.tickSchedule(timeState.currentAttemptTime);
if (Key.isPressed(Settings.controlsSettings.blast) if (Key.isDown(Settings.controlsSettings.blast)
|| (MarbleGame.instance.touchInput.blastbutton.pressed) || (MarbleGame.instance.touchInput.blastbutton.pressed)
|| Gamepad.isPressed(Settings.gamepadSettings.blast) || Gamepad.isDown(Settings.gamepadSettings.blast)
&& !this.isWatching && !this.isWatching
&& this.game == "ultra") { && this.game == "ultra") {
this.marble.useBlast(); if (this.marble.useBlast()) {
if (this.isRecording) { if (this.isRecording) {
this.replay.recordMarbleStateFlags(false, false, false, true); this.replay.recordMarbleStateFlags(false, false, false, true);
}
} }
} }

View file

@ -44,9 +44,15 @@ class PathedInterior extends InteriorObject {
var baseOrientation:Quat; var baseOrientation:Quat;
var baseScale:Vector; var baseScale:Vector;
var prevPosition:Vector;
var position:Vector;
public var velocity:Vector; public var velocity:Vector;
var _storedColliderTransform:Matrix;
var stopped:Bool = false; var stopped:Bool = false;
var stoppedPosition:Vector;
var soundChannel:Channel; var soundChannel:Channel;
@ -133,8 +139,25 @@ class PathedInterior extends InteriorObject {
onFinish(); onFinish();
} }
public function pushTickState() {
this._storedColliderTransform = this.collider.transform.clone();
var tform = this.getAbsPos();
if (this.isCollideable) {
collider.setTransform(tform);
collisionWorld.updateTransform(this.collider);
}
}
public function popTickState() {
if (this.isCollideable) {
collider.setTransform(this._storedColliderTransform);
collisionWorld.updateTransform(this.collider);
}
}
public function computeNextPathStep(timeDelta:Float) { public function computeNextPathStep(timeDelta:Float) {
stopped = false; stopped = false;
prevPosition = this.position.clone();
if (currentTime == targetTime) { if (currentTime == targetTime) {
velocity.set(0, 0, 0); velocity.set(0, 0, 0);
} else { } else {
@ -158,10 +181,10 @@ class PathedInterior extends InteriorObject {
currentTime += delta; currentTime += delta;
} }
var curTform = this.getAbsPos(); var curTform = this.position;
var tForm = getTransformAtTime(currentTime); var tForm = getTransformAtTime(currentTime);
var displaceDelta = tForm.getPosition().sub(curTform.getPosition()); var displaceDelta = tForm.getPosition().sub(curTform);
velocity.set(displaceDelta.x / timeDelta, displaceDelta.y / timeDelta, displaceDelta.z / timeDelta); velocity.set(displaceDelta.x / timeDelta, displaceDelta.y / timeDelta, displaceDelta.z / timeDelta);
this.collider.velocity = velocity.clone(); this.collider.velocity = velocity.clone();
} }
@ -172,9 +195,17 @@ class PathedInterior extends InteriorObject {
return; return;
if (this.velocity.length() == 0) if (this.velocity.length() == 0)
return; return;
var newp = this.getAbsPos().getPosition().add(velocity.multiply(timeDelta)); velocity.w = 0;
this.setPosition(newp.x, newp.y, newp.z); var newp = position.add(velocity.multiply(timeDelta));
this.setTransform(this.getTransform()); var tform = this.getAbsPos().clone();
tform.setPosition(newp);
// this.setPosition(newp.x, newp.y, newp.z);
if (this.isCollideable) {
collider.setTransform(tform);
collisionWorld.updateTransform(this.collider);
}
// this.setTransform(this.getTransform());
this.position = newp;
if (this.soundChannel != null) { if (this.soundChannel != null) {
var spat = this.soundChannel.getEffect(Spatialization); var spat = this.soundChannel.getEffect(Spatialization);
@ -182,12 +213,22 @@ class PathedInterior extends InteriorObject {
} }
} }
public function update(timeState:TimeState) {} public function update(timeState:TimeState) {
if (!stopped)
this.setPosition(prevPosition.x
+ velocity.x * timeState.dt, prevPosition.y
+ velocity.y * timeState.dt,
prevPosition.z
+ velocity.z * timeState.dt);
else
this.setPosition(stoppedPosition.x, stoppedPosition.y, stoppedPosition.z);
}
public function setStopped(stopped:Bool = true) { public function setStopped(stopped:Bool = true) {
// if (!this.stopped) // if (!this.stopped)
// this.stopTime = currentTime; // this.stopTime = currentTime;
this.stopped = stopped; this.stopped = stopped;
this.stoppedPosition = this.position.clone();
} }
function computeDuration() { function computeDuration() {
@ -205,6 +246,8 @@ class PathedInterior extends InteriorObject {
function updatePosition() { function updatePosition() {
var newp = this.getAbsPos().getPosition(); var newp = this.getAbsPos().getPosition();
this.position = newp;
this.prevPosition = newp;
this.setPosition(newp.x, newp.y, newp.z); this.setPosition(newp.x, newp.y, newp.z);
this.collider.setTransform(this.getTransform()); this.collider.setTransform(this.getTransform());
this.collider.velocity = this.velocity; this.collider.velocity = this.velocity;

View file

@ -94,7 +94,7 @@ class GuiXboxListButton extends GuiControl {
_prevMousePos = mouseState.position.clone(); _prevMousePos = mouseState.position.clone();
} }
if (selected && !disabled) { if (selected && !disabled) {
if (Key.isDown(Key.MOUSE_LEFT)) { if (Key.isDown(Key.MOUSE_LEFT) && renderRect.inRect(mouseState.position)) {
this.button.anim.currentFrame = 1; this.button.anim.currentFrame = 1;
this.buttonIcon.anim.currentFrame = 1; this.buttonIcon.anim.currentFrame = 1;
buttonText.text.textColor = 0x101010; buttonText.text.textColor = 0x101010;

View file

@ -1,5 +1,6 @@
package rewind; package rewind;
import h3d.Matrix;
import mis.MissionElement.MissionElementBase; import mis.MissionElement.MissionElementBase;
import triggers.CheckpointTrigger; import triggers.CheckpointTrigger;
import src.PathedInterior.PIState; import src.PathedInterior.PIState;
@ -13,7 +14,10 @@ import shapes.Gem;
@:publicFields @:publicFields
class RewindFrame { class RewindFrame {
var timeState:TimeState; var timeState:TimeState;
var marblePosition:Vector; var marbleColliderTransform:Matrix;
var marblePrevPosition:Vector;
var marbleNextPosition:Vector;
var marblePhysicsAccmulator:Float;
var marbleOrientation:Quat; var marbleOrientation:Quat;
var marbleVelocity:Vector; var marbleVelocity:Vector;
var marbleAngularVelocity:Vector; var marbleAngularVelocity:Vector;
@ -22,7 +26,9 @@ class RewindFrame {
var mpStates:Array<{ var mpStates:Array<{
curState:PIState, curState:PIState,
stopped:Bool, stopped:Bool,
position:Vector stoppedPosition:Vector,
prevPosition:Vector,
position:Vector,
}>; }>;
var gemCount:Int; var gemCount:Int;
var gemStates:Array<Bool>; var gemStates:Array<Bool>;
@ -52,7 +58,10 @@ class RewindFrame {
public function clone() { public function clone() {
var c = new RewindFrame(); var c = new RewindFrame();
c.timeState = timeState.clone(); c.timeState = timeState.clone();
c.marblePosition = marblePosition.clone(); c.marbleColliderTransform = marbleColliderTransform.clone();
c.marblePrevPosition = marblePrevPosition.clone();
c.marbleNextPosition = marbleNextPosition.clone();
c.marblePhysicsAccmulator = marblePhysicsAccmulator;
c.marbleOrientation = marbleOrientation.clone(); c.marbleOrientation = marbleOrientation.clone();
c.marbleVelocity = marbleVelocity.clone(); c.marbleVelocity = marbleVelocity.clone();
c.marbleAngularVelocity = marbleAngularVelocity.clone(); c.marbleAngularVelocity = marbleAngularVelocity.clone();
@ -75,6 +84,8 @@ class RewindFrame {
}, },
stopped: s.stopped, stopped: s.stopped,
position: s.position.clone(), position: s.position.clone(),
prevPosition: s.prevPosition.clone(),
stoppedPosition: s.stoppedPosition != null ? s.stoppedPosition.clone() : null,
}); });
} }
c.trapdoorStates = []; c.trapdoorStates = [];

View file

@ -21,8 +21,11 @@ class RewindManager {
public function recordFrame() { public function recordFrame() {
var rf = new RewindFrame(); var rf = new RewindFrame();
rf.timeState = level.timeState.clone(); rf.timeState = level.timeState.clone();
rf.marblePosition = level.marble.getAbsPos().getPosition().clone(); rf.marbleColliderTransform = level.marble.collider.transform.clone();
rf.marbleOrientation = level.marble.getRotationQuat().clone(); rf.marblePrevPosition = @:privateAccess level.marble.oldPos.clone();
rf.marbleNextPosition = @:privateAccess level.marble.newPos.clone();
rf.marbleOrientation = @:privateAccess level.marble.prevRot.clone();
rf.marblePhysicsAccmulator = @:privateAccess level.marble.physicsAccumulator;
rf.marbleVelocity = level.marble.velocity.clone(); rf.marbleVelocity = level.marble.velocity.clone();
rf.marbleAngularVelocity = level.marble.omega.clone(); rf.marbleAngularVelocity = level.marble.omega.clone();
rf.marblePowerup = level.marble.heldPowerup; rf.marblePowerup = level.marble.heldPowerup;
@ -40,7 +43,9 @@ class RewindManager {
velocity: x.velocity.clone(), velocity: x.velocity.clone(),
}, },
stopped: @:privateAccess x.stopped, stopped: @:privateAccess x.stopped,
position: x.getAbsPos().getPosition().clone(), position: @:privateAccess x.position.clone(),
prevPosition: @:privateAccess x.prevPosition.clone(),
stoppedPosition: @:privateAccess x.stoppedPosition != null ? @:privateAccess x.stoppedPosition.clone() : null,
} }
}); });
rf.powerupStates = []; rf.powerupStates = [];
@ -82,10 +87,15 @@ class RewindManager {
public function applyFrame(rf:RewindFrame) { public function applyFrame(rf:RewindFrame) {
level.timeState = rf.timeState.clone(); level.timeState = rf.timeState.clone();
level.marble.setMarblePosition(rf.marblePosition.x, rf.marblePosition.y, rf.marblePosition.z); @:privateAccess level.marble.oldPos.load(rf.marblePrevPosition);
level.marble.setRotationQuat(rf.marbleOrientation.clone()); @:privateAccess level.marble.newPos.load(rf.marbleNextPosition);
level.marble.velocity.set(rf.marbleVelocity.x, rf.marbleVelocity.y, rf.marbleVelocity.z); @:privateAccess level.marble.collider.transform.load(rf.marbleColliderTransform);
level.marble.omega.set(rf.marbleAngularVelocity.x, rf.marbleAngularVelocity.y, rf.marbleAngularVelocity.z); @:privateAccess level.marble.physicsAccumulator = rf.marblePhysicsAccmulator;
@:privateAccess level.marble.prevRot.load(rf.marbleOrientation);
// level.marble.setMarblePosition(rf.marblePosition.x, rf.marblePosition.y, rf.marblePosition.z);
// level.marble.setRotationQuat(rf.marbleOrientation.clone());
level.marble.velocity.load(rf.marbleVelocity);
level.marble.omega.load(rf.marbleAngularVelocity);
if (level.marble.heldPowerup == null) { if (level.marble.heldPowerup == null) {
if (rf.marblePowerup != null) { if (rf.marblePowerup != null) {
@ -123,15 +133,17 @@ class RewindManager {
@:privateAccess level.orientationChangeTime = -1e8; @:privateAccess level.orientationChangeTime = -1e8;
} }
level.currentUp.set(rf.currentUp.x, rf.currentUp.y, rf.currentUp.z); level.currentUp.load(rf.currentUp);
level.marble.lastContactNormal.set(rf.lastContactNormal.x, rf.lastContactNormal.y, rf.lastContactNormal.z); level.marble.lastContactNormal.load(rf.lastContactNormal);
for (i in 0...rf.mpStates.length) { for (i in 0...rf.mpStates.length) {
level.pathedInteriors[i].currentTime = rf.mpStates[i].curState.currentTime; level.pathedInteriors[i].currentTime = rf.mpStates[i].curState.currentTime;
level.pathedInteriors[i].targetTime = rf.mpStates[i].curState.targetTime; level.pathedInteriors[i].targetTime = rf.mpStates[i].curState.targetTime;
level.pathedInteriors[i].velocity.set(rf.mpStates[i].curState.velocity.x, rf.mpStates[i].curState.velocity.y, rf.mpStates[i].curState.velocity.z); level.pathedInteriors[i].velocity.load(rf.mpStates[i].curState.velocity);
@:privateAccess level.pathedInteriors[i].stopped = rf.mpStates[i].stopped; @:privateAccess level.pathedInteriors[i].stopped = rf.mpStates[i].stopped;
level.pathedInteriors[i].setPosition(rf.mpStates[i].position.x, rf.mpStates[i].position.y, rf.mpStates[i].position.z); @:privateAccess level.pathedInteriors[i].position.load(rf.mpStates[i].position);
level.pathedInteriors[i].setTransform(level.pathedInteriors[i].getTransform()); @:privateAccess level.pathedInteriors[i].prevPosition.load(rf.mpStates[i].prevPosition);
@:privateAccess level.pathedInteriors[i].stoppedPosition = rf.mpStates[i].stoppedPosition;
// level.pathedInteriors[i].setTransform(level.pathedInteriors[i].getTransform());
} }
var pstates = rf.powerupStates.copy(); var pstates = rf.powerupStates.copy();
var lmstates = rf.landMineStates.copy(); var lmstates = rf.landMineStates.copy();