现在的位置: 首页 > 综合 > 正文

Unity3D研究院之主角面朝方向一定区域内对象角度计算

2013年09月11日 ⁄ 综合 ⁄ 共 8153字 ⁄ 字号 评论关闭

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

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

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

01 using
UnityEngine;
02 using
System.Collections;
03   
04 public
class
Test : MonoBehaviour
05 {
06   
07     public
Transform Target;
08   
09     void
LateUpdate ()
10     {
11         Quaternion rotation = Quaternion.Euler(0f,30f,0f) * Target.rotation;
12         Vector3  newPos = rotation *
new Vector3(10f,0f,0f);
13         Debug.DrawLine(newPos,Vector3.zero,Color.red);
14         Debug.Log("newpos "
+ newPos +" nowpos "
+ Target.position + " distance "
+ Vector3.Distance(newPos,Target.position));
15     }
16   
17 }

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

 2.已知3D模型的角度求它的向量。

已知3D模型Target,Y轴旋转30度后向前平移。

01 using
UnityEngine;
02 using
System.Collections;
03   
04 public
class
Test : MonoBehaviour
05 {
06   
07     public
Transform Target;
08   
09     void
LateUpdate ()
10     {
11   
12         if(Input.GetMouseButton(0))
13         {
14             Quaternion rotation = Quaternion.Euler(0f,30f,0f) * Target.rotation;
15             Vector3  newPos = rotation * Vector3.forward;
16             Target.Translate(newPos.x,newPos.y,newPos.z);
17         }
18     }
19   
20 }

 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米以外的点。

 

屏幕快照 2013-01-29 下午8.13.32

 

 

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

 

01 private
float
distance = 5f;
02 void
Update () 
03 {
04     Quaternion r= transform.rotation;
05     Vector3 f0 =  (transform.position  + (r *Vector3.forward) * distance);
06     Debug.DrawLine(transform.position,f0,Color.red);
07     Quaternion r0= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y - 30f,transform.rotation.eulerAngles.z);
08     Quaternion r1= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y + 30f,transform.rotation.eulerAngles.z);
09     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 }

 

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

 

屏幕快照 2013-01-29 下午8.21.47

 

 

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

01 using
UnityEngine;
02 using
System.Collections;
03   
04 public
class
MyTest : MonoBehaviour {
05   
06     public
Transform cube;
07   
08     private
float distance = 5f;
09     void
Update () 
10     {
11         Quaternion r= transform.rotation;
12         Vector3 f0 =  (transform.position  + (r *Vector3.forward) * distance);
13         Debug.DrawLine(transform.position,f0,Color.red);
14   
15         Quaternion r0= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y - 30f,transform.rotation.eulerAngles.z);
16         Quaternion r1= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y + 30f,transform.rotation.eulerAngles.z);
17   
18         Vector3 f1 =  (transform.position  + (r0 *Vector3.forward) * distance);
19         Vector3 f2 =  (transform.position  + (r1 *Vector3.forward) * distance);
20   
21         Debug.DrawLine(transform.position,f1,Color.red);
22         Debug.DrawLine(transform.position,f2,Color.red);
23   
24         Debug.DrawLine(f0,f1,Color.red);
25         Debug.DrawLine(f0,f2,Color.red);
26   
27         Vector3 point = cube.position;
28   
29         if(isINTriangle(point,transform.position,f1,f0) || isINTriangle(point,transform.position,f2,f0) )
30         {
31             Debug.Log("cube in this !!!");
32         }else 
33         {
34             Debug.Log("cube not in this !!!");
35         }
36   
37     }
38   
39     private 
float triangleArea(float
v0x,float
v0y,
float v1x,float
v1y,float
v2x,
float v2y) 
40     {
41         return
Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y
42             - v1x * v0y - v2x * v1y - v0x * v2y) / 2f);
43     }
44   
45     bool
isINTriangle(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2)
46     {
47         float
x = point.x;
48         float
y = point.z;
49   
50         float
v0x = v0.x;
51         float
v0y = v0.z;
52   
53         float
v1x = v1.x;
54         float
v1y = v1.z;
55   
56         float
v2x = v2.x;
57         float
v2y = v2.z;
58   
59         float
t = triangleArea(v0x,v0y,v1x,v1y,v2x,v2y);
60         float
a = triangleArea(v0x,v0y,v1x,v1y,x,y) + triangleArea(v0x,v0y,x,y,v2x,v2y) + triangleArea(x,y,v1x,v1y,v2x,v2y);
61   
62         if
(Mathf.Abs(t - a) <= 0.01f) 
63         {
64             return
true;
65         }else 
66         {
67             return
false;
68         }
69     }
70 }

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

