3
\$\begingroup\$

This question has been asked many times before, but most of the answers give solution to the problem where ball (target) is assumed to be moving at a constant velocity.

In my scenario, I'm making a football game. When I kick the ball into a direction by applying some force to the ball's rigidbody, I want a second AI player to find the point in the ball's path where he can intercept the ball. Now this ball can keep slowing down per frame, it does not keep moving with a constant speed.

I have attached an image for visualisation.

enter image description here

I know the ball's position, ball's current velocity, AI player's position, AI player's constant speed. How do I find such a point, where AI player can intercept the ball?

I am able to calculate such a point with the current velocity of the ball, but that point is not accurate, and changes as ball's current velocity changes per frame, as the ball can keep slowing down after every frame. This makes the AI player act kind of like a homing missile. Instead, I want the AI player to predict a point and just run to it.

Here's the C# (Unity) Code I have till now:

public Vector3 CalculateIntercept()    
{       
     Vector3 pos = Ball.GetInstance().transform.position;
     Vector3 dir = Ball.GetInstance().GetVelocity();
     dir.y = transform.position.y;

     float dist = (pos - transform.position).magnitude;
     return pos + (dist / 6.17f) * dir; //6.17 is the AI player's constant speed.
}

There's no drag on the ball, but there is a physics material with friction. I suppose to solve this, I might need to account for acceleration maybe.

Please help me figure this out. Thanks!

\$\endgroup\$

3 Answers 3

1
\$\begingroup\$

I'm sure there is probably a really complicated proper solution to this problem but I think we can probably cheat and get a quick answer using cached data and some functions.

Assuming the friction is constant on your field, you could probably calculate the amount of distance the ball travels over time by using something like:

// Attach me to the ball
public class BallLogger : MonoBehaviour
{
    public bool run = false;
    private float kickStartTime = 0.0f;
    private Vector3 kickStartPosition = Vector3.zero;
    private Vector3 lastPosition = Vector3.zero;

    private void Update()
    {
        if (run)
        {
            float kickTime = Time.time - kickStartTime;
            float kickDistance = (kickStartPos - transform.position).magnitude;
            float ballSpeed = Mathf.Abs(lastPosition - transform.position) / Time.deltaTime;
            Debug.Log("X (Time): " + kickTime + ", Y (Dist): " + kickDistance + ", Z (Speed): " + ballSpeed);

            run = ballSpeed > 0.001f;
        }
    }

    private void StartKick()
    {
        kickStartTime = Time.time;
        kickStartPosition = transform.position;
        lastPosition = transform.position;
    }
}

Once those values are known you can generate a function for determining the distance by feeding some of your values into a curve fitting tool (I use https://mycurvefit.com/, don't worry it's not an exercise website for ladies). Once you pick the equation that looks best for your data you should know how far away your ball is at any point in reasonable time (not accounting for crazy bounces and ricochets).

At this point we know where the ball is and will be at any given time, and now need to find where the player should intercept it. I'm sure there is a really smart way to do this, but I don't know it, so brace yourself. From here I would use a binary search like algorithm to see at which point on the balls path the player can reach without being either too early or too late. Some pseudo code for this would be like:

// true means I could probably get the ball, false means I can't
bool CheckMidPoint(float startTime, float endTime, int checksRemaining, out Vector3 bestMatch)
{
    if (checksRemaining > 0) // true if should we keep looking for a better place to get the ball.
    {
        float checkTime = 0.5f * (endTime - startTime);
        Vector3 futureBallPosition = WhereWillMyBallBe(checkTime);
        float myTime = PlayerTimeToPoint(futureBallPosition);

        if (myTime == checkTime) // this will probably never happen
        {
            return true;
        }
        else if (myTime < checkTime) // I got here too early
        {
            bestMatch = futureBallPosition;
            return true || CheckMidPoint(startTime, checkTime, checksRemaining-1, out bestMatch);
        }
        else // I got here too late
        {
            return CheckMidPoint(checkTime, startTime, checksRemaining-1, out bestMatch);
        }
    }
    else
    {
        return false; // lets hope one of the earlier checks passed otherwise let's give up, this guy is too chonky to get the ball.
    }
}

I apologize for not testing that and giving you better code but I am a bit short on time. Anyway that should return the best point to intercept the ball if it continues on the expected path. Be sure to keep your check count low (probably 10 is fine if only the closest player for each team is trying to get the ball) otherwise your frame rate might start to crawl.

\$\endgroup\$
0
\$\begingroup\$

Your only option is to dry run the simulation as the ball is kicked, then have the Ai begin moving to that location.

\$\endgroup\$
3
  • \$\begingroup\$ What do you mean by dry run? Do you mean run the simulation ahead of time? Can you help me understand how this can be done in unity if possible? \$\endgroup\$ Commented Aug 18, 2020 at 17:03
  • 1
    \$\begingroup\$ Why would this be the only option? Granted, modelling the slowdown of the ball and intercepting this non-linear motion is messy, but it's by no means impossible. \$\endgroup\$
    – DMGregory
    Commented Aug 18, 2020 at 17:20
  • \$\begingroup\$ By Dry Run I mean you need to calculate the position of the ball at a specified time, this is the same as running the simulation-ish, as you'll need to run the equations to calculate this. @DMGregory I guess it's not the only option on a second look. You could use a graph function that closely resembles distance at time and query that using an initial velocity provided by the kick. I guess that would model psychology better as humans can judge initial velocity and then query their own experience for how far that ball will travel. \$\endgroup\$
    – Natalo77
    Commented Aug 19, 2020 at 9:18
0
\$\begingroup\$

What I would do is calculate it as if it was constant speed, but re-calculate it as it is in the air, possibly every frame. As the ball gets closer to target, your constant speed calculations should approach the correct solution.

As a side-effect, you will get a realistic AI, as it will adjust itself as the ball approaches.

\$\endgroup\$

You must log in to answer this question.

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