Need some help with math...

Hey guys,

So I’m prototyping a level for my game where the player’s movement is restricted to the area of a circle. So far, I have it so the player can move within the circle without leaving it’s bounds without the use of colliders. I’m trying to create a dodge mechanic where the player can dodge to the left or right without leaving the circle’s bounds. The goal is to have the player stop at the edge of the circle if they try to dodge and the distance from the player to the wall is less than the full length of the dodge. For the dodge mechanic, I have the following coroutine:

IEnumerator Dodge()
{
	Vector3 targetPos;
	if (dodgeDir == DodgeDirection.right)
	{
		// if the target dodge destination is beyond the bounds of the circle,
		// update the target pos to be (radius length - 0.5f) from the center
		// of the circle (Vector3.zero) along the vector that points from the
		// center to the current target destination
		targetPos = transform.position + (Vector3.right * dodgeDistance);
		if (Vector3.Distance(transform.position, targetPos) >= radius)
		{
			targetPos = targetPos.normalized * (radius - 0.5f);
		}
	}
	else
	{
		targetPos = transform.position + (-Vector3.right * dodgeDistance);
		if (Vector3.Distance(transform.position, targetPos) >= radius)
		{
			targetPos = targetPos.normalized * (radius - 0.5f);
		}
	}

	//move to target destination
	while (Vector3.Distance(transform.position, targetPos) > 0.3f)
	{
		transform.position = Vector3.MoveTowards(transform.position, targetPos, Time.deltaTime * dodgeSpeed);

		float distance = Vector3.Distance(targetPos, Vector3.zero);
		if (distance > radius)
		{
			transform.position = transform.position.normalized * radius;
			break;
		}
		yield return null;
	}
}

This works fine if the player’s height is zero, but if the player is around the top or the bottom of the circle, the updated target destination actually ends up closer to the top or the bottom rather than either straight to the left or right. Hopefully the following little diagram helps make it a little clearer:

I know I could just stick a cylinder collider around the circle and do a raycast but I feel that there should be a way to accomplish this goal mathematically and without having to use colliders/raycasting. Any help is much appreciated. Thanks!

While I’m not certain I really understand all that you are describing, I’ll work from the diagram instead of the code or the description.
The math answer to the diagram is basically x = sqrt( rsquared - ysquared), where r is the radius and y is the y of the blue dot. This gives you x on the circle at that y using Pythagoras.
Here’s the thought process.
Translate this discussion to your coordinate plane, because while you might be working the XZ plane, a typical 2D diagram like this is discussed in XY, so X is left/right, Y is up/down.

The green dot is inside the circle, but the target in blue was where it was headed. The real question this diagram poses is “where is X on the circle when at the height of the blue dot’s Y coordinate”.

The objective is, therefore, to fashion an X at this Y that is to the left of the calculated point on the circle. In this case left is the direction because of the quadrant the diagram is showing, it would be to the right if this were mirrored on the Y axis, and the blue dot were on the left side of the center (thus X would be a negative coordinate). Perhaps you want something either on the circle, or close to it, but I note that if the blue’s Y is closer to radius, there are fewer and fewer points within the circle that are not in line with the circle’s center, or near the top (which is part of your description I’m not sure I really understood).

For any given Y and radius, there is 1 X that is on the circle. The implied right triangle has a hypotenuse of radius, one leg is Y and so the remaining leg, which becomes the X on the circle, is found by adjusting the Pythagorean theorem, in this case rsquared = xsquared + ysquared becomes xsquared = rsquared - ysquared, so x = sqrt( rsqaured - ysquared ). You must then adjust for the appropriate quadrant. Your diagram is in the quadrant where x and y are positive, but the x result will always be positive, so you have to negate it if the target in blue had negative x coordinates.

This can be used for any circle, such that if the green dot is on a circle that is r * .9, or some other factor, simply use the smaller radius for an X where the green dot appears. Note that fails if Y is greater than the adjusted radius - you’ll be attempting to get the square root of a negative number, which is the imaginary domain.

Note there is more than one way to do this. If you notice that the center to blue to green implies a non-right triangle, you could use the law of cosines and/or law of sines, which can be a way of avoiding a square root calculation (occasionally it can be a slightly faster, though more complicated way of getting the answer).

A super simple way of doing this that I could think of is using a Sphere collider (for your radius), set it as a trigger.

void OnTriggerEnter = enters the trigger.
void OnTriggerStay = Player is within the sphere.

void OnTriggerExit = Player left the sphere, and this is ultimately where i’d put the “CanMove = false;” type command…or teleport them back within the sphere ever so slightly…or an animation to make them u turn back.