zoukankan      html  css  js  c++  java
  • Tanks坦克大战

    创建工程,场景:

      将素材导入,Unity5以上的版本,无需担心素材包的路径问题,中文路径也可以直接导入了,简单方法就是将素材包直接拖到Project面板

      

      游戏所需要的场景在Prefabs里的LevelArt,拖入后,加载很慢,是因为场景在渲染,这时需要去设置Window-lighting,选中Scene,讲auto的勾去掉,就不会自动渲染,其他设置以后再研究。

      

      然后设置Camera中的背景色,选择自己喜欢的颜色,然后调整Camera的位置,适应场景

      

      选择视野,设置为正交

      

    添加坦克,控制坦克前后移动:

      坦克由Tank,DustTrail组成。为坦克添加Box Collider,点击Edit Collider调整Collider大小

      

      为Tank添加Rigidbody,然后将整个Tank制成Prefab。

      代码控制Tank前后移动(TankMovement.cs):为什么用FixedUpdate而不是Update

    public float speed = 5;
    private Rigidbody rigidbody;
    // Use this for initialization
    void Start () {
            rigidbody = this.GetComponent<Rigidbody>();
    }
        
    // Update is called once per frame
    void FixedUpdate () {
            float v = Input.GetAxis("Vertical");
            //速度
            rigidbody.velocity = transform.forward * v * speed;
    }

      运行程序后发现Tank会翻转,导致向上运动,需要设置Rigidbody中的属性,y轴位置是不变的,所以将Y轴定死,Tank是围绕Y轴旋转,并不围绕其他两轴旋转,则定死X,Z轴

      

    控制坦克的旋转

    1 float h = Input.GetAxis("Horizontal");
    2 rigidbody.angularVelocity = transform.up * h * angularSpeed;

     修改坦克控制的灵活性(增加坦克编号)
      因为有两个坦克对战,一个允许使用A,S,W,D控制,一个允许使用方向键控制,则需要增加同样的控制不同的名称定义,在Edit-Project Setting-Input

      

      同理,vertical也可以这样操作。

      然后定义变量number,区分坦克1和坦克2。

    1 float v = Input.GetAxis("VerticalPlayer" + number);
    2 //速度
    3 rigidbody.velocity = transform.forward * v * speed;
    4 float h = Input.GetAxis("HorizontalPlayer" + number);
    5 rigidbody.angularVelocity = transform.up * h * angularSpeed;

     控制坦克子弹的发射

      在Model文件夹中找到Shell,然后为Shell添加Capsule Collider(胶囊碰撞器),然后将其制成Prefab;

      在Tank下创建Empty Gameobject,将其拖到坦克炮筒口,定义一个TankAttack.cs,控制子弹的生成,利用GameObject.Instantiate().

     1 public class TankAttack : MonoBehaviour {
     2 
     3     public GameObject shellPrefab;
     4 
     5     public KeyCode fireKey = KeyCode.Space;
     6 
     7     private Transform firePosition;
     8     // Use this for initialization
     9     void Start () {
    10         firePosition = transform.Find("FirePosition");
    11     }
    12     
    13     // Update is called once per frame
    14     void Update () {
    15         if (Input.GetKeyDown(fireKey))
    16         {
    17             GameObject.Instantiate(shellPrefab, firePosition.position, firePosition.rotation);
    18         }
    19     }
    20 }

     控制炸弹的飞行和爆炸

      子弹的飞行需要速度,速度则需要刚体组件,为Shell添加Rigidbody。在TankAttack.cs中定义子弹的速度,public型,便于在界面上修改调试。

     1 public class TankAttack : MonoBehaviour {
     2 
     3     public GameObject shellPrefab;
     4 
     5     public KeyCode fireKey = KeyCode.Space;
     6 
     7     private Transform firePosition;
     8 
     9     public float shellSpeed = 15;
    10     // Use this for initialization
    11     void Start () {
    12         firePosition = transform.Find("FirePosition");
    13     }
    14     
    15     // Update is called once per frame
    16     void Update () {
    17         if (Input.GetKeyDown(fireKey))
    18         {
    19             GameObject go = GameObject.Instantiate(shellPrefab, firePosition.position, firePosition.rotation) as GameObject;
    20             go.GetComponent<Rigidbody>().velocity = go.transform.forward * shellSpeed;
    21         }
    22     }
    23 }

       子弹发射后会存在很多Prefab,占内存,需要销毁,使用Destroy(),为Shell创建Shell.cs组件,子弹爆炸的动画效果,需要ShellExplosion这个prefab。这个Prefab勾选Play on awake,表示在实例化成功时即开始运行动画效果。

      

     1 public class Shell : MonoBehaviour {
     2 
     3     public GameObject shellExplosionPrefab;
     4     // Use this for initialization
     5     void Start () {
     6     
     7     }
     8     
     9     // Update is called once per frame
    10     void Update () {
    11 
    12     }
    13 
    14     void OnTriggerEnter(Collider col) {
    15         GameObject.Instantiate(shellExplosionPrefab, transform.position, transform.rotation);  
    16         GameObject.Destroy(this.gameObject);
    17     }
    18 }

      然后爆炸的动画Prefab没有自动销毁,为ShellExplosion创建组件DestoryForTime.cs,在Start方法中就调用Destory()方法销毁,但不是立即销毁,而是在一定时间以后。然后该动画的Duration = 1.5s,所以设置为1.5秒以后销毁。

     1 public class DestoryForTime : MonoBehaviour {
     2 
     3     public float time;
     4     // Use this for initialization
     5     void Start () {
     6         Destroy(this.gameObject, time);
     7     }
     8     
     9     // Update is called once per frame
    10     void Update () {
    11     
    12     }
    13 }

     控制炸弹对坦克的伤害

      为Tank的Prefab添加tag名为"Tank",在Shell.cs中使用SendMessage()方法,在碰撞后触发方法中参数的方法。

    1 if (col.tag == "Tank")
    2 {
    3       col.SendMessage("TankDamage");
    4 }

      为Tank创建组件TankHealth.cs。这里涉及使用tank爆炸的动画Prefab,TankExplosion,注意里面的方法必须与Shell中SendMessage()方法中的参数相同。

     1 public class TankHealth : MonoBehaviour {
     2 
     3     public int hp = 100;
     4     public GameObject tankExplosion;
     5     // Use this for initialization
     6     void Start () {
     7     
     8     }
     9     
    10     // Update is called once per frame
    11     void Update () {
    12 
    13     }
    14 
    15     void TankDamage()
    16     {
    17         if (hp <= 0) return;
    18         hp -= Random.Range(10, 20);
    19         if (hp <= 0)
    20         {
    21             GameObject.Instantiate(tankExplosion, transform.position + Vector3.up, transform.rotation);
    22             Destroy(this.gameObject);
    23         }
    24     }
    25 }

      然后创建第二个坦克,注意修改键盘按键。

      修改坦克的外观

    控制相机视野的跟随

      为Camera创建FollowTarget.cs  

      这里是两个Gameobject,则跟随物体移动,取两者中点与相机(Camera)的距离保持不变:offset = this.transform.position - (player1.position + player2.position) / 2

      控制视野的大小:相机随两物体中点的变化在移动,渐渐的会失去某一个物体的视野,由于我们相机的Projection选择的是Orthographic,所以可以控制其Size属性,使其Size和两坦克之间的距离的比例保持不变,这样当距离变大时,Size也变大,视野就变大,两个坦克就会一直在视野中。我们一开始的Size定为10,两个坦克之间的距离是16,10/16 = 0.625,比例是定值。运动过程中求两物体间距离,使用Vector3.Distance().

      然后这里还存在一个问题,当某个坦克被消灭时,则某个物体的position就取不到,是空指针,这时我们继续去算Distance或者中点,就会报错,需要加上null的判断。

     1 public class FollowTarget : MonoBehaviour {
     2 
     3     public Transform player1;
     4     public Transform player2;
     5 
     6     private Vector3 offset;
     7     private Camera camera;
     8     // Use this for initialization
     9     void Start () {
    10         offset = this.transform.position - (player1.position + player2.position) / 2;
    11         camera = GetComponent<Camera>();
    12     }
    13     
    14     // Update is called once per frame
    15     void Update () {
    16         if (player1 == null || player2 == null) return;
    17         transform.position = (player1.position + player2.position) / 2 + offset;
    18         float distance = Vector3.Distance(player1.position, player2.position);
    19         float size = distance * 0.625f;
    20         camera.orthographicSize = size;
    21     }
    22 }

    给游戏添加音效

      添加音乐两种方法:1.为物体添加AudioSource组件,如果不需要Awake时播放,就把勾去掉,从代码里使用AudioSource.play();2.代码里定义一个AudioClip,然后使用AudioSource.PlayClipAtPoint();

      背景音乐:创建一个空物体,命名为GameManager,添加AudioSource组件。然后添加音乐,勾选循环播放即可。

      坦克爆炸的声音:在爆炸的时候播放而不是在Awake的时候播放,在代码里添加;

    public AudioClip tankExplosionAudio;
    
    AudioSource.PlayClipAtPoint(tankExplosionAudio, transform.position);

      添加子弹打出的声音:在TankAttack.cs中添加;

    public AudioClip shootAudio;
    
    AudioSource.PlayClipAtPoint(shootAudio, transform.position);

      添加子弹爆炸的声音:在Shell.cs中添加;

    public AudioClip shellExplosionAudio;
    
    AudioSource.PlayClipAtPoint(shellExplosionAudio, transform.position);

     给坦克添加音效

      因为坦克声音一直存在,所以可以通过添加组件AudioSource,然后用play()来使用。坦克有两种状态,行走和停止,要切换声音,在TankMovement.cs中通过代码控制。

     1 void FixedUpdate () {
     2         float v = Input.GetAxis("VerticalPlayer" + number);
     3         //速度
     4         rigidbody.velocity = transform.forward * v * speed;
     5         float h = Input.GetAxis("HorizontalPlayer" + number);
     6         rigidbody.angularVelocity = transform.up * h * angularSpeed;
     7         //tank声音切换
     8         if (Mathf.Abs(v) > 0.1 || Mathf.Abs(h) > 0.1)
     9         {
    10             audio.clip = drivingAudio;
    11             if(audio.isPlaying == false)
    12                 audio.Play();
    13         }
    14         else
    15         {
    16             audio.clip = idelAudio;
    17             if (audio.isPlaying == false)
    18                 audio.Play();
    19         }
    20 }

     给坦克添加血条控制

      利用UGUI的Slider,但是Slider是长条进度条,要做成圆形,可以去Sprite的文件中利用Health Wheel。系统的Slider,删除Handle Slide Area,这是进度条的拖动点,不需要。将Slider的Background的Source Image设置成Health Wheel,将Fill Area中的Fill的Source Image也设置成Health Wheel。然后修改Slider的大小,改成40*40;然后修改滑动方式,修改成360度的,修改Fill的Image Type属性,改成Filled。为了让两个Health Wheel重叠,设置Background、Fill Area、Fill的Stretch,选择上下左右填充。然后将Canvas的Render Mode设置成World Space(设置成世界空间的原因是为了让Main Camara渲染)。将Cavas整体移动到Tank中。

      修改Canvas的大小,发现并没有变化,是因为Slider并没有在Stretch中选择四周填充。,将Slider调整到与地面平行,适当的大小。

     1 void TankDamage()
     2     {
     3         if (hp <= 0) return;
     4         hp -= Random.Range(10, 20);
     5         hpSlider.value = (float)hp / hpTotal;
     6         if (hp <= 0)
     7         {
     8             //没血了,播放爆炸的声音
     9             AudioSource.PlayClipAtPoint(tankExplosionAudio, transform.position);
    10             GameObject.Instantiate(tankExplosion, transform.position + Vector3.up, transform.rotation);
    11             Destroy(this.gameObject);
    12         }
    13     }
  • 相关阅读:
    理解区块链背后的Merkle Tree
    黑科技!当会爬虫的Python遇上会画图的FineBI……
    PlayFramework 1.x 生产环境部署 源码编译
    特别推荐:系统性能提升优先法宝 | 缓存应用实践
    Python爬虫入门教程 38-100 教育部高校名单数据爬虫 scrapy
    BI分析工具选型:从PowerBI到FineBI的9个理由!
    集群的定义以及类别定义
    python cx_oracle 绑定变量
    [故障解决]图文:windows apache无法启用 端口被占用
    设计模式之抽象工厂模式
  • 原文地址:https://www.cnblogs.com/kesteler/p/5625268.html
Copyright © 2011-2022 走看看