Unity武器与子弹碰撞检测


在想进行碰撞检测制造伤害或生成特效时,有两种常用的方法,一种是使用碰撞器和刚体,检测到碰撞后会自动调用OnCollisionEnter等函数,一种是使用Physics接口下的OverlapBox等检测函数。


一、采用碰撞器和刚体进行碰撞检测

在使用Collider进行碰撞检测时,至少要有一方是带有刚体组件。在默认设置的情况下这样就能够进行碰撞检测,但是在设置物体为静态或勾选刚体的动力学选项后会有不同。
关于这两种碰撞什么情况下可以检测到请看该链接

不关心碰撞位置的情况:

可以把碰撞检测方的碰撞器设置为IsTrigger,并在碰撞组件同级挂载碰撞检测后调用的代码。把碰撞器设置为IsTrigger后,能检测到碰撞并且调用OnTriggerEnter,OnTriggerStay,OnTriggerExit,但是不会对双方造成物理作用。

	/// <summary>
    /// 进入碰撞范围时自动调用
    /// </summary>
    /// <param name="other">碰撞检测到的物体,以下简称目标物</param>
    private void OnTriggerEnter(Collider other)
    {
    	// owner是持有武器的角色身上的碰撞器,目标物的碰撞体为拥有者的碰撞体时直接返回
        if (other.GetInstanceID() == owner.GetInstanceID())
            return;
		
		// 判断目标物是否为可以被攻击的物体
        Controller entity;
        if (!other.TryGetComponent(out entity))
            return;
		
		// 调用目标物的受到伤害的函数
        entity.TakeDamage(1);
    }

关心碰撞位置的情况:

有时可能需要碰撞的位置来生成特效,比如子弹打中哪里就在哪里生成击中特效,在OnTriggerEnter中做不到这一点,当然也能在此时碰撞体所在的位置生成特效,但位置仍是不准确的。
此时不能把碰撞器设置为IsTrigger,因为需要使用OnCollisionEnter函数,同样在碰撞组件同级挂载碰撞检测后调用的代码。

/// <summary>
    /// 进入碰撞范围时自动调用
    /// </summary>
    /// <param name="collision">碰撞检测到的物体,以下简称目标物</param>
	private void OnCollisionEnter(Collision collision)
    {
    	// 发生碰撞的位置
        Vector3 hitPoint = collision.contacts[0].point;
        // 实例化特效
        GameObject hitEffect = Instantiate(effectPrefab);
        // 将特效放置在碰撞点
        hitEffect .transform.position = hitPoint;
    }

如果想要更精确的模拟击中特效,可以将生成的特效的方向改为碰撞体的反方向,比如子弹击中后,血液往子弹来的方向喷。

二、使用代码检测

在这里插入图片描述
Physics接口中有许多碰撞检测的函数可以调用,每个函数的返回值和参数都不一样,但用法大同小异,这里就拿OverlapBox作为例子。

	// 进行检测的层级,暴露在属性页面进行勾选
	[SerializeField] LayerMask impactLayer;
	// 碰撞检测的物体
	[SerializeField] Transform colBox;
	
	private void Update()
    {
        BoxCheck(colBox);
    }

	/// <summary>
    /// 箱型检测
    /// </summary>
    /// <param name="colBox">箱子物体,可以空物体,作为武器的子物体跟随移动</param>
    void BoxCheck(Transform colBox)
    {
        // 检测中心点
        Vector3 center = colBox.position;
        // 碰撞器的缩放,以Unity默认的正方体为标准
        Vector3 checkBox= new Vector3(1, 0.1f, 0.1f);
        
        // 碰撞检测到的碰撞体
        Collider[] colliders = Physics.OverlapBox(center, checkBox, colBox.rotation, impactLayer);
        foreach (var col in colliders)
        {
            // 碰撞体是自身
            if (col.GetInstanceID() == owner.GetInstanceID())
                continue;
            
            // 判断目标物是否为可以被攻击的物体
            Controller entity;
            if (!col.TryGetComponent(out entity))
                continue;
            
            // 调用目标物的受到伤害的函数
            entity.TakeDamage(1);
            
        }
    }

用代码检测碰撞时不需要刚体组件,但与OnTriggerEnter一样获取不到碰撞位置。

在使用武器攻击敌人时,如果不对敌人的碰撞体进行记录,会产生多段伤害,因为每一帧都在调用碰撞检测,所以上面的代码需要进行优化。

1、只在武器挥出的时候进行检测,可以在动画里设置帧事件,在攻击动作的前后设置开启和关闭
2、标记碰撞体以避免重复检测

	// 已经被伤害过的碰撞体
	HashSet<int> colsMarked = new HashSet<int>();

	//是否开启碰撞检测
	bool enableDamage;

    private void Update()
    {
        if (!enableDamage)
            return;
            
        BoxCheck(colBox);
    }	

	/// <summary>
    /// 箱型检测
    /// </summary>
    /// <param name="colBox">箱子物体,可以空物体,作为武器的子物体跟随移动</param>
    void BoxCheck(Transform colBox)
    {
        // 检测中心点
        Vector3 center = colBox.position;
        // 碰撞器的缩放,以Unity默认的正方体为标准
        Vector3 checkBox= new Vector3(1, 0.1f, 0.1f);
        
        // 碰撞检测到的碰撞体
        Collider[] colliders = Physics.OverlapBox(center, checkBox, colBox.rotation, impactLayer);
        foreach (var col in colliders)
        {
            // 碰撞体是自身
            if (col.GetInstanceID() == owner.GetInstanceID())
                continue;
			
            // 判断目标物是否为可以被攻击的物体
            Controller entity;
            if (!col.TryGetComponent(out entity))
                continue;

			// 向HashSet添加成功时返回True,否则返回False
			// 返回False时说明已经被添加过了,不能再次造成伤害
			if (!colsMarked.Add(col.GetInstanceID()))
				continue;
            
            // 调用目标物的受到伤害的函数
            entity.TakeDamage(1);
        }

		/// <summary>
    	/// 清空标记,可以通过动画帧事件进行调用
    	/// </summary>
    	/// <param name="enable">是否开启碰撞检测</param>
    	public void EnableDamage(bool enable)
    	{
    		// 清空标记过的碰撞体
    	    colsMarked.Clear();
    	    // 开启或关闭检测
    	    enableDamage = enable;
    	}

    }
  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity中,可以使用碰撞器(Collider)和刚体(Rigidbody)组件来实现物体之间的碰撞检测。假设我们有一个小球和一个正方体,我们希望在它们之间发生碰撞时执行一些操作,可以按照以下步骤进行设置: 1. 将小球和正方体的游戏对象上分别添加碰撞器和刚体组件。在碰撞器组件中,可以选择使用球形碰撞器或盒形碰撞器,分别对应于小球和正方体的形状。 2. 在小球或正方体的游戏对象上添加脚本,用于检测碰撞事件。脚本中需要实现一个OnCollisionEnter函数,该函数会在物体发生碰撞时被调用。 3. 在OnCollisionEnter函数中,可以检查碰撞事件的相关信息,例如碰撞的物体是哪个,碰撞发生的位置和力的大小等。根据需要执行相应的操作,例如改变小球的颜色、播放音效或增加分数等。 以下是一个简单的示例代码,演示了如何检测小球和正方体之间的碰撞事件: ```csharp using UnityEngine; public class CollisionDetector : MonoBehaviour { void OnCollisionEnter(Collision collision) { if (collision.gameObject.tag == "Cube") { Debug.Log("Ball collided with cube"); // 在这里执行相应的操作,例如改变小球颜色 GetComponent<Renderer>().material.color = Color.green; } } } ``` 在这个代码中,我们检查了碰撞事件中碰撞物体的标签,如果是“Cube”则说明是小球和正方体之间的碰撞,然后改变小球的颜色为绿色。可以根据需要修改代码来实现不同的碰撞检测和操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值