Search code examples
unity-game-engine2dphysicsgame-physicsprediction

2D projectile trajectory prediction (unity3d)


(Using unity3d 4.3 2d, it uses box2d like physics).

I have problems with predicting trajectory I'm using:

Vector2 startPos;
float power = 10.0f;
float interval = 1/30.0f; 
GameObject[] ind;


void Start (){
        transform.rigidbody2D.isKinematic = true;
        ind = new GameObject[dots];
        for(int i = 0; i<dots; i++){
            GameObject dot = (GameObject)Instantiate(Dot);
            dot.renderer.enabled = false;
            ind[i] = dot;
        }
    }

void Update (){
        if(shot) return;
        if(Input.GetAxis("Fire1") == 1){
            if(!aiming){
                aiming = true;
                startPos = Input.mousePosition;
                ShowPath();
            }
            else{
                CalculatePath();
            }

        }
        else if(aiming && !shot){
            transform.rigidbody2D.isKinematic =  false; 
            transform.rigidbody2D.AddForce(GetForce(Input.mous  ePosition));        
            shot = true;
            aiming = false;
            HidePath();
        }
}

Vector2 GetForce(Vector3 mouse){
        return (new Vector2(startPos.x, startPos.y)- new Vector2(mouse.x, mouse.y))*power;

}

void CalculatePath(){
        ind[0].transform.position = transform.position; //set frist dot to ball position
        Vector2 vel = GetForce(Input.mousePosition); //get velocity

        for(int i = 1; i < dots; i++){          
            ind[i].renderer.enabled = true; //make them visible
            Vector3 point = PathPoint(transform.position, vel, i); //get position of the dot 
            point.z = -1.0f;
            ind[i].transform.position = point;
        } 
    }

    Vector2 PathPoint(Vector2 startP, Vector2 startVel, int n){
               //Standard formula for trajectory prediction
        float t = interval;
        Vector2 stepVelocity = t*startVel;
        Vector2 StepGravity = t*t*Physics.gravity;

        Vector2 whattoreturn = ((startP + (n * stepVelocity)+(n*n+n)*StepGravity) * 0.5f);

        return whattoreturn;
    }

Using this, I get wrong trajectory. 1. It's like gravity doesn't drag trajectory down at all, and yes i know that gravity is weak because:

t*t*Physics.gravity = 0.03^2 * vector2(0, -9.8) = vector2(0, -0.00882)

But that is the formula :S 2. Since gravity is low, velocity is too strong.

Here is the video: http://tinypic.com/player.php?v=1z50w3m&s=5

Trajectory formula form: http://www.iforce2d.net/b2dtut/projected-trajectory

What should I do?

I found that if I set StepGravity to something stronger like (0, -0.1) and devide startVel by 8 I get nearly right trajectory, but i don't want that, I need true trajectory path.

Users from answer.unity3d.com said I should ask here, because here is a bigger group of mathematical coders.

And I searched a lot about this problem (that how I found that formula).


Solution

  • you're only calculating the effect of gravity over 1/30th of a second for each step - you need to do it cumulatively. Step 1 should end with a velocity of 0.09G, Step 2 with .18G, step3 with .27G etc.

    Here's a very simple example that draws the ballistic trajectory based on start velocity and a supplied time:

    using UnityEngine;
    using System.Collections;
    
    public class grav : MonoBehaviour {
    
        public Vector3 StartVelocity;
        public float PredictionTime;
        private Vector3 G;
    
        void OnDrawGizmos()
        {
            if (G == Vector3.zero)
            {
                 // a hacky way of making sure this gets initialized in editor too...
                // this assumes 60 samples / sec
                G = new Vector3(0,-9.8f,0) / 360f;
            }
            Vector3 momentum = StartVelocity;
            Vector3 pos = gameObject.transform.position;
            Vector3 last = gameObject.transform.position;
            for (int i = 0; i < (int) (PredictionTime * 60); i++)
            {
                momentum += G;
                pos += momentum;
                Gizmos.DrawLine(last, pos);
                last = pos;
            }
    
        }
    }
    

    In you version you'd want draw your dots where I'm drawing the Gizmo, but it's the same idea unless I'm misunderstanding your problem.