Complex clamping Vector2

Hi, everybody.
I need to achieve clamped “anchoredPosition” transformation within specific range (marked in illustration as blue field) to move object (for example Star) only in this range and stop at edges. Maybe someone know how to do this trick. Thanks!

Convert the cartesian position to polar coordinates:

Get the angle using Mathf.Atan2(y,x) and the distance using vector2.magnitude. Then just clamp the distance to your desired range and convert back to cartesian.


You mentioned the anchoredPosition. Do you want this to be updated by the rectTransform layout system? It’s possible to do this trick that prevents Unity from both editing and saving certain rectTransform values, so they can be updated in editor without causing a change to the scene - for that, check out:

If you really just want to have the same direction from the center and clamp the magnitude of the vector to between 1 and 2, this is all you have to do:

v = v.normalized * Mathf.Clamp(v.magnitude, 1, 2);

If you love micro optimizations and want to avoid the double square root here, you can instead write

var magnitude = v.magnitude;
v = v / magnitude * Mathf.Clamp(magnitude, 1, 2);

Of course, in both cases, make sure first that v is not (0, 0).

By looking at the illustration the inner circle ends at 1 unit, and the outer (blue) ends at 2 units away from origin (0, 0),
It’s pretty simple, something like:

/// C#
[SerializeField] private float min = 1, max = 2;
private float minSq, maxSq;
float distance;
RectTransform tf; // for UI, use Transform for normal objects, set it in Awake()/Start()
Vector2 pos, direction;
private void Awake() {
	tf = (RectTransform)transform; // for UI, remove the cast for normal objects
	minSq = min * min;
	maxSq = max * max;
}
// if your checking the range in update for example
private void Update() {
	pos = tf.anchoredPosition; // for UI, use tf.position for normal objects
	float distance = pos.x * pos.x + pos.y * pos.y; // get the squared distance and skipping the root for performance
	if (distance < minSq) {
		direction = pos.normalized;
		// fix the position, set to min distance (clamp)
		tf.anchoredPosition = min * direction; // for UI, use tf.position for normal objects
	} else if (distance > maxSq) {
		direction = pos.normalized;
		// fix the position, set to max distance (clamp)
		tf.anchoredPosition = max * direction; // for UI, use tf.position for normal objects
	}
}

Though not tested, not sure if tf.anchoredPosition = max * direction; will actually give the right pos but you get the idea.