unity 2d 近战攻击判定的三种方式以及精确获取碰撞点

news2024/11/28 11:00:41

精确获取碰撞点

核心是获取武器碰撞盒最顶点,然后获取敌人碰撞盒距离该点最近的点

/// <summary>
    /// 获取获取武器前端位置   碰撞盒最左或最右顶点
    /// </summary>
    /// <param name="collider"></param>
    /// <param name="facingRight"></param>
    /// <returns></returns>
    public static Vector3 GetCollider2DEdgePoint(Transform deployer, bool facingRight)
    {
        var collider = deployer.GetChild(0).GetComponentInChildren<CapsuleCollider2D>();
        // 获取碰撞器的包围盒
        Bounds bounds = collider.bounds;

        // 计算面向的方向向量(右或左)
        Vector2 attackDirection = facingRight ? Vector2.right : Vector2.left;

        // 根据面向方向和碰撞器的边界来获取边缘点
        Vector3 edgePoint = bounds.center + (Vector3)(attackDirection * bounds.extents.x);

        // 如果需要在局部空间中获取边缘点,需要将世界坐标转换为局部坐标
        // edgePoint = deployer.InverseTransformPoint(edgePoint);

        return edgePoint;
    }

//使用
 public void CreateHit(Collider2D other, CharacterStats target, bool isCrit = false)
 Vector3 edgePoint = Tool.GetCollider2DEdgePoint(transform, Entity.facingRight);
        var hitPosition = other.ClosestPoint(edgePoint);

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2192356.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何把数组作为参数传递给函数(注意,只是传递数组名)?

直接上代码吧&#xff1a; template<class T, size_t nSize> void printArray(T(&Array)[nSize]) {T* pt Array;for (size_t n 0; n < nSize; n) {cout << *(pt n) << "\t";}cout << "\n"; } int main() {int ia[] {…

6款不错的本地大模型运行工具推荐

运行大型语言模型 (LLM)&#xff08;如 ChatGPT 和 Claude&#xff09;通常涉及将数据发送到 OpenAI 和其他 AI 模型提供商管理的服务器。虽然这些服务是安全的&#xff0c;但一些企业更愿意将数据完全离线&#xff0c;以保护更大的隐私。 本文介绍了开发人员可以用来在本地运…

基于Vue.js + 大屏Datav + Spring Boot后端的养殖场环境设备实时监测控制系统

开发一个基于Vue.js 大屏Datav Spring Boot后端的养殖场环境设备实时监测控制系统是一个复杂而全面的任务。下面将详细介绍整个项目的架构设计、技术选型、开发实现和测试部署过程。 1. 需求分析 1.1 功能需求 环境参数监控&#xff1a;实时监控温度、湿度、光照强…

C/C++/EasyX——入门图形编程(5)

【说明】友友们好&#xff0c;今天来讲一下键盘消息函数。&#xff08;其实这个本来准备和鼠标消息函数放在一起的&#xff0c;但是上一篇三个放在一起&#xff0c;内容就有点多了&#xff0c;只写一个又太单调了&#xff0c;所以键盘消息函数的内容就放在这一篇了 (^&#xff…

大语言模型中文本分割策略的综合指南

整理 本文整理了一些简单的文本切分方式&#xff0c;适用于大语言模型经典应用RAG或相似场景。 一般切分 如果不借助任何包&#xff0c;很容易想到如下切分方案&#xff1a; text "我是一个名为 ChatGLM3-6B 的人工智能助手&#xff0c;是基于清华大学 KEG 实验室和智…

模型 SECI(知识的创造)

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。知识创造的螺旋转化模型。 1 SECI的应用 1.1 Tech Innovations移动应用创新 Tech Innovations是一家软件开发公司&#xff0c;致力于开发创新的移动应用程序。为了提升团队的知识共享和创新能力&…

力扣6~10题

题6&#xff08;中等&#xff09;&#xff1a; 思路&#xff1a; 这个相较于前面只能是简单&#xff0c;个人认为&#xff0c;会print打印菱形都能搞这个&#xff0c;直接设置一个2阶数组就好了&#xff0c;只要注意位置变化就好了 python代码&#xff1a; def convert(self,…

感知机及其实践

说明 感知机是SVM(support vector machine,支持向量机)的基础&#xff0c;更是机器学习的基础。本文的目的在于把感知机的相关概念捋清楚&#xff0c;并基于感知机做最基本的线性可分的二分类实践。 有关机器学习的一些基础概念&#xff0c;读者可以参考本专栏的第一篇博文[4]&…

Oracle创建用户报错-ORA-65096: invalid common user or role name

