2D Sidescroller: Bullet changing direction along with the player after being instantiated

Hi everyone. I’m a game artist that’s trying to make the transition to indie game developer and I’ve been studying C# and working with Unity for the past 2 years.

I’m currently working on my first game using C#. The game is a simple 2D side-scrolling shooter.

So far I’ve been pretty successful. I have managed to code the character’s left/right movement, jumping and his ability to shoot projectiles. But I’ve run into a problem I can’t seem to solve. If my character sprite is facing screen left or screen right and I press the fire button a bullet prefab is instantiated and travels in the correct direction and eventually self destructs. Sounds good right? Well there’s one small problem…

If I change the direction my player sprite is moving before the bullet prefab expires, it will also change direction along WITH the player. I know there’s a simple fix out there, but I’m not quite there with my understanding of C# to be able to figure it out on my own.

Here’s the script that controls my player sprite’s movement. There’s a boolean variable in there called facingRIght that I’m using to tell the bullet prefab which way the sprite is facing when it’s instantiated.

using UnityEngine;
using System.Collections;

public class CharacterEngine : MonoBehaviour
{
    //running variables
    public float speed = 15.0f;
    public bool facingRight = true;

    //jump variables
    Animator anim;
    public float jumpSpeed = 400.0f;
    public bool grounded = true;
    public float jumpTimer;
    float jumpDelay = 0.05f;
    public bool jumped;
   
//---------------------------------------------------------------------------------------------------

    void Start ()
    {
        //initializes the Animator component in Unity, so we can switch between animations
        anim = GetComponent<Animator> ();
    }

//---------------------------------------------------------------------------------------------------   
    void Update ()
    {
        //the speed variable is used in the Animator to switch between idle and walk animation
        anim.SetFloat("speed", Mathf.Abs(Input.GetAxis("Horizontal")));
        //if the player presses A or D move the character along positive X
        //or if the player presses left or right on joystick1
        Vector2 x = Input.GetAxis ("Horizontal") * transform.right * Time.deltaTime * speed;
        transform.Translate (x);

        //if the input is moving the player right and the player is facing left...
        if (Input.GetAxis ("Horizontal") > 0 && !facingRight)
        {
            //...flip the player
            Flip ();
        }
        //Otherwise if the input is moving the player left and the player is facing right...
        else if(Input.GetAxis ("Horizontal") < 0 && facingRight)
        {
            //...flip the player.
            Flip();
        }

        //if the player holds down shift while pressing D or A increase the movement rate
        if (Input.GetKey (KeyCode.JoystickButton0)||Input.GetKey (KeyCode.LeftShift))
        {
            speed = 25.0f;
        }
        else
        {
            speed = 15.0f;
        }

        //if the character presses space bar move the character up along Y
        if (Input.GetButton ("Jump"))
        {
            Jump();
        }

        //this causes the jumpTimer to start counting down
        jumpTimer -= Time.deltaTime;
    }

//---------------------------------------------------------------------------------------------------

    void Flip ()
    {
        //switch the way the player is labelled as facing
        facingRight = !facingRight;
       
        //multiply the player's x local scale by -1
        Vector3 theScale = transform.localScale;
        theScale.x *= -1;
        transform.localScale = theScale;
    }

//---------------------------------------------------------------------------------------------------

    void Jump()
    {
        //make sure the player is on the ground then move him up vertically
        if (grounded == true)
            {
                rigidbody2D.AddForce (Vector2.up * jumpSpeed);
                anim.SetTrigger("jump");
                jumpTimer = jumpDelay;
                jumped = true;
                grounded = false;
            }
    }

//---------------------------------------------------------------------------------------------------

    void OnCollisionEnter2D (Collision2D hit)
    {
        //once the player hits the ground after a jump trigger the land state in the animator
        grounded = true;
        if (jumpTimer <= 0 && grounded && jumped)
        {
            anim.SetTrigger ("land");
            jumped = false;
        }
    }
}

Here’s the code I’m using to fire the projectile:

using UnityEngine;
using System.Collections;

