Transcript for:
Understanding Vector Angles in Roblox

Vectors are those three number little constructs in Roblox that are very useful for a number of things. But why would you ever want to find the angle between two vectors? Well, for one, you can use that to assign a value to a hinge constraint, which I made a video on, to make some nice smooth animations that also interact with physics. And you could also do something like make a FOV range for an enemy NPC.

they can detect you like that. There are many uses for finding an angle between two vectors, but historically it's been quite difficult to do that because the math was complex and it was just annoying. But now Roblox released a vector three angle method that I will talk about today and tell you how to use. So let's get right into it. Although the math is already done for you, it is good to know how angles between vectors actually work under the hood so you can best know how to use them.

So we're going to start with a simple 2D example. So let's say you had a vector starting at the origin, origin going to here, and we have one starting at the origin. The angle between them would obviously be this angle, or like theta 1. And that's that. But one thing you gotta keep in mind is we're just asking for the angle. We're not asking for a signed angle.

So if there were to be a vector drawn here, the angle you would think, and on first thought, it would be like all the way around down here. That's actually not the case. It would find the shortest angle between them, which would be like right here.

So when you're finding the angle between two vectors, it'll always find like the most acute angle. And there is functionality in the code to allow you to determine whether or not it's signed. But you still won't be able to get the full 360 degrees out of the box.

It only goes up to 180. And then you have to specify the axis on which it's on to go to 360. Let's actually go to 3D and talk about that. So here we have our 3D grid. We added a new z-axis.

Let's say you get a vector. Just chilling down here and you get another one chilling up here You want to find the angle between vectors and for that you can't just like, you know choose and like choose wherever and draw like a line to them because that just Clear in 3d you need to specify something more. So what happens is There's like an imaginary plane where the two vectors sit on. So I'm just going to take a different color. So I'm going to draw this plane real quick.

You got like this imaginary plane. Obviously it's not drawn to scale, but like you get the idea. It's kind of skewed. And then this would be the angle between them sitting on this plane.

Notice how this plane is not aligned with any one axis. Not with the y, not with the x, not with the z. If you want to, you can obviously flatten any one of these vectors to a specific axis and figure out the angle that way. But just out of the box, when you have two random angles or vectors in space, the angle between them is just the closest thing you can get to them by a plane.

And there's this thing called the axis that is perpendicular to this plane. And you can specify this axis. in order to determine the sign of the angle.

So, see this orange line? A little more clear. If the angle is on, like, this side, whatever, it can be positive, and then you have another vector pointing this way, or whatever.

The angle between them might be negative, because you determined this axis. And the best, honestly, I'm not going to lie, you could figure out all this stuff mathematically on paper. before you actually commit it to code.

But the best bet that I've found is to just go in and start experimenting, figuring out what works for your setup. This kind of idea of how the angle between two vectors is just the closest angle you can get on an imaginary plane, that is just a good concept to keep in mind when you're demoing stuff. Because oftentimes, you want the angle to be kind of flattened towards a specific axis, which you can do that easily by taking a random vector. and multiplying it by another vector that zeroes in it to get rid of the components. I will demo a little later.

So, let's move on to actual Roblox. So I'm here in a Roblox baseplate, and I have two parts created. I have one part called the ref, R-E-F, and this is just a basic block, doesn't really matter with properties, make sure it's just anchored. And then I have the target, which I'm also going to make anchored. And this one is just a little differentiated, because this is what we're going to be finding.

We just have our ref, like base, our starting vector of. Because this is where you'll find the angles, vectors. relation to the other because vectors start from the origin.

But oftentimes you want to base it off another object as we're doing here. Now in the workspace, I'm just gonna create a script, zoom in a little bit. And we're going to get our ref based ref, and then our target workspace.

And then for demonstration purposes, I'm going to create a render step loop. by using game and get service run service dot stepped i guess stepped i should say not render stepped and we're going to connect a function it's time and delta time don't really need to worry about that and then in here we want to first get the target vectors position in relation to this object so you could obviously use two world space or two object space On this part, I have a video talking about that, just like converting the world to object spaces. But honestly, the most intuitive method is to subtract the position of the target part with the ref's position.

We're going to say local dir for direction. Direction equals target.position minus ref.position.unit. So this is a unit vector, meaning its magnitude is 1. it's going to be pointing from the ref to the target. So like the ref to the target.

That's what this minus is for. You start with the target position, you offset it by the ref position. That gives you a relative vector to the target. And so now, let's just say we want to find the angle between this target position, or this target part, and the... x-axis relative.

So you see up here in my little widget, the x is like from left to right. So right now it's like perfectly aligned with the x-axis. So we can just say local angle equals, actually we can say vector3.x-axis angle direction.

For now, we're only going to leave one parameter, which is the other vector you want to find an angle with. This is vector3.x-axis. is basically shorthand for a vector3.new but this angle actually isn't in what we're used to.

This angle is in radians, not degrees. So if we were to print it out, and this is the whole reason I'm using this run service loop, is because when you print it out, it'll print every frame, which is pretty useful. So we're going to run this.

You can see it's printing 3, whatever. And the numbers aren't really that intuitive. That's because they're in radians. They're from 0 to 2 pi. So if we want them in a nice numbering system, we can just wrap this in a math.degree.

math.dig converts a radian's degrees into degrees. Degrees are what we usually use. It's what hinge constraints use.

It's just more intuitive to use and a whole host of bugs result from people forgetting to do this math.degree. So make sure you do that. So now if we were to run it once again, we get some nice angles.

We get 0 all the way to 180. But you'll notice as I go back around, it goes all the way back around to 180 without changing signs. So you don't know. If a part is here, it's like an identical angle to down here. It's around like 130s, 120s. So you have to find a way to differentiate that.

