Please Be Kind

      

Posts:
02/05/2013
02/14/2013
02/18/2013
03/21/2013
04/03/2013



Introduction

Hello everyone, Derek Dittmer here.

Rewind systems in games like Prince of Persia and Braid are fascinating, and as part of a school project, I will by trying to recreate one. I'm most likely going to be using the Unity engine to make a simple 2d platformer that has the rewind system.




04/03/13

And I'm back! This will be the last time, because I have finished it! I found some bugs, and put some extra polish into it.

So the first thing that I did was finish getting those sounds to rewind. After actually getting a sound to play in reverse, it wasn't too hard, though I did have some trouble with it. I knew I would need to save the time stamps of when these sounds played, so they could be played in reverse, but I didn't know how to organize them. I tried and failed a few times, but it is working quite well now. All the sounds are kept in a master sound list, with the time stamp (int variable) and an index into an array that holds that sound (byte variable), so that I know which sound was played at that time.

No problem - until I ran into something that I had not foreseen. I knew for playing the sounds backwards, I would need to save them when the sound finished playing and play it from there. Cool, that works, but when I rewind the rewind (play it forward) the sounds are really messed up. That is because they are playing at the end of when they should be playing. Even if I saved the sounds when the sound started, it would sound weird if I played them now in reverse. Hmm… I thought of having two different sound lists for rewinding and forward, along with a bunch of other bad ideas, but found a better solution: save them when they are played, and when rewinding, check the time stamp minus the clip's length. It isn't frame perfect I'm sure, but it sounds great and I can't even tell that it isn't perfect. Now the game sounds really awesome!

I then found a bunch of little things that made it better. The rewind would mess up if the frame rate dropped, so I just used a constant variable of what the target frame rate was and used that instead of Time.deltaTime. It isn't perfect, but it looks a lot better than it did, and it also saves me from having to save off the deltas for everything that can be rewinded. I found a nice texture import setting: changing filter mode to point made my little sprites look nice and pixilated. I also fixed quite a few very strange problems with rewinding deaths. One was where if the player died and you tapped the rewind button, the game would never do that pause when you died. I also remember the enemy reviving itself when it should have been dead. It seems to all be working fine now. I also stumbled upon something called delegates, which helped me a ton. I was trying to figure out how to let other things know when the rewind started, ended, or speed changed, and the delegate was just perfect. Basically, it is just a bunch of function pointers, so if you call the delegate, it just calls everything in it. It cleaned up my code and was super easy to use.

Alright, after I fixed a few things, I started adding more. I put in that blinking "SHIFT" message when the player dies, so he knows what to do. It was basically the same thing as the showing rewind speed, but only if the player was dead. I also changed the fonts in my game so looks a bit nicer than the default Arial fonts.

The next thing I wanted to add was some screen effect when you are rewinding, like in Braid how it goes into black and white when you rewind and the screen just kind of moves around. After doing a bit of researching (googling), I found that only Unity Pro supports screen effects. Since I couldn't find any way to do it in Unity Free, and I didn't feel like learning how to write my own shader, I went with something kind of hacky. I took Unity's water, added some transparency to it, tweaked some of the water's shader's variables, made it change colors if you are rewinding or rewinding your rewind, made it fade nicely in and out depending on the speed, and bam. To be completely honest, it doesn't look as good as I hoped, but it's still better than nothing. I wasn't going to do all that work and end up with no screen effects.

Alright, the last thing I really wanted to add to my game was those motion trails when you are rewinding, like how Braid does it. It really looks awesome, and I'm glad I did it. It took me quite a while to get it working right. I had a lot of problems figuring out how to save those positions and put the sprites there. Basically, what I did was have 12 game objects in a list, and going through and setting the last one in the list to the first one in the list, and also set that objects position to the players'. So now it cycles through the objects and puts them at them at the player. That wasn't too hard.

What was hard was getting the transparency just right. I wanted to have three of them show up for each rewind speed (so 3 for 1x, 6 for 2x, and so on), and have the last three's transparency lower than the last's, so the end of that motion trail would look cool. The way I was cycling through the list didn't quite work with that in more than one way, so I changed up the way I cycled through the list. I made two sections of the list and cycled through them both, basically the active ones and the inactive ones (because they need to be updated also so they have the right positions when they show up). That worked very nicely. Then I made it so they fade in and fade out, and after a bit of tinkering with it, it looked great.