public class BulletSpawner : MonoBehaviour
{
    public GameObject bulletPrefab;
    public float fireDelay = 0.25f;
    float coolDownTimer =  0;
   
//---------------------------------------------------------------------------------------------------

    void Update ()
    {
        //this causes the coolDownTimer to start counting down
        coolDownTimer -= Time.deltaTime;
        //if the player presses Fire1 after the coolDownTimer reaches 0 a bullet is created as a GameObject
        if (Input.GetButtonDown("Fire1") && coolDownTimer <= 0)
        {
            coolDownTimer = fireDelay;
            GameObject bulletGo = (GameObject)Instantiate(bulletPrefab, transform.position, transform.rotation)as GameObject;
        }
    }
}

And this is the code I’ve applied to the bullet prefab and this, I’m fairly certain, is where the problem lies:

using UnityEngine;
using System.Collections;

public class BulletEngine : MonoBehaviour
{
    float maxSpeed = 40f;
    CharacterEngine characterEngine;

//---------------------------------------------------------------------------------------------------
    void Awake ()
    {
        characterEngine = GameObject.Find("PlayerCharacter").GetComponent<CharacterEngine>();
    }
   
//---------------------------------------------------------------------------------------------------

    void Update ()
    {
        if(characterEngine.facingRight == true)
           {
                Vector3 pos = transform.position;
                Vector3 velocity = new Vector3(maxSpeed * Time.deltaTime, 0, 0);
                //pos += transform.rotation * velocity;
                pos += velocity;
                transform.position = pos;
            }

        if(characterEngine.facingRight == false)
           {
                Vector3 pos = transform.position;
                Vector3 velocity = new Vector3(maxSpeed * Time.deltaTime, 0, 0);
                //pos -= transform.rotation * velocity;
                pos -= velocity;
                transform.position = pos;
            }
    }
}

The code is a bit of a chimera of several different tutorials, text books and online examples but I’ve done my best to keep the logic and naming conventions consistent. I apologize in advance for any NOOB mistakes I’ve made in the posting of this. I’m new to the forum and asking for help in general.

Any insight you guys and gals could provide would be GREATLY appreciated.

Perhaps the bullet and player have collides interacting unfavorably.

I’d guess it’s that last script in the update function.

It looks like you’re making the bullet go right if the player is facing right and left if he’s facing left… EVERY time you update.

Perhaps what you want is to put the stuff you have in update() into awake() or start()

I definitely need to disassociate the projectile from the player sprite after it’s instantiated.

Now that you mention it, it does seem like it’d be smart to move the part where the bullet determines which way it’s going to travel to the awake() or start() function so that it only uses the player sprite’s position when it’s first created.

LOL! That should have been obvious to me!

THANKS!

I’ve done exactly the same thing before :>

1 Like

Okay. It’s working just fine now. Many thanks to renman3000 and wkarma for taking the time to respond and offer advice. I wound up moving the code that controls which way the bullet is facing when it spawns to the Start () function and that fixed the issue.

For future reference in case anyone else ever has the same problem, here’s the corrected code for the BulletEngine:

using UnityEngine;
using System.Collections;

public class BulletEngine : MonoBehaviour
{
    public float maxSpeed = 40f;
    CharacterEngine characterEngine;
    Vector3 pos;
    Vector3 velocity;

//---------------------------------------------------------------------------------------------------
    void Awake ()
    {
        characterEngine = GameObject.Find("PlayerCharacter").GetComponent<CharacterEngine>();
        velocity = new Vector3(maxSpeed * Time.deltaTime, 0, 0);
        pos = transform.position;
    }
   
//---------------------------------------------------------------------------------------------------

    void Start ()
    {
        if(characterEngine.facingRight == true)
           {
                velocity = new Vector3(maxSpeed * 1 * Time.deltaTime, 0, 0);
            }

        else
           {
                velocity = new Vector3(maxSpeed * -1 * Time.deltaTime, 0, 0);
            }
    }

//---------------------------------------------------------------------------------------------------
    void Update ()
    {
        pos += velocity;
        transform.position = pos;
    }
}