Bullet Fire in random direction

I was working on a small project to learn more about 3D games and was developing a simple shooting system. However, the bullet moves in a random direction even though I’ve specified where it should go in the code. If anyone could help with this problem, I would be grateful

A video of the bug:
Bullet shoot in random Direction

Code:
Gun script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using static UnityEngine.GraphicsBuffer;
using UnityEngine.Pool;

public class Gun : MonoBehaviour
{

    public int DefaultCapacity = 8;
    public int MaxMagazineSize = 8;
    [SerializeField]
    private float _forwardForce, _upForce;
    [SerializeField]
    private float _fireCooldwon;
    [SerializeField]
    private Transform _fireePoint, _cam;
    [SerializeField]
    private Bullet _bullet;
    RaycastHit hit;


    // throw an exception if we try to return an existing item, already in the pool
    private bool _collectionCheck = true;



    private IObjectPool<Bullet> _objectPool;
    private bool _canFire;
    private bool _magazineEmpty = false;

    private void Awake()
    {
        _objectPool = new ObjectPool<Bullet>(CreateProjectil, OnGetFromPool, OnReleaseToPool, OnDestroyPooledObject, _collectionCheck, DefaultCapacity, MaxMagazineSize);   
    }

    void Start()
    {
        _canFire = true;
    }

    private void Update()
    {
        CheckMagazine();
        
    }

    public void Attack(InputAction.CallbackContext ctx)
    {
        if (ctx.performed && _canFire && !_magazineEmpty)
        {
            FireBullet();
        }
    }

    private void FireBullet()
    {
        _canFire = false;

        Vector3 targetDirection;
        targetDirection = _cam.forward;

        if (Physics.Raycast(_cam.position, _cam.forward, out hit, 500f))
        {
            targetDirection = hit.point - _fireePoint.position;


        }

        Vector3 fireDirection;

        fireDirection = targetDirection.normalized * _forwardForce + _cam.up * _upForce;

        Bullet projectile = _objectPool.Get();
        if(projectile == null )
        {
            return;
        }

        projectile.transform.position = _fireePoint.position;

        Rigidbody bulletRB = projectile.GetComponent<Rigidbody>();

        bulletRB.AddForce(fireDirection, ForceMode.Impulse);

        ConsumeBullet(1);

        projectile.DeactivateBullet();

        Invoke(nameof(FireAgain), _fireCooldwon);


    }

    private void GetFireDirection()
    {

    }

    private void FireAgain()
    {
        _canFire = true;
    }

    private void ConsumeBullet(int amount)
    {
        DefaultCapacity -= amount;
    }

    public void ReloadMagazine(InputAction.CallbackContext ctx)
    {
        if (ctx.performed)
        {
            DefaultCapacity = MaxMagazineSize;
            _magazineEmpty = false;  
        }
    }

    private void CheckMagazine()
    {
        if(DefaultCapacity <= 0)
        {
            _magazineEmpty = true;
        }
    }


    // invoke when creating an item to populate the object pool
    private Bullet CreateProjectil()
    {
        Bullet bulletInstance = Instantiate(_bullet);
        bulletInstance.ObjectPool = _objectPool;
        return bulletInstance;
    }

    // invoke when retrieving the next item from the object pool
    private void OnGetFromPool(Bullet pooledObject)
    {
        pooledObject.gameObject.SetActive(true);
    }

    // invoke when returning an item from the object pool
    private void OnReleaseToPool(Bullet pooledObject)
    {
        pooledObject.gameObject.SetActive(false);
    }

    private void OnDestroyPooledObject(Bullet pooledObject)
    {
        Destroy(pooledObject.gameObject);
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        if (Physics.Raycast(_cam.position, _cam.forward, out hit, 500f))
        Gizmos.DrawLine(_cam.position, hit.point);
    }
}

Bullet Code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;

public class Bullet : MonoBehaviour
{
    [SerializeField]
    private float _deactivationTime = 2f;
    private Rigidbody _rb;
    private bool _hitTarget = false;
    internal IObjectPool<Bullet> ObjectPool;

    private void Start()
    {
        _rb = GetComponent<Rigidbody>();
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (_hitTarget)
        {
            return;
        }
        else
        {
            _hitTarget = true;
        }
        _rb.isKinematic = true;
        transform.SetParent(collision.transform);


    }

    public void DeactivateBullet()
    {
        StartCoroutine(DeactivateRoutine(_deactivationTime));
    }

    IEnumerator DeactivateRoutine(float delay)
    {
        yield return new WaitForSeconds(delay);
        ObjectPool.Release(this);
    }

}

Your Bullet.cs code is kinda weird. When OnCollisionEnter is called on a bullet you set _hitTarget to true and make the Rigidbidy kinematic. But when you pull it from the pool again, _hitTarget is now true and the Rigidbody is kinematic. So your applying AddForce to a kinematic body and OnCollisionEnter will just be returned out of.
As soon as I saw the video I new it was a Rigidbody problem.

The part you’re talking about doesn’t matter(the bullet Rigidbody) , I tried removing the whole thing, and it didn’t change anything

Hi @kats_21,

Belive that your bullet rigidbodies stacking force…

Before return to ObjectPool call:
(+) _rb.Sleep();
(+) _rb.velocity = Vector3.zero

And then prior to (shoot) AddForce:
(+) _rb. WakeUp()

Hope will do! Let us know below!

IT WORKED!! thank you soo much

1 Like

If you increase the velocity of your projectiles you will run into problems. Rigid bodies are not designed to travel as fast as a bullet.

We use raycasting for this, and if you want to simulate bullets over time you only raycast as far as the bullet kan travel in one frame. You can apply drag, gravity etc at your liking to get it more realistic.