Help with TimeWarp - Bullet Time Effects

I’ve attached a test project which should produce a Max Paine like Bullet-Time effect.

The capsule is physics based torque - just to show Time.timeScale working

The sphere is a non physics based rotatation - this object should go about time unaffected - but this is not the case and I would like to understand what is going on here.

The cube is just a center point of reference - OnMouseDown will start the effect for 1 second and SHOULD return to normal in 1 second.

Multiple clicks prove that the rotation is not the 100% correct speed for the sphere - not to mention the jump ahead that happens.

What am I’m doing wrong here? Thanks for the replies.

Cheers,

46774–1707–$timewarptest_182.unitypackage (8.24 KB)

Several things seem to be happening.

  1. The “jagged” movement of the capsule happens because you don’t lower Time.fixedDeltaTime together with Time.delta time. (You almost always want to do that.)

  2. The jump of the sphere seems to happen because the change in timescale doesn’t seem to affect deltaTime until the next frame. Hence when you increase the speed of the sphere it rockets forward for a single frame. (This must be bug, you should file it to OTEE)
    For now you can circumnavigate the problem by waiting a single frame before lowering the sphere speed.

  3. While I can’t get the sphere to move backwards, the slowdown on multiple clicks happens if you click before the coroutine is done and thus start another one (So that you now have 2 running). This cause Time.timeScale to be lower by another factor s and of course maliciously interfere with the WaitForSeconds in the first Coroutine as time is now flowing much slower. The solution is to either prevent the user from starting a timewarp while another is in progress or cancel the first one before starting the new.
    Normally you should be able to stop the coroutine with StopCoroutine(“TimeWarp”), but there also seems to be a bug with that, since when I tried this, the new Coroutine terminates at the time the old one was supposed to and not when it’s own WaitForSecounds should. (You should file this to OTEE as well. There must be some data that doesn’t get cleaned up properly) However, as long as the behavior doesn’t use any other coroutines, you can use StopAllCoroutines() instead, as that seems to be working.

private var m_RotSpeed : int = 60; //The Clock's Speed
private var m_RotDirect: int = 1; //ClockWise = 1, CounterClockWise = -1
private var m_OldRotSpeed = m_RotSpeed; //Store the current speed

//Start - make sure timeScale is fresh
function Start() { 
	Time.timeScale = 1;
	Time.fixedDeltaTime = 0.02;	
}

//Update - rotare the clock
function LateUpdate() {
	transform.Rotate(Vector3.up, m_RotSpeed * m_RotDirect * Time.deltaTime); 
}

//OnMouseDown - Let's Do the TimeWarp
function OnMouseDown(){
	Reset(); //Stop and reset coroutine in case it's needed
	TimeWarp(5.0, 25.0);
}

//TimeWarp - t = how much time, s = by what scale
function TimeWarp(t : float, s : float) {
	Time.timeScale = Time.timeScale/s; //Divide the timeScale by the scale amount (s)
	Time.fixedDeltaTime = Time.fixedDeltaTime/s; //Divide the timeScale by the scale amount (s)
	
	yield 0; //Wait one frame
	
//	print("Let's Do The TimeWarp");
	
	m_RotSpeed = m_RotSpeed*s; //To counter the timeScale effects multiple our rotation by the scale (s)
	
	yield WaitForSeconds(t/s); //let the effect take place for the length of time (t)
	
	//now were done set everything back to normal
	m_RotSpeed = m_OldRotSpeed;
	Time.timeScale = 1;
	Time.fixedDeltaTime = 0.02;
	
//	print("Let's Stop Now");
}

function Reset() {
//	StopCoroutine("TimeWarp"); //There seems to be a bug with this
	StopAllCoroutines();
	
	m_RotSpeed = m_OldRotSpeed;
	Time.timeScale = 1;
	Time.fixedDeltaTime = 0.02;
}

Thanks for the reply and sorry it took so long to get back to you. The Top Dog contest has me running thin.

If I recall correctly I tried the yield one frame for the sphere to behave more correctly but it didn’t help.

I’m not sure what “jagged” issues you saw with the capsule - like I said it was there just to show physics under the timewarp – I’ll note the Time.deltaTime suggestion - thanks.

  1. ← this was my main concern

  2. ← yeah I realized that shortly after I posted
    I normally stop each Coroutine one at a time when I do such a thing - I didn’t even know there was a StopAllCoroutines

Thanks again!

Cheers,

Just to make sure when you say lower Time.fixedDeltaTime – you really mean increase the value of Time.fixedDeltaTime in order to decrease the frequency of occurrence.

Cheers,

No, It must be lowered (usually just by the same amount as timeScale). fixedDeltaTime is the realtime interval between physics updates in seconds.

E.g. let’s say that timeScale is one and fixedDeltaTime time is 0.02 and that you have an object rotating with physics. This object is of course moved in small discrete notches but will appear to rotate smoothly since for each second that passes it will be moved 1/0.02 = 50 times. Now lets say you decrease timeScale to 0.1, you will be able to see the object move in notches since for each real life second the passes it will only be moved 0.1/0.02 = 5 times. So if lowering timeScale by a factor 10 you should also lower fixedDeltaTime be a factor 10.

If it sounds a bit confusing then try to make a scene with an physics rotated object and raise/lower timeScale and fixedDeltaTime individually and see the effets.

Good luck with Top Dog.

YEAH! I got it working!

Thanks Guys.

Now on to the next bugs…

Cheers,

For people who are new to Unity and trying to do a similar slow motion effect, just want to point out that you can set the default fixedDeltaTime under Edit - Project Settings - Time - Fixed Timestep.