问题描述 ORA-65096: invalid common user or role name 原因分析 这可能是创建角色的容器为cdb导致&#xff0c;当然如果想继续执行&#xff0c;可以在角色名前加C##或者c##&#xff0c;但是这样会导致用户名多了c##&#xff0c;我们不要这样的用户名 解决步骤 用sysdba 登录&…

SCUC博客摘录「 储能参与电能市场联合出清:SCUC和SCED模型应用于辅助服务调频市场(IEEE39节点系统)」2024年10月6日

2.1 SCUC模型在本方法中&#xff0c;首先利用SCUC模型确定机组出力计划和储能充放电计划。SCUC模型是电力系统经济调度的重要工具&#xff0c;通过优化发电机组出力计划和调度&#xff0c;实现电力系统的经济性和可靠性。在考虑储能的情况下&#xff0c;SCUC模型需要考虑储能的…

vue3常用组件通信方法

title: vue3常用组件通信方法 date: 2024-10-06 15:00:54 tags: vue3 组件通信 一、父传子—defineProps 1.父亲 通过属性传值 2.儿子 通过defineProps接收相关的数据 二、子传父 1&#xff09;使用defineExposeref 1.子组件 在子组件中使用defineExpose先暴露出来 2.父…

基础算法之滑动窗口--Java实现(上)--LeetCode题解:长度最小的子数组-无重复字符的子串-最大连续1的个数III-将x减到0的最小操作数

这里是Thembefue 今天讲解算法中较为经典的一个算法 > 滑动窗口 本讲解主要通过题目来讲解以理解算法 讲解分为三部分&#xff1a;题目解析 > 算法讲解 > 编写代码 滑动窗口 在正式进入题目的讲解之前&#xff0c;得先了解一下什么是滑动窗口&#xff0c;以及应该在什…

一篇文章教会你DHT11读取温湿度,附STM32代码示例

目录 一、DHT11说明&#xff1a; 1.典型电路&#xff1a; 2.串行通信说明&#xff08;单线双向&#xff09;&#xff1a; 单总线说明&#xff1a; 单总线传送数据位定义&#xff1a; 校验位数据定义&#xff1a; 二、DHT11读取时为啥要切换模式&#xff1a; 1. 通信时序…

基于深度学习的手势控制模型

关于深度实战社区 我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 社区特色…

理解递归和回溯

文章目录 什么是递归回溯 什么是递归 回溯 //使用递归回溯来给小球找路//说明//1. map 表示地图//2. i,j 表示从地图的哪个位置开始出发 (1,1)//3. 如果小球能到 map[6][5] 位置&#xff0c;则说明通路找到.//4. 约定&#xff1a; 当map[i][j] 为 0 表示该点没有走过 当为 1 表…

【Python】wxPython 高 DPI 缩放问题(笔记本上字体模糊问题)

问题 使用 wxPython 编写的程序在某些高 DPI 的电脑&#xff08;通常是笔记本&#xff09;上显示出来的字体会非常模糊&#xff1a; 事实上 wxPython 是支持高 DPI 的&#xff0c;但是由于我们的程序没有显式指明支持高 DPI&#xff0c;因此系统默认不支持高 DPI&#xff0c;…

Bolt.new:终极自动化编程工具

兄弟们&#xff0c;终极写代码工具来了—— Bolt.new&#xff01;全方位的编程支持&#xff1a; StackBlitz 推出了 Bolt․new&#xff0c;这是一款结合了 AI 与 WebContainers 技术的强大开发平台&#xff0c;允许用户快速搭建并开发各种类型的全栈应用。 它的主要特点是无需…

【小沐学GIS】QGIS导入导出OpenStreetMap数据(QuickMapServices、OSM)

文章目录 1、简介1.1 OpenStreetMap地图1.2 QGIS 2、安装插件2.1 QuickMapServices2.2 OSMDownloader2.3 Qgis2threejs 3、使用插件结语 1、简介 1.1 OpenStreetMap地图 https://www.openstreetmap.org/ https://extract.bbbike.org/ Openstreetmap是一种开源地图&#xff0c…

微服务swagger解析部署使用全流程

1、介绍 swagger是一个在线接口说明文档&#xff0c;在代码中通过注解的方式将说明问题集成到项目&#xff0c;代码发生修改&#xff0c;说明文档同步修改&#xff0c;前后台联调可以快速同步数据。 2、应用 1、引入依赖 <dependency><groupId>io.springfox<…

如何使用ssm实现基于Web的穿戴搭配系统的设计与实现+vue

TOC ssm784基于Web的穿戴搭配系统的设计与实现vue 第1章 绪论 1.1 研究背景 互联网概念的产生到如今的蓬勃发展&#xff0c;用了短短的几十年时间就风靡全球&#xff0c;使得全球各个行业都进行了互联网的改造升级&#xff0c;标志着互联网浪潮的来临。在这个新的时代&…