Referencing the Collision of two other objects to allow for an animation to be played on the scripted object.

Hi all,

Will preface this by saying that I am a beginner when it comes to C# and Unity.

So i’m creating a script for animations to play on a weapon model (in an FPS context) when relevant keys are pressed, and this is simple enough for the WASD keys which will not (in my case) require any conditions in order to disable or enable running animations contextually.

However, the jump animation is another story. Currently the animation works fine whenever space is pressed, but I want the animation trigger to be disabled whenever the player is airborne. As it is, spamming space will play the animation regardless of whether the player is in contact with the ground.

The weapon model is not a child of the Player gameobject (because of mesh warping issues when parented), I have a simple script that references the Player object and Camera object and sets the position and rotation of the weapon model accordingly.

I’ve also managed to disable the actual jump action on the player movement script, by setting up a bool called ‘m_Grounded’ that is false by default, and becomes true when the player’s collider contacts another collider with the tag ‘ground’, and the jump action can only be performed when space is pressed AND m_grounded = true (pressing space in this case sets m_Grounded back to false after performing the jump).

I’ve tried to make a similar method in the weapon animation script to dictate when the animation is available to be played, but I can’t quite get my head around what kind of function I need to make to reference the collider (and it’s collision with another object tagged ‘Ground’) of an object (the Player) that is completely separate from the object that has this script attached (the weapon).

Here’s my current script, I’m fairly certain that OnCollisionEnter is looking for the weapon’s collider to be touching the ‘Ground’, and not the Player GameObject as seen in this code.

using UnityEngine;

public class WeaponAnim : MonoBehaviour
{
    public GameObject Player;

    private Animator anim;
    private bool _Grounded = false;
    private Collider playerCol;



    // Use this for initialization
    void Start()
    {
        anim = GetComponent<Animator>();
        playerCol = Player.GetComponent<Collider>();
    }

    void OnCollisionEnter(Collision CollisionInfo)
    {
        if (CollisionInfo.collider.tag == "Ground")
        {
            _Grounded = true;
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey("w") || (Input.GetKey("s")) || (Input.GetKey("a")) || (Input.GetKey("d")))
        {
            anim.SetBool("isRunning", true);
        }
        else
        {
            anim.SetBool("isRunning", false);
        }

        if ((Input.GetKeyDown("space")) && (_Grounded == true))
        {
            anim.SetTrigger("jump");
            _Grounded = false;
        }

    }



}

Can anyone point me in the right direction? I have a feeling it’s a simple one-line solution that I’m just not aware of.

Thanks for any help.

Hi @TheFeenster

I don’t work with models too often however I am positive there should be a better solution to your weapon child/parent issue. Also, for your input, you should try and use Input.GetAxis or Input.GetAxisRaw because it allows players to customise their controls. As for your collision issue, you were correct. You selected an appropiate solution to your issue however the OnCollisionEnter function is checking for collision resulting from the object that the script is attached to. What you could do is place the grounded variable and OnCollisionEnter code into the player control script and use the reference you have to complete your if statement like so:

If (Player.grounded && Input.GetAxisRaw("space") != 0) {
    // Do Stuff
}

Notes -
a) You don’t need to specify a bool variable as true or false but instead can just leave it alone for a true check, or use the ! operator for a false check. i.e. myBool or !myBool

b) Also the input function I used doesn’t take the name of the key pressed, but rather the name of the input profile. You can learn more about this by googling about “Unity Input Manager”, or just click the link I provide.

c) Since you’re new to unity the best bit of advice I could give is to always use the script reference when you are using in-built functions. It’s super useful.

Links -

Input Class - Unity - Scripting API: Input

OnCollisionEnter - Unity - Scripting API: Collider.OnCollisionEnter(Collision)

Thanks for the info! Regarding the mesh distortion, I have seen that creating empty GameObjects for each mesh in the model and making the meshes children of their respective empty GameObjects is the right way to sort them to avoid abnormalities, but the brief attempt I made didn’t yield any results, but I’m not sure if I made an empty object for every single mesh in the model, come to think of it.

I’ve changed the if statement regarding WASD to GetAxis Horizontal and Vertical, but I’ve left the jump as a GetKeyDown for the time being because there’s some delay in the execution of it if I convert it to GetAxis Jump. Does it perhaps need to be under FixedUpdate rather than Update?

I’m still having trouble referencing the ‘grounded’ bool from the PlayerMotor script. Currently the Player reference is a GameObject, does it need to be something different?

I do indeed already have a grounded variable (named m_Grounded specifically) and the OnCollisionEnter method in the PlayerMotor script attached to the actual player, which dictates when the actual movement of the jump action can be done. But whenever I try and input something like: Player.Grounded or Player.m_Grounded into the WeaponAnim script, it tells me; ‘GameObject does not contain a definition for ‘m_grounded’’. I set the m_grounded bool in the PlayerMotor script to public just in case that was the issue, but it still doesn’t seem to be able to be referenced.

I assume the code example you wrote is supposed to be part of the WeaponAnim script and not the PlayerMotor, but the same issue prevails even vice versa. Instead of trying to reference the PlayerMotor, i would be trying to reference the weapon’s Animator.

I feel there’s something fundamental I am misunderstanding to being able to reference the script of another object that has been added as a variable.

For clarity, here’s the PlayerMotor script (Most of it is following a tutorial by Brackeys);

using UnityEngine;

[RequireComponent(typeof(Rigidbody))]
public class PlayerMotor : MonoBehaviour
{

    [SerializeField]
    private Camera cam;

    [SerializeField]
    private float jumpForce = 500f;

    public bool m_Grounded = false;
    private Vector3 velocity = Vector3.zero;
    private Vector3 rotation = Vector3.zero;
    private float cameraRotationX = 0f;
    private float currentCameraRotationX = 0f;

    [SerializeField]
    private float cameraRotationLimit = 90f;

    private Rigidbody rb;

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

    //Acquires a movement vector
    public void Move(Vector3 _velocity)
    {
        velocity = _velocity;
    }

    //Acquires a rotational vector
    public void Rotate(Vector3 _rotation)
    {
        rotation = _rotation;
    }

    //Acquires a camera rotational vector
    public void RotateCamera(float _cameraRotationX)
    {
        cameraRotationX = _cameraRotationX;
    }

    void OnCollisionEnter(Collision CollisionInfo)
    {
        if (CollisionInfo.collider.tag == "Ground")
        {
            m_Grounded = true;
        }
    }

    void Update()
    {
        if ((Input.GetKeyDown("space")) && (m_Grounded == true))
        {
            rb.AddForce(0f, jumpForce * Time.fixedDeltaTime, 0f, ForceMode.VelocityChange);
            m_Grounded = false;
        }
    }
    //Runs every physics iteration, Remember FixedUpdate instead of Update for physics calculations
    void FixedUpdate()
    {
        PerformMovement();
        PerformRotation();
        
        
    }

    //Perform movement based on velocity variable
    void PerformMovement()
    {
        if (velocity != Vector3.zero)
        {
            rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
        }

    }

    //Perform rotation
    void PerformRotation()
    {
        rb.MoveRotation(rb.rotation * Quaternion.Euler(rotation));
        if (cam != null)
        {
            //set our rotation and clamp it to the value set by the cameraRotationLimit float value
            currentCameraRotationX -= cameraRotationX;
            currentCameraRotationX = Mathf.Clamp(currentCameraRotationX, -cameraRotationLimit, cameraRotationLimit);

            //Apply our rotation to the transform of our camera
            cam.transform.localEulerAngles = new Vector3(currentCameraRotationX, 0f, 0f);
        }
    }
  
}