写在前面的话,前两天有个朋友在QQ上问我 如何获取主角面朝方向一定区域中的敌人对象。这个命题看似简单,其实里面蕴含了很多数学方面的东西。今天刚好有时间我就彻底的把这个疑问写在博客中。希望可以帮助到他。

在上代码之前请大家跟我先做几个简单的练习题,角度向量的计算一定要学会,不然后面的东西会很难懂。

1.已知3D坐标,和一个旋转角度,以及一段距离,求目标点的3D坐标。

已知当前点为Target,目标点沿着Target的Y轴旋转30度,沿着Target的X轴延伸10米求目标点的3D坐标?

  1. using UnityEngine;
  2. using System.Collections;
  3. public class Test : MonoBehaviour
  4. {
  5. public Transform Target;
  6. void LateUpdate ()
  7. {
  8. Quaternion rotation = Quaternion.Euler(0f,30f,0f) * Target.rotation;
  9. Vector3  newPos = rotation * new Vector3(10f,0f,0f);
  10. Debug.DrawLine(newPos,Vector3.zero,Color.red);
  11. Debug.Log("newpos " + newPos +" nowpos " + Target.position + " distance " + Vector3.Distance(newPos,Target.position));
  12. }
  13. }

输出结果 :新坐标 (8.7, 0.0, -5.0) 当前坐标 (0.0, 0.0, 0.0)两点之间的距离 10。

2.已知3D模型的角度求它的向量。已知3D模型Target,Y轴旋转30度后向前平移。

  1. using UnityEngine;
  2. using System.Collections;
  3. public class Test : MonoBehaviour
  4. {
  5. public Transform Target;
  6. void LateUpdate ()
  7. {
  8. if(Input.GetMouseButton(0))
  9. {
  10. Quaternion rotation = Quaternion.Euler(0f,30f,0f) * Target.rotation;
  11. Vector3  newPos = rotation * Vector3.forward;
  12. Target.Translate(newPos.x,newPos.y,newPos.z);
  13. }
  14. }
  15. }

3.已知一个目标点,让模型朝着这个目标点移动。这是一个比较简单的例子,大家应该都能看明白。

  1. Target.transform.LookAt(new Vector3 (100f,200f,300f));
  2. Target.Translate(Vector3.forward);

这里我要说的就是Vector3.forward ,它等价与 new Vector3(0,0,1);它并不是一个坐标,它是一个标准向量,方向是沿着Z轴向前。这样平移一次的距离就是1米, 如果Vector3.forward * 100那么一次平移的距离就是100米。 在看看下面这段代码.

  1. Vector3 vecn = (TargetCube.position - Target.position).normalized;
  2. Target.Translate(vecn *0.1f);

用向量减去一个向量求出它们的差值,normalized 是格式化向量,意思是把它们之间向量格式化到1米内。这样就可以更加精确的计算一次平移的距离了 vecn *0.1f 就标示一次平移1分米,蛤蛤。 向量不仅可以进行X Y Z轴的移动,同样可以进行旋转 ,下面这段代码就是让向量沿着Y轴旋转30度。

  1. Vector3 vecn = (TargetCube.position - Target.position).normalized;
  2. vecn = Quaternion.Euler(0f,30f,0f) * vecn;
  3. Target.Translate(vecn *0.1f);

如果上述三道简单的练习题 你都能了然于心的话,那么本文最大的难题我相信也不会是什么难事,继续阅读吧。假设我们需要计算主角面前5米内所有的对象时。以主角为圆心计算面前5米外的一个点,为了让大家看清楚我现将这条线绘制出来。

  1. private float distance = 5f;
  2. void Update ()
  3. {
  4. Quaternion r= transform.rotation;
  5. Vector3 f0 =  (transform.position  + (r *Vector3.forward) * distance);
  6. Debug.DrawLine(transform.position,f0,Color.red);
  7. }

如下图所,我们已经将这两个点计算出来了。此时你可以动态的编辑主角Y轴的坐标,这个点永远都是沿着主角当前角度面前5米以外的点。

<ignore_js_op> 
接下来,我们需要计算主角面前的一个发散性的角度。假设主角看到的是向左30度,向右30度在这个区域。

  1. private float distance = 5f;
  2. void Update ()
  3. {
  4. Quaternion r= transform.rotation;
  5. Vector3 f0 =  (transform.position  + (r *Vector3.forward) * distance);
  6. Debug.DrawLine(transform.position,f0,Color.red);
  7. Quaternion r0= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y - 30f,transform.rotation.eulerAngles.z);
  8. Quaternion r1= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y + 30f,transform.rotation.eulerAngles.z);
  9. Vector3 f1 =  (transform.position  + (r0 *Vector3.forward) * distance);
  10. Vector3 f2 =  (transform.position  + (r1 *Vector3.forward) * distance);
  11. Debug.DrawLine(transform.position,f1,Color.red);
  12. Debug.DrawLine(transform.position,f2,Color.red);
  13. Debug.DrawLine(f0,f1,Color.red);
  14. Debug.DrawLine(f0,f2,Color.red);
  15. }