I've read that the way I am cycling through the list is a bit inefficient (saving the last one, deleting the last one, and putting the saved off at the front of the list), but it was the best solution I could think of. Also, it starts looking a bit strange when you rewind at 8x speed, because even updating the trail's positions every frame isn't enough to keep up and look good. I've tried getting around that somehow, but figured it isn't too big of a problem. Other than those two problems, I think it works fine though.

The last thing I added were some spikes to kill the player, because I wanted to make sure the player could die and figure out the rewind button (because it now flashes "SHIFT") rather then getting frustrated. Just a design thing, but still important.

Alright, now it's done! Well almost. I had problems with the aspect ratio in an actual build because I used the Free Aspect when I was in the editor. So, everything was scaled to this strange aspect ratio that I couldn't make a build of. So I just changed it to 1024x768 and added some more level to it.

This time it is finished for good! I did everything that I wanted to do to this project and more, because I had so much fun with it and managed my time right. I ran into tons of problems, but luckily was able to overcome most of them. I learned a ton more about Unity and programming in general. Just a couple of months ago, I thought rewinding in a game was magic. Now, the magic is gone and I understand how it works. It is kind of sad, but after playing through my little test level, I am glad I took on this awesome project.

I've put up the game and the project if you would like to play it or see how I did put it together, so be sure to check that out.

Thanks for reading! I hope you found it interesting or learned something!




03/21/13

Whew, it's been a long time since my last post, but that doesn't mean I have been slacking off. I have been adding new things, struggling with problems, and doing a lot of organizing. I am going to go over some of the high-level things that I did, because if I were to write everything down that I did, it would be quite lengthy and no one would read it.

One of the things that I did that I thought was pretty cool, was shrink down the size of my saved positions, by stuffing the positions (floats) into shorts. Right now, my map is pretty small, and since my positions never get too high or low, I am able to stuff them into the short by multiplying by 1000, and then dividing by 1000, when taking them out. This allows for precision to the 0.001, which is more than enough for positions. If I change the 1000 to 100, I can make my maps 10 times the size and will still have 0.01 precision, which isn't too bad. I'm sure it could be better: maybe check the size before shrinking it, and then multiply by a certain number to get the most precision possible. Oooo, I'm going to try that now. Alright, so now I'm saving 6 less bytes for my XPos, YPos, and Velocity (see below) floats combined. Might not seem like much, but when these things are getting saved 10 times a second, those bytes add up real quick.

Another cool thing that I got working was having the variable rewind speeds. Like in Braid, if you are rewinding and use the up/down arrow keys, you can speed up your rewind. What I did not know was that if you continue holding shift, you can actually rewind your rewind (crazy) to get to the point where you started your rewind. That threw a wrench in my code, and made everything quite a mess while I was trying to get it to work correctly, but now it's a bit cleaner and works pretty smooth. Of course, I had to modify my animation script to allow for that also.

Alright, one of the things that took up a lot of my time was trying to save off the velocity, so when you stop rewinding you keep on going as if you had just jumped there. This caused me so many problems. I spent a week and it was still not right. Then I changed how I was saving my time stamps from floats (delta times) to ints (frames), and that worked much better. It still isn't perfect, but it is much better than what I was getting with the floats. Me and floats aren't on good terms at the moment, for what they did to me that long week.

With that velocity problem came a whole ton of other problems. I was able to calculate my velocity by applying some gravity to it depending on the time stamp (how many frames), but that only worked for my player, because I was handling its gravity myself. My enemy had a rigidbody and I was unable to figure out the gravity applied to it at the time, because it did its gravity logic in the FixedUpdate(). This led me to make the player's physics its own class, and have the player and enemy inherit from that. With my enemy no longer having a rigidbody, most of its logic needed to change as well. Fun. At least the velocity problem is almost fixed.

I got the enemy rewinding also. It works just about the same, but it only records every couple of frames while it is in the air – while on the ground, it only saves when it hits a wall and changes direction. This makes the rewind still look good, and also saves some memory. I decided to give the enemy the Rewindable script, because I wanted him to be able to fall off a ledge, and have that rewind also, just like in Braid.

The moving platform also rewinds pretty easy. Because it is a looping animation, I don't even need to save its positions: just set the animation speed to -1 when rewinding. So much for "more complex movement" as I called it before – that was 100 times easier than the enemy!

I made a one-shot animation class, that is close to how my animation class works, but doesn't loop. Basically, you enable the script, and it runs through the animation and stops on the last frame. I slapped that script on my treasure chest, and now it opens and stays open without a problem.

