基础GamePlay知识-碰撞检测

将会持续更新gameplay的一些基础知识,一同学习。

扇形检测

扇形检测是Gameplay里面很常见的场景。比如荒野乱斗中,大部分的近战角色都是扇形攻击。在扇形范围内就认为是受击。
扇形检测只有两个参数,一个是扇形的角度一个是扇形的半径大小。
在这里插入图片描述

效果

在这里插入图片描述

获取鼠标朝向

技能必然是和鼠标朝向一致的,所以学习检测务必先学一下怎么得到鼠标朝向,以及得到朝向对应的旋转角度。
思路是利用Camera.main.ScreenPointToRay(Input.mousePosition)方法,能够得到相机朝向屏幕空间下某点的射线,从而得到射线的碰撞点,然后计算角色朝向碰撞点的方向,这时候碰撞点的横坐标x和轴坐标z是已知的,所以用反三角函数Atan2可以得到旋转到碰撞点的旋转角度。
值得一提的是Camera.main.ScreenPointToRay(Input.mousePosition)在诸如用户注视某个物品/3dui的交互上面都可以使用。

 void Update(){ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)){//射线检测的是平面点的位置,实际需要的是平行于平面的方向,所以修改y坐标Vector3 horizontalPoint = new Vector3(hit.point.x, transform.position.y, hit.point.z);Debug.DrawLine(transform.position, horizontalPoint, Color.red);//方便观察skillDirection = (horizontalPoint - transform.position).normalized;//z轴取反是因为unity的旋转api是顺时针旋转的skillAngle = Mathf.Atan2(-skillDirection.z, skillDirection.x) * Mathf.Rad2Deg;}}

尝试利用画出一个扇形

为了方便我们看检测的结果,先实现一个绘制扇形的工具将技能范围画出来,这里提供使用Debug.DrawLine和使用LineRender两种办法。需要注意如果用LineRender的SetPostition方法,需要在组件里面设置好Position数组的大小,防止出现数组越界的报错。
在这里插入图片描述
利用LineRender和Debug.DrawLine的思路是一样的,先绘制扇形的中心点以及左边界点,再从左边界点往另一个边界以某个角度间隔绘制一个个点,连接起来就是一个圆弧

private void DrawFan_DebugDrawLine(float radius, int euler){int segments = 100; //圆弧那一段需要用多少个点来表示float deltaAngle = euler / segments;Vector3 forward = transform.forward;Vector3[] vertices = new Vector3[segments + 2];vertices[0] = transform.position;for (int i = 1; i < vertices.Length; i++){float curAngle = -euler / 2 + deltaAngle * (i - 1) + skillAngle;//从-1/2扇形角度开始绘制,每次偏移deltaAngleVector3 pos = Quaternion.Euler(0f, curAngle, 0f) * forward * radius + transform.position;vertices[i] = pos;}// 画圆弧for (int i = 1; i < vertices.Length - 1; i++){Debug.Log(vertices[i]);Debug.DrawLine(vertices[i], vertices[i + 1], showColor);}// 画两条边Debug.DrawLine(vertices[0], vertices[vertices.Length - 1], showColor);Debug.DrawLine(vertices[0], vertices[1], showColor);}/// <summary>/// 利用LinerRender绘制扇形/// </summary>private void DrawFan_LineRender(float radius, int euler){ResetLinerRenderPoints();m_LineRenderer.startColor = showColor; //碰撞的时候会切换展示的颜色m_LineRenderer.endColor = showColor;m_LineRendererPoints.Add(transform.position);//每一度一个点,绘制思路和debug.DrawLine相同for(int angles = -euler/2; angles <= euler/2; angles++){m_LineRendererPoints.Add(Quaternion.Euler(0, angles + skillAngle, 0) * transform.right * radius + transform.position);}m_LineRenderer.SetPositions(m_LineRendererPoints.ToArray());}

扇形和点的碰撞检测

判断某个点在扇形内的办法
距离判断:
点和玩家的距离小于扇形半径。
角度判断:
设玩家到受击角色的向量为a,玩家技能朝向为b
方法一:判断a和b所形成的角度小于1/2的扇形夹角。
只需要拿到a和单位向量和b的单位向量进行点积,就能够得到a和b夹角的cos值,再利用Acos得到夹角大小。

设扇形左边界为left,扇形右边界为right
方法二:利用向量叉乘,如果a在扇形的左边界之外或扇形的右边界之外则不满足。
这里需要注意Unity的世界坐标系是左手系,叉乘的方向满足的是左手定则
a x left所得向量的y轴坐标大于0说明在左边界以左,
right x a所得向量的的y轴左边大于0说明在右边界以右

这里两个办法都实现一下

三角函数法

    public bool Dectect_ACos(Vector3 enemyPos){float distance = Vector3.Distance(transform.position, enemyPos);//距离超过检测半径if (distance > radius){return false;}Vector3 enemyDirection = (enemyPos - transform.position).normalized;//两个单位向量的点乘等于其夹角的余弦值float enemyAngle = Mathf.Acos(Vector3.Dot(skillDirection, enemyDirection)) * Mathf.Rad2Deg;//敌人朝向和技能朝向的夹角小于二分之一扇形角说明在扇形范围内if (enemyAngle <= angle / 2){return true;}return false;}

向量叉乘

    public bool Dectect_Cross(Vector3 enemyPos){float distance = Vector3.Distance(transform.position, enemyPos);//距离超过检测半径if (distance > radius){return false;}//扇形左边界Vector3 leftBound = Quaternion.Euler(0f, -angle / 2 + skillAngle, 0f) * transform.right;Debug.DrawLine(transform.position, transform.position + leftBound, Color.blue);//扇形右边界Vector3 RightBound = Quaternion.Euler(0f, angle / 2 + skillAngle, 0f) * transform.right;Debug.DrawLine(transform.position, transform.position + RightBound , Color.yellow);Vector3 enemyDir = enemyPos - transform.position;//注意左手系的叉乘是左手定则bool isLeft = Vector3.Cross(enemyDir, leftBound).y > 0 ? true : false; bool isRight = Vector3.Cross(RightBound, enemyDir).y > 0 ? true : false;Debug.Log("isLeft:" + isLeft + "isRight" + isRight);return !isLeft && !isRight;}

完整实现

挂载在角色身上的脚本,注意鼠标是利用射线检测,所以需要再角色下面放一个平面接收射线。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FanDetector : MonoBehaviour
{public float radius; //扇形半径public int angle;  //扇形角度public Vector3 skillDirection;private Ray ray;private LineRenderer m_LineRenderer;private List<Vector3> m_LineRendererPoints;private Color showColor;public float skillAngle;// Start is called before the first frame updatevoid Start(){InitLineRender();}// Update is called once per framevoid Update(){GetSkillDirection(Color.green);//DrawFan_DebugDrawLine(radius, angle);DrawFan_LineRender(radius, angle);}/// <summary>/// 对外接口,敌人是否在技能范围内/// </summary>public bool Dectect(Vector3 enemyPos){bool isDecteced = Dectect_Cross(enemyPos);if(isDecteced){showColor = Color.red;return isDecteced;}showColor = Color.green;return isDecteced;}/// <summary>/// 利用Acos检测碰撞/// </summary>/// <param name="enemyPos"></param>/// <returns></returns>public bool Dectect_ACos(Vector3 enemyPos){float distance = Vector3.Distance(transform.position, enemyPos);//距离超过检测半径if (distance > radius){return false;}Vector3 enemyDirection = (enemyPos - transform.position).normalized;//两个单位向量的点乘等于其夹角的余弦值float enemyAngle = Mathf.Acos(Vector3.Dot(skillDirection, enemyDirection)) * Mathf.Rad2Deg;//敌人朝向和技能朝向的夹角小于二分之一扇形角说明在扇形范围内if (enemyAngle <= angle / 2){return true;}return false;}/// <summary>/// 利用叉乘检测/// </summary>/// <param name="enemyPos"></param>/// <returns></returns>public bool Dectect_Cross(Vector3 enemyPos){float distance = Vector3.Distance(transform.position, enemyPos);//距离超过检测半径if (distance > radius){return false;}//扇形左边界Vector3 leftBound = Quaternion.Euler(0f, -angle / 2 + skillAngle, 0f) * transform.right;Debug.DrawLine(transform.position, transform.position + leftBound, Color.blue);//扇形右边界Vector3 RightBound = Quaternion.Euler(0f, angle / 2 + skillAngle, 0f) * transform.right;Debug.DrawLine(transform.position, transform.position + RightBound , Color.yellow);Vector3 enemyDir = enemyPos - transform.position;//注意左手系的叉乘是左手定则bool isLeft = Vector3.Cross(enemyDir, leftBound).y > 0 ? true : false; bool isRight = Vector3.Cross(RightBound, enemyDir).y > 0 ? true : false;Debug.Log("isLeft:" + isLeft + "isRight" + isRight);return !isLeft && !isRight;}/// <summary>/// 获取鼠标朝向/// </summary>private void GetSkillDirection(Color color){ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)){//射线检测的是平面点的位置,实际需要的是平行于平面的方向,所以修改y坐标Vector3 horizontalPoint = new Vector3(hit.point.x, transform.position.y, hit.point.z);Debug.DrawLine(transform.position, horizontalPoint, color);skillDirection = (horizontalPoint - transform.position).normalized;//z轴取反是因为unity的旋转api是顺时针旋转的skillAngle = Mathf.Atan2(-skillDirection.z, skillDirection.x) * Mathf.Rad2Deg;}}/// <summary>/// 利用Debug工具绘制扇形/// </summary>private void DrawFan_DebugDrawLine(float radius, int euler){int segments = 100; //圆弧那一段需要用多少个点来表示float deltaAngle = euler / segments;Vector3 right = transform.right;Vector3[] vertices = new Vector3[segments + 2];vertices[0] = transform.position;for (int i = 1; i < vertices.Length; i++){float curAngle = -euler / 2 + deltaAngle * (i - 1) + skillAngle;//从-1/2扇形角度开始绘制,每次偏移deltaAngleVector3 pos = Quaternion.Euler(0f, curAngle, 0f) * right * radius + transform.position;vertices[i] = pos;}// 画圆弧for (int i = 1; i < vertices.Length - 1; i++){Debug.Log(vertices[i]);Debug.DrawLine(vertices[i], vertices[i + 1], showColor);}// 画两条边Debug.DrawLine(vertices[0], vertices[vertices.Length - 1], showColor);Debug.DrawLine(vertices[0], vertices[1], showColor);}/// <summary>/// 利用LinerRender绘制扇形/// </summary>private void DrawFan_LineRender(float radius, int euler){ResetLinerRenderPoints();m_LineRenderer.startColor = showColor;m_LineRenderer.endColor = showColor;m_LineRendererPoints.Add(transform.position);//每一度一个点,绘制思路和debug.DrawLine相同for(int angles = -euler/2; angles <= euler/2; angles++){m_LineRendererPoints.Add(Quaternion.Euler(0, angles + skillAngle, 0) * transform.right * radius + transform.position);}m_LineRenderer.SetPositions(m_LineRendererPoints.ToArray());}private void InitLineRender(){m_LineRendererPoints = new List<Vector3>();m_LineRenderer = GetComponent<LineRenderer>();m_LineRenderer.endWidth = 0.1f;m_LineRenderer.startWidth = 0.1f;m_LineRenderer.loop = true; //绘制路径将会闭合}private void ResetLinerRenderPoints(){m_LineRendererPoints.Clear();}
}

敌人身上的脚本,可以移动

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy : MonoBehaviour
{// Start is called before the first frame updatepublic float speed = 2f;private FanDetector fanSkill;void Start(){fanSkill = GameObject.FindWithTag("Player").GetComponent<FanDetector>();}// Update is called once per framevoid Update(){transform.position += Input.GetAxis("Horizontal") * speed * transform.right * Time.deltaTime;transform.position += Input.GetAxis("Vertical") * speed * transform.forward * Time.deltaTime;SkillDetect();}private void SkillDetect(){if (fanSkill.Dectect(transform.position)){Debug.Log("进入扇形技能范围");}}}

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

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

相关文章

直播预告|小白开箱: 云数据库在五朵云上的评测

3 月 7 日&#xff0c;周四晚上 19:00-20:30 由明说三人行组织&#xff0c;邀请了 NineData 国际总经理(GM) Ni Demai、云猿生数据 CTO &#xff06; 联合创始人子嘉&#xff0c;和《明说三人行》创始人 &主持人明叔&#xff0c;共同围绕《小白开箱: 云数据库在五朵云上的评…

官网正在被哪些产品蚕食,定制网站又被哪些建站产品挤占。

2023-12-09 16:22贝格前端工场 官网建设是一个被大多数人看衰的市场&#xff0c;本文来理性分析下&#xff0c;谁在蚕食这个市场&#xff0c;谁又在挤占这个产品生存空间&#xff0c;欢迎大家评论&#xff0c;探讨。 网站正在被以下产品形式取代&#xff1a; 1. 移动应用&…

揭秘Web缓存:提升网站性能与用户体验

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

金融数据采集与风险管理:Open-Spider工具的应用与实践

一、项目介绍 在当今快速发展的金融行业中&#xff0c;新的金融产品和服务层出不穷&#xff0c;为银行业务带来了巨大的机遇和挑战。为了帮助银行员工更好地应对这些挑战&#xff0c;我们曾成功实施了一个创新的项目&#xff0c;该项目采用了先进的爬虫技术&#xff0c;通过ope…

七彩虹@电脑cpu频率上不去问题@控制中心性能模式cpu频率上不去@代理服务器超时@账户同步设置失败

文章目录 windows电脑cpu频率上不去新电脑的系统时间问题系统时间不准造成的具体问题举例代理超时vscode同步请求失败自动校准时间 windows电脑cpu频率上不去 问题描述,标压处理器的笔记本,cpu频率上不去 如果cpu没问题的话,就应该是系统限制了功耗导致的有的笔记本有控制中心…

动手学深度学习PyTorch版

基本的数据操作 import torch # 创建一个行向量&#xff0c;默认为从0开始的12个整数 # n维数组也称为张量 x torch.arange(12) x # 张量的形状 x.shape# 张量的大小,张量所有元素的个数 x.numel()#修改张量的形状 x x.reshape(3,4)#生成形状为3*4的两个向量&#xff0c;向…

深度学习与人类的智能交互:迈向自然与高效的人机新纪元

引言 随着科技的飞速发展&#xff0c;深度学习作为人工智能领域的一颗璀璨明珠&#xff0c;正日益展现出其在模拟人类认知和感知过程中的强大能力。本文旨在探讨深度学习如何日益逼近人类智能的边界&#xff0c;并通过模拟人类的感知系统&#xff0c;使机器能更深入地理解和解…

20240308-1-校招前端面试常见问题CSS

校招前端面试常见问题【3】——CSS 1、盒模型 Q&#xff1a;请简述一下 CSS 盒模型&#xff1f; W3C 模式&#xff1a;盒子宽widthpaddingbordermargin 怪异模式&#xff1a;盒子宽widthmargin Q&#xff1a;inline、block、inline-block 元素的区别&#xff1f; inline&am…

设计模式大题做题记录

设计模式大题 09年 上半年&#xff1a; 09年下半年 10年上半年 10年下半年 11年上半年 11年下半年 12年上半年 12年下半年 13年上半年 13年下半年

Springboot教程(六)——异常处理

拦截异常 在Spring Boot中&#xff0c;我们可以将异常统一放在全局处理类来处理&#xff0c;创建一个全局异常处理类需要用到ControllerAdvice和ExceptionHandler注解。 ControllerAdvice类似一个增强版的Controller&#xff0c;用于标注类&#xff0c;表示该类声明了整个项目…

嵌入式学习-FreeRTOS-Day3

嵌入式学习-FreeRTOS-Day3 一、思维导图 二、 1.FreeRTOS任务的调度算法及实现 默认是抢占式调度时间片轮询 1.抢占式调度&#xff1a;任务优先级高的可以打断任务优先级低的执行&#xff08;适用于不同优先级&#xff09; 2.时间片轮转&#xff1a;每一个任务拥有相同的时…

使用 Cypress 进行可视化回归测试:一种务实的方法

每次组件库 Picasso 发布新版本时&#xff0c;都会更新所有的前端应用程序&#xff0c;让绝大部分新功能能与整个平台的设计保持一致。上个月&#xff0c;推出了 Toptal Talent Portal 的 Picasso 更新&#xff0c;这是我们的用户用来找工作和与客户互动的平台。 已知了这个版本…

软考70-上午题-【面向对象技术2-UML】-UML中的图1

一、图的定义 图是一组元素的图形表示&#xff0c;大多数情况下把图画成顶点、弧的联通图。 顶点&#xff1a;代表事物&#xff1b; 弧&#xff1a;代表关系。 可以从不同的角度画图&#xff0c;UML提供了13种图&#xff1a;&#xff08;只看9种&#xff09; 类图&#xff…

数据结构实现

目录 一、线性表中顺序表的实现&#xff1a; 二、线性表的链式存储&#xff08;链表-带头节点&#xff09; 三、习题练习&#xff1a; 四、栈&#xff08;stack&#xff09; 五、循环队列 1.数组形式&#xff1a; 2.链表形式&#xff1a; 3.习题练习 六、二叉树 1.…

226. 翻转二叉树

代码实现&#xff1a; 方法1&#xff1a;先序遍历 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/// 交换左右子树 void swap(struct TreeNode *root) {struct TreeNode *l root…

Linux grep

文章目录 1. 基本用法2.字符转义3.二进制文件查找4.打印目标字段的附近行4. 多条件过滤5. 目录中过滤——用于在文件夹中筛选/排除指定后缀文件6.反向过滤——用于筛选7.只输出匹配内容——用于统计8. 筛选出包含字段的文件9.正则匹配10.管道和grep11.grep和wc/uniq/sort的合用…

B端系统优化,可不是换个颜色和图标,看看与大厂系统的差距。

Hi&#xff0c;我是贝格前端工场&#xff0c;优化升级各类管理系统的界面和体验&#xff0c;是我们核心业务之一&#xff0c;欢迎老铁们评论点赞互动&#xff0c;有需求可以私信我们 一、不要被流于表面的需求描述迷惑。 很多人找我们优化系统界面&#xff0c;对需求总是轻描淡…

小白跟做江科大51单片机之AD/DA

1.看原理图找接口 2.看时序图编写读取数据代码 XPT2046.c代码 #include <REGX52.H> //引脚定义 sbit XPY2046_DINP3^4; sbit XPY2046_CSP3^5; sbit XPY2046_DCLKP3^6; sbit XPY2046_DOUTP3^7; unsigned int XPT2046_ReadAD(unsigned char Command) { unsigned char …

sqllab 11-22

11.有回显&#xff0c;单引号 首先判断是字符型还是数字型 通过order by 来获取字段数 方便后续union联合 注意这里mime表明了内容要进行url编码&#xff0c;测试3报错&#xff0c;2正常&#xff0c;所以有2列。 还需要判断显示位&#xff0c;因为只有显示位的数据才能被爆出…

论文笔记:Efficient Bootstrapping for Confidential Transactions

EcoBoost: Efficient Bootstrapping for Confidential Transactions 设计了一种被称为EcoBoost的新方法&#xff0c;以提高支持机密交易的区块链的引导效率。具体来说&#xff0c;利用随机抽样来验证高概率保密交易的正确性。因此&#xff0c;与事务数量相比**&#xff0c;验证…