0
\$\begingroup\$

So I have a very basic racing game, where I would like the car to stop once it hits the finish line. Respectively when the distance between the car and the finish line hits or goes under 0 the car stops, but instead of stopping it continues to go on. How can I fix this?

Here's my code:

    public float speed = 0f;
    public float gravity = 0f;
    public Transform finishline;
    public Transform car;
    public Transform finish;


    void CarMove () 
    {
        if (Vector2.Distance (finishline.position, car.position) != 0) 
        {
            if ( Input.GetKey(KeyCode.RightArrow))
            {
                transform.Translate(Vector2.right * speed * Time.deltaTime);
            }

            else
            {
                return;
            }
        }
    }

    // Update is called once per frame
    void Update () 
    {
        CarMove();
    }
}
\$\endgroup\$
  • \$\begingroup\$ Try adding a Debug.Log(Vector2.Distance(finishline.position, car.position)) in the Update method. You'll understand your problem, then eventually know what to do. \$\endgroup\$ – Zee May 20 '15 at 5:40
3
\$\begingroup\$

The problem your having is that motion in games, as smooth as it might look, is better seen as a series of short teleportations. So, since distance is an unsigned value (always greater than zero), your car is just teleporting right past the absolute distance of zero. That causes the check to never go off.

You have 3 options:

  1. You can add a margin of error (eg. if (distance < 0.2f) instead of d != 0) But this can be a problem because if the car is moving too fast, or is too far to the left of your finish lines "point", then it still teleports past.

  2. You can scrap the idea of measuring distance all together, taking advantage of Unity's OnTriggerEnter functionality to filter out the finish line/checkpoints and determine the cars victory or place. That would allow you to add in checkpoints or finish line's simply by dragging a prefab from the editor (it's always nice to have that mobility)

    Fun Note: This rout should also be more stable because of sweep collision testing. Most game engines, before they teleport an object from point A to point B, do a sort of collision test that checks for collisions with objects between the points A and B. While your standard functions are only called at point A or B for performance reasons, the OnTriggerEnter will be called even if the object is just teleported to the other side.

  3. Rather than keeping track of the distance, try keeping track of how it's changing. If you're getting closer and closer, and then suddenly getting farther and farther, then you probably crossed the finish line. This can lead to a false positive though. A 360 degree turn for example, would trigger this.

\$\endgroup\$
  • \$\begingroup\$ I didn't notice this post was 3 months old. \$\endgroup\$ – Wolfgang Skyler Aug 19 '15 at 3:05
1
\$\begingroup\$

This wouldn't answer the question of measuring the distance but for the scenario that you described, I find that placing a collider as trigger on the finish line and checking OnTriggerEnter in your car would be a better solution rather than calculating the distance.

For distance check, Dexyne is totally correct but you could also check using the sqrMagnitude which yield better performance.

You would do a check like that (finishline.position - car.position).sqrMagnitude < Mathf.Epsilon

\$\endgroup\$
1
\$\begingroup\$

Augment your finish line point with a direction vector representing the "forward" direction. Then, instead of:

if (Vector2.Distance (finishline.position, car.position) != 0) 
[...]

Do:

if (Vector2.Dot(car.position - finishline.position, finishline.direction) > 0) 
[...]

Note, if the direction happens to be aligned to a cartesian axis, say +X, the above is equivalent to:

if (car.position.X - finishline.position.X > 0) 
[...]
\$\endgroup\$
-1
\$\begingroup\$

Update – My bad, as @DMGregory says the value of a distance cannot be negative (and it makes sense). As @Kimserey and I says, you can use a trigger. Probably better in this case and easier to use.


when the distance between the car and the finish line hits or goes under 0

I think the problem is your if statement.

Your test should be:

if (Vector2.Distance (finishline.position, car.position) <= 0)

and not if (Vector2.Distance (finishline.position, car.position) != 0) as a vector can be negative.

Note: You can also use a trigger collider on the finishing line and set the car speed to 0 when it hit the finishing line.

\$\endgroup\$
  • 1
    \$\begingroup\$ A vector can be negative, but a distance cannot. The return value of Vector2.Distance() is always non-negative. \$\endgroup\$ – DMGregory May 20 '15 at 12:17
  • \$\begingroup\$ @DMGregory: While distance cannot ever be negative, the projection of a vector on an axis can be and is easily calculated as the dot product of the original vector and a unit basis vector for the axis. \$\endgroup\$ – Pieter Geerkens Jun 20 '15 at 5:29
  • \$\begingroup\$ @DMGregory: Often when distance is being referred to the intended meaning is not actually it's technical meaning, the magnitude of a displacement vector, but rather the projection of a displacement vector onto a preferred axis. In these cases it does in fact make sense to allow both negative and positive distances. \$\endgroup\$ – Pieter Geerkens Jun 20 '15 at 5:32
  • \$\begingroup\$ @Pieter, here I'm referring to the Vector2.Distance() function described in Dexyne's answer, which refers unambiguously to positive/non-signed distance, and so is not suitable for solving the asker's problem. Jaybird's answer uses a dot product as you describe. \$\endgroup\$ – DMGregory Jun 20 '15 at 5:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.