unity3d Unity 3D中的对象不碰撞

fquxozlt  于 2023-01-05  发布在  其他
关注(0)|答案(2)|浏览(236)

我正在跟随凯西·哈德曼用Unity和C#从游戏编程中创建障碍游戏。我已经在第16章的前几页达到了你创建一个危险来杀死玩家的地步。在开始阶段,你编写了一段代码,如果玩家对象与障碍物碰撞,就杀死玩家对象。(据我所知)完全正确,然而当我创建一个球体作为测试危险,将脚本分配给它,并将玩家对象运行到其中时,当它们碰撞时没有发生任何事情。我想可能是危险代码有错误,所以我注解掉了"当与玩家层上的对象碰撞时,杀死玩家"代码,我写了代码,让它在冲突时只写入控制台,并进行了测试。不幸的是,当这两个物体相互接触时,似乎没有任何碰撞检测。我在谷歌上搜索了"物体不碰撞统一体"和我能想到的"碰撞不检测统一体"的每一种组合,没有一个答案有帮助,所以我在这里发帖,希望我能得到一个答案。我包含了这两个对象及其设置的屏幕截图、Unity中的物理设置以及为这两个对象编写的代码,希望有人能发现我做错了什么。
The Player Object
The Test Hazard Object
Layer Collision Matrix

播放器对象脚本

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

我试过:
向播放器对象添加单独的长方体碰撞器
将刚体添加到一个、两个和其他对象
扯我的头发
重启Unity
重新启动我的计算机
将播放器对象标记为播放器(我看到一个问题看起来和我的问题很相似,所以我想这可能会有帮助;我对Unity或C#还不是很熟悉,所以我不确定什么或为什么会有帮助。)
以上这些都没有让Unity看起来像是在检测这两个对象之间的碰撞。

wa7juj8i

wa7juj8i1#

下面是OnTriggerEnter文档中的一行:
第一个月
您是否尝试过将Collider添加到您的播放器中,同时将Rigidbody组件添加到危险中?

68bkxrlz

68bkxrlz2#

对于OnTriggerEnter(),你需要一个选中Is Trigger的对撞机和一个刚性体。但是这个检查

if (other.gameObject.layer == 8)

层值被用作位掩码,请阅读here的更多信息。要检查正确的层,您需要按位操作:

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

相关问题