All of this added stuff was to get my rewind system rewinding objects correctly. I found out that it is still not rewinding correctly just yet. Even though I am saving the frames (ints) instead of the elapsed time (floats), I still am using Time.deltaTime in my rewind lerp script. If the frame rate drops, there will be some strangeness to my rewind, as I was able to see with my enemy. I'm sure my game isn't going to be dropping anyone's frame rate, but something external to my game could be running that can drop the frame rate. Either way, I would like to do it right. So, now I need to save another variable for how long it has been since the last save position. That way, even if the Time.deltaTime changes, the lerp will still work correctly.

Other than that small issue, my rewind system is working quite well, so I have started putting some cool stuff in. The first is having players and enemies die, and being able to rewind that death. When the player dies, the game will stop also (kind of like in Braid, but without the cool animations). This is fully working. The other cool thing I have just started messing with is rewinding sounds. I was sure Unity had some way of doing this, and when I looked online, people said that setting the sounds pitch to a negative number would make it play in reverse. So, I added some sound effects to the game, and then spent a couple of hours messing with pitch and just about everything else trying to get it to play backwards. Then, because I had tried everything else, I converted my sounds to .wav and everything worked fine. I guess compression does not like being played in reverse; wish someone online would have mentioned that.

Sorry I wasn't able to dig deep into everything that I did. Don't worry though, when I am finished with this project, I will be posting the project on my site so you can download it and see exactly how I did everything. I've been using a lot of comments, not only so I know what the heck I am doing, but so someone else can hopefully understand what I am doing also.

Here's a short video of what I got so far. Things show off are in this order: | enemies and moving platform rewinding | velocities rewinding | player dying | enemy dying | rewind speeds | one shot animations | start of my reversed sounds |.

Thanks a lot; see you next time!




02/18/13

At this point, I am knee deep in the problems of making the rewind system. It is tough to try to do anything else but try to fix this almost-working system, but I figure this is one of the most important parts of my thought process.

I made two new scripts: the TimeManager, and the Rewindable.

