- Home /
The question is answered, right answer was accepted
Itween path, how to find the closest point to the player/Vector3
Hey there,
I'm currently trying to create a system where the camera follows the player along a path. Basically I have created a 3D path using Itween where the camera should find the closest point towards the player along that path and stick to it. How could this be done? I was able to make the camera stick to a porcentage of the path but have no idea how to make that porcentage be equal to the closes point towards the player.
I'm currently scripting in C#.
Answer by _Gkxd · Aug 29, 2015 at 04:28 PM
This page lists a function called PointOnPath
which essentially gives you a parametric equation describing that path.
What you can do using this is sample the path at multiple parts, and keep track of the distance that is the minimum. (This is pseudocode because I don't know how paths are structured in iTween.)
float minDistance = float.PositiveInfinity;
float minPercent = 0;
for (float t = 0; t <= 1; t += 0.02f) {
float dist = Vector3.Distance(playerPosition, PointOnPath(/* path */, t));
if (dist < minDistance) {
minDistance = dist;
minPercent = t;
}
}
This will give you an approximation of the closest distance and the percent along the path that corresponds to it. For most purposes, an approximation like this should be good enough.
Hey there, I have tryed what you said and it kind of worked. It does follow the player a bit , but it's very buggy and laggy. It also doesn't work quite well and at curves it doesn't work at all, I guess because of the fact that it 's close to more than one point.
here is the code :
using UnityEngine;
using System.Collections;
public class FollowCameraPath : $$anonymous$$onoBehaviour {
public GameObject Path;
public float PathValue;
public GameObject Player;
float $$anonymous$$Distance = float.PositiveInfinity;
float $$anonymous$$Percent = 0;
// Use this for initialization
void Update () {
//iTween.$$anonymous$$oveTo( Path ,iTween.Hash("path" , iTweenPath.GetPath("CameraPath"), "time" , 200 ));
for (float t = 0; t <= 1; t += 0.001f) {
float dist = Vector3.Distance (Player.transform.position, iTween.PointOnPath (iTweenPath.GetPath("CameraPath" ), t));
if (dist < $$anonymous$$Distance) {
$$anonymous$$Distance = dist;
$$anonymous$$Percent = t;
}
}
iTween.PutOnPath(this.gameObject, iTweenPath.GetPath("CameraPath"), $$anonymous$$Percent);
}
}
In general, finding a point on a path that is closest to another point not an easy thing to do, especially if the path is arbitrary. For straight lines, you can just solve an equation to get the closest point, but for more complicated paths, there's no easy equation to solve, and there might be multiple points that are the "closest" to a point (like a point in the middle of a circular path). This is why you need to sample points along the path to actually find the $$anonymous$$imum. You may be able to use Newton's method as a faster way of finding the closest point, but again, this will only work for certain paths (and it's more complicated to implement).
It may be the implementation of the iTween libraries that are slow too. You can use the profiler in Unity to see which functions take the most time to execute.
It will also help if you describe what the bugs are, ins$$anonymous$$d of just saying that there are bugs, though if the issue is from iTween, I may not be able to help.
This code lags because you are perfor$$anonymous$$g 50 sqrt operations every frame! Look at my answer below for a much much more optimized version.
Answer by EvilTak · Aug 30, 2015 at 10:26 AM
Modifying @_Gkxd 's answer, you can use a (much much much much) more optimized version of it as follows:
for (float t = 0; t <= 1; t += 0.005f) {
float dist = (Player.transform.position - iTween.PointOnPath (iTweenPath.GetPath("CameraPath" ), t)).sqrMagnitude;
if (dist < minDistance) {
minDistance = dist;
minPercent = t;
}
}
I'm using sqrMagnitude here because we're just comparing distances, and we don't actually need the actual distance so we can avoid the expensive Sqrt operation which @_Gkxd was performing 20 times (you were doing it 1000 times!!!) every frame in his code - of course it'll be laggy! You might have noticed I've also increased the step value in the loop to 0.005, which depending on the length of your path can be increased more. If it is a long path, you don't need a high step value, but if it's a short one, you might want to keep a smaller step.
Didn't quite work, about the laggy part, I didn't meant FPS , I think I didn't quite clarify on that part. The actual camera movement is laggy as it is almost as if it was sticking to some parts of the path . The buggy part is that it doesn't really flow from the start to the end, it in someparts stops and then grabs to a further away part.
@Rafael Barbosa
It's pretty difficult to see what the problem could be if you don't show us the path that you're using. Depending on what your path is, the situation that you're describing could be the correct behavior.
@Evil Tak
I wouldn't say that it's that much more optimized. It is faster code, but it's not clear that the reason for the lag is using the square root function. It may be some other bottleneck in the code that causes a slowdown.
Here is some test code that I used.
public class SqrtTest : $$anonymous$$onoBehaviour {
void Update () {
A();
B();
}
void A() {
for (float i = 0; i < 1; i += 0.001f) {
float a = Vector3.Sqr$$anonymous$$agnitude(Vector3.one * i);
}
}
void B() {
for (float i = 0; i < 1; i += 0.001f) {
float a = Vector3.Distance(Vector3.zero, Vector3.one * i);
}
}
}
I ran the above code using the deep profiler. Here are the results:
The second column from the right is the amount of milliseconds that it takes to run that function.
Do note that the deep profiler does use a significant amount of resources. Here is the time of the update function with the deep profiler disabled:
So running each operation 1000 times per frame only takes 0.3-0.4 milliseconds each frame, which shouldn't have a large impact. It is something to consider when your resources are limited, but it shouldn't be the main problem at this point.