Section 9. Scaling Vectors
Vectors have another important property inherent in how they are recorded and the way we think of them. To understand this, it’s best to think of them as represented by arrows. This quality that they have is called the “magnitude” and it’s represented by the length of the vector.
When the vector represents movement (velocity), the length represents speed. A ball moving at a velocity vector of (1,1) is moving one unit upward and one unit to the right every unit of time that passes. (In most cases, our unit of time is frames, which is many times per second, but we’ll go into that later.) When we apply vectors to position, the arrow points in the direction of movement and the length of the arrow is how fast it’s moving. A Vector2(1,1) has a magnitude of 1. Magnitudes of 1 are kind of special and useful – we call them “normalized” vectors. If the vector’s length was any shorter or longer, it wouldn’t be normalized. For example, Vector2(3,3) is not normalized.
We tend to get nice, normalized vectors when we use Unity’s built-in vectors because they are all normalized. We can add Vector3.up, Vector3.right, and Vector3.forward in any order and we’ll always get a normalized vector as a result.
Normalized vectors are really easy to scale. A vector can be scaled by multiplying it times a float. This is a bit counter-intuitive, because it’s usually hard to perform math operations with two different data types. But in this case, a vector times a float, will always get you a new vector of a different size. This is called scaling and is really useful because it doesn’t change the direction of the vector.
Normally, the pythagream theorem is used to calculate magnitudes, but Unity will do this for you. In fact, when you create a Vector2, it’s magnitude is stored as a variable within that Vector2 function call. So, remember our jump vector. It’s really easy to get the magnitude of that: jump.magnitude
That tells us basically how fast something is jumping (per frame, in this case, which is absurdly fast. More on that later.) To turn this into a normalized vector, I can divide both coordinates by the magnitude… or I could just let Unity do it. Once again, it’s built into our Vector2s.
Vector2.normalized
This will get us a new Vector2, which will have the same direction as the original Vector2 but have a magnitude (arrow length) of exactly 1.
So let’s say, I wanted to build a jump function.
void HasJumped()
{
}
In this function, I’m take the character’s current position (wherever that might be) and I want to send it upwards. Let’s ignore “jump” for right now and use Unity’s built in “Vector2.up”, which is already normalized for us.
void HasJumped()
{
transform.position = newPositionAfterJumping;
}
What is newPositionAfterJumping? Well, it has to start from where you are now (the old position), and then we apply the up vector (jumping), and that gets us our new position. So it will be "transform.position + Vector2.up".
void HasJumped()
{
transform.position = transform.position + Vector2.up;
}
But how much does he jump? It’s logical at that some point we’re going to make a “jump speed” variable (that we’ll call jumpSpeed) and we want to apply this to the jump. Since the vector’s magnitude represents the speed, we want to adjust that magnitude by scaling the vector by jumpSpeed. (When we multiply a number to scale the vector that number is called the “scalar”.)
We’re going to be doing this a lot. “Position + (Vector * speed)” Don’t write that down quite yet, until we get to part 2 of this section.
So here’s how our function looks right now:
void HasJumped()
{
transform.position = transform.position + (Vector2.up * jumpSpeed);
}
Just to look at that in more detail:
(Vector2.up * jumpSpeed) // A vector times a float gets us a new vector.
// A normalized vector times a scalar gets us a new scaled vector
transform.position + (Vec… // A position plus a vector gets us a new position
transform.position = tra… // The new position is stored in the transform’s position property
Section 9, part 2. Time
Just a quick note because it’s come up quite a bit. Speed is a measure of distance over time. In scripts, our unit of time is one frame. Games run on many frames per second, such as 30fps, 60fps, etc. depending on hardware performance.
Speed is a measure of distance over time. Vectors are a measure of distance. The length of the arrow is how much distance is covered in one frame of time.
So, if you want to move a unit 6 units to the right, then you want to move it by “Vector2.right * moveSpeed”, but if you want to take 3 seconds to get there, how low should moveSpeed be? If you have 30 fps, then you can calculate that as 1/15, but I don’t know how to cap the fps and I’m not sure I’d want to.
Unity gives us a useful value to work with called Time.deltaTime. Time.deltaTime is the amount of time that passed since the last frame was loaded. It’s a very small amount of time - like 1/50th of a second. If you multiply a value by this number, the result will be very small, but then, you want only a small amount of movement each frame. In fact, this property is useful because if you multiply Time.deltaTime by any given value, that will result in a number of seconds equal to that value.
Let’s say each frame takes 1/50th of a second, or 0.02 seconds. If you multiplied speed of 2 by this amount, you’d get 0.04 speed. This is a small amount, but it moves 0.04 unity units every frame. So if you had 50 frames per second, then you would move exactly 2 units after 50 frames (1 second) had passed. Now, the frame times will fluctuate, but so will Time.deltaTime, so it will all work out.
If we want to move 6 units to the right, and we want it to take about 3 seconds, we need a moveSpeed of 3. When we apply this moveSpeed though, we can’t just use vector * moveSpeed, because that will mvoe us 3 units every frame, and there’s dozens of frames each second. What we need to do is say vector * moveSpeed * Time.deltaTime.
Here’s the quick summary: whenever you use speed, always multiply it by Time.deltaTime. This essentially gets you “distance per second” instead of just “distance”.