The purpose of this lesson is going to be to introduce you to a very useful Unity concept called Lerp or Lerping. Lerp refers to a commonly used, but often poorly understood method in the Unity engine called Lerp(), which stands for Linear Interpolation. Actually there are several different versions of the Lerp method found in a few different classes that mainly differ in what kind of values they operate on, but otherwise they all function under the same premise of linear interpolation. If you understand one type of Lerp, you pretty much understand them all. Here is another funny sounding term which is actually really simple on its basis. It’s basically just transitioning a value from point A to point B or a time. One of the reasons why this is so useful in Unity is because of the difficulty of handling changes over time via an update loop. Now we saw how this could be accomplished with ordinary Controller-based movement, but the Lerp method mainly comes into play whenever you need a predictable change to occur and then presumably stop after a period of time. This could be anything from change in the color of the background to say day to night or it could be fading a GameObject until it disappears or moving a GameObject from here to there, such as with the enemy movement pattern.
Whatever the case, learning how to Lerp is crucial to any of these tasks. To start off with we’ll demonstrate how Lerp methods work by setting up a new test script called LerpTest and we’ll attach it to the Test GameObject and we’ll go from there. LerpTest, and attach it to the Test GameObject. Don’t need that outputting anymore. We’ll open it up. Just to start out with, we’ll just make it fairly simple and we’ll say float Accumulator, which will make sense shortly, and we’ll give it that value; and float output. For consistency's sake, it doesn’t matter, use PascalCase. In the update we’ll call the Lerp() method, so the one that handles floats and outputs a float is in the Mathf.Lerp().As you see there, it takes a three floats. From point A to point B over a percentage, which represents time as a percentage of a value between A and B. I’ll explain that all in a minute here. I’ll pass in -5 for the point A, 5 for point B, and I’ll reference the Accumulator right there. Since returns a float, we'll return it to our Output field. Here we’ll increment the Accumulator += a relatively small value, but not too small, .004f. Here is a primer as to what to expect from this. In this case we’ve setup the first input parameter as - 5 and the second as 5. As I said earlier, the from and to points respectively. To transition between them, we refer to the third parameter, which is what we create as the Accumulator.
Now the way that this transition occurs is it’s a percentage, it represents a percentage between those two values. For instance 50% of the way between - 5 and 5 is 0, right? If I just stick in 0.5 as in 50% in his third parameter and then just for now to the debug log, we’ll output that. What should you expect? I just told you, but there 0 as being output on every frame, so that’s not very optimal. We’ll do something about this in a minute. That 50% represents the midway point, pretty easy. That’s great, but what we really need is a gradual transitioning between the two values over time, so what we really need to do is change this third parameter over time, so that it continues to represent a progressive percentage point between minus 5 and 5. In another words we want to go from returning from almost 0% of the way between these two values, which would be -5, all the way up to 100% of the way, which is 5. So that would mean, for example, 25% of the way would be -2.5, 50% is zero, 75% will be 2.5 and so on. That’s why we use the Accumulator that I setup here to store the value that is constantly increasing with each update call. Let’s now reference the Accumulator here instead of that static or I should say unchanging percentage. Accumulator will accumulate a percentage over time, so to better see what’s being output than what we are seeing through the debug log, let’s output it to a GUI as we define here.
Let’s just define an onGUI() method, and here let’s just give it at a content color, so it stands out, say magenta. Let’s give it a Label, new Rect(105, 250, ) and here we’ll go String.Format() We’ll say Lerp Accumulator for this output where you want to see. We’ll also want to output the Output right here. We want to see how these both output, make this slightly different and make this Output. This wants the output. Let’s run that, let’s actually take out Debug.Log(), we don’t need that anymore. It’s going to be outputting through the OnGUI() call. There you go. As the Accumulator is accumulating, we are getting closer to 100% and past 100% as I mentioned earlier, we get 5. Not too difficult to wrap our head around. At this point it should be fairly clear as to what this Lerp() method does, but now let’s make it a little bit more obvious and more akin to what you’ll be using it for in actual projects by attaching a SpriteRenderer component and have the return result of a Lerp() method move the Sprite from one point to another. Let’s do this. I don’t want to make a whole new Sprite for this, so let’s just go to our images here and let’s put our Tabor on there for the SpriteRenderer. Let’s just arbitrarily put it on the layer there. It stands out and we know what we are dealing with here and we don’t get it mixed up with our other items, just change this a bit. I don't know, there we go. Make it like a little green sort of, I guess a zombie Tabor of sorts. We can pretend, I guess it’s going after, has insatiable thirst for brains and we’ll be Lerping from there to wherever the brains are. Let’s just imagine that being the case.
Now let’s go ahead and move the Lerp-specific code into its own method called LerpTypes(), just to make it a little bit easier to keep separate. We’ll be returning the Output of the float because that’s returning a float. In update let’s just say, we've got to put it into a temporary Vector3 that will assign them to the transform for this zombie Tabor. In that Vector3 constructor, we’ll pass in for the X because let’s say we want to move it on the X coordinate. We’ll just reference LerpTypes() as the X input argument, and then just 1 and 1 for the second and third input, and then assign that to the transform.position. So, it actually moves it on every frame. Don’t get too confused here by using the return keyword, having return type and output being a field that survives between calls to LerpTypes() method. I’m simply doing this so that I could reference LerpTypes() as a method directly within the constructor as you saw here or otherwise I’d have to call LerpTypes() on an another line of code and then reference Output, the field where I’m referencing Lerp types. That’s the only reason I’m doing that, otherwise you don’t have to use the return in this case. I’ll run this now, so you can see the results of Lerp() a little bit more explicitly, there's our zombie Tabor here. Here you go, it’s going from -5 to, we’ll expect it at 100%, to stop at 5.
This pretty much demonstrates the general use of Lerping, but you’ll see a bunch of different ways of using Lerping in different cases. This particular usage is a very constant motion from one point to another. That’s because of the fixed incrementing Accumulator, and the fixed point A to point B input parameters. We could make Lerping also speed up faster and faster, simply by using an exponentially increasing Accumulator simply by doing the following. Instead of a constant, we can simply have plus equal itself and I’ll add a little multiplier just so it’s little slower, it’s not going too fast. I’ll make a little comment here. I’ll say Accumulator Type1 and this one is Exponential, which you’ll see running in a second here. Doubling, so it’s going to double every time it’s called, this method is called. For the other type of Accumulator which is linear, I guess you could say, so I’ll say, "Accumulator Type2: Linear Fixed Accumulator." I’ll say Accumulator plus equals what it was before, so 0.004f, and that’s the linear one, but right now we are going to just comment that out and stick with this one, which will be the exponentially increasing one. This is going to be like going 2 + 2 = 4, 4 + 4 = 8, 8 + 8 = 16, and so on. Rather than the previous Accumulator calculation, which was more like 1 + 1 = 2, 2 + 1 = 3, 3 + 1 = 4, and so on.
Now let’s just run this and you’ll see the difference. That’s also a very different type of Lerp motion and it’s also useful. Just the really simple change and you have a very different type of motion. Now as were commenting here, I’ll show a new little thing here that I didn’t show you before called Regions. All you do is to create a region is use the #region. There you go, it’s already as you can see in IntelliSense, it's already a recognized keyword. I’m going to say ACCUMULATOR TYPES, so you can look at this at a glance and know what the region has to do with. Regions are basically just for organization and I’ll show you here, #endregion, for the closing tag of that. Basically this is its use is you can then roll up the entire block here and get out of the way, but have just the note that’s useful, so that you can then open it up and then go back to it. Now I’ll show you a different Lerp(). In this case what I’m going to do is I’m going to have the 'from' input parameter gradually change over time rather than remain static, staying as -5 and then the Accumulator or the third parameter representing percentage of a way between point A to point B. I’m going to have that -5 change an increase, and so the percentage will represent a different value as that point A starting point changes over time.
Why not feed that return value back in as the first input, and in doing so, we can keep the percentage, the third input fixed. This will result in a motion that has the effect of smoothing when it reaches its destination since the relative percentage decreases the closer we get from point A to point B. It’ll be all pretty obvious here when I’m doing it. Let’s start off with another region as I show you this other kind of Lerp behavior. Here let’s say... let’s call this the fixed type, the fixed "from" Accumulator. "Lerp Type1: Constant transition, Fixed "from," and comment that out immediately. I’ll fix this up. That’s just so if you uncomment, the actual comment stays as a comment if you uncomment the entire block there. Now the other type that I just mentioned we’ll call "Lerp Type2: Smooth Transition, "No Accumulator Required." For this we will feed the output back in as the evolving point A. For this, we don’t even need the Accumulator anymore, we can use the static percentage. Boy, I’m making a mess out of this, kind of getting out of my control here. The only reason I did this, so you can just roll those up really quickly and come back to them because I think you will come back to this when you employ Lerping later on and see how you did it. Let’s see what this Lerp is like. It slowly finds way to its destination point. Almost gets to 5, not quite, but basically it will be interpreted as 5, which would be 100% of the way.
The way that this works is if you look at what output first holds, it starts off with zero. The first time this Lerp() method runs, it returns … 0.02 was our percentage for the third parameter, so it returns 2% of the way between 0 and 5, which is 0.1.Then it returns 2% of the way between 0.1 and 5, which is a slightly smaller increment, 0.098. This process continues all the way up until you’re close to 5, so for instance 2% between 4.9 and 5 will be an increment of only 0.002, but since it still hasn’t reached 5, the endpoint point B, it’ll still increment, however small, as you saw here towards the end there and produces a smoothing effect as it reaches its end destination. For this reason this Lerp is sometimes called a "Smooth Lerp." Often gives a more appealing looking result for gameplay purposes. A common one would be using the GameObjects current transform.position as input for the first point A position, and in Lerp from that position to wherever you want to end up, and outputting the value return back to the GameObjects transform.position in order to create that movement. Since every call to this Lerp() would make the transform.position a little bit closer to the desired endpoint, you get this kind of smoothing effect. You could do that simply by making a little modification to this, you’ll have the exact same effect but you’ll just type in transform.position.x.
It’s for the same basic idea, we are taking it from where it currently is and just increasing until it gets to the final destination. We are putting it back into the transform.position with the smoothing behavior. Basically you’ll have to pick and choose which Lerping approach is best for your particular mechanic that you’re trying to create. Bear in mind that there are a lot of different potential formulas you can apply to generate a particular Lerp motion. For instance, if you want to create say a wave pattern, you could use a smooth lerp on the Y-axis that loops up and down, and then have maybe a steady Lerp on the X-axis or any variation between to produce a wavelike pattern. In this case I purposefully chose very simple math formulas using just simple addition and multiplication because you can get pretty much any behavior you want that way. Honestly I’m not much for math and this is my hand-fisted way of approaching things, but in the end it works and you can achieve just about anything you really want with simple formulations. Before we leave this lesson and move on, I want to do something really quick and pretty simple, which is not going to make a lot of sense right away. I want to attach a SpriteRenderer to this GameObject, this test GameObject and I want to keep it all in code, so I’ll be attaching all this stuff in code rather than in the Unity Editor. This isn’t going to make a lot of sense, but it’ll be a bit of a preview to what you’ll learn later on. I’ll explain why I’m doing this in a second.
In Start() we are going to setup our GameObject and here I’ll put a comment, SpriteRenderer. I’ll say SpriteRenderer renderer, so that’s a local variable, equals GameObject. I’m referencing this GameObject and I’m calling the add component method, and then something you probably haven’t seen before, at least not in this course is, now I’m going to reference a type here in these angle brackets. I’ll go all into this later, it’s called generic type, actually in this case a generic method, because I’m calling method. It’s that line, I’m setting the renderer here in code, and then I’m accessing that renderer and feeding it a Sprite. Actually I have to hold off on that in a second, I’ll come back to it. renderer.sortingLayerName so it’s exactly as we set it up, Player1 and what did we do, we made a bit of a zombie-like color. color, new Color() and what was it here? here. These are, it’s not float values but colors here in the constructor taken floats. I’ll have to change what I had to a percentage as a percentage between those points. It’s just awkward, so 0%, 1%, 1 would be 255, 0 would be 0. I don't know, add about 60 I think so let’s just say 0.3. It was 255. This is about 30% of the way I think. I know my math is probably bad. I should make a green Tabor as we had before. Before we can get this working, we are going to have to … I’ll talk about this more later, but this is how you load assets dynamically in code. You have to do it through a resources folder. I’m going to create a Resources folder and any assets you add here you can reference in code and load it from that folder. In this folder what I’m going to do is I'm going to make an Images folder. Once again I’ll talk more about this later, this is more of a prelude to that, all these topics, I’ll mention why I’m doing this in the second.
What I want to do is I want to take my Tabor here and put it in my, I can't copy and paste, so I’ll have to import as a new asset. Now I can reference this folder on this line of code to import that Sprite. I access the... uncomment that first, I access the Resources class and the Load() method, which again, we use these angle brackets. In that method we’ll pass in the string reference to that image to that Sprite, so it loads that Sprite image. It’s not a spite, it’s a Sprite. That’s the property for, the renderer has a Sprite property. That looks, it’s all good. Now here I can just remove the SpriteRenderer here entirely, and it will show up. As long as the script is enabled, it’ll run the start method and it’ll create the SpriteRenderer dynamically in code. Now when we press play, it should create our SpriteRenderer and have it just as it was setup before. Great. That was a little quick diversion. Again, I’ll go back to this topic later about how to attach components in code and manage them a little bit more in code. That was more of a prelude to that, mainly so that I could get rid of this SpriteRenderer in the inspector. It kind of was ugly sitting around there with all these other scripts. I didn’t want you to worry about enabling and disabling and remembering that when you come back to this Lerp example. That’s quite a bit of work for today. I’ll see you in the next video.
Lesson 35 - Understanding the Lerp Method