Time Rewinding

Published by mark on

Time Rewinding

Meta Data

Teamsize: Solo

Project Length: 6h

Engine: unity

I had was wondering to make and I suddenly had an idea to make a Time rewinding prototype for unity. so i went on with it after school and created it. after i was done creating it i was very pleased with the result that i started working on something bigger and better. with way more functions

Demo video

Video demostrates the performance of the rewinding with 1300 objects rewinding in time.

Package

Would you like to open a the project yourself and take a look at it? Great, click the button below to download the unitypackage.

 

Ps be sure your unity project .Net version is set to 4.6

Sample Code

Sample code of the quick prototype rewinding manager

using System.Collections.Concurrent;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;

namespace Rewind
{

    public class RewindManager : MonoBehaviour {

        private struct Rewindable
        {
            internal volatile ConcurrentStack Position;
            internal volatile ConcurrentStack Quaternion;
            internal volatile ConcurrentStack RigidbodyVelocity;
        }

        private static volatile ConcurrentDictionary m_RewindalbeobjectsStacks;
        private static volatile List m_RewindableObjects;

        private void Start()
        {
            if (m_RewindalbeobjectsStacks == null)
            {
                m_RewindalbeobjectsStacks = new ConcurrentDictionary();
                m_RewindableObjects = new List();

                m_RewindableObjects.Capacity = 1000;
            }

            //set time value for rewindableobjects
            RewindableObject.RecordingSpeed = (1f / 120f);
        }



        private void Update()
        {


            //update rewindtimer for rewindable object and if triggerd then update items in manager
            if (RewindableObject.TimerUpdate())
            {
                bool mouse = Input.GetKey(KeyCode.R);
                //Update RewindValue
                Parallel.For(0, m_RewindableObjects.Count, (int i) =>
                {
                    ChangeRewindValue(m_RewindableObjects[i], mouse);
                });

                //create tempqueue for next update
                ConcurrentQueue> updatequeue = new ConcurrentQueue>();

                //start rewinding indexing in another thread
                Task TaskRewind = Task.Factory.StartNew( () =>
                {
                    updatequeue = RewindUpdate();
                });

                Task.WaitAll(TaskRewind); // wait for task to be completed then continue update

                while(updatequeue.Count != 0)
                {
                    KeyValuePair pair;
                    updatequeue.TryDequeue(out pair);
                    Rewind(pair.Value, pair.Key);
                }
            }

        }

        /// 
        /// returns queue of objects to be rewinded
        /// 
        /// 
        private ConcurrentQueue> RewindUpdate()
        {
            ConcurrentQueue> updateQueue = new ConcurrentQueue>();

            //do for loop in parrallel with additional threads
            Parallel.For(0, m_RewindableObjects.Count, (int i) =>
            {
                IRewindable currentRewindable = m_RewindableObjects[i];
                Rewindable currentRewind;
                if (currentRewindable == null)//Connected Dictionary has lost reference and should remove the entry
                {
                    m_RewindalbeobjectsStacks.TryRemove(currentRewindable, out currentRewind);
                    m_RewindableObjects.Remove(currentRewindable);
                }
                else
                {
                    if (m_RewindalbeobjectsStacks.TryGetValue(currentRewindable, out currentRewind))
                    {
                        //if == True add to rewindqueue
                        if (currentRewindable.Rewinding)
                        {
                            updateQueue.Enqueue(new KeyValuePair(currentRewindable, currentRewind));
                        }
                    }
                }
            });

            return updateQueue;
        }

        /// 
        /// updates dictionary instance 'key' with new modified rewindable values from 'comparevalue'
        /// 
        /// 
        /// 
        private static void ModifyRewindable(IRewindable key, Rewindable comparevalue)
        {
            Rewindable currentvalue;
            m_RewindalbeobjectsStacks.TryGetValue(key, out currentvalue);
            m_RewindalbeobjectsStacks.TryUpdate(key, comparevalue, currentvalue);
        }

        /// 
        /// changes the rewindable according to the 'Value' given
        /// 
        /// 
        /// 
        public static void ChangeRewindValue(IRewindable targetobject, bool Value)
        {
            Rewindable rewindstruct;

            if (m_RewindalbeobjectsStacks.TryGetValue(targetobject, out rewindstruct))
            {
                if (rewindstruct.Position.Count != 0 && Value == true)
                    targetobject.Rewinding = Value;
                else
                    targetobject.Rewinding = false;
            }
        }

        /// 
        /// Rewinds the object given, if no more rewinds avalible it will pauze object
        /// 
        /// 
        /// 
        private static void Rewind(Rewindable rewindable, IRewindable instance)
        {
            if (rewindable.Position.Count != 0 && rewindable.Quaternion.Count != 0 && rewindable.RigidbodyVelocity.Count != 0)
            {
                Vector3 rewindpositon;
                Quaternion rewindrotation;
                Vector3 RigidbodyVelocity;

                if(rewindable.Position.Count > 1)
                    rewindable.Position.TryPop(out rewindpositon);
                else
                    rewindable.Position.TryPeek(out rewindpositon);

                if (rewindable.Quaternion.Count > 1)
                    rewindable.Quaternion.TryPop(out rewindrotation);
                else
                    rewindable.Quaternion.TryPeek(out rewindrotation);

                if (rewindable.RigidbodyVelocity.Count > 1)
                    rewindable.RigidbodyVelocity.TryPop(out RigidbodyVelocity);
                else
                    rewindable.RigidbodyVelocity.TryPeek(out RigidbodyVelocity);

                instance.Rewind(rewindpositon, rewindrotation);
            }
        }

        /// 
        /// adds a rewind instance
        /// 
        /// 
        /// 
        /// 
        /// 
        public static void AddRewind(IRewindable target, Vector3 position, Quaternion Rotation, Vector3 velocity)
        {
            Rewindable WorkingRewind;

            if (!m_RewindalbeobjectsStacks.TryGetValue(target, out WorkingRewind))
            {
                WorkingRewind = new Rewindable()
                {
                    Position = new ConcurrentStack(),
                    Quaternion = new ConcurrentStack(),
                    RigidbodyVelocity = new ConcurrentStack(),
                };
                m_RewindableObjects.Add(target);
                m_RewindalbeobjectsStacks.TryAdd(target, WorkingRewind);
            }


            if (!target.Rewinding)
            {
                WorkingRewind.Position.Push(position);
                WorkingRewind.Quaternion.Push(Rotation);
                WorkingRewind.RigidbodyVelocity.Push(velocity);

                ModifyRewindable(target, WorkingRewind);
            }
        }
    }
}


}
Categories: Prototype