Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

Time Manipulation in Unity 6

Started by rg-poly Apr 7 at 9:10 PM 1 replies 750+ views
Original Post
rg-poly
rg-poly

Hey everyone,

I’ve been experimenting with a time rewind / slow-motion system in Unity past few months, and what started as a small prototype got way more complicated than I expected.

At first, I thought it would just be about recording positions and playing them backward. But once I tried to make it work in an actual gameplay scenario, everything started breaking — physics, NavMesh agents, particles, even basic scripts.

It quickly turned into a much bigger system, so I started treating it more like an engine. I ended up building something I now call the Time Paradox Engine.
Here are the 4 biggest hurdles and how I solved them.

### 1. The Memory Nightmare (Solving it with Zero-GC & Bitwise Masking)

If you record Transform data for 100 objects at 60 FPS for 10 seconds, and use standard List<T> or classes, the Garbage Collector will eventually cause massive lag spikes.

To fix this, I used NativeArrays and a pure struct for snapshots. To make the circular buffer lightning-fast, I forced its size to be a power of two. This allows us to use bitwise masking instead of the slow % modulo operator for wrapping around the buffer.

``csharp

// Inside TimeWarpBuffer.cs

// AAA OPTIMIZATION: Power of 2 sizing for bitwise masking

int rawCount = Mathf.CeilToInt(framerate * maxTime);

Count = Mathf.NextPowerOfTwo(rawCount);

_mask = Count - 1; // Used for ultra-fast wrapping

public int GetIndex(int offset)

{

// Completely eliminates while loops and modulo operations. O(1) retrieval.

return (Head - 1 - offset) & _mask;

}

``

To actually apply these thousands of recorded positions during a rewind, I offloaded the work to the Burst Compiler and Job System using IJobParallelForTransform with unmanaged pointers TransformSnapshot**). The main thread barely notices the rewind is happening.

### 2. Frozen Physics & The "Stasis" Problem

What happens when you shoot an enemy while time is stopped? Unity's default behavior is to do nothing, because to freeze a Rigidbody, you usually set isKinematic = true.

I built a KineticAccumulator to catch these forces. If time is stopped, the object absorbs the force into a Queue<Vector3>. When time resumes, a Coroutine releases the stored hits sequentially, creating an awesome delayed-impact effect.

``csharp

// Inside KineticAccumulator.cs

public void AddKineticImpact(Vector3 forceVector)

{

if (TimeWarpManager.Instance.GlobalTimeState == TimeState.Normal) {

_rb.AddForce(forceVector, ForceMode.Impulse);

return;

}

// Accumulate energy during the freeze!

_accumulatedForce += forceVector;

_impactQueue.Enqueue(forceVector);

}

private IEnumerator ReleaseSequentialRoutine()

{

while (_impactQueue.Count > 0)

{

if (_rb.isKinematic) yield break; // Time stopped again? Pause the queue!


Vector3 hit = _impactQueue.Dequeue();

_rb.AddForce(Vector3.ClampMagnitude(hit, MaxForceCap), ForceMode.Impulse);

yield return new WaitForSeconds(SequentialDelay);

}

}

``

### 3. Creating "Time Ghosts" without melting the CPU

Rewinding is cool, but what if you want to leave a clone (Echo) that replays your past actions?

The hardest part is replaying events (like shooting a gun) without triggering massive memory allocations. I created a TimeEventPayload—a lightweight struct that acts as a data pocket.

``csharp

// Inside TimeEventPayload.cs

[System.Serializable]

public struct TimeEventPayload

{

public int EventHash; // e.g., Animator.StringToHash("Shoot")

public float Float1;

public int Int1; // Ammo index, weapon ID, etc.

public Vector3 Vector1; // Aim direction

}

``

When the player shoots, they pass this struct into the TimeEventRecorder. When the Ghost spawns, it interpolates through the recorded history. If it hits a frame with a recorded EventHash, a GhostEventReceiver catches it and calls the exact same PerformShoot(Vector3 dir, float force, int ammo) method the player uses.

It’s completely decoupled and relies on string hashes, meaning you can plug it into any existing weapon script without rewriting your game logic.

### 4. The Kill-Switch for Foreign Scripts

The final realization: No time system can magically fix a badly written character controller.

If your Turret script is constantly looking at the player in Update(), it will fight the Rewind system.

Instead of modifying every script in the game, I built a TimeWarpComponentManager. It acts as an automated kill-switch. When an anomaly starts, it automatically disables non-time-aware Behaviour components.

``csharp

// Inside TimeWarpComponentManager.cs

bool shouldBeDisabled = isRewinding && DisableOnRewind || isTimeStopped && DisableOnTimeStop;

if (shouldBeDisabled && !_componentsAreDisabledByUs)

{

for (int i = 0; i < TargetComponents.Count; i++)

TargetComponents[i].enabled = false;


_componentsAreDisabledByUs = true;

}

// When time resumes, it re-enables them and fires OnTimeWarpResume()

// via an ITimeWarpStateListener interface so they can reset their internal timers.

``

### Final Thoughts

Building a robust time system forces you to treat Unity differently. You stop relying on Time.deltaTime and start thinking in ticks, custom scaling, and decoupled data buffers.

If you’re interested in checking out the full system, I’m packaging it into an asset called the Time Paradox Engine.

👉 [[Link to Demo Showcase](https://play.unity.com/en/games/8d96e8fc-1cd5-4892-a2bd-058ce5fb19bc/time-paradox-engine)]

Have any of you used rewinding mechanics? What was the hardest thing to sync in your experience?

frob
frob

It can be a great mechanic. Unfortunately as you point out, it isn't something many game systems are built around.

Physics systems particularly, as game physics systems often implement physics substepping techniques and similar techniques, and plenty of systems and optimizations make assumptions that time only goes forward. Assumptions about gravity and other accelerations might not work out with negative timesteps.

Playing games that use time as a mechanic, like Braid, can be mind-blowing and some people can't wrap their minds around it.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.