Limiting Vector2 directions to certain angles

Say there’s a function and it receives a Vector2 (think of some impact that may come from any direction), another Vector2 that tells the optimal direction and a number of degrees from that optimal direction that it still accepts.

If the first Vector2 matches the direction perfectly - the funciton returns it unchanged.

If it doesn’t match perfectly but falls into allowed range - the function makes it smaller depending how far it is from desired direction. The farther it is - the smaller the magnitude gets.

If the vector falls out of the allowed range - the function returnse Vector2.zero.

I bet I don’t know about something pretty obvious and there’s something simple that solves this problem exactly.

138050-untitled.png

Based on my previous comment to your answer and on how to make it more efficient.


The following code does something similar. In my code I use sqrMagnitude instead of magnitude. because it is way more efficient. It yields a slightly different result, but depending on what you want, I’m thinking the result of using sqrMagnitude is actually more accurate then using magnitude… Especially when target is not normalized (like a value of [10,10], which makes the magnitude of your result explode in a way I don’t think you intended)


The only real difference in this code is that it doesn’t ‘suffer’ (don’t know whether it is intended or not) from the same problem that you have when pointing in the opposite direction of target, and if you change sqrmagnitude to magnitude, it will do everything else exactly the same as your current answer as far as I could test…

	public Vector2 Vector2Limiter2(Vector2 input, Vector2 target, float angle)
	{
		// If we imagine input is a point is space and target is a line from [0,0] to target,
		// then pointInLine is the closest point on that line to input
		Vector2 pointOnLine = target * Vector2.Dot(input, target) / target.sqrMagnitude;

		float difference = Vector2.Angle(input, target);
		float t = Mathf.Max(0, 1f - difference / angle);
		
		return Vector2.Lerp(pointOnLine, input, t);
	}

So basically. Most of the stuff I’m doing is the same thing as what you are doing, sqrMagnitude is the only real difference in performance, and personally I think it is slightly more readable. But I might be biased :smiley:

Okaaay, it goes something like this:

public void Vector2Limiter(Vector2 amount,Vector2 axis,float axisDegrees){ 
	float axisFreedom=Mathf.Max(0f,1f-(Mathf.Min(Vector2.Angle(axis,amount),Vector2.Angle(-axis,amount))/axisDegrees));
	Vector2 axisAmount=axis*(Vector2.Dot(axis,amount)/axis.magnitude);
	return axisAmount+(amount-axisAmount)*axisFreedom;
}

It takes a vector, an axis and a number of degrees we allow to deviate from the axis before vector turns to zero. This function allows moving to both directions on the axis but it’s easy to change that.

So the idea is to create a new vector which is a projection of the amount on the axis and then subtract that projection from original amount to find the vector perpendicular to the axis and then multiply it by an axisFreedom number which is a representation of how far we deviated from the axis from 0 to 1.

That’s exactly what I wanted. But maybe there’s a more efficient way of doing it? I’m doing it every frame and it would help a lot if someone new a better way.