- Home /
Rewinding and Replaying multiple objects' through their respective waypoints by manipulating a time variable
I'm saving the transform.position of my object every 0.2 secs, inside a waypoints list as follows.
public List<Vector3> waypoints = new List<Vector3>();
void Start() {
InvokeRepeating("addWaypoints", 0, 0.2f);
}
void addWaypoints()
{
if (!Input.GetKey("space"))
waypoints.Add(transform.position);
}
void OnTriggerEnter (Collider obj)
{
waypoints.Add(transform.position);
CancelInvoke("addWaypoints");
gameObject.tag = "blue";
}
There are many such objects which fall under the tag 'blue', and each and every entity has a different length of journey to reach a goal object. Upon reaching the goal object, the input control for each object gets disabled, so as to allow the rewind and replay to happen. How do I create a global time variable, which I can connect to all these objects, that I can just decrement to zero, so as to rewind these objects, and to replay them again, when the rewind is done happening, and all the blue tagged objects have reached their first waypoints simultaneously ??
Answer by Kiwasi · Oct 12, 2014 at 06:35 AM
This is the type of question I hang around waiting for.
A couple of design questions to consider
Do you need interpolation?
Will your time step always be fixed at 0.2?
Will the replaying be occurring while other GameObjects are still moving?
Do you need multiple instances running or can you make things static?
Here is the basic structure I would use
Create a manager class and a waypoint class
Collect all of the waypoints to be managed in a List
Each waypoint should check in from OnEnable, and out in OnDisable
Each waypoint will have a function that can set its position according to a time
The manager class will call the new time on every waypoint in the list
Here is some pseudo code to get you started
// This class is static. Call TimeManager.SetTime from anywhere.
public static class TimeManager {
private static List<Player> players = new List<Player>();
public static void AddToList (Player player){
players.Add(player);
}
public static void RemoveFromList (Player player){
players.Remove(player);
}
public static void SetTime (float time){
foreach (Player player in players){
player.SetTime(time);
}
}
}
// This class gets added to each GameObject to be managed
public class Player : MonoBehavior {
public List<Vector3> waypoints = new List<Vector3>();
void Start() {
InvokeRepeating("addWaypoints", 0, 0.2f);
}
void addWaypoints(){
if (!Input.GetKey("space")) waypoints.Add(transform.position);
}
void OnTriggerEnter (Collider obj) {
waypoints.Add(transform.position);
CancelInvoke("addWaypoints");
gameObject.tag = "blue";
TimeManager.AddToList(this);
}
void OnDisable (){
TimeManager.RemoveFromList(this);
}
public void SetTime (float time){
int index = (int)(time / 0.2f);
if (index >= waypoints.count){
Debug.LogError ("Time outside of allowed range, clamping")
index = waypoints.count;
}
transform.position = waypoints[index];
}
}
You will have to adjust if you decide you want flexible time steps. That will only be doable using a time stamp.
I haven't coded in interpolation. To do this you take the index and the index + 1, then lerp based on the difference of time from the lower time step. Let me know if you want pseudo code for this.
I made the manager class static as it seems to be you would only have one of these running around. But you don't have to do it this way.
If you want to be still moving GameObjects while setting the time for others you will need to move adding them to the list out of OnEnable as appropriate.
Edit: Clarified pseudo code based on comments
Hi @Bored$$anonymous$$ormon , I guess I wasn't precise or maybe there was some misunderstanding. There will need to be a seperate set of waypoints for each entity of the object, so saving all of them inside the Time$$anonymous$$anagers' waypoint list will not serve the purpose. That is pretty much why I had the script on each copy of the object. The 0.2f is just a number for now, that I might have to change, depending on how accurately the recording works. Also, the player movement I have happens at a linear speed with no easings at all but, when I used lerp for an earlier project to move through the waypoints, there appeared to be easing into and easing out of each waypoint position for some reason. The best example for what I require would be - THIS. So basically, rewind at an incrementally faster speed but replaying at the same playback game speed. Pretty sure there would be only one instance of the Time$$anonymous$$anager class, and waypoints of only the currently controlled object would be stored at any time. The way this seems to be working is by manipulating just the global game Time variable, and the movements of the previous ghosts happen accordingly.
You missed my answer. The waypoint class I have described goes on each GameObject, just like your current set up. Each GameObject still uses your code to track it's position over time.The manager class contains a list of all of the waypoint scripts on each GameObject. I may have been misleading with my class na$$anonymous$$g. What is the name of the script in your op? I will update my answer to suit.
Ah, I misunderstood then. The name of the script is 'Player'. I tried going through your answer but I'm still confused. Does the Time$$anonymous$$anager hold the waypoints list of all the objects ? If so, why do you suggest that a particular objects waypoints list be removed from the list inside Time$$anonymous$$anager on being disabled ? Or have I misunderstood yet again ? I'm sorry I'm finding this a tad confusing.
All good. While the coding is not super complex it's not trivial either. I'll post more clarifications when I get to my computer. Unsubscribing in OnDisable is habit. $$anonymous$$ight not be needed for your specific use case.
The time manager simply holds a reference to the script on each GameObject that wants to be managed.
There is some better pseudo code now.
Looking at it you could also accomplish the same thing using events. Pseudo code is pretty similar, but slightly simpler.
Answer by gribbly · Oct 11, 2014 at 07:00 PM
Does the list waypoints contain waypoints for all objects that you want to rewind? Or is this script attached to each object?
If it's the former, it seems like you'll need to store more than just a list of co-ords. Wouldn't you need:
1) The game object 2) A way point 3) A timestamp
Here's how I would do this:
Put a replay script on each "blue" gameobject
Every 0.2s the script adds to a dictionary which is {timestamp, waypoint}
Get time stamp by storing Time.time in Start() then doing Time.time - startTime
Then for playback you sort the dictionary by timeStamp, and iterate over it setting the position to waypoint each time.
Thanks for taking the time to answer, @gribbly. Nope, the list waypoints doesn't contain waypoints for all the objects I want to rewind. This script is attached to each object and hence, has its' own respective waypoints list. How do I add a timestamp along with the currently added waypoint in the list ? I'm a little confused on that part. Also, I'm not sure how to make the object move between the waypoint values with respect to the timestamp.
Your answer
![](https://koobas.hobune.stream/wayback/20220613164904im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Rewind? *confused* 4 Answers
Cube To Follow Waypoints - Help! Att: Picture 1 Answer
character recognition 0 Answers
Another argument out of range (sorry) 2 Answers
Determine transform.position of location between two waypoints on bezier path 0 Answers