# Restrict movement within a radius

I asked a similar question recently but now I think I know more about what I really want to know. I can answer my own question if I get to understand this bit.

I have a situation where a sprite's center point needs to be constrained within a certain boundary in 2d space. The boundary is circular so the sprite is constrained within a radius. This radius is defined as a distance from the center of a certain point.

I know the position of the center point and I can track the center position of the sprite.

This is the code to detect the distance:

``````    float distance = Vector2.Distance(centerPosition, spritePosition));
if (distance > allowedDistance) {

}
``````

The positions can be wherever on the grid, they are not described as in between -1 or 1. So basically the detecting code works, it only prints when the sprite is outside of it's boundary I just don't know what to do when it oversteps. Please explain any math used as I really want to understand what you're thinking to be able to elaborate on it myself.

-

Take the position of the object, minus the origin of the circle. This will give you a vector from the origin to the object. The length of this vector is the distance to the object. Multiply this vector by the circle's radius divided by the distance to the object. Set the object's position to the circle's origin plus this vector.

Psuedo-Code:

``````Vector FromCircleToObject = Object.Position - Circle.Origin;
Object.Position = Circle.Origin + FromCircleToObject;
``````

You can optimize this by using the vector's length squared. This saves you a square root. If you use the vector's length squared, you must use the circle's radius squared. Luckily, squaring is cheaper than square rooting, so there's still an optimization to be had.

-

What you need to do is reset the sprite's position back to it's greatest extent.

You can do this by taking the vector from the centre to the sprites position, normalising it and then multiplying that by the allowed distance. However, that involves a square root which may be too slow for your game.

Another approach is to limit the sprite to a box around the centre position so your test would become:

``````if (spritePosition.x > centrePosition.x + allowedDistance)
{
spritePosition.x = centrePosition.x + allowedDistance;
}
else if (spritePosition.x < centrePosition.x - allowedDistance)
{
spritePosition.x = centrePosition.x - allowedDistance;
}
``````

and the same for the `y`.

This obviously doesn't give the same effect but may be quicker. You'd have to profile them both to see and also check the behaviour to see if was acceptable.

-
I tried this but in a somewhat different manner, this results in the sprite position to be constrained within a square of the center point. I really want the boundary to be circular.. thx though! –  Phil Mar 6 '11 at 17:42
Oh, and I'll try to use your first suggestion, I was there at one point but didn't figure it out, I'll try it again. Would be extremely thankful if you could show me that part in code. –  Phil Mar 6 '11 at 17:44
@Phil - I should have made it clear that while the box check is quicker it is just that a box check. –  ChrisF Mar 6 '11 at 17:46
You did :) I was too fast in my comment and missed your line just above the code. –  Phil Mar 6 '11 at 17:50

So, your sprite has a rectangular shape? If so, you are effectively asking, "How do I move a rectangle that intersects with a circle inside the circle so that the rectangle no longer intersects". I assume then that the rectangle is in fact smaller than your circle and the sprite position represents the center of the sprite. If it doesn't, you can convert from top-left to center by simply adding 1/2 the width, height, that is:

``````center.X = spritePosition.x + spriteImageSize.x/2;
center.Y = spritePosition.y + spriteImageSize.y/2;
``````

In that case, you need to consider the 4 points of the sprite. Check if the first one is outside, and if it is, move it so it isn't. I don't have a formal proof, but I conjecture that it is impossible for you to move a corner inside the circle such that it puts another corner outside that was previously inside. This depends strongly on the fact that the rectangle fits inside the circle.

The code would be something like this:

``````TL = sprite.getTopLeft();
if(outside(TL, circle)) {
newPoint = moveInside(TL); //see how to move a point inside
delta = newPoint - TL; //figure out how much we moved
spritePosition += delta; //move the center of the sprite
}

//repeat for TR, BL, BR -- IF YOU MOVE THE SPRITE, YOU MUST RECOMPUTE THE CORNERS!
``````

If you don't need that level of detail and you'd rather treat the sprite as an infinitely small single point, then you simply need to detect when it is outside the circle and set it so that it is inside. See ChrisF's response on how to do that.

-
It's just the center point of the sprite that needs to be within the radius, not effectively the sprite itself. Updated my question, sorry for being unclear. –  Phil Mar 6 '11 at 17:41