Unity3D——主⾓⾯朝⽅向⼀定区域内对象⾓度计算
写在前⾯的话,前两天有个朋友在QQ上问我如何获取主⾓⾯朝⽅向⼀定区域中的敌⼈对象。这个命题看似简单,其实⾥⾯蕴含了很多数学⽅⾯的东西。今天刚好有时间我就彻底的把这个疑问写在博客中。希望可以帮助到他。
在上代码之前请⼤家跟我先做⼏个简单的练习题,⾓度向量的计算⼀定要学会,不然后⾯的东西会很难懂。
1.已知3D坐标,和⼀个旋转⾓度,以及⼀段距离,求⽬标点的3D坐标。
已知当前点为Target,⽬标点沿着Target的Y轴旋转30度,沿着Target的X轴延伸10⽶求⽬标点的3D坐标?
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour
{
public Transform Target;
void LateUpdate ()
{
Quaternion rotation = Quaternion.Euler(0f,30f,0f) * ation;
Vector3 newPos = rotation * new Vector3(10f,0f,0f);
Debug.DrawLine(,d);
Debug.Log("newpos " + newPos +" nowpos " + Target.position + " distance " + Vector3.Distance(newPos,Target.position));
}
}
输出结果:新坐标 (8.7, 0.0, -5.0) 当前坐标 (0.0, 0.0, 0.0)两点之间的距离 10。
2.已知3D模型的⾓度求它的向量。
已知3D模型Target,Y轴旋转30度后向前平移。
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour
{
public Transform Target;
void LateUpdate ()
{
if(Input.GetMouButton(0))
{
Quaternion rotation = Quaternion.Euler(0f,30f,0f) * ation;
Vector3 newPos = rotation * Vector3.forward;
Target.Translate(newPos.x,newPos.y,newPos.z);
}
}
}
3.已知⼀个⽬标点,让模型朝着这个⽬标点移动。
这是⼀个⽐较简单的例⼦,⼤家应该都能看明⽩。
Target.Translate(Vector3.forward);
冬则温这⾥我要说的就是Vector3.forward ,它等价与 new Vector3(0,0,1);它并不是⼀个坐标,它是⼀个标准向量,⽅向是沿着Z轴向前。这样平移⼀次的距离就是1⽶,如果Vector3.forward * 100那么⼀次平移的距离就是100⽶。
在看看下⾯这段代码
Vector3vecn=(TargetCube.position-Target.position).normalized;
Target.Translate(vecn*0.1f);
⽤向量减去⼀个向量求出它们的差值,normalized 是格式化向量,意思是把它们之间向量格式化到1⽶内。这样就可以更加精确的计算⼀次平移的距离了 vecn *0.1f 就标⽰⼀次平移1分⽶,蛤蛤。
向量不仅可以进⾏X Y Z轴的移动,同样可以进⾏旋转,下⾯这段代码就是让向量沿着Y轴旋转30度。
Vector3vecn=(TargetCube.position-Target.position).normalized;
vecn=Quaternion.Euler(0f,30f,0f)*vecn;
Target.Translate(vecn*0.1f);
偏振镜片如果上述三道简单的练习题你都能了然于⼼的话,那么本⽂最⼤的难题我相信也不会是什么难事,继续阅读吧。
假设我们需要计算主⾓⾯前5⽶内所有的对象时。以主⾓为圆⼼计算⾯前5⽶外的⼀个点,为了让⼤家
看清楚我现将这条线绘制出来。
private float distance = 5f;中原爱子
void Update ()
{
Quaternion r= ation;
Vector3 f0 = (transform.position + (r *Vector3.forward) * distance);
Debug.DrawLine(transform.position,d);
}
如下图所,我们已经将这两个点计算出来了。此时你可以动态的编辑主⾓Y轴的坐标,这个点永远都是沿着主⾓当前⾓度⾯前5⽶以外的点。
接下来,我们需要计算主⾓⾯前的⼀个发散性的⾓度。假设主⾓看到的是向左30度,向右30度在这个区域。
private float distance = 5f;
void Update ()
{
Quaternion r= ation;
Vector3 f0 = (transform.position + (r *Vector3.forward) * distance);
Debug.DrawLine(transform.position,d);
Quaternion r0= Quaternion.ation.eulerAngles.ation.eulerAngles.y - ation.eulerAngles.z); Quaternion r1= Quaternion.ation.eulerAngles.ation.eulerAngles.y + ation.eulerAngles.z);
Vector3 f1 = (transform.position + (r0 *Vector3.forward) * distance);
Vector3 f2 = (transform.position + (r1 *Vector3.forward) * distance);
Debug.DrawLine(transform.position,d);
Debug.DrawLine(transform.position,d);
Debug.DrawLine(f0,d);
Debug.DrawLine(f0,d);
}
如下图所⽰,这时主⾓⾯前的区域就计算出来了。看起来就是两个三⾓形之间的区域。
最后就是简单的套⽤公式,计算⼀个点是否在三⾓形内,在本⽂中就是计算敌⼈的点是否在⾯前的这两个三⾓形内。
using UnityEngine;
using System.Collections;
public class MyTest : MonoBehaviour {
public Transform cube;
private float distance = 5f;
void Update ()
{
Quaternion r= ation;
Vector3 f0 = (transform.position + (r *Vector3.forward) * distance);
Debug.DrawLine(transform.position,d);
Quaternion r0= Quaternion.ation.eulerAngles.ation.eulerAngles.y - ation.eulerAngles.z); Quaternion r1= Quaternion.ation.eulerAngles.ation.eulerAngles.y + ation.eulerAngles.z);
葡萄目Vector3 f1 = (transform.position + (r0 *Vector3.forward) * distance);
Vector3 f2 = (transform.position + (r1 *Vector3.forward) * distance);
Debug.DrawLine(transform.position,d);
Debug.DrawLine(transform.position,d);
Debug.DrawLine(f0,d);
Debug.DrawLine(f0,d);
Vector3 point = cube.position;
if(isINTriangle(point,transform.position,f1,f0) || isINTriangle(point,transform.position,f2,f0) )
{
Debug.Log("cube in this ");
}el
{
Debug.Log("cube not in this ");
怎么说话幽默}
}
private float triangleArea(float v0x,float v0y,float v1x,float v1y,float v2x,float v2y)
{
return Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y
- v1x * v0y - v2x * v1y - v0x * v2y) / 2f);
}
bool isINTriangle(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2)
{
float x = point.x;
float y = point.z;
float v0x = v0.x;
float v0y = v0.z;
float v1x = v1.x;
float v1y = v1.z;
float v2x = v2.x;
float v2y = v2.z;
float t = triangleArea(v0x,v0y,v1x,v1y,v2x,v2y);
float a = triangleArea(v0x,v0y,v1x,v1y,x,y) + triangleArea(v0x,v0y,x,y,v2x,v2y) + triangleArea(x,y,v1x,v1y,v2x,v2y);
if (Mathf.Abs(t - a) <= 0.01f)
{
return true;
}el
{
return fal;
}
}
}
如下图所⽰,如果箱⼦对象是主⾓的视野中就会检测到。
注意,上图中我的视野选择了两个三⾓形,如果你需要视野⽬标点是椭圆形的话,那么可以多设置⼀些三⾓形。但是这样就会⾮常消耗效率,我觉得这⾥完全可以使⽤1个三⾓形,,只是正对的⽬标点会出现⼀些偏差,影响其实并不会很⼤。如下图所⽰
代码简单的修改⼀下即可。
using UnityEngine;
using System.Collections;
public class MyTest : MonoBehaviour {
public Transform cube;
private float distance = 5f;
void Update ()
{
Quaternion r= ation;
Vector3 f0 = (transform.position + (r *Vector3.forward) * distance);
Debug.DrawLine(transform.position,d);
Quaternion r0= Quaternion.ation.eulerAngles.ation.eulerAngles.y - ation.eulerAngles.z); Quaternion r1= Quaternion.ation.eulerAngles.ation.eulerAngles.y + ation.eulerAngles.z);
Vector3 f1 = (transform.position + (r0 *Vector3.forward) * distance);
Vector3 f2 = (transform.position + (r1 *Vector3.forward) * distance);
Debug.DrawLine(transform.position,d);
Debug.DrawLine(transform.position,d);
in是什么意思Debug.DrawLine(f1,d);
Vector3 point = cube.position;
if(isINTriangle(point,transform.position,f1,f2))
{
Debug.Log("cube in this ");
}el
{
Debug.Log("cube not in this ");
}
}
private float triangleArea(float v0x,float v0y,float v1x,float v1y,float v2x,float v2y)
{
return Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y
- v1x * v0y - v2x * v1y - v0x * v2y) / 2f);英雄联盟怎么举报
}
长乐县bool isINTriangle(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2)
{
float x = point.x;
float y = point.z;