Объекты не сталкиваются в Unity 3D

Я слежу за созданием игры с препятствиями из Game Programming with Unity и C# Кейси Хардмана. На первых нескольких страницах главы 16 я дошел до того, что вы создаете Опасность, чтобы убить игрока. На начальных этапах вы пишете код, который убивает объект игрока, если объект игрока сталкивается с опасностью. Я следовал инструкциям (насколько я могу судить) до буквы, и все же, когда я создал сферу в качестве тестовой опасности, назначил ей сценарий и запустил в нее объект игрока, ничего не произошло, когда они столкнулись. Я подумал, что, возможно, была ошибка с кодом Hazard, поэтому я закомментировал код «при столкновении с объектом на уровне игрока, убить игрока», написал код, чтобы он просто писал в консоль, когда они сталкиваются, и протестировал его. К сожалению, когда эти два объекта соприкасаются друг с другом, похоже, не происходит обнаружения столкновений. Я погуглил «объекты, не сталкивающиеся с единством», и все комбинации «столкновение, не обнаруженное в единстве», которые я могу придумать, и ни один из ответов не помог, поэтому я публикую здесь в надежде получить ответ. Я включаю скриншоты двух объектов и их настроек, мои настройки физики в Unity и код, который я написал для обоих объектов, в надежде, что кто-нибудь поймет, что я делаю неправильно.

Объект игрока

Тестовый объект опасности

Матрица столкновения слоев

Скрипт объекта игрока:

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);
    }
}

Сценарий опасного объекта:

`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()
    {
        
    }
}`

Я пытался:

Добавление отдельного коллайдера коробки к объекту игрока

Добавление Rigidbody к одному, обоим и другим объектам

Выдергивая мои волосы

Перезапуск единства

Перезагружаю компьютер

Пометка объекта Player как Player (я увидел вопрос, похожий на мой, поэтому подумал, что, может быть, это поможет; я еще не очень хорошо знаком с Unity или C#, поэтому я не уверен, что и почему что-то может помочь.)

Ничего из вышеперечисленного не создавало впечатления, что Unity обнаруживает столкновение между этими двумя объектами.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Для OnTriggerEnter() нужны коллайдеры с галочкой Is Trigger и твердое тело. Но этот чек

if (other.gameObject.layer == 8)

не то, на что это похоже. Значения слоя используются как битовые маски, подробнее об этом здесь. Чтобы проверить правильный слой, вам нужны побитовые операции:

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");
}

Будьте осторожны при использовании побитовых операторов, чтобы не быть обманутыми приоритетами операторов. Короткая версия сверху будет

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

Это сработает для всех объектов в слое игрока. Альтернативой может быть установка тега объекта игрока и сравнение с этим тегом:

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

Пока ничего не меняя в коде, я добавил Box Collider к объекту Player И Rigid Body к объекту Hazard, и это, похоже, помогло. Возможно, я где-то пропустил шаг, который заставил меня добавить Box Collider к объекту Player, потому что я вообще не помню, чтобы этот шаг был указан в списке (на самом деле, автор говорит, что они нам не нужны в дочерних объектах Base и Top объекта). Player, потому что, имея CharacterController в объекте Player, нам также не нужен коллайдер, но что угодно). Тем не менее, спасибо за это понимание!

LittleRukia 05.01.2023 22:32
Ответ принят как подходящий

Вот строка из документации для OnTriggerEnter:

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

Пробовали ли вы добавить Collider к своему игроку одновременно с компонентом Rigidbody к вашей опасности?

Это сделало это! Большое спасибо! Клянусь, в книге ничего не сказано о наличии коллайдера на объекте Player или Rigidbody на Hazard, не говоря уже об обоих, но, похоже, это помогло. Я не могу передать вам, насколько я ценю это предложение!

LittleRukia 05.01.2023 22:34

Круто, я рад, что это сработало! Пожалуйста, пометьте ответ как принятый, и мы можем закрыть вопрос

Matt Eng 05.01.2023 23:38

Другие вопросы по теме