代码改变世界

Unity3D之飞机游戏追踪导弹制作

2015-12-07 18:51  阿诚de窝  阅读(7772)  评论(0编辑  收藏  举报

最近开发完成一款打飞机的游戏,记录一下制作追踪导弹的方法,最开始在网上找到的资料制作出来的追踪导弹都不够真实,主要的问题是没有对导弹进行一个阀值处理,导弹每帧都始终会面向目标,而不是按照一定的角度进行旋转,导致无法躲避跟踪导弹,下面我来说一下更加真实的跟踪导弹的制作方法。

拖拽

首先,我的Demo里有两个小飞机,一个是主角,一个是敌机,有一个需求就是这两个飞机可以通过鼠标进行拖拽,所以先给出拖拽的脚本,直接绑定即可,当然记得给GameObject添加一个BoxCollder。

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 /// <summary>
 5 /// 拖拽脚本.
 6 /// </summary>
 7 public class DragAndDrop : MonoBehaviour
 8 {
 9     bool isCatched = false;
10 
11     void Update()
12     {
13         if(Input.GetMouseButtonDown(0))
14         {
15             //根据鼠标位置创建一条垂直于屏幕的射线
16             Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
17             //保存射线信息的结构体
18             RaycastHit hit;
19             //对射线进行碰撞, 如果存在碰撞
20             if(Physics.Raycast(ray, out hit))
21             {
22                 //碰撞到当前对象时
23                 if(hit.collider.gameObject == this.gameObject)
24                 {
25                     //标记为抓取状态
26                     isCatched = true;
27                 }
28             }
29         }
30 
31         if(Input.GetMouseButtonUp(0))
32         {
33             //取消抓取状态
34             isCatched = false;
35         }
36 
37         if(isCatched)
38         {
39             //获取鼠标点在场景中的位置
40             Vector3 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
41             pos.z = 0;
42             //设置位置
43             this.transform.position = pos;
44         }
45     }
46 }

管理类

我使用UGUI添加了一个发射导弹的按钮,需要一个管理类来管理这部分的逻辑:

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 /// <summary>
 5 /// 控制脚本.
 6 /// </summary>
 7 public class TrackDemoScript : MonoBehaviour
 8 {
 9     public GameObject player;
10 
11     public GameObject enemy;
12 
13     /// <summary>
14     /// 开火.
15     /// </summary>
16     public void Fire()
17     {
18         GameObject go = Resources.Load<GameObject>("Prefab/Bullet");
19         GameObject bullet = Instantiate(go, player.transform.position, Quaternion.identity) as GameObject;
20         bullet.GetComponent<BulletScript>().target = enemy;
21     }
22 }

导弹被我制作为了一个预制件。

导弹逻辑

最重要的就是阀值了,我规定了每帧允许旋转的一个最大值,保证模拟出现实世界的效果,导弹要转弯肯定是画出一个弧线而不是马上掉头的。

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 /// <summary>
 5 /// 跟踪导弹脚本.
 6 /// </summary>
 7 public class BulletScript : MonoBehaviour
 8 {
 9     /// <summary>
10     /// 每秒最大可旋转的角度.
11     /// </summary>
12     private const float MAX_ROTATION = 90;
13     
14     /// <summary>
15     /// 每帧最大可旋转的角度.
16     /// </summary>
17     private static float MAX_ROTATION_FRAME = MAX_ROTATION / ((float) (Application.targetFrameRate == -1 ? 60 : Application.targetFrameRate));
18 
19     /// <summary>
20     /// 攻击目标.
21     /// </summary>
22     public GameObject target;
23 
24     void Start()
25     {
26     }
27     
28     void Update()
29     {
30         //转向目标
31         float dx = target.transform.position.x - this.transform.position.x;
32         float dy = target.transform.position.y - this.transform.position.y;
33         float rotationZ = Mathf.Atan2(dy, dx) * 180 / Mathf.PI;
34         //得到最终的角度并且确保在 [0, 360) 这个区间内
35         rotationZ -= 90;
36         rotationZ = MakeSureRightRotation(rotationZ);
37         //获取增加的角度
38         float originRotationZ = MakeSureRightRotation(this.transform.eulerAngles.z);
39         float addRotationZ = rotationZ - originRotationZ;
40         //超过 180 度需要修改为负方向的角度
41         if(addRotationZ > 180)
42         {
43             addRotationZ -= 360;
44         }
45         //不超过每帧最大可旋转的阀值
46         addRotationZ = Mathf.Max(-MAX_ROTATION_FRAME, Mathf.Min(MAX_ROTATION_FRAME, addRotationZ));
47         //应用旋转
48         this.transform.eulerAngles = new Vector3(0, 0, this.transform.eulerAngles.z + addRotationZ);
49         //移动
50         this.transform.Translate(new Vector3(0, 2.0f * Time.deltaTime, 0));
51     }
52 
53     /// <summary>
54     /// 确保角度在 [0, 360) 这个区间内.
55     /// </summary>
56     /// <param name="rotation">任意数值的角度.</param>
57     /// <returns>对应的在 [0, 360) 这个区间内的角度.</returns>
58     private float MakeSureRightRotation(float rotation)
59     {
60         rotation += 360;
61         rotation %= 360;
62         return rotation;
63     }
64 }

运行即可查看效果。

源码下载

http://pan.baidu.com/s/1qWBsvSg