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\$
1
  • \$\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
    Commented May 20, 2015 at 5:40

4 Answers 4

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\$
1
  • \$\begingroup\$ I didn't notice this post was 3 months old. \$\endgroup\$ Commented Aug 19, 2015 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\$
4
  • 1
    \$\begingroup\$ A vector can be negative, but a distance cannot. The return value of Vector2.Distance() is always non-negative. \$\endgroup\$
    – DMGregory
    Commented May 20, 2015 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\$ Commented Jun 20, 2015 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\$ Commented Jun 20, 2015 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
    Commented Jun 20, 2015 at 5:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .