2
votes

I'm having a hard time grasping the concept of position in Unity.

Have a parent object (Player). On that player, I have a child object called "Gun". On the gun, I have a script to fire bullets. When I fire the bullets, it spawns to the left of the gun, and the player.

I've tried offsetting the bullet's position on spawn, but when I turn around, the location is incorrect (it's still not centered on the gun). I also have a feeling that the offset that I've tried is a hack, and that I've missed something somewhere.

My code for the firing script on the gun :

void Update()
{
    if (Input.GetAxisRaw("Fire1") > 0)
    {
        var pos = transform.position;
        print(pos.ToString());
        var proj = Instantiate(projectile, pos, Quaternion.identity);

        proj.transform.rotation = transform.rotation;

    }
}

The only other thing touching the bullet, is my BulletController, a script on the bullet :

void Start()
{
    rb = GetComponent<Rigidbody2D>();
    //rb.AddForce(transform.forward * 100, ForceMode.Impulse);
    rb.velocity = transform.up * 10;

}

Attached screenshot of my setup enter image description here

3
Can you print out the position of the bullet on the frame after it is spawned and also when the movement is updated? It's possible that the first frame of movement is offsetting, or that your bullet prefab is not set to 0, 0, 0Eliasar
@Eliasar Unsure what you mean with "on the frame after it is spawned", but what I've done is added a script on the bullet, that prints out its position on Update, and that is 0,0,0WynDiesel

3 Answers

2
votes

You want to position the bullet to a relative offset based on the facing of the gun, right? If you set the position as you do now, you do it in world position unrelated to the facing of the gun.

Now, there are 2 ways how you can do it:

Place the bullet as a child object of the gun with a relative local position and unparent it immediately. Not a nice solution and resembles more a hack.

Or use the following methods, which I created:

/// <summary> Returns a vector which is relative to the facing and position of 'c'. </summary>
public static Vector3 RelativePosition (Transform c, Vector3 target)
{
    return c.right * target.x + c.up * target.y + c.forward * target.z + c.position;
}

/// <summary> Returns a vector which is relative. </summary>
public static Vector3 RelativePosition (Vector3 position, Vector3 forward, Vector3 up, Vector3 right, Vector3 target)
{
    return right * target.x + up * target.y + forward * target.z + position;
}

And complementary this:

/// <summary> Returns a vector which is relative to the facing of 'c'. </summary>
public static Vector3 RelativePositionZero (Transform c, Vector3 target)
{
    return c.right * target.x + c.up * target.y + c.forward * target.z;
}

/// <summary> Returns a vector which is relative. </summary>
public static Vector3 RelativePositionZero (Vector3 forward, Vector3 up, Vector3 right, Vector3 target)
{
    return right * target.x + up * target.y + forward * target.z;
}

Usage: Use the RelativePosition method, provide the Transform of the gun as parameter and the relative offset for the Vector3 parameter. Example:

        item.position = RelativePosition (Camera.Main.transform, new Vector3 (1.5f, 0f, 4.0f));

This would place the position of 'item' 4 unity distance in front of the camera and 1.5 unity distance to the right.

Hint: RelativePosition will give you the resulting world position as it is. This is what you use to receive the relative position you seek as world position. RelativePositionZero will give you the relative offset from the Transform object to the given Vector3 position. That can be used to determine if something is left or right, above or below, in front or behind the given Transform.

1
votes

feeling that the offset that I've tried is a hack

I don't see any offset .. you could do e.g.

public float offset = 0.5f;


if (Input.GetAxisRaw("Fire1") > 0)
{
    // add the offset here
    var pos = transform.position + transform.up * offset;
    print(pos.ToString());

    var proj = Instantiate(projectile, pos, Quaternion.identity);

    proj.transform.rotation = transform.rotation;
}

transform.position spawns the bullet at the same place as the gun. I added transform.up since it seems this is the direction your player is looking to (in 3D space it would e.g. be transform.forward but in 2D it is either transform.up or transform.right depending in which direction the player looks by default). offset is just how far you want the bullet be placed in the given direction in meters/units.


If you rather want a Vector3 offset for more control/for debugging which axis is the correct one you could instead use

public Vector3 offset;

//...

var proj = Instantiate(projectile, transform.position, Quaternion.identity);

proj.transform.rotation = transform.rotation;

// Now move it to the offset in local space
proj.transform.Translate(offset, Space.Self);

You don't want to spawn it as child ... because if you than move or rotate after, your bullets will all also move and rotate together with you!

1
votes

The problem was that I instantiated the sprite on the bullets on an offset, and not 0,0,0 relative to the actual gameobject.