The object does successfully move to the destination position the first time, but after that it only seems to happen randomly. I am sure this is probably occurring because of the problem I mentioned above.
Is there a different check I should use?
Here is my code:
void OnMouseOver()
{
// If terrain tile receives left click then move the previously selected token to this terrain tile.
if(Input.GetButtonDown("LeftClick"))
{
// Movement distance between terrain tiles.
_journeyLength = Vector3.Distance(_token.transform.position, transform.position);
// Movement start time.
_transformStartTime = Time.time;
}
}
// Update is called once per frame
void Update () {
if(_token != null)
{
if(_token.transform.position != transform.position)
{
float distanceCovered = (Time.time - _transformStartTime) * 3.0F;
float amountOfJourneyCompleted = distanceCovered / _journeyLength;
_token.transform.position = Vector3.Lerp(_token.transform.position, transform.position, amountOfJourneyCompleted);
Debug.Log("Translating...");
}
}
}
You should check based on the distance from your current position to your destination rather than if your object has arrived at that exact destination. This is because your object may never arrive at the destination due to floating point accuracy. For example, if let’s say your destination is Vector3(1, 1, 1). If let’s say your object stops at Vector3(0.99999, 0.99999, 0.9999), it still hasn’t arrived at its destination.
Also another thing to note is that if you’re using Vector3.Lerp, it actually makes the object slow down as it nears its destination. So although you can’t actually see it moving and you assume it has arrived at its destination, it’s actually still moving.
Lerp is also fine for constant speed linear movement if you pass in a constant value for the first argument, rather than passing in the transform which you’re progressively changing over time. So, in addition to tracking _transformStartTime, add another variable for _transformStartPosition, and pass that into the lerp as the first argument. That way you’ll get a constant speed movement and you can stop lerping when your amountOfJourneyCompleted is greater than 1.
Unity also has a Vector3.MoveTowards function which provides this behaviour more concisely, if you do want a constant movement speed.
This is not correct. Lerp does a linear interpolation — there is no smoothing or deceleration involved.
(Of course you could make it do that by passing in values of t that get progressively closer to 1, without ever actually reaching it — but that’s not what this code is doing.)
I think the actual problem the OP is having here is the opposite: it’s overshooting. On one frame, amountOfJourneyCompleted is 0.98; and on the next frame, it’s 1.02 (for example). If that parameter never equals exactly 1.0, then the position will never equal exactly the target. This is easily fixed by clamping it to the range 0-1:
Then your code elsewhere just needs to set _targetPosition to whatever you like, and every frame the object will move towards it with speed Speed, and stop when it gets there without overshooting.
where startPosition is the position at the start of the journey. (I know you know this, gfoot, but perhaps Magian was still unclear on this point.)
Absolutely agree with that. I tend to be too quick to reach for Lerp myself, when often MoveTowards (or RotateTowards, etc.) would do the job in a much simpler way.
Thanks for all of the responses! Definitely some very good information.
After running this project this evening, I notice that the movement of the token is not occurring randomly at all. Instead, the token is translating only when the direction is northwest, north, or northeast.
In addition, I have changed my code to check distance in the conditional statement, but “Translating…” is still appearing in the Console repeatedly and never stopping.
void Update () {
if(_token != null)
{
if(Vector3.Distance(_token.transform.position, transform.position) > 0.1F)
{
// Movement is only occuring in N, NE, NW directions.
float distanceCovered = (Time.time - _transformStartTime) * 3.0F;
float amountOfJourneyCompleted = distanceCovered / _journeyLength;
_token.transform.position = Vector3.Lerp(_token.transform.position, transform.position, amountOfJourneyCompleted);
//Debug.Log("distanceRemaining: " + distanceRemaining.ToString());
Debug.Log("Translating...");
}
}
}
I just tried this exactly as you have it entered and, while I think it is excellent information that I will note for future reference, it does not change anything about my problem.
Just tried this but I have not wrapped my head around what exactly is happening yet. “Translating…” is only appearing once in the Console per click as it should, however, the token is not translating and instead a blue cube seems to be appearing at the clicked destination. No idea on this one yet and my daughter is basically howling in my ear, so I will have to come back to this shortly…
I have output the distance and and I am using Vector3.MoveTowards as suggested. The token moves part of the way and then jerks repeatedly.
Outputting the distance on each call to Update() shows that, after the token travels a bit of distance, it ping-pongs back and forth between two values (4.337266 and 0.084…). It appears that something else in the code is acting on the token, but I cannot figure out what it could be. The only other time a token appears to be transformed is during the call to Start() when the token is first instantiated.
Sounds like you’re right - that something else must be changing the position of the _token object. That 0.084 value though would definitely stop the posted translation loop…
Are you still stuck at this? I don’t want to get a whole project — Unity projects are large and a pain to pass around.
So my suggestion is this: try to reproduce the problem in a trivial project… nothing in the scene but, say, a cube and a sphere. Call one of these the token, attach this script to the other one, assign the first to its _token property in the editor, and run. There are only two possibilities at this point:
It works — now see how your real game differs from this trivial version. Rip stuff out of your real game piece by piece until that starts working, too, and then study the last piece ripped out to see why it was causing failure.
…or…
It doesn’t work — but now you have a trivial case; post the code here, with a description of how your scene is set up, and any of us should be able to reproduce it. (But I doubt this will be the case, as the code by this point should be pretty fool-proof.)
I’d also note that the “MaxDelt” as it’s being used here is a speed, not a max delta… step is the max delta. If you actually want to pass in a max delta, then the whole method above boils down to exactly Vector3.MoveTowards!
(Still not sure how this relates to the OP’s problem, though.)