屏幕快照 2013-01-29 下午9.43.41

 

 

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

 

屏幕快照 2013-01-29 下午9.50.11

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

01 using
UnityEngine;
02 using
System.Collections;
03   
04 public
class
MyTest : MonoBehaviour {
05   
06     public
Transform cube;
07   
08     private
float distance = 5f;
09     void
Update () 
10     {
11         Quaternion r= transform.rotation;
12         Vector3 f0 =  (transform.position  + (r *Vector3.forward) * distance);
13         Debug.DrawLine(transform.position,f0,Color.red);
14   
15         Quaternion r0= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y - 30f,transform.rotation.eulerAngles.z);
16         Quaternion r1= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y + 30f,transform.rotation.eulerAngles.z);
17   
18         Vector3 f1 =  (transform.position  + (r0 *Vector3.forward) * distance);
19         Vector3 f2 =  (transform.position  + (r1 *Vector3.forward) * distance);
20   
21         Debug.DrawLine(transform.position,f1,Color.red);
22         Debug.DrawLine(transform.position,f2,Color.red);
23         Debug.DrawLine(f1,f2,Color.red);
24   
25         Vector3 point = cube.position;
26   
27         if(isINTriangle(point,transform.position,f1,f2))
28         {
29             Debug.Log("cube in this !!!");
30         }else 
31         {
32             Debug.Log("cube not in this !!!");
33         }
34   
35     }
36   
37     private 
float triangleArea(float
v0x,float
v0y,
float v1x,float
v1y,float
v2x,
float v2y) 
38     {
39         return
Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y
40             - v1x * v0y - v2x * v1y - v0x * v2y) / 2f);
41     }
42   
43     bool
isINTriangle(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2)
44     {
45         float
x = point.x;
46         float
y = point.z;
47   
48         float
v0x = v0.x;
49         float
v0y = v0.z;
50   
51         float
v1x = v1.x;
52         float
v1y = v1.z;
53   
54         float
v2x = v2.x;
55         float
v2y = v2.z;
56   
57         float
t = triangleArea(v0x,v0y,v1x,v1y,v2x,v2y);
58         float
a = triangleArea(v0x,v0y,v1x,v1y,x,y) + triangleArea(v0x,v0y,x,y,v2x,v2y) + triangleArea(x,y,v1x,v1y,v2x,v2y);
59   
60         if
(Mathf.Abs(t - a) <= 0.01f) 
61         {
62             return
true;
63         }else 
64         {
65             return
false;
66         }
67     }
68 }

 

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

 

屏幕快照 2013-01-30 上午10.59.03

 

代码:

01 using
UnityEngine;
02 using
System.Collections;
03   
04 public
class
MyTest : MonoBehaviour {
05   
06     public
Transform cube;
07   
08     private
float distance = 5f;
09     void
Update () 
10     {
11         Quaternion r= transform.rotation;
12         Vector3 left =  (transform.position  + (r *Vector3.left) * distance);
13         Debug.DrawLine(transform.position,left,Color.red);
14   
15         Vector3 right =  (transform.position  + (r *Vector3.right) * distance);
16         Debug.DrawLine(transform.position,right,Color.red);
17   
18         Vector3 leftEnd = (left  + (r *Vector3.forward) * distance);
19         Debug.DrawLine(left,leftEnd,Color.red);
20   
21         Vector3 rightEnd = (right  + (r *Vector3.forward) * distance);

抱歉!评论已关闭.