如下图所示,这时主角面前的区域就计算出来了。看起来就是两个三角形之间的区域。<ignore_js_op>

最后就是简单的套用公式,计算一个点是否在三角形内,在本文中就是计算敌人的点是否在面前的这两个三角形内。

  1. using UnityEngine;
  2. using System.Collections;
  3. public class MyTest : MonoBehaviour {
  4. public Transform cube;
  5. private float distance = 5f;
  6. void Update ()
  7. {
  8. Quaternion r= transform.rotation;
  9. Vector3 f0 =  (transform.position  + (r *Vector3.forward) * distance);
  10. Debug.DrawLine(transform.position,f0,Color.red);
  11. Quaternion r0= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y - 30f,transform.rotation.eulerAngles.z);
  12. Quaternion r1= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y + 30f,transform.rotation.eulerAngles.z);
  13. Vector3 f1 =  (transform.position  + (r0 *Vector3.forward) * distance);
  14. Vector3 f2 =  (transform.position  + (r1 *Vector3.forward) * distance);
  15. Debug.DrawLine(transform.position,f1,Color.red);
  16. Debug.DrawLine(transform.position,f2,Color.red);
  17. Debug.DrawLine(f0,f1,Color.red);
  18. Debug.DrawLine(f0,f2,Color.red);
  19. Vector3 point = cube.position;
  20. if(isINTriangle(point,transform.position,f1,f0) || isINTriangle(point,transform.position,f2,f0) )
  21. {
  22. Debug.Log("cube in this !!!");
  23. }else
  24. {
  25. Debug.Log("cube not in this !!!");
  26. }
  27. }
  28. private  float triangleArea(float v0x,float v0y,float v1x,float v1y,float v2x,float v2y)
  29. {
  30. return Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y
  31. - v1x * v0y - v2x * v1y - v0x * v2y) / 2f);
  32. }
  33. bool isINTriangle(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2)
  34. {
  35. float x = point.x;
  36. float y = point.z;
  37. float v0x = v0.x;
  38. float v0y = v0.z;
  39. float v1x = v1.x;
  40. float v1y = v1.z;
  41. float v2x = v2.x;
  42. float v2y = v2.z;
  43. float t = triangleArea(v0x,v0y,v1x,v1y,v2x,v2y);
  44. float a = triangleArea(v0x,v0y,v1x,v1y,x,y) + triangleArea(v0x,v0y,x,y,v2x,v2y) + triangleArea(x,y,v1x,v1y,v2x,v2y);
  45. if (Mathf.Abs(t - a) <= 0.01f)
  46. {
  47. return true;
  48. }else
  49. {
  50. return false;
  51. }
  52. }
  53. }

如下图所示,如果箱子对象是主角的视野中就会检测到。

<ignore_js_op>

注意,上图中我的视野选择了两个三角形,如果你需要视野目标点是椭圆形的话,那么可以多设置一些三角形。但是这样就会非常消耗效率,我觉得这里完全可以使用1个三角形,,只是正对的目标点会出现一些偏差,影响其实并不会很大。如下图所示

<ignore_js_op>

代码简单的修改一下即可。

  1. using UnityEngine;
  2. using System.Collections;
  3. public class MyTest : MonoBehaviour {
  4. public Transform cube;
  5. private float distance = 5f;
  6. void Update ()
  7. {
  8. Quaternion r= transform.rotation;
  9. Vector3 f0 =  (transform.position  + (r *Vector3.forward) * distance);
  10. Debug.DrawLine(transform.position,f0,Color.red);
  11. Quaternion r0= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y - 30f,transform.rotation.eulerAngles.z);
  12. Quaternion r1= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y + 30f,transform.rotation.eulerAngles.z);
  13. Vector3 f1 =  (transform.position  + (r0 *Vector3.forward) * distance);
  14. Vector3 f2 =  (transform.position  + (r1 *Vector3.forward) * distance);
  15. Debug.DrawLine(transform.position,f1,Color.red);
  16. Debug.DrawLine(transform.position,f2,Color.red);
  17. Debug.DrawLine(f1,f2,Color.red);
  18. Vector3 point = cube.position;
  19. if(isINTriangle(point,transform.position,f1,f2))
  20. {
  21. Debug.Log("cube in this !!!");
  22. }else
  23. {
  24. Debug.Log("cube not in this !!!");
  25. }
  26. }
  27. private  float triangleArea(float v0x,float v0y,float v1x,float v1y,float v2x,float v2y)
  28. {
  29. return Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y
  30. - v1x * v0y - v2x * v1y - v0x * v2y) / 2f);
  31. }
  32. bool isINTriangle(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2)
  33. {
  34. float x = point.x;
  35. float y = point.z;
  36. float v0x = v0.x;
  37. float v0y = v0.z;
  38. float v1x = v1.x;
  39. float v1y = v1.z;
  40. float v2x = v2.x;
  41. float v2y = v2.z;
  42. float t = triangleArea(v0x,v0y,v1x,v1y,v2x,v2y);
  43. float a = triangleArea(v0x,v0y,v1x,v1y,x,y) + triangleArea(v0x,v0y,x,y,v2x,v2y) + triangleArea(x,y,v1x,v1y,v2x,v2y);
  44. if (Mathf.Abs(t - a) <= 0.01f)
  45. {
  46. return true;
  47. }else
  48. {
  49. return false;
  50. }
  51. }
  52. }

上面我们介绍了三角形判断,当然也可以通过矩形来判断是否相交。。

<ignore_js_op>

代码:

  1. using UnityEngine;
  2. using System.Collections;
  3. public class MyTest : MonoBehaviour {
  4. public Transform cube;
  5. private float distance = 5f;
  6. void Update ()
  7. {
  8. Quaternion r= transform.rotation;
  9. Vector3 left =  (transform.position  + (r *Vector3.left) * distance);
  10. Debug.DrawLine(transform.position,left,Color.red);
  11. Vector3 right =  (transform.position  + (r *Vector3.right) * distance);
  12. Debug.DrawLine(transform.position,right,Color.red);
  13. Vector3 leftEnd = (left  + (r *Vector3.forward) * distance);
  14. Debug.DrawLine(left,leftEnd,Color.red);
  15. Vector3 rightEnd = (right  + (r *Vector3.forward) * distance);
  16. Debug.DrawLine(right,rightEnd,Color.red);
  17. Debug.DrawLine(leftEnd,rightEnd,Color.red);
  18. Vector3 point = cube.position;
  19. if(isINRect(point,leftEnd,rightEnd,right,left))
  20. {
  21. Debug.Log("cube in this !!!");
  22. }else
  23. {
  24. Debug.Log("cube not in this !!!");
  25. }
  26. }
  27. private float Multiply(float p1x , float p1y, float p2x,float p2y, float p0x,float p0y)
  28. {
  29. return ((p1x - p0x) * (p2y - p0y) - (p2x - p0x) * (p1y - p0y));
  30. }
  31. bool isINRect(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2,Vector3 v3)
  32. {
  33. float x = point.x;
  34. float y = point.z;
  35. float v0x = v0.x;
  36. float v0y = v0.z;
  37. float v1x = v1.x;
  38. float v1y = v1.z;
  39. float v2x = v2.x;
  40. float v2y = v2.z;
  41. float v3x = v3.x;
  42. float v3y = v3.z;
  43. if (Multiply(x,y, v0x,v0y, v1x,v1y) * Multiply(x,y, v3x,v3y, v2x,v2y) <= 0 && Multiply(x,y, v3x,v3y, v0x,v0y) * Multiply(x,y, v2x,v2y, v1x,v1y) <= 0)
  44. return true;
  45. else
  46. return false;
  47. }
  48. }

如果大家看了这篇文章后发现在你的项目中还有一些比较麻烦的角度与向量的算法,欢迎在下面留言给我,如果我有时间我会第一时间把方法贴在博客中。互相学习互相进步,加油!哇咔咔。。马上过年了,雨松MOMO在这里祝福大家2013年幸幸福福的过日子,嘿嘿。

2013年4月补充感谢楼下朋友给我的留言。, 我在补充一下这篇博客。

  1. using UnityEngine;
  2. using System.Collections;
  3. public class NewBehaviourScript : MonoBehaviour {
  4. public Transform target;
  5. void Update()
  6. {
  7. float distance = Vector3.Distance(target.position,transform.position);
  8. Quaternion right         = transform.rotation * Quaternion.AngleAxis(30,Vector3.up);
  9. Quaternion left         = transform.rotation * Quaternion.AngleAxis(30,Vector3.down);
  10. Vector3 n =         transform.position + (Vector3.forward * distance);
  11. Vector3 leftPoint = left *         n ;
  12. Vector3 rightPoint =  right *n ;
  13. Debug.DrawLine(transform.position,leftPoint,Color.red);
  14. Debug.DrawLine(transform.position,rightPoint,Color.red);
  15. Debug.DrawLine(rightPoint,leftPoint,Color.red);
  16. }
  17. }

<ignore_js_op>

这里我以角色左右个30度。 这样就可以根据两个模型的距离以及角度来判断了。。

转载于:https://www.cnblogs.com/weiqiangwaideshijie/p/6632922.html

Unity3D之主角面朝方向一定区域内对象角度计算(转)相关推荐

  1. Unity3D——主角面朝方向一定区域内对象角度计算

    写在前面的话,前两天有个朋友在QQ上问我 如何获取主角面朝方向一定区域中的敌人对象.这个命题看似简单,其实里面蕴含了很多数学方面的东西.今天刚好有时间我就彻底的把这个疑问写在博客中.希望可以帮助到他. ...

  2. unity3d做会减少的血条_2019-2020年Unity3D——人物主角的血条-经验的显示.doc

    Unity3D--人物主角的血条 经验的显示 今天说一下人物主角的血量和经验还有人物等级金币的显示.? ? ???//主角刚出现的时候现有血量? ? public static int blood = ...

  3. 通过卫星图像预测区域内降雨范围和降雨量

    来源:DeepHub IMBA本文约3000字,建议阅读5分钟 本文介绍了如何通过模型预测区域内降雨范围和降雨量. 介绍 在农业.自动驾驶.航空或能源领域,预测和了解天气是十分重要的.例如,天气条件对 ...

  4. 过滤所有用户的行车轨迹查找在某一区域内的用户

    2019独角兽企业重金招聘Python工程师标准>>> // 判断经纬度是否在此区域内public void selectDevice2() throws IOException{S ...

  5. 判断一个点是否在多边形区域内--C算法

    /* 函数的输入: (1)当前点的坐标p (2)区域顶点数组pt[]: (3)顶点数nCount  输出: 在区域内返回TRUE,否则返回FALSE.    Point类型是一个结构:  struct ...

  6. 百度地图——判断一个点是否在一个区域内?

    由于目前的一个项目涉及离线地图,经过查找资料论证,最终还是决定采用百度地图.在项目过程中,遇到一个比较实际的问题:怎么判断地图上的一个点(经纬坐标下)在一个多边形区域内? 由于我采用的是百度地图Jav ...

  7. JVM - 结合代码示例彻底搞懂Java内存区域_对象在堆-栈-方法区(元空间)之间的关系

    文章目录 Pre 示例demo 总体关系 代码示例论证 反汇编 Pre JVM - 结合代码示例彻底搞懂Java内存区域_线程栈 | 本地方法栈 | 程序计数器 中我们探讨了线程栈中的内部结构 ,大家 ...

  8. ITK:像素是否在区域内

    ITK:像素是否在区域内 内容提要 输出结果 C++实现代码 内容提要 确定像素是否在区域内 输出结果 [1, 1] Inside [6, 6] Outside C++实现代码 #include &q ...

  9. 百度地图开发总结----3.判断一个点是否在一片区域内

    主要用到了BMapLib.GeoUtils.isPointInPolygon(point, apolygon)这个函数,第一个参数为百度坐标点对象,new BMap.Point(x,y), 第二个参数 ...

最新文章

  1. 【2】Vue项目引用Element UI(饿了么框架)菜单导航条初期配置
  2. 动态创建DeepZoom
  3. 数据分析师常用的十种数据分析思路,你都知道吗?
  4. matlab等待按键响应,matlab中figure对象的按键响应
  5. Flask web开发之路二
  6. POJ2115-C Looooops【扩欧,同余】
  7. python opencv 读取视频流不解码_python + opencv: 解决不能读取视频的问题
  8. mysql old key files_mysql出现“Incorrect key file for table”解决办法
  9. iOS多线程技术—多线程简单介绍
  10. linux连接交换机软件,如何用超级终端连接交换机 - 全文
  11. 物联网和区块链:挑战与风险
  12. 免费手机电脑同屏神器——Mirroid
  13. 私域流量分析之李子柒
  14. 关于 python 在 pycharm 下载库的两种方法
  15. uniapp 自定义下拉框
  16. 利普西斯常数_只有西斯绝对
  17. 选取十二个“一”,写一篇8000字小说
  18. 51单片机c语言按键扫描程序,单片机按键扫描数码管显示C语言程序
  19. 如何安装Ruby和RubyGems
  20. 计算机毕业设计jsp小福星宠物领养管理系统

热门文章

  1. 前端如何实现网络速度测试功能_前端组件单元测试
  2. sprongboot mysql登录注册_后端开发:SpringBoot实现注册与登录功能
  3. 【ES8(2017)】async / await
  4. 用框图说明计算机控制系统,计算机控制系统试题
  5. Python笔记-沪深三百与茅台简单分析(2021年数据)
  6. 信息安全工程师笔记-综合知识冲刺(四)
  7. C++笔记-char*存储的二进制转成long long十进制(读串口的时候经常用到)
  8. HTML期末网页作业-仿QQ官网QQ注册网页
  9. windows中mysql添加环境变量_windows 下添加mysql到系统环境变量
  10. nodejs获得服务器响应,轻松创建nodejs服务器(6):作出响应