The time manager is very simple. It just keeps track of time. It has two, very important static variables: a bool to see if you are rewinding or not, and what the current time is (starting when the game loads). The bool makes the time count down if you are rewinding (won't go below zero), otherwise it keeps going up. Simple, but gets the job done.

The reason that I did this, was there are other things that need to know if you are rewinding of not, which makes sense. My animation class is one of them. Which way should the animation go? Ask the TimeManager. The reason for keeping track of time is for knowing when things happen. I was talking with another student, who had listened to one of Jonathan Blows talks, and he told me that in Braid your movements are only saved if you are moving. That makes a ton of sense to me. It saves a lot of space by not saving the position every time. I just need to save an extra float to have that time stamp of when he was in this position. Awesome.

Right now, the only things that use the TimeManager are my animationBase class and my Rewindable. The animation class uses the static bool to make the animation go the opposite way. Basically, you are facing the wrong way, and you are playing the animation in reverse if it is rewinding. It seemed like an easy way to do it to me.

Alright, onto the Rewindable class: the big one. My idea is that all you have to do is slap this script onto the player, and he will be rewindable. Here's some of the important data:
private class LastPos
{
   float mTimeStamp;
   float mXPos;
   float mYPos;
   public void Set(float aTimeStamp, float aXPos, float aYPos)
   {
      mTimeStamp = aTimeStamp;
      mXPos = aXPos;
      mYPos = aYPos;
   }

   public float GetTimeStamp() { return mTimeStamp; }
   public float GetXPos()      { return mXPos; }
   public float GetYPos()      { return mYPos; }
}
List mActions; //List of last positions

LastPos contains all the data that I need when rewinding. I tried to make it a struct, but for some reason the Set function wasn't working, so I just changed it to a class and everything worked perfect.

Using a list seemed like the perfect way to hold all the LastPos'. I need to push new stuff on all the time, so being dynamic was a must. It also is easy to push things onto the back, and pop them off. So, when I am rewinding, all I need to do is look at the last one, and keep popping them off when I get there.

I put this onto the player, then I just needed to Lerp between the positions. I already had the positions, and I also have how long is in between by comparing the timestamps. I didn't plan it, because I didn't know exactly how Lerp worked, but saving the timestamps also let me go backwards at the same speed as I did it forward.

Basically, how it works is, if you are going forward: every couple of frames, it checks if you have moved. If you have, it will save that position and push it onto the mActions list. If you are rewinding, it will initialize the lerp (start pos, end pos, and how long) and then will move you there. I was able to use the TimeManagers currentTime to see if you are past where you are supposed to be, and then just pop off the last thing, and lerp to the next point.

Getting it to rewind at the right speed was tough, because I didn't quite understand what the time argument in Lerp was. To be completely honest, I still don't know exactly how it works. It is a number between 0 and 1, and is kind of a progress bar for how far along you are from your startPos to your endPos. So, 0 is at the start, and 1 is at the end. Either way, it now rewinds at the right speed.

Right now, I am having issues with the animations playing backwards. It is very jittery, and not playing the full animation. I am guessing that it is finding that the character isn't moving, which sets it to the standing animation. So, the rewind is kind of working and the animations are kind of working, but they just aren't working together. It shouldn't be too much of a problem; I just need some time to mess with it to make it work.

Also, I only added the Rewindable to the player. I am thinking I could just add some extra logic to the enemy and moving platform to get them to move backwards when rewinding. That way, I can save more room to get the player to rewind for a longer time. That's the plan at least. The only thing that is rewinding right now is the player, and only his position with broken animation. It will probably still need to be smoothed out after that.

Alright, enough talk for now; there are problems that need fixing! But in the meantime, check out what I got so far:

Just a quick update: I just moved my checking if you should go to the next point logic above the moving logic, and it smoothed the animation out very nicely. Looking good!




02/14/13

Alright, I'm back. I've got a lot of work done on the platformer, but not much actual work done on the rewind system.

First let me talk about how I made the basic platformer. I thought it would be easy; "boring stuff" as I called it in my last post. It always seems easy when thinking about it, but until you actually start making something, you never find out how much work it really is. Because of this, I seem to always bite off more than I can chew.

Anyway, the first thing I needed was movement. I had left and right movement, and was about to start doing jumping, when I decided to go to see if there were any tutorials on Google. I knew I could do it myself, I've done it before, but rather than do what I already knew, I was sure I could learn something if I took a look at another way of doing it. Of course, there were tons of different tutorials on Google, but I found one that looked very well done. It used a lot of things that I didn't know about, so I had to learn about them.

The first thing was, he was using a CharacterController. I've never used one of them before, but they are very useful. Looking into the Inspector, it seemed that all it is is a hit-box and some slope settings, so you can walk up stairs and whatnot. It wasn't until I got into the code that I found how useful these CharacterControllers are. It has its own Move function, but my favorite was the isGrounded check. It checks if you are on the ground, which is much easier than me trying to check if the character is hitting something, and then checking if that thing is the ground. Very useful; glad I took the time to learn about CharacterControllers.

The next thing I learned about was InputManager. The tutorial was using Input.GetAxis() a lot, and I had no idea what that was. It is actually a very flexible way to get input, and there is already a lot of functionality built right into Unity. Input.GetAxis("Horizontal") basically checks what horizontal movement buttons are being pressed: it is negative when you are going left, and positive when going right. That made it easy to find out where the player was going. There were a lot of other things you could play with like acceleration/deceleration when pressing/ not pressing the move buttons. I played around with most of it, just to get a feel for it. I also found that the player can set these input buttons before they start the game, so it is very flexible.

Other than those two things, I could figure out the rest of the code pretty easily, and when I got it working, it worked very nicely.

The next thing I wanted to do was add moving platforms. "More complex movement" to rewind I think I said. So, this moving platform moves with the animation editor in Unity. It moves in a 'n' like pattern. Well, that was easy - except one thing: the player does not move with the platform. I tried just about everything, changing the objects' mass, putting rigidbodies and different colliders on the objects. Nothing seemed to work. When I get to this point, I ask for advice from my old friend Google. There were a lot of different ways to get something to follow a moving platform, but the one that seemed the easiest was just parenting the player to the moving platform when you hit it. I was trying to find a good way to find if you are hitting a moving platform, but ended up just giving moving platforms a tag. That, combined with the CharacterControllers isGrounded, made it pretty simple from there. It now works like a charm.

bat Next up is the enemy. Overall, pretty simple, though I did have trouble with its collision. I tried when you hit a wall, just move the other direction, but the floor is made up of small blocks, and the enemy would just keep hitting different parts of the floor and get stuck. Then I remembered seeing that there were flags for which side you got hit in the CharacterController (CollisionFlags.Sides). I thought that would make it easy to just have an enemy walk back and forth until it hit something. And I was right, it did make it easy, but trying to test if it hit the player was not. I am guessing that there is only supposed to be one CharacterController, because they don't collide very well I found. I ended up just parenting a box collider to the enemy, and everything worked perfect.

Like the first enemies in Braid, you kill them by jumping on them, and they also give you a little jump boost. They can also kill you if you are hit by its sides. This caused all kinds of problems for me. I tried using the CollisionFlags.Sides, but that was not working very well. I actually ended up just checking if the players y position + its collider bounds was greater than the enemy, then kill the enemy, otherwise player is dead. That worked out very well. So, now I have an enemy!

Now, I wanted make a key and have that key open a chest to win. There wasn't any huge issues with this. I made the key parent itself to the character when you hit it, then if the key hits the chest, open it. The only thing I had to change to the player was make it scale its x-axis by -1 so that the key would look like it is staying where you are going and not just floating there. It is similar to how Braid does it.

The next thing I wanted to do was clamp the frames per second. I don't know what number to clamp it to yet, but I wanted to make sure I could. Application.targetFrameRate made it very easy to do that. Then I went to the Unity wiki and found a show frames per second script that works very well. Now I can see how fast it is going, and how fast I will be saving the players position for the rewind.

The last thing I added was some simple 2d animation for the player and the enemy. I couldn't find any good ways to do it online, so I just did it myself. I'm really happy how it turned out. It is just a base class that anything can inherit. I got it all set up for the player, and then all I had to do was set the frames for the enemy, inherit from the animation class, and it just worked. Nice!

I put some textures on everything, because the white, untextured blocks looked weird with the nicely animating player and enemy. Now it is time to start making these things rewind!




02/05/13

Alright, so at this point, I haven't actually started making the rewind system, but I have done a lot of thinking.

My vision for a really finished project would be to have:

So the rewind would affect the position and animations mostly, but if I find that I have some extra time, reversing the player and enemy deaths would be cool also. I would also like to have the sound effects that can be played backwards, but we will see how good I do with position and animations first.

Since I am here just to test my programming, I decided to take my art from RPG Maker, because they have simple animation sheets for characters and such. Here are some pictures that I will probably use in my system:

                    

When I decided to go with the rewind system, I thought it would be impossible for me - it seemed like magic. But after a bit of Googling and talking with some other students, it has moved from impossible to just really hard.

A lot of the solutions I found on the internet were just keeping a big collection of the character's previous positions. That sounds easy, but if I were to have many moving platforms and enemies on the screen, these collections would add up very quickly. I don't know exactly how long Braid can rewind, but I would like to be able to rewind as much as possible, so keeping these collection sizes down will be the key.

Just today, when I was thinking about this, I came up with some ideas on not only how to keep the sizes down, but also how to possibly get rid of some of the collections. I thought I would need to keep arrays/lists of each object's position and animation frames. But, since the enemies and moving platforms are not going to have any crazy AI or randomness to them, I could just tell them to do what they are doing, but backwards when time is rewinding. It will probably take some more programming, and I may even have to do something unique for each object, but it seems to be a much more efficient way to do it.

I also think that for the player, I may only need to have an array/list for the positions, and not animations or anything else. I was thinking of many different ways to save where the player was: the player input, the forces acting on the object at that point, but I think positions will work just fine. As for getting the animations to play backwards, I am thinking of taking a look at the current and previous rewinding positions to see which direction the player was moving at that point, and then play the right animation according to that. My movement probably won't be very complex, so I should be able to put something along those lines together. It works well in my head, but I will have to try putting it into action before I will know how well it works. If it does work, then that will be one less thing to keep track of (making more room for saving the player position), because I will be replicating the animations instead of pulling them from a saved off collection.

If I do have time to mess with player and enemy death, I think I have a way to do it. When you kill the enemy (probably jump on its head), instead of deleting it, just disable its renderer, collider, and scripts. I figured this would be much easier than trying to remake a deleted object. When the player dies, it can just stop player movement until you rewind. Actually, it seemed a lot easier before I wrote that last sentence, because that would require a different state for the player, which may also need to be saved somewhere. I may be able to just have everything pause while you are dead, and if you rewind, you will no longer be colliding with the enemy, which means you are alive. Hmm… I will cross that bridge if I get there.

Alright, I think I have enough info at this point to start my project. I feel that rewinding time is a lot more possible than it was when I just started. Before I get started, though, I will need to get the boring stuff out of the way: making a simple platformer in Unity before I try to add the rewind system.

I'll see you again when I try putting this stuff together. I am foreseeing a lot of small things that I haven't thought of that are going to cause a lot of problems for me (it seems to always work that way).