And also, if you move up and down, you can see the angle changes. And a lot of times, that's not desirable either. So for now, my goal for this little ref part is going to be to make a little system to work with a hinge constraint and orient the hinge constraint to point a little pointer.

at the target. So I'm going to get that set up real quick and show you how it works. So I have this new part, which we're going to attach to the ref and make a hinge.

I'm going to go to model, create hinge constraint, and we're going to slap that right on there. Actually, we want this centered. So we're going to set the position and not the world position just normal position zero zero zero and then just move it up and then move this roughly over top and i cover hinges in more details in a separate video if you want to check that out but here we go the hinge is slapped on if we play it oh i don't play with my character if we just run it Works out fine.

It rotates just fine, which is great. So now we want to turn this hinge into a servo. It can go to a desired angle, and the target angle right now is going to be zero, and we want the angular speed to be like two, whatever.

It doesn't matter. Max torque, crank that thing up to a big value so it moves a lot. And you'll notice that these blue arrows point to where the target angle is supposed to be.

So right now the target angle is zero. It's pointing that way. If we play it, it'll move. Actually, it won't move at all because it's already at the target angle.

It's because the secondary axes of the attachments are actually aligned in this position. Just because they're at an alternate angle doesn't mean they're not aligned. I don't know.

Hinges are really wacky. That's why we use trial and error. So let's do that.

So let's go back into the Erron service. Let's get our good old hinge, which is actually within the part. So I'm going to rename this part to the pointer. Because why not?

Let's say local pointer is equal to workspace.pointer. And local hinge equals pointer.hingeConstraint. So we want to set the hinge constraint, the hinge.targetAngle, to... the angle that we had before.

Let's test this out. I severely doubt this will work first time, and as it did not, but you can see it does have relation. Notice how it's also wiggling, and we move it up and down, it also wiggles. We gotta fix that too.

So let's start with the little wiggling issue because that's the easiest to address. That's because this direction has a y component as well. So as we move it up, the angle changes.

We don't want that. So all we have to do to fix that is just say like local flat direction. This is a flattened direction equals direction times vector3.new 101. So what this does is we multiply each component, the x, y, and z of our vector by 1, keeping it, doesn't change it. 0, we get rid of the y component, and then 1, we keep the z component.

That keeps it on the flat plane, so if we were like, it keeps all of this data, but it gets rid of the up-down. Because we don't want that, since our hinge cannot move more than one axis. So, now instead of finding the angle between the x-axis and the flat dir, or in the dir, we're going to find it to the flat direction. Now let's try that, see if that eliminates our pesky wiggle.

You can see it does. We move it up and down. zero change on the angle because we only care about the flatness.

Now moving forward, let's try to fix our little mix-up when the little pointer is pointing the wrong way. I don't want it to point the opposite way. I want to point this way. You could obviously edit the hinge, and most of the time, that's probably like the best solution, but honestly, it's a pain, and a lot of times, it's much easier just to, for example, negate the angle.

We say negative. math.agree whatever and that didn't work but that was only one test let's try something else because you also got to keep in mind let me just actually go back i'm going to debug this with with me i'm going to keep in mind this angle see how it goes back that's because Back here, it reaches the limit of the angle and Since there's no sign indicating whether it's positive or negative, you can't get the full degree of rotation, which is obviously not good. Luckily, the angle method in Roblox has an extra parameter, which is the axis, which determines the sign of the angle. So you just want to set this axis to something perpendicular to the plane in which you're measuring your angle.

In our case, the plane in which we want to measure our angle is the xz plane. You get the x and you got the z. So the axis we want is just the y-axis. It's like the full cromwell, which is rotating.

It's like the up and down. Because you see this little yellow thing? This is the y-axis of the world, and it's like the primary axis of our rotation or our hinge.

So we're just going to set our axis to vector3.y-axis, which is the same thing as saying vector3.new 0, 1, 0. So let's try this again. provide a full like rotation but we still have it going backwards it's kind of annoying so now we have full continuous rotation and it always points the right direction which is great so now if we want to you know flip it the right direction i think the easiest way would just be to flip the actual vector let's try that out there we go now it's pointing that way you And now it points properly forward, which is absolutely wonderful. This is what I want.

Then you got a little pointer. Now you could, there's a lot of possibilities with this. This looks sort of like a tank, like a 2D tank. You could obviously do that.

There's a bunch of other things you can do. I've actually made a full AI turret with this. So let me show you that.

Now, this is the AI turret that I designed. that is based off the same concept I just told you. You can see the residual target block just lying around. So let me show you what it does.

It can aim in two two dimensions and when it sees me it shoots. It's pretty cool and regardless of its orientation it will always aim at me. Even if I rotate it wildly it'll still aim at me. which is really cool. So this is what you can get to when you master using the vector three angle method and just other C frame transforms.

What we just made and not doesn't have this functionality just yet. But if you want to see a tutorial on this, I'm always free to make one. So just put your comments down below. But that about wraps up this video. It was kind of all over the place, and it was kind of messy, but that's just how dealing with vectors and C frames are.

You can never just like theorize about what's going to happen when you write certain things. You just got to shove it in there and get some intuition. Like I've dealt with these problems so often that I can like visualize what happens, what's supposed to happen and how things are like. And it would also help if you had like a vector three visualizer, which I think they exist.

I made one pretty quickly on one. You can make one pretty quick, pretty simple. You know, I'll use like my rate visualizing video too.

That could help. But. Overall, just jump into it, get your hands dirty, and make some pretty cool things. So if you enjoyed the video, make sure to like it and subscribe to my channel for more content.

Make sure to comment, especially if you want this tutorial because I've been thinking about doing it. It is kind of in-depth food. It's short, but there's a lot going on.

But if you want that, just comment down below. But with that, I hope you have a nice day, and goodbye.