unity 2d 近战攻击判定的三种方式

1. 给攻击帧添加碰撞盒

优点:配置直观,无需事件触发
缺点:无法定制,效率低

检测放在子物体,可以控制旋转
在这里插入图片描述

添加触发器事件

注意OnTriggerEnter2D只会在挂载了collider的组件上触发

protected virtual void OnTriggerEnter2D(Collider2D other)
    {
        Debug.Log(this.name + "命中" + other);
        entity.AttackTrigger(other);
    }
 
在角色脚本执行攻击检测
 public override void AttackTrigger(Collider2D other)
    {
        if (other.gameObject.layer == LayerMask.NameToLayer("Enemy"))
        {
            base.AttackTrigger(other);
            AttackColliderCheck<Enemy>(other, (enemy) => enemy.BeDamage(stats));
        }
    }

2. 为每个攻击动画状态使用射线检测

优点:效率高于碰撞盒,可以定制,比如增加攻击范围
缺点:配置麻烦不直观

部分代码,仅供参考

定义每个动画的检测范围
[Header("攻击状态对应的碰撞盒")]
        public Dictionary<Entity.States, AttackRanges> attackRangeDict = new();

//索引是攻击的状态 + 连击数,获取对应攻击的范围
[System.Serializable]
public class AttackRanges
{
    /// <summary>
    /// 对应的连击次数  作为索引
    /// </summary>
    public AttackRange[] ranges = new AttackRange[1];

    //索引器
    public AttackRange this[int index]
    {
        get
        {
            // return ranges.FirstOrDefault(x => x.combo == index);
            //如果没有,默认用第一个
            if (index >= ranges.Length)
                return ranges[0];
            return ranges[index];
        }
    }
}


[System.Serializable]
public class AttackRange
{
    public SerializableVector2 offset = new();
    public SerializableVector2 size = new();
    public float rotation = 0;

    public UnityEngine.Vector2 Offset => offset.ToVector2();
    public UnityEngine.Vector2 Size => size.ToVector2();
}
添加帧事件
private void AttackTrigger()
    {
        entity.AttackTrigger();
    }
执行检测与绘制范围
 /// <summary>
    /// 攻击检测
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="action"></param>
    protected void AttackColliderCheck<T>(Action<T> action) where T : Entity
    {
        AttackRange attackRange = stats.attackRangeDict[States.PrimaryAttack][ComboCounter];
        var offset = facingRight ? attackRange.offset.ToVector2() : new Vector2(-attackRange.offset.x, attackRange.offset.y);
        var rotation = facingRight ? attackRange.rotation : -attackRange.rotation;

        Collider2D[] colliders = Physics2D.OverlapBoxAll(offset, attackRange.size.ToVector2(), rotation);

        foreach (Collider2D hit in colliders)
        {
            if (hit.TryGetComponent<T>(out T entity))
            {
                action?.Invoke(entity);
            }
        }
    }

// 默认情况下就会在编辑模式下运行
    protected virtual void OnDrawGizmos()
    {
        // Vector3 boxCenter = groundCheck.position + Vector3.down * groundCheckDistance / 2;
        // Gizmos.DrawCube(boxCenter, new Vector3(groundCheckWidth, groundCheckDistance, 0));
        Gizmos.DrawLine(groundCheck.position, new Vector3(groundCheck.position.x, groundCheck.position.y - groundCheckDistance));//绘制一条从 from(前面的) 开始到 to(后面的) 的线。
        Gizmos.DrawLine(wallCheck.position, new Vector3(wallCheck.position.x + wallCheckDistance, wallCheck.position.y));//绘制一条从 from(前面的) 开始到 to(后面的) 的线。

        if (stats == null) return;
        Gizmos.color = Color.red;
        var attackRange = stats.attackRangeDict.ContainsKey(States.PrimaryAttack) ? stats.attackRangeDict?[States.PrimaryAttack]?[ComboCounter] : new AttackRange();

        Vector3 center = (Vector3)attackRange.Offset;
        // 设置 Gizmos 的变换矩阵
        Matrix4x4 oldMatrix = Gizmos.matrix;
        Gizmos.matrix = Matrix4x4.TRS(center, Quaternion.Euler(0, 0, attackRange.rotation), Vector3.one);
        Gizmos.DrawWireCube(transform.position + (Vector3)attackRange.Offset, (Vector3)attackRange.Size);
        // 恢复原来的矩阵
        Gizmos.matrix = oldMatrix;
    }

3. 所有动画共用一个射线检测

优点:简单
缺点:不精确

不推荐使用

在帧事件触发,调用检测方法即可
 /// <summary>
    /// 攻击检测
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="action"></param>
    protected void AttackColliderCheck<T>(Action<T> action) where T : Entity
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(attackCheck.position, attckCheckRadius);

        foreach (Collider2D hit in colliders)
        {
            if (hit.TryGetComponent<T>(out T entity))
            {
                action?.Invoke(entity);
            }
        }
    }
以下是一个简单的Unity 2D敌人攻击的代码示例: ```c# public class EnemyAttack : MonoBehaviour { public float damage = 10f; public float attackDelay = 1f; public float attackRange = 1f; public LayerMask attackMask; private Animator animator; private Transform target; private float nextAttackTime = 0f; void Start() { animator = GetComponent<Animator>(); target = GameObject.FindGameObjectWithTag("Player").transform; } void Update() { if (Time.time >= nextAttackTime) { float distanceToTarget = Vector2.Distance(transform.position, target.position); if (distanceToTarget <= attackRange) { Attack(); nextAttackTime = Time.time + attackDelay; } } } void Attack() { animator.SetTrigger("attack"); Collider2D[] hitTargets = Physics2D.OverlapCircleAll(transform.position, attackRange, attackMask); foreach (Collider2D target in hitTargets) { target.GetComponent<PlayerHealth>().TakeDamage(damage); } } void OnDrawGizmosSelected() { Gizmos.color = Color.red; Gizmos.DrawWireSphere(transform.position, attackRange); } } ``` 该代码包含了以下功能: - 敌人使用 `attackDelay` 变量来限制攻击频率。 - 敌人使用 `attackRange` 变量来限制攻击范围。 - 敌人使用 `attackMask` 变量来指定攻击时需要检测的层。 - 敌人使用 `animator` 变量来播放攻击动画。 - 敌人使用 `OnDrawGizmosSelected()` 函数来在场景视图中显示攻击范围的可视化。 - 敌人使用 `Physics2D.OverlapCircleAll()` 函数来检测攻击范围内的目标。 - 敌人使用 `TakeDamage()` 函数来对检测到的目标造成伤害。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值