Home > database >  Objects not colliding in Unity 3D
Objects not colliding in Unity 3D

Time:01-05

I am following along with creating the Obstacle Game from Game Programming with Unity and C# by Casey Hardman. I have reached the point in the first few pages of Chapter 16 where you create a Hazard to kill the player. In the beginning stages, you write code that kills the player object if the player object collides with the hazard. I've followed the instructions (as far as I can tell) to the letter and yet when I created a sphere as a test hazard, assigned the script to it, and ran the player object into it, nothing happened when they collided. I thought maybe there was an error with the Hazard code, so I commented out the "when collide with object on player layer, kill player" code, wrote code to have it just write to the console when they collide, and tested it. Unfortunately, there doesn't seem to be any collision detection when these two objects touch each other. I've Googled "objects not colliding unity" and every combination of "collision not detected in unity" I can think of and none of the answers have helped so I'm posting here in hopes I get an answer. I'm including screenshots of the two objects and their settings, my physics settings in Unity, and the code I've written for both objects in hopes that someone can catch what I'm doing wrong.

The Player Object

The Test Hazard Object

Layer Collision Matrix

The Player Object Script:

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

public class Player : MonoBehaviour
{

    //References
    [Header("References")]
    public Transform trans;
    public Transform modelTrans;
    public CharacterController characterController;

    //Movement
    [Header("Movement")]
    [Tooltip("Units moved per second at maximum speed.")]
    public float movespeed = 24;

    [Tooltip("Time, in seconds, to reach maximum speed.")]
    public float timeToMaxSpeed = .26f;

    private float VelocityGainPerSecond{ get { return movespeed / timeToMaxSpeed; }}
    
    [Tooltip("Time, in seconds, to go from maximum speed to stationary.")]
    public float timeToLoseMaxSpeed = .2f;

    private float VelocityLossPerSecond { get { return movespeed / timeToLoseMaxSpeed; }}

    [Tooltip("Multiplier for momentum when attempting to move in a direction opposite the current traveling direction (e.g. trying to move right when already moving left.")]
    public float reverseMomentumMultiplier = 2.2f;

    private Vector3 movementVelocity = Vector3.zero;

    private void Movement()
    {
        // IF W or the up arrow key is held:
        if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
        {
            if (movementVelocity.z >= 0) // If we're already moving forward
            //Increase Z velocity by VelocityGainPerSecond, but don't go higher than 'moveSpeed':
            movementVelocity.z = Mathf.Min(movespeed,movementVelocity.z   VelocityGainPerSecond * Time.deltaTime);

            else // Else if we're moving back
            //Increase Z velocity by VelocityGainPerSecond, using the reverseMomentumMultiplier, but don't raise higher than 0:
            movementVelocity.z = Mathf.Min(0,movementVelocity.z   reverseMomentumMultiplier * Time.deltaTime);
        }

        //If S or the down arrow key is held:
        else if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
        {
            if (movementVelocity.z > 0) // If we're already moving forward
            movementVelocity.z = Mathf.Max(0,movementVelocity.z - VelocityGainPerSecond * reverseMomentumMultiplier * Time.deltaTime);

            else // If we're moving back or not moving at all
            movementVelocity.z = Mathf.Max(-movespeed,movementVelocity.z - VelocityGainPerSecond * Time.deltaTime);

        }
        
        else //If neither forward nor back are being held
        {
            //We must bring the Z velocity back to 0 over time.
            if (movementVelocity.z > 0) // If we're moving up,
            //Decrease Z velocity by VelocityLossPerSecond, but don't go any lower than 0:
            movementVelocity.z = Mathf.Max(0,movementVelocity.z - VelocityLossPerSecond * Time.deltaTime);

            else //If we're moving down,
            //Increase Z velocity (back towards 0) by VelocityLossPerSecond, but don't go any higher than 0:
            movementVelocity.z = Mathf.Min(0,movementVelocity.z   VelocityLossPerSecond * Time.deltaTime);
        }

        if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
        {
            if (movementVelocity.x >= 0) //If we're already moving right
            //Increase X velocty by VelocityGainPerSecond, but don't go higher than 'movespeed':
            movementVelocity.x = Mathf.Min(movespeed,movementVelocity.x   VelocityGainPerSecond * Time.deltaTime);

            else //If we're moving left
            //Increase X velocity by VelocityGainPerSecond, using the reverseMomentumMultiplier, but don't raise higher than 0:
            movementVelocity.x = Mathf.Min(0,movementVelocity.x   VelocityGainPerSecond * reverseMomentumMultiplier * Time.deltaTime);
        }

        else if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
        {
            if (movementVelocity.x > 0) //If we're already moving right
            movementVelocity.x = Mathf.Max(0,movementVelocity.x - VelocityGainPerSecond * reverseMomentumMultiplier * Time.deltaTime);

            else // If we're moving left or not at all
            movementVelocity.x = Mathf.Max(-movespeed,movementVelocity.x - VelocityGainPerSecond * Time.deltaTime);
        }
            
            else //If neither left nor right are being held
            {
                //We must bring the X Velocity back to 0 over time.
                if (movementVelocity.x > 0) //If we're moving right,
                //Decrease X velocity by VelocityLossPerSecond, but don't go any lower than 0:
                movementVelocity.x = Mathf.Max(0,movementVelocity.x - VelocityLossPerSecond * Time.deltaTime);

                else //If we're moving left
                //Increase X velocity (back towards 0) by VelocityLossPerSecond, but don't go any higher than 0:
                movementVelocity.x = Mathf.Min(0,movementVelocity.x   VelocityLossPerSecond * Time.deltaTime);
            }
        //If the player is moving in either direction (left/right or up/down):
        if (movementVelocity.x != 0 || movementVelocity.z != 0)
        {
            //Applying the movement velocity:
            characterController.Move(movementVelocity * Time.deltaTime);

            //Keeping the model holder rotated towards the last movement direction:
            modelTrans.rotation = Quaternion.Slerp(modelTrans.rotation, Quaternion.LookRotation(movementVelocity), .18F);
        }
    }
    //Death and Respawning
    [Header("Death and Respawning")]
    [Tooltip("How long after the player's death, in seconds, before they are respawned?")]
    public float respawnWaitTime = 2f;

    private bool dead = false;

    private Vector3 spawnPoint;
    private Quaternion spawnRotation;

    private void Update()
        {
            Movement();
    }
    void Start()
    {
        spawnPoint = trans.position;
        spawnRotation = modelTrans.rotation;
    }

    public void Die()
    {
        if (!dead)
        {
            dead = true;
            Invoke("Respawn", respawnWaitTime);
            movementVelocity = Vector3.zero;
            enabled = false;
            characterController.enabled = false;
            modelTrans.gameObject.SetActive(false);
        }
    }

    public void Respawn()
    {
        modelTrans.rotation = spawnRotation;
        dead = false;
        trans.position = spawnPoint;
        enabled = true;
        characterController.enabled = true;
        modelTrans.gameObject.SetActive(true);
    }
}

The Hazard Object Script:

`using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Hazard : MonoBehaviour
{
    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.layer == 8)
        {
            //Player player = other.GetComponent<Player>();
            //if (player != null)
            //player.Die();

            Debug.Log("Yay!");

            
        }
    }

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}`

I have tried:

Adding a separate box collider to the Player Object

Adding a Rigidbody to one, both, and the other objects

Pulling my hair out

Restarting Unity

Restarting my computer

Tagging the Player Object as Player (I saw a question that looked similar to mine so I thought maybe this would help; I'm not very familiar with Unity or C# yet so I'm unsure what or why things would help.)

None of the above has made it seem like Unity is detecting collision between these two objects.

CodePudding user response:

Here's a line from the documentation for OnTriggerEnter:

"Both GameObjects must contain a Collider component. One must have Collider.isTrigger enabled, and contain a Rigidbody."

Have you tried adding the Collider to your player at the same time as the Rigidbody component to your hazard?

CodePudding user response:

For OnTriggerEnter() you need colliders with Is Trigger ticked and a ridig body. But this check

if (other.gameObject.layer == 8)

does not what it looks like. Layer values are used as bit masks, read more about it here. To check against the correct layer, you need bitwise operations:

int playerMask = LayerMask.GetMask("Player");   // something like  00110101001
int otherLayer = 1 << other.gameObject.layer;   // something like  00010000000
if ((playerMask | otherLayer ) != 0) {          // we hit the mask ...1.......
    Debug.Log("yay");
}

Be careful when using bitwise operators to not get tricked by operator precedences. Short version from above would be

if ((playerMask | (1 << other.gameObject.layer)) != 0) { ...  // extra parentheses!

This will succeed for all objects within the player layer. An alternative would be to set the tag of the player object and compare against that tag:

if (other.gameObject.CompareTag("Player")) { ... // "Player" tag is not the same as "Player" layer
  • Related