Search code examples
c#unity-game-enginegame-physics

Object coordinates not updating as expected


I'm having an issue with a prefab I'm instantiating in my script. What I'm attempting to do is simulate the physics behind the projectile motion of a cannonball. I have the following script attached to my prefab:

using UnityEngine;
using System.Collections;

public class ShootPhysics : MonoBehaviour {

    // vectors & angles to be calculated
    private float fx = 0f;
    private float fy = 0f;
    private float angle;

    // forces acting upon object
    private float gravity = 9.8f;
    private float force = 1.2f;

    // new distance & vector variables
    private float dis_x = 0f;
    private float dis_y = 0f;

    // Script & CannonBall transform
    private CannonPhysics cannon_angle;

    void Start() {
        cannon_angle = GameObject.FindWithTag("Gun").GetComponent<CannonPhysics>();
        angle = cannon_angle.getAngle ();
        fx = Mathf.Round (force * Mathf.Cos(Mathf.Deg2Rad * angle));
        fy = Mathf.Round (force * Mathf.Sin(Mathf.Deg2Rad * angle));
    }

    void FixedUpdate() {
        dis_x = (float)(fx * Time.timeSinceLevelLoad);
        dis_y = (float)(fy + Time.timeSinceLevelLoad + (0.5) * (-gravity) * Time.timeSinceLevelLoad * Time.timeSinceLevelLoad);
        Debug.Log (dis_x+", "+dis_y);
        gameObject.transform.Translate (new Vector2(dis_x, dis_y));
    }

}

And the prefab will be instantiated from the following script:

using UnityEngine;
using System.Collections;

public class CannonPhysics : MonoBehaviour {

    // This will be our script to rotate our cannon
    private float angle = 0f;

    // cannonball object
    public Transform FirePoint;
    GameObject cannon = null;

    void Update() {
        if(Input.GetKey(KeyCode.UpArrow)) {
            angle = angle + 1;
        }
        if(Input.GetKey(KeyCode.DownArrow)) {
            angle = angle - 1;
        }

        // update cannon angle
        transform.rotation = Quaternion.Euler (new Vector3(0, 0, angle));

        if(Input.GetMouseButtonDown(0)) {
            CreateCannon();
        }
    }

    public float getAngle() {
        return angle;
    }

    private void CreateCannon() {
        cannon = Instantiate (Resources.Load("Prefabs/CannonBall"), FirePoint.position, FirePoint.rotation) as GameObject;
        Destroy (cannon, 3f);
    }

}

The object gets instantiated as it should, and the object is destroyed after 3 seconds as it should, however the object x and y position do not change at all, and are not what i should expect them to be. Let me give you an example:

These are the x and y coordinates i should expect which i have displaying in the console.

enter image description here

However these are the actual coordinates displayed in Unity's inspector:

enter image description here

What's strange too, is that these coordinates will not change for each object, they will literally stay the same, even after the object has been destroyed. Can anyone explain why this is happening? And perhaps offer a solution?

Edit: For a more clear example:

Each time i instantiate my cannonball object the x and y coordinates for the next object to be instantiated are referenced from the last. Here are the result of my first instantiated object after being destroyed.

enter image description here

And here they are after instantiating a second object.

enter image description here

Now what I'm expecting is that each new object instantiated should start from it "original" position (figuratively speaking) and the x and y values should reset and start again effectively.


Solution

  • There are a few things happening in the code you have provided in the FixedUpdate() portion of your code which I have copied below:

    void FixedUpdate()
    {
        dis_x = (float)(fx * Time.timeSinceLevelLoad);
        dis_y = (float)(fy + Time.timeSinceLevelLoad + (0.5) * (-gravity) * Time.timeSinceLevelLoad * Time.timeSinceLevelLoad);
        Debug.Log (dis_x+", "+dis_y);
        gameObject.transform.Translate (new Vector2(dis_x, dis_y));
    }
    

    First, Time.timeSinceLevelLoad provides you the time, in seconds, that has passed since your level was loaded. What this means for your code is that dis_x and dis_y always have larger values the longer you have your application open. So, when you spawn a new prefab, the d_x and d_y values are already at a position that seems as if it's using the position of the last prefab.

    Instead, if you want to calculate the new position of an object given it's velocity, you'd typically want to use the deltaTime instead. For example:

    dx = vel.x * Time.fixedDeltaTime;
    dy = vel.y * Time.fixedDeltaTime;
    

    In this example, dx and dy represent the change in position given the velocity of the object. Time.fixedDeltaTime represents the amount of time in seconds that has passed since the last time FixedUpdate() was called. You would then add dx and dy to your position to get the new position.

    Secondly, gameObject.transform.Translate() translates the position of the GameObject; it does not set the position of the GameObject. Translate will just add the Vector3 to your current position. This is why your debugging output looks so strange; dis_x and dis_y are not your positions; they are how far you moved the GameObject by calling Translate().

    To set the position of the GameObject, do this instead:

    gameobject.transform.position = newPosition;
    

    ...where newPosition is a Vector3 that represents the new position of your gameobject.