When player is moving backwards, projectiles fire backwards as well

Basically in the title. The other thing about it is that it only happens sometimes. If I am firing while moving backward, half the time the projectiles will go forward and the other half will go backward. I’m not exactly sure what could be causing it—hoping to get some help here.

This is the main code that is firing the projectiles

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;

public class PlayerInteractions : MonoBehaviour
{
    private PlayerStats playerStats;

    [SerializeField] private Transform camera;
    [SerializeField] private Transform attackPoint;
    [SerializeField] private GameObject objectToThrow;

    PhotonView PV;

    private void Awake()
    {
        playerStats = GetComponent<PlayerStats>();
        PV = GetComponent<PhotonView>();
    }

    // Update is called once per frame
    void Update()
    {
        if(PV.IsMine)
        {
            Throw();
        }
    }   

    void Throw()
    {
        if(Input.GetButtonDown("Fire1") && playerStats.ThrowablesLeft > 0)
        {
            //Spawn projectile and grab Rigidbody
            GameObject projectile = PhotonNetwork.Instantiate(objectToThrow.name, attackPoint.position, camera.rotation);
            Rigidbody projectileRb = projectile.GetComponent<Rigidbody>();

            //Calculate direction
            Vector3 forceDirection = camera.transform.forward;
            RaycastHit hit;
            if(Physics.Raycast(camera.position, camera.forward, out hit, Mathf.Infinity))
            {
                forceDirection = (hit.point - attackPoint.position).normalized;
            }

            //Calculate force of throw and apply to projectile
            Vector3 force = forceDirection * playerStats.ForwardThrowForce + transform.up * playerStats.UpwardThrowForce * Time.deltaTime;
            projectileRb.AddForce(force, ForceMode.Impulse);

            playerStats.ThrowablesLeft--;
        }
    }

}

This code is supplemental to the one above. I doubt its causing any issues but just to be safe

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;

public class PlayerStats : MonoBehaviour
{
    [SerializeField]
    private int _health;
    public int Health
    {
        get {
            return _health;
        }
        set {
            _health = value;
        }
    }

    [SerializeField]
    private float _speed;
    public float Speed
    {
        get {
            return _speed;
        }
        set {
            _speed = value;
        }
    }

    [SerializeField]
    private float _jumpHeight;
    public float JumpHeight
    {
        get {
            return _jumpHeight;
        }
    }

    [SerializeField]
    private bool _hasDoubleJump;
    public bool HasDoubleJump
    {
        get {
            return _hasDoubleJump;
        }
        set {
            _hasDoubleJump = value;
        }
    }

    [SerializeField]
    private bool _isPlayerGrounded;
    public bool IsPlayerGrounded
    {
        get {
            return _isPlayerGrounded;
        }
        set {
            _isPlayerGrounded = value;
        }
    }

    [SerializeField]
    private float _forwardThrowForce;
    public float ForwardThrowForce
    {
        get {
            return _forwardThrowForce;
        }
    }

    [SerializeField]
    private float _upwardThrowForce;
    public float UpwardThrowForce
    {
        get {
            return _upwardThrowForce;
        }
    }

    [SerializeField] private int _maxThrowables;

    [SerializeField]
    private int _throwablesLeft;
    public int ThrowablesLeft
    {
        get {
            return _throwablesLeft;
        }
        set {
            _throwablesLeft = value;
            if (_throwablesLeft > _maxThrowables)
            {
                _throwablesLeft = _maxThrowables;
            }
        }
    }

    [SerializeField]
    private bool _hasSpeedBoost;
    public bool HasSpeedBoost
    {
        get {
            return _hasSpeedBoost;
        }
        set {
            _hasSpeedBoost = value;
        }
    }
}

Any input would be appreciated!

Are you sure you can’t just sprinkle Debug.Log all over that Throw method and see what exactly goes wrong?
I can’t see an obvious error. The error is probably in some other set up or there is a bad assumption on your part.

So when I did try that, I did Debug.Log(force) and noticed that when it would shoot backwards, the force was inverted. I was thinking of inverting the force when the player is moving backwards, but since the problem happens 50% of the time, that’s not really a solution for me since it would still occur. I’m just not sure what could make the force inverted when the player moves backwards

You probably still need to Debug.Log through each stage or your logic to see where the negative value is coming from.

From a look I don’t see anything that cares about the players velocity here, so the issue probably isn’t entirely directly related to ‘moving backwards’. More likely some part of your logic returns a negative value where you don’t expect it to.

I see. I was really hoping it was something I wasn’t seeing, but I’ll do that. Appreciate the input!

Probably completely unrelated to the projectile going backwards but you shouldn’t use time delta in calculations for force impulse transform.up * playerStats.UpwardThrowForce * Time.deltaTime . It makes no sense from physics perspective and will likely cause undesirable behavior changing trajectory based on framerate.

Use:

  • ForceMode.Force → for forces that happen continuously over some period of time (attraction or repelling between objects, simulating additional friction, maybe force of river trying to move your character sideways, water hose or continuous beam weapon pushing your character backwards). Don’t multiply by delta time! Call from FixedUpdate (possibly indirectly).
  • ForceMode.Impulse → for instantaneous transfer of impulse. Use it for one time events like throwing/shooting an object, or giving an extra kick when object collide, when a hitscan weapon hits a target. Don’t multiply by delta time!

You have an issue with forceDirection:

            Vector3 forceDirection = camera.transform.forward;
            RaycastHit hit;
            if(Physics.Raycast(camera.position, camera.forward, out hit, Mathf.Infinity))
            {
                forceDirection = (hit.point - attackPoint.position).normalized;
            }

I guess you copied the code by hand and you meant camera.transform.position and camera.transform.forward here.

Since the problem only occurs 50% of the time, I guess it is related to the if block, and you need to check if it occurs when it is inside the if block or when the if block does not trigger. For that you can simply comment out the if block and/or invert the initialization.

camera is of type Transform. What’s wrong is camera.transform.forward but that works somehow.

question for OP: to which object is this script attached? is that object moving?

The script is attached to the player which then instantiates the projectile. The projectile itself only has a script that detects collision and nothing else.

BTW, I’m loving all the input and will definitely be trying all of these later today

Just wanted to let you guys know I was able to fix the bug. What seemed to be happening was when the player moved backward, the raycast was hitting the player’s body since the camera was placed inside the character controller collider, thus giving the wrong direction to the projectile. What I did was place an empty gameobject as a child of the camera and moved it right in front of the camera, outside of the collider and reference the Transform of the empty gameobject. Projectiles now behave as intended no matter which way the player moves. Thank you all for your inputs!!

4 Likes