- Home /
Lerp that wraps around a variable x
The 'Mathf.LerpAngle' function is incredibly useful. This is like a lerp, but it wraps correctly around 360. How would I create a lerp that wraps correctly around a variable x? I have a racing game, where the course consists of frequent worldpoints. These points have indexes ranging from 0 to x, and I need a lerp that would appropriately take the shortest distance to any given point. Therefore, if I'm at (x-1) and want to go to 0, the lerp would go to x then zero, rather than (x-2), (x-3)... As bonus points, could an answer also include a version of this for MoveTowards?
Answer by Ymrasu · Jan 31, 2019 at 11:45 PM
If you have an 1D axis (your variable x) that repeats/loops/wraps-around you can think of as a circle. We know that if the distance from A to B on a circle is more than half the circumference, it means that you went the wrong way and that going to other way is shorter which. Lets say you have indexes from 0 to 9 (length of 10).If you want to go from 2 to 8; if would count 2,3,4,5,6,7,8, you get a distance of 6.This is more than half the length (6/10 = 60%) so we know going the other directionis shorter, 2,1,0,9,8 for a distance of 4. This can also be done by doing length - distance (10 - 6 = 4).
// from a to b
int a = 2;
int b = 8;
int length = 10; // length can be array.lenth if you keep the points in an array
int distance = Mathf.Abs(a - b); // distance is 6 in this case
// then we can check if it is more than half way
if (distance > (float)length * 0.5f) {
distance = length - distance;
}
// now that we have our shortest distance
// which way do we travel?
int dir = 0;
// we can check if traveling positive is correct
if (a + distance == b) {
// it is! make the dir positive
dir = 1;
} else {
// nope the direction is neg
dir = -1;
}
// with the direction and distance figured out, we can lerp!
int x = Mathf.RoundToInt(Mathf.Lerp(a, a + (distance*dir), time));
// then we wrap around 0 if needed
if (x < 0) {
x += length;
} else if (x > length) {
x -= length;
}
This will make x lerp from a to b taking the shortest distance wraping around 0-length. You will need to figure out where to put all this, you only need to check the distance once. I did not test any of this code, there may be typos.
Awesome solution, paired with a great explanation. Thank you for the answer!
I was curious about using movetowards to wrap around the world so I came up with this:
// I had my player at (2,0,2) and targetPos at (8,0,8) public Vector3 targetPos; public float length = 10f; public float width = 10f;
private void $$anonymous$$oveWrapAroundWorld()
{
Vector3 pos = transform.position;
Vector3 dist = new Vector3($$anonymous$$athf.Abs(pos.x - targetPos.x), 0, $$anonymous$$athf.Abs(pos.z - targetPos.z));
if (dist.x > length * 0.5f) {
dist.x = length - dist.x;
}
if (dist.z > width * 0.5f) {
dist.z = width - dist.z;
}
Vector3 dir;
if (pos.x + dist.x == targetPos.x) {
dir.x = 1;
} else {
dir.x = -1;
}
if (pos.z + dist.z == targetPos.z) {
dir.z = 1;
} else {
dir.z = -1;
}
Vector3 newTargetPos = new Vector3(pos.x + (dist.x * dir.x), 0, pos.z + (dist.z * dir.z));
pos = Vector3.$$anonymous$$oveTowards(pos, newTargetPos, 1f * Time.deltaTime); // put in your speed variables
if (pos.x < 0) {
pos.x += length;
} else if (pos.x > length) {
pos.x -= length;
}
if (pos.z < 0) {
pos.z += width;
} else if (pos.z > width) {
pos.z -= width;
}
transform.position = pos;
}
void Update()
{
$$anonymous$$oveWrapAroundWorld();
}
Your answer
Follow this Question
Related Questions
Unable to fully rotate GameObject on tap 2 Answers
Mathf.Lerp like User Define Function 2 Answers
Mathf repeat at the end? help! 1 Answer
Line drawing: How can I interpolate between points to create a smooth arc? 4 Answers
Simple math always returns 0 1 Answer