Moving a prefab forward 2D

I am not able to move a prefab in a script without creating a new script. I have a turret that points toward the player in a 2D game and it shoots a prefab but when I try to make it move with a Rigidbody2D it gives me an error that says

cannot convert from ‘UnityEngine.GameObject’ to 'UnityEngine.Vector2

and I can’t seem to fix it even after 2 hours.

public void PewPewThing()
{
    Invoke("PewPewThing", fireRate);
    GameObject projectile = Instantiate(shootyThing, transform.position, transform.rotation);
    projectile.GetComponent<Rigidbody2D>().AddForce(projectile);
}

Hey AlexanderMigdal,

I encourage you to read all of this, even if it is much.

First of all, you are trying to call the method from the method itself, with a paramter it won’t accept.

Invoke(“PewPewThing”, fireRate); // Your code

Even if you put the invoke methode somewhere else, Invoke would not work for this. You should rather use InvokeRepeating like this:

private void Update()
{
    InvokeRepeating(nameof(ShootProjectile), 0f, fireRate);
}

private void ShootProjectile()
{
    // Instantiate projectile
    GameObject projectile = Instantiate(_Projectile, transform.position, transform.rotation);

    // Add force
    projectile.GetComponent<Rigidbody2D>().AddForce(projectileForce * transform.up); // Or transform.right, if you want to shoot right (-right for left)
}

Also instead of

Invoke(“PewPewThing”, fireRate);

you should use

Invoke(nameof(PewPewThing), delay); // The second parameter is a delay, not a repeat time

This

GameObject projectile = Instantiate(shootyThing, transform.position, transform.rotation);
projectile.GetComponent().AddForce(projectile);

won’t work, because you forgot to get a reference to the Rigidbody2D component.

projectile.GetComponent<Rigidbody2D>().AddForce(projectile);

is what you tried to do.
Also I don’t know what the projectile variable is supposed to be, but it has to be a Vector2 (or Vector3, but we’re in 2D)


2 Solutions for this

I tested this myself and came up with 2 new solutions. (Make sure, your projectile’s gravity is set to 0, if you want to build a top-down-shooter.)

You could either use an IEnumerator like this:

public class ShootScript : MonoBehaviour
{
    // Firerate
    private readonly float fireRate = 600f; //Rounds per minute

    // Projectile reference
    [SerializeField] // Apply in inspector
    private GameObject _Projectile;

    // Force, that will be applied on the projectile
    private readonly float projectileForce = 1000f;

    // Shoot?
    private bool doShoot = false;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Mouse0) && !doShoot)
        {
            doShoot = true;
            StartCoroutine(Shoot());
        }
        else if (Input.GetKeyUp(KeyCode.Mouse0) && doShoot)
        {
            doShoot = false;
            StopCoroutine(Shoot());
        }   
    }

    private IEnumerator Shoot()
    {
        while (doShoot)
        {
            // Instantiate projectile
            GameObject projectile = Instantiate(_Projectile, transform.position, transform.rotation);

            // Add force
            projectile.GetComponent<Rigidbody2D>().AddForce(projectileForce * transform.up);

            // Wait for this time
            else { yield return new WaitForSeconds(1 / (fireRate / 60)); }
        }

    }
}

Or you could use a REPEATED Invoke (not suggested) like this:

public class ShootScript : MonoBehaviour
{
    // Firerate
    private readonly float fireRate = 600f; //Rounds per minute

    // Projectile reference
    [SerializeField] // Apply in inspector
    private GameObject _Projectile;

    // Speed of the projectile
    private readonly float projectileSpeed = 1000f;

    // Shoot?
    private bool doShoot = false;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Mouse0) && !doShoot)
        {
            doShoot = true;
            InvokeRepeating(nameof(ShootProjectile), 0, 1 / (fireRate / 60));
        }
        else if (Input.GetKeyUp(KeyCode.Mouse0) && doShoot)
        {
            doShoot = false;
            CancelInvoke(nameof(ShootProjectile));
        }
    }

    private void ShootProjectile()
    {
        while (doShoot)
        {
            // Instantiate projectile
            GameObject projectile = Instantiate(_Projectile, transform.position, transform.rotation);

            // Add force
            projectile.GetComponent<Rigidbody2D>().AddForce(projectileForce * transform.up);
        }
    }
}

If you want to shoot to your right, you should use

// Add force
projectile.GetComponent<Rigidbody2D>().AddForce(
projectileSpeed * transform.right // Instead of transform.up
);

Important notes:

Make sure that the object where this script is on, is not the same object the visuals are on.
Always have the prefabs like this:

Prefab Parent (with movement script and rigidbody)
  -> Prefab Child (with visuals, for example circle, square...)