在Unity游戏开发过程中,经常会遇到各种碰撞检测的问题。本文将介绍如何修复Mesh Collider和Box Collider的问题,以确保游戏对象之间的正确交互。
在第12天的开发中,为骑士创建了一个Mesh Collider。然而,发现一个问题:即使多次执行攻击动画,碰撞器也只会与敌人碰撞一次。
Mesh Collider不能跟随模型的动画,这意味着当骑士第一次接触时,网格可能会触碰到,但之后如果玩家没有被碰撞器推开,网格就再也不会触碰到了。
为了解决这个问题,需要对Mesh Collider进行一些修改。仍然需要Mesh Collider来防止穿过敌人。目前,面临的问题是可以穿过骑士,但现在会修复这个问题。
将在骑士的手上添加一个Box Collider。这样,就可以确保当玩家被击中时,能够检测到碰撞。
目前,不能移动网格,因为它在父体中。根据关于不正确网格定位的帖子,将创建一个新的空对象,并在那里添加网格碰撞器。
这对来说是有效的,因为只需要网格进行碰撞检测和射线投射射击。
首先,需要从knightprefab游戏对象中移除Mesh Collider。选择knightprefab,右键单击并选择Create Empty,以创建一个新的游戏对象。让将这个对象重命名为Collider。
选择Collider并添加一个新的Mesh Collider组件。对于Mesh,选择body以恢复骑士模型。
现在,不能只是走过骑士。
现在已经解决了Mesh Collider的问题,将修复最初的问题,即在敌人攻击时处理伤害。
为此,将在骑士的拳头上添加box collider。具体来说,在knightprefab->hips->spine->chest->L_shoulder/R_shoulder->一直到L_Wrist/R_Wrist。
对于每个box collider,将盒子的scale设置为0.25以适应手的大小。
现在已经这样做了,需要将一个脚本附加到手模型上,以便可以检测碰撞。父对象的脚本不能检测其子对象的碰撞。
同样重要的是,原来的脚本:EnemyAttack,仍然需要保留在原处,因为需要访问位于父对象中的animator组件。
为了解决问题,将从EnemyAttack移动碰撞部分的代码到一个新的脚本,名为FistCollider。
C# using UnityEngine; public class FistCollider : MonoBehaviour { private GameObject _player; private bool _collidedWithPlayer; void Start() { _player = GameObject.FindGameObjectWithTag("Player"); _collidedWithPlayer = false; } void OnCollisionEnter(Collision other) { if (other.gameObject == _player) { _collidedWithPlayer = true; } print("enter collided with _player"); } void OnCollisionExit(Collision other) { if (other.gameObject == _player) { _collidedWithPlayer = false; } print("exit collided with _player"); } public bool IsCollidingWithPlayer() { return _collidedWithPlayer; } }
代码的流程如下:
像EnemyAttack脚本一样,想要访问玩家游戏对象,并检查否与敌人发生了碰撞。
在Start()中,确保实例化了两个变量。
在OnCollisionEnter()和OnCollisionExit()中,如果与玩家发生了碰撞,那么将设置布尔标志。
在IsCollidingWithPlayer()中,将布尔_collidedWithPlayer提供给任何调用它的人。注意这个函数是public的,所以其他脚本可以访问这个。将在后面使用它。
让将脚本附加到L_Wrist和R_Wrist。
现在已经将碰撞代码的一部分从EnemyAttack移动到FistCollider,让在EnemyAttack中使用FistCollider。
C# using UnityEngine; public class EnemyAttack : MonoBehaviour { public FistCollider LeftFist; public FistCollider RightFist; private Animator _animator; private GameObject _player; void Awake() { _player = GameObject.FindGameObjectWithTag("Player"); _animator = GetComponent(); } void OnTriggerEnter(Collider other) { if (other.gameObject == _player) { _animator.SetBool("IsNearPlayer", true); } print("enter trigger with _player"); } void OnTriggerExit(Collider other) { if (other.gameObject == _player) { _animator.SetBool("IsNearPlayer", false); } print("exit trigger with _player"); } private void Attack() { if (LeftFist.IsCollidingWithPlayer() || RightFist.IsCollidingWithPlayer()) { _player.GetComponent().TakeDamage(10); } } }
代码中的更改如下:
首先,创建了新的public变量:LeftArm和RightArm,它们是刚刚创建的FistCollider脚本。
清理了很多代码,特别是碰撞部分以及与之相关的任何内容。
在Attack()中,使用新FistCollider进行与玩家的碰撞,然后当动画的攻击事件被触发时,检查玩家是否被击中。如果他们被击中(意味着骑士的拳头与玩家发生了碰撞),玩家将受到伤害。
现在脚本已经完成,最后需要做的是确保将FirstCollider对象附加到玩家上。
可以直接将游戏对象附加到位置,脚本将自动被选中。