2D坦克大戰 像素版git
遊戲規則: github
玩家經過上、下、左、右移動坦克,空格鍵發射子彈數組
敵人AI出身時朝向己方大本營(未防止遊戲快速結束,心臟上方三個單位障礙物設爲剛體) dom
當玩家被擊殺次數>=3 或 心臟被子彈擊穿 從新加載遊戲場景ide
控制遊戲每4秒發射一顆子彈(可本身作修改) 工具
遊戲項目已託管到Github上 傳送門 優化
(文章最下邊有遊戲腳本)動畫
場景搭建this
設置Main Camera攝像頭參數spa
遊戲中製做預製體與動畫
建立一個Cube做爲參照,Cube長寬高都爲1m
建立一個Player1_0做爲玩家
將Player1_0製做成預製體
製做遊戲磚塊、鋼鐵、草叢、基地預製體
建立遊戲物體出生動畫Animation
快速建立動畫:點擊第一張圖片->按住Shift->點擊最後一張圖片
保存好後場景出現Born_0動畫,修改scale大小爲3 3 3
製做坦克出生無敵、坦克爆炸、河流特效
動畫大小與預製體適配
控制玩家的移動
添加Player.cs腳本,綁定到Player玩家坦克上
默認移動速度
public float moveSpeed = 3;
監聽玩家水平軸輸入
float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World);
監聽玩家垂直軸輸入
float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World);
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { public float moveSpeed = 3; // Use this for initialization void Start () { } // Update is called once per frame void Update () { //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World); //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World); } }
控制圖片的移動和切換
製做坦克渲染
添加精靈數組的引用
private SpriteRenderer sr; public Sprite[] tankSprite;
(上 右 下 左)
玩家按上下左右控制坦克方向的移動
//監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World); if (h < 0) { sr.sprite = tankSprite[3]; }else if (h>0) { sr.sprite = tankSprite[1]; } //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; } else if (v > 0) { sr.sprite = tankSprite[0]; }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { public float moveSpeed = 3; private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World); if (h < 0) { sr.sprite = tankSprite[3]; }else if (h>0) { sr.sprite = tankSprite[1]; } //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; } else if (v > 0) { sr.sprite = tankSprite[0]; } } }
碰撞器的添加
碰撞檢測
兩個物體都有碰撞器
一個物體上掛載剛體組件
給玩家Player添加2D剛體和2D碰撞器
剛體的Gravity Scale設置爲0,取消重力因素的影響
給Barriar、Wall、River、Heart添加Box Collider 2D碰撞器
發現坦克方向座標軸會改變,在Rigidbody 2D中Constraints下的Freeze Rotation Z 進行綁定,當它碰撞到物體時座標不發生偏移
解決抖動問題
使用private void FixedUpdate()
FixedUpdate () 和 Update ()
同:當MonoBehaviour啓用時,其在每一幀被調用。都是用來更新的
異:Update()每一幀的時間不固定,即第一幀與第二幀的時間t1和第三幀與第四幀的時間t2不必定相同。FixedUpdate()每幀與每幀之間相差的時間是固定的.
Update受當前渲染的物體影響,這與當前場景中正在被渲染的物體有關(好比人物的面數,個數等),有時快有時慢,幀率會變化,Update被調用的時間間隔就會發生變化。可是FixedUpdate則不受幀率的變化影響,它是以固定的時間間隔來被調用。
因此一些物理屬性的更新操做應該放在FxiedUpdate中操做,好比Force,Collider,Rigidbody等。外設的操做也是,好比說鍵盤或者鼠標的輸入輸出Input,由於這樣GameObject的物理表現的更平滑,更接近現實。
FixedUpdate的時間間隔能夠在項目設置中更改,Edit->Project Setting->time 找到Fixed timestep。就能夠修改了
//監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.fixedDeltaTime,Space.World); //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);
FixedUpdate()方法留空就行
private void FixedUpdate() { }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { public float moveSpeed = 3; private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.fixedDeltaTime,Space.World); if (h < 0) { sr.sprite = tankSprite[3]; }else if (h>0) { sr.sprite = tankSprite[1]; } //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; } else if (v > 0) { sr.sprite = tankSprite[0]; } } // private void FixedUpdate() { } }
解決玩家按方向鍵左右的同時按上下
在監聽玩家垂直軸輸入後對v方向按鍵進行判斷,若是爲0則在Update()中直接返回
float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; } else if (v > 0) { sr.sprite = tankSprite[0]; } if(v!=0) { return; } //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.fixedDeltaTime,Space.World); if (h < 0) { sr.sprite = tankSprite[3]; }else if (h>0) { sr.sprite = tankSprite[1]; }
整理一下Player.cs腳本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { //屬性值 public float moveSpeed = 3; //引用 private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { } private void FixedUpdate() { Move(); } //坦克的移動方法 private void Move() { //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; } else if (v > 0) { sr.sprite = tankSprite[0]; } if (v != 0) { return; } //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); if (h < 0) { sr.sprite = tankSprite[3]; } else if (h > 0) { sr.sprite = tankSprite[1]; } } }
2D渲染層級
設置遊戲物體的層級
坦克的攻擊
坦克的攻擊方法
private void Attack() { if(Input.GetKeyDown(KeyCode.Space)) { Instantiate(bullectPrefab,transform.position,transform.rotation); } }
private void FixedUpdate() { Move(); Attack(); }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { //屬性值 public float moveSpeed = 3; //引用 private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 public GameObject bullectPrefab; // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { } private void FixedUpdate() { Move(); Attack(); } //坦克的攻擊方法 private void Attack() { if(Input.GetKeyDown(KeyCode.Space)) { Instantiate(bullectPrefab,transform.position,transform.rotation); } } //坦克的移動方法 private void Move() { //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; } else if (v > 0) { sr.sprite = tankSprite[0]; } if (v != 0) { return; } //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); if (h < 0) { sr.sprite = tankSprite[3]; } else if (h > 0) { sr.sprite = tankSprite[1]; } } }
子彈的朝向和移動
經過按鍵V和H來判斷子彈旋轉的角度
定義子彈旋轉的角度
private Vector3 bullectEulerAugles;
子彈參數的角度:當前坦克的角度+子彈應該旋轉的角度
Instantiate(bullectPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bullectEulerAugles));
---恢復內容結束---
未完~
完成時會有完整項目展現
場景搭建
設置Main Camera攝像頭參數
遊戲中製做預製體與動畫
建立一個Cube做爲參照,Cube長寬高都爲1m
建立一個Player1_0做爲玩家
將Player1_0製做成預製體
製做遊戲磚塊、鋼鐵、草叢、基地預製體
建立遊戲物體出生動畫Animation
快速建立動畫:點擊第一張圖片->按住Shift->點擊最後一張圖片
保存好後場景出現Born_0動畫,修改scale大小爲3 3 3
製做坦克出生無敵、坦克爆炸、河流特效
動畫大小與預製體適配
控制玩家的移動
添加Player.cs腳本,綁定到Player玩家坦克上
默認移動速度
public float moveSpeed = 3;
監聽玩家水平軸輸入
float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World);
監聽玩家垂直軸輸入
float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World);
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { public float moveSpeed = 3; // Use this for initialization void Start () { } // Update is called once per frame void Update () { //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World); //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World); } }
控制圖片的移動和切換
製做坦克渲染
添加精靈數組的引用
private SpriteRenderer sr; public Sprite[] tankSprite;
(上 右 下 左)
玩家按上下左右控制坦克方向的移動
//監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World); if (h < 0) { sr.sprite = tankSprite[3]; }else if (h>0) { sr.sprite = tankSprite[1]; } //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; } else if (v > 0) { sr.sprite = tankSprite[0]; }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { public float moveSpeed = 3; private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World); if (h < 0) { sr.sprite = tankSprite[3]; }else if (h>0) { sr.sprite = tankSprite[1]; } //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; } else if (v > 0) { sr.sprite = tankSprite[0]; } } }
碰撞器的添加
碰撞檢測
兩個物體都有碰撞器
一個物體上掛載剛體組件
給玩家Player添加2D剛體和2D碰撞器
剛體的Gravity Scale設置爲0,取消重力因素的影響
給Barriar、Wall、River、Heart添加Box Collider 2D碰撞器
發現坦克方向座標軸會改變,在Rigidbody 2D中Constraints下的Freeze Rotation Z 進行綁定,當它碰撞到物體時座標不發生偏移
解決抖動問題
使用private void FixedUpdate()
FixedUpdate () 和 Update ()
同:當MonoBehaviour啓用時,其在每一幀被調用。都是用來更新的
異:Update()每一幀的時間不固定,即第一幀與第二幀的時間t1和第三幀與第四幀的時間t2不必定相同。FixedUpdate()每幀與每幀之間相差的時間是固定的.
Update受當前渲染的物體影響,這與當前場景中正在被渲染的物體有關(好比人物的面數,個數等),有時快有時慢,幀率會變化,Update被調用的時間間隔就會發生變化。可是FixedUpdate則不受幀率的變化影響,它是以固定的時間間隔來被調用。
因此一些物理屬性的更新操做應該放在FxiedUpdate中操做,好比Force,Collider,Rigidbody等。外設的操做也是,好比說鍵盤或者鼠標的輸入輸出Input,由於這樣GameObject的物理表現的更平滑,更接近現實。
FixedUpdate的時間間隔能夠在項目設置中更改,Edit->Project Setting->time 找到Fixed timestep。就能夠修改了
//監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.fixedDeltaTime,Space.World); //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);
FixedUpdate()方法留空就行
private void FixedUpdate() { }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { public float moveSpeed = 3; private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.fixedDeltaTime,Space.World); if (h < 0) { sr.sprite = tankSprite[3]; }else if (h>0) { sr.sprite = tankSprite[1]; } //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; } else if (v > 0) { sr.sprite = tankSprite[0]; } } // private void FixedUpdate() { } }
解決玩家按方向鍵左右的同時按上下
在監聽玩家垂直軸輸入後對v方向按鍵進行判斷,若是爲0則在Update()中直接返回
float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; } else if (v > 0) { sr.sprite = tankSprite[0]; } if(v!=0) { return; } //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.fixedDeltaTime,Space.World); if (h < 0) { sr.sprite = tankSprite[3]; }else if (h>0) { sr.sprite = tankSprite[1]; }
整理一下Player.cs腳本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { //屬性值 public float moveSpeed = 3; //引用 private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { } private void FixedUpdate() { Move(); } //坦克的移動方法 private void Move() { //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; } else if (v > 0) { sr.sprite = tankSprite[0]; } if (v != 0) { return; } //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); if (h < 0) { sr.sprite = tankSprite[3]; } else if (h > 0) { sr.sprite = tankSprite[1]; } } }
2D渲染層級
設置遊戲物體的層級
坦克的攻擊
坦克的攻擊方法
private void Attack() { if(Input.GetKeyDown(KeyCode.Space)) { Instantiate(bullectPrefab,transform.position,transform.rotation); } }
private void FixedUpdate() { Move(); Attack(); }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { //屬性值 public float moveSpeed = 3; //引用 private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 public GameObject bullectPrefab; // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { } private void FixedUpdate() { Move(); Attack(); } //坦克的攻擊方法 private void Attack() { if(Input.GetKeyDown(KeyCode.Space)) { Instantiate(bullectPrefab,transform.position,transform.rotation); } } //坦克的移動方法 private void Move() { //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; } else if (v > 0) { sr.sprite = tankSprite[0]; } if (v != 0) { return; } //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); if (h < 0) { sr.sprite = tankSprite[3]; } else if (h > 0) { sr.sprite = tankSprite[1]; } } }
子彈的朝向和移動
經過按鍵V和H來判斷子彈旋轉的角度
定義子彈旋轉的角度
private Vector3 bullectEulerAugles;
子彈參數的角度:當前坦克的角度+子彈應該旋轉的角度
Instantiate(bullectPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bullectEulerAugles));
private void Attack() { if(Input.GetKeyDown(KeyCode.Space)) { //子彈參數的角度:當前坦克的角度+子彈應該旋轉的角度 Instantiate(bullectPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bullectEulerAugles)); timeVal = 0; } }
給子彈添加方向速度
public float moveSpeed = 10;
給子彈添加判斷是不是友軍
public bool isPlayerBullect;
void Update () { transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World); }
添加子彈攻擊CD間隔
if (timeVal>=0.4f) { //間隔大於0.4的時候纔有攻擊效果 Attack(); } else { timeVal += Time.deltaTime; }
給組件添加標籤
給子彈添加碰撞體和觸發器
添加Heart.cs腳本,當Heart心臟被子彈攻擊時,切換死亡圖片
private SpriteRenderer sr; public Sprite BrokenSprite; // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); }
添加Heart.cs心臟死亡時方法
private void Die() { sr.sprite = BrokenSprite; }
添加Explosion.cs腳本
當坦克銷燬時觸發腳本
public class Explosion : MonoBehaviour { // Use this for initialization void Start () { //坦克銷燬後0.167秒銷燬爆炸特效 Destroy(gameObject,0.167f); } // Update is called once per frame void Update () { } }
子彈觸發碰撞檢測
當子彈碰撞到物體時觸發OnTriggerEnter2D(Collider2D collision)方法
子彈碰到「Tank」判斷是不是友軍,不是的話擊毀本身
子彈碰到"Wall"時,銷燬子彈自身
子彈碰到"Heart"時,觸發基地死亡方法
子彈碰到"Barrier"剛體時,銷燬子彈
private void OnTriggerEnter2D(Collider2D collision) { switch(collision.tag) { case "Tank": if(!isPlayerBullect) { collision.SendMessage("Die"); } break; case "Heart": collision.SendMessage("Die"); Destroy(gameObject); break; case "Enemy": break; case "Wall": //銷燬自身和牆 Destroy(collision.gameObject); Destroy(gameObject); break; case "Barrier": Destroy(gameObject); break; default: break; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { //屬性值 public float moveSpeed = 3; private Vector3 bullectEulerAugles; public float timeVal; private float defendTimeVal=1; private bool isDefended=true; //引用 private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 public GameObject bullectPrefab; public GameObject explosionPrefab; public GameObject defendEffectPrefab; // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //保護是否處於無敵狀態 if(isDefended) { defendEffectPrefab.SetActive(true); defendTimeVal -= Time.deltaTime; if (defendTimeVal<=0) { isDefended = false; defendEffectPrefab.SetActive(false); } } //攻擊的CD if (timeVal>=0.4f) { //間隔大於0.4的時候纔有攻擊效果 Attack(); } else { timeVal += Time.deltaTime; } } private void FixedUpdate() { Move(); } //坦克的攻擊方法 private void Attack() { if(Input.GetKeyDown(KeyCode.Space)) { //子彈參數的角度:當前坦克的角度+子彈應該旋轉的角度 Instantiate(bullectPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bullectEulerAugles)); timeVal = 0; } } //坦克的移動方法 private void Move() { //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; bullectEulerAugles = new Vector3(0, 0, -180); } else if (v > 0) { sr.sprite = tankSprite[0]; bullectEulerAugles = new Vector3(0, 0, 0); } if (v != 0) { return; } //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); if (h < 0) { sr.sprite = tankSprite[3]; bullectEulerAugles = new Vector3(0, 0, 90); } else if (h > 0) { sr.sprite = tankSprite[1]; bullectEulerAugles = new Vector3(0, 0, -90); } } //坦克的死亡方法 private void Die() { if(isDefended) { return; } //產生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation); //死亡 Destroy(gameObject); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Explosion : MonoBehaviour { // Use this for initialization void Start () { //坦克銷燬後0.167秒銷燬爆炸特效 Destroy(gameObject,0.167f); } // Update is called once per frame void Update () { } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Heart : MonoBehaviour { private SpriteRenderer sr; public Sprite BrokenSprite; // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } private void Die() { sr.sprite = BrokenSprite; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Bullect : MonoBehaviour { public float moveSpeed = 10; public bool isPlayerBullect; // Use this for initialization void Start () { } // Update is called once per frame void Update () { transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World); } //子彈觸發碰撞檢測 private void OnTriggerEnter2D(Collider2D collision) { switch(collision.tag) { case "Tank": if(!isPlayerBullect) { collision.SendMessage("Die"); } break; case "Heart": collision.SendMessage("Die"); Destroy(gameObject); break; case "Enemy": break; case "Wall": //銷燬自身和牆 Destroy(collision.gameObject); Destroy(gameObject); break; case "Barrier": Destroy(gameObject); break; default: break; } } }
敵人的製做
Ctrl+D一份玩家,修改圖片渲染,製做敵人
添加敵人腳本Enemy.cs
玩家的移動和敵人的移動差很少,把Player.cs腳本中內容複製到Enemy.cs當中
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Enemy : MonoBehaviour { //屬性值 public float moveSpeed = 3; private Vector3 bullectEulerAugles; public float timeVal; private float defendTimeVal = 1; private bool isDefended = true; //引用 private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 public GameObject bullectPrefab; public GameObject explosionPrefab; public GameObject defendEffectPrefab; // Use this for initialization void Start() { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update() { //保護是否處於無敵狀態 if (isDefended) { defendEffectPrefab.SetActive(true); defendTimeVal -= Time.deltaTime; if (defendTimeVal <= 0) { isDefended = false; defendEffectPrefab.SetActive(false); } } //攻擊的CD if (timeVal >= 0.4f) { //間隔大於0.4的時候纔有攻擊效果 Attack(); } else { timeVal += Time.deltaTime; } } private void FixedUpdate() { Move(); } //坦克的攻擊方法 private void Attack() { if (Input.GetKeyDown(KeyCode.Space)) { //子彈參數的角度:當前坦克的角度+子彈應該旋轉的角度 Instantiate(bullectPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bullectEulerAugles)); timeVal = 0; } } //坦克的移動方法 private void Move() { //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; bullectEulerAugles = new Vector3(0, 0, -180); } else if (v > 0) { sr.sprite = tankSprite[0]; bullectEulerAugles = new Vector3(0, 0, 0); } if (v != 0) { return; } //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); if (h < 0) { sr.sprite = tankSprite[3]; bullectEulerAugles = new Vector3(0, 0, 90); } else if (h > 0) { sr.sprite = tankSprite[1]; bullectEulerAugles = new Vector3(0, 0, -90); } } //坦克的死亡方法 private void Die() { if (isDefended) { return; } //產生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation); //死亡 Destroy(gameObject); } }
(由於敵人沒有出生無敵3s,運行時無敵預製體defendEffectPrefab會出現報空)
添加基地死亡時動畫
public GameObject explosionPrefab;
private void Die() { sr.sprite = BrokenSprite; Instantiate(explosionPrefab,transform.position,transform.rotation); }
(關閉項目後爆炸腳本失活了,最後的時候再作一個補上)
添加一個玩家出生時腳本Born.cs
延時玩家出生和死亡動畫
public GameObject playerPrefab; // Use this for initialization void Start () { Invoke("BornTank",1f); Destroy(gameObject,1f); } private void BornTank() { Instantiate(playerPrefab,transform.position,Quaternion.identity); }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Born : MonoBehaviour { public GameObject playerPrefab; // Use this for initialization void Start () { Invoke("BornTank",0.8f); Destroy(gameObject,0.8f); } // Update is called once per frame void Update () { } private void BornTank() { Instantiate(playerPrefab,transform.position,Quaternion.identity); } }
製做大坦克和小坦克,添加坦克方向變化時改變坦克方向圖片
坦克改變方向順序按上、右、下、左進行添加
小敵人同打敵人設置當坦克方向改變時切換自身圖片
將大敵人和小敵人設置成預製體
小敵人速度調大一些,改成5
編寫Born.cs腳本判斷是否產生敵人
public bool createPlay;
private void BornTank() { if (createPlay) { Instantiate(playerPrefab, transform.position, Quaternion.identity); } else { int num = Random.Range(0, 2); Instantiate(enemyPrefabList[num], transform.position, Quaternion.identity); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Born : MonoBehaviour { public GameObject playerPrefab; public GameObject[] enemyPrefabList; //判斷是否產生敵人 public bool createPlay; // Use this for initialization void Start () { Invoke("BornTank",1f); Destroy(gameObject,1f); } private void Update() { } private void BornTank() { if (createPlay) { Instantiate(playerPrefab, transform.position, Quaternion.identity); } else { int num = Random.Range(0, 2); Instantiate(enemyPrefabList[num], transform.position, Quaternion.identity); } } }
編寫敵人AI
子彈間3s攻擊一次
void Update() { //攻擊的時間間隔 if (timeVal >= 0.3f) { //間隔大於0.4的時候纔有攻擊效果 Attack(); } else { timeVal += Time.deltaTime; } }
//坦克的攻擊方法 private void Attack() { //子彈參數的角度:當前坦克的角度+子彈應該旋轉的角度 Instantiate(bullectPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bullectEulerAugles)); timeVal = 0; }
坦克的移動不須要按下上下左右鍵盤,只須要管理V和H的值對敵人AI進行方向的控制
定義兩個計時器
public float timeVal; public float timeValChangeDirection;
修改敵人移動的方法
private void Move() { if(timeValChangeDirection>=4) { int num = Random.Range(0,8); if(num>5) { v = -1; h = 0; }else if (num == 0) { v = 1; h = 0; }else if (num > 0 && num <= 2) { h = -1; v = 0; }else if (num > 2 && num <= 4) { h = 1; v = 0; } timeValChangeDirection = 0; } else { timeValChangeDirection += Time.fixedDeltaTime; } //監聽玩家垂直軸輸入 transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; bullectEulerAugles = new Vector3(0, 0, -180); } else if (v > 0) { sr.sprite = tankSprite[0]; bullectEulerAugles = new Vector3(0, 0, 0); } if (v != 0) { return; } //監聽玩家水平軸輸入 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); if (h < 0) { sr.sprite = tankSprite[3]; bullectEulerAugles = new Vector3(0, 0, 90); } else if (h > 0) { sr.sprite = tankSprite[1]; bullectEulerAugles = new Vector3(0, 0, -90); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Enemy : MonoBehaviour { //屬性值 public float moveSpeed = 3; private Vector3 bullectEulerAugles; private float v; private float h; //引用 private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 public GameObject bullectPrefab; public GameObject explosionPrefab; //計時器 public float timeVal; public float timeValChangeDirection=4; // Use this for initialization void Start() { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update() { //攻擊的時間間隔 if (timeVal >= 0.3f) { //間隔大於0.4的時候纔有攻擊效果 Attack(); } else { timeVal += Time.deltaTime; } } private void FixedUpdate() { Move(); } //坦克的攻擊方法 private void Attack() { //子彈參數的角度:當前坦克的角度+子彈應該旋轉的角度 Instantiate(bullectPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bullectEulerAugles)); timeVal = 0; } //坦克的移動方法 private void Move() { if(timeValChangeDirection>=4) { int num = Random.Range(0,8); if(num>5) { v = -1; h = 0; }else if (num == 0) { v = 1; h = 0; }else if (num > 0 && num <= 2) { h = -1; v = 0; }else if (num > 2 && num <= 4) { h = 1; v = 0; } timeValChangeDirection = 0; } else { timeValChangeDirection += Time.fixedDeltaTime; } //監聽玩家垂直軸輸入 transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; bullectEulerAugles = new Vector3(0, 0, -180); } else if (v > 0) { sr.sprite = tankSprite[0]; bullectEulerAugles = new Vector3(0, 0, 0); } if (v != 0) { return; } //監聽玩家水平軸輸入 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); if (h < 0) { sr.sprite = tankSprite[3]; bullectEulerAugles = new Vector3(0, 0, 90); } else if (h > 0) { sr.sprite = tankSprite[1]; bullectEulerAugles = new Vector3(0, 0, -90); } } //坦克的死亡方法 private void Die() { //產生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation); //死亡 Destroy(gameObject); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Bullect : MonoBehaviour { public float moveSpeed = 10; public bool isPlayerBullect; // Use this for initialization void Start () { } // Update is called once per frame void Update () { transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World); } //子彈觸發碰撞檢測 private void OnTriggerEnter2D(Collider2D collision) { switch(collision.tag) { case "Tank": if(!isPlayerBullect) { collision.SendMessage("Die"); } Destroy(gameObject); break; case "Heart": collision.SendMessage("Die"); Destroy(gameObject); break; case "Enemy": if(isPlayerBullect) { collision.SendMessage("Die"); } Destroy(gameObject); break; case "Wall": //銷燬自身和牆 Destroy(collision.gameObject); Destroy(gameObject); break; case "Barrier": Destroy(gameObject); break; default: break; } } }
初始化地圖工具
判斷地圖長度
地圖大小:長20 寬16
添加MapCreation.cs地圖管理器來控制草和地圖等建築物
public class MapCreation : MonoBehaviour { //用來裝飾初始化地圖所需物體的數組 //0.老家 1.牆 2.障礙 3.出生效果 4.河流 5.草 6.空氣牆 public GameObject[] item; }
製做老家心臟和心臟周圍的圍牆
private void Awake() { //實例化老家 Instantiate(item[0], new Vector3(0, -8, -0), Quaternion.identity); //用牆把老家圍起來 Instantiate(item[1], new Vector3(-1, -8, -0), Quaternion.identity); Instantiate(item[1], new Vector3(1, -8, -0), Quaternion.identity); for(int i=-1;i<2;i++) { Instantiate(item[1],new Vector3(i,-7,0),Quaternion.identity); } }
對同一個位置上進行判斷,判斷是否有障礙物在上面,若是在上面那再也不額外生成其它建築物
已經有東西位置的列表
private List<Vector3> itemPositionList = new List<Vector3>();
private void CreateItem(GameObject createGameObject,Vector3 createPosition,Quaternion createRotate) { GameObject itemGo = Instantiate(createGameObject, createPosition, createRotate); itemGo.transform.SetParent(gameObject.transform); itemPositionList.Add(createPosition); }
製做外圍牆,也就是遊戲邊界
for(int i=-11;i<12;i++) { CreateItem(item[6], new Vector3(i, 9, 0), Quaternion.identity); } for(int i=-11;i<12;i++) { CreateItem(item[6], new Vector3(i, -9, 0), Quaternion.identity); } for(int i=-8;i<9;i++) { CreateItem(item[6], new Vector3(-11, i, 0), Quaternion.identity); } for(int i=-8;i<9;i++) { CreateItem(item[6], new Vector3(-11, i, 0), Quaternion.identity); }
產生隨機位置的方法
private Vector3 CreateRamdomPosition() { //不生成x=-10,10的兩列,y=-8和8這兩行的位置 while(true) { Vector3 createPosition = new Vector3(Random.Range(-9, 10), Random.Range(-7, 8),0); if(!HasThePosition(createPosition)) { return createPosition; } } }
用來判斷位置列表中是否有這個位置
private bool HasThePosition(Vector3 createPos) { for(int i=0;i<itemPositionList.Count;i++) { if(createPos==itemPositionList[i]) { return true; } } return false; }
修復子彈觸發碰撞檢測
private void OnTriggerEnter2D(Collider2D collision) { switch(collision.tag) { case "Tank": if(!isPlayerBullect) { collision.SendMessage("Die"); Destroy(gameObject); } break; case "Heart": collision.SendMessage("Die"); Destroy(gameObject); break; case "Enemy": if(isPlayerBullect) { collision.SendMessage("Die"); Destroy(gameObject); } break; case "Wall": //銷燬自身和牆 Destroy(collision.gameObject); Destroy(gameObject); break; case "Barrier": Destroy(gameObject); break; default: break; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Bullect : MonoBehaviour { public float moveSpeed = 10; public bool isPlayerBullect; // Use this for initialization void Start () { } // Update is called once per frame void Update () { transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World); } //子彈觸發碰撞檢測 private void OnTriggerEnter2D(Collider2D collision) { switch(collision.tag) { case "Tank": if(!isPlayerBullect) { collision.SendMessage("Die"); Destroy(gameObject); } break; case "Heart": collision.SendMessage("Die"); Destroy(gameObject); break; case "Enemy": if(isPlayerBullect) { collision.SendMessage("Die"); Destroy(gameObject); } break; case "Wall": //銷燬自身和牆 Destroy(collision.gameObject); Destroy(gameObject); break; case "Barrier": Destroy(gameObject); break; default: break; } } }
實例化地圖
for(int i=0;i<20;i++) { CreateItem(item[1], CreateRamdomPosition(), Quaternion.identity); } for(int i=0;i<20;i++) { CreateItem(item[2], CreateRamdomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) { CreateItem(item[4], CreateRamdomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) { CreateItem(item[5], CreateRamdomPosition(), Quaternion.identity); }
初始化玩家
GameObject go = Instantiate(item[3], new Vector3(-2, -8, 0), Quaternion.identity); go.GetComponent<Born>().createPlay = true;
產生敵人
CreateItem(item[3], new Vector3(-10,8,0),Quaternion.identity); CreateItem(item[3], new Vector3(0, 8, 0), Quaternion.identity); CreateItem(item[3], new Vector3(10, 8, 0), Quaternion.identity);
實例化地圖而且讓圍牆的數量儘量的多
for (int i=0;i<60;i++) { CreateItem(item[1], CreateRamdomPosition(), Quaternion.identity); } for(int i=0;i<20;i++) { CreateItem(item[2], CreateRamdomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) { CreateItem(item[4], CreateRamdomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) { CreateItem(item[5], CreateRamdomPosition(), Quaternion.identity); }
產生敵人的方法
private void CreateEnemy() { int num = Random.Range(0, 3); Vector3 EnemyPos = new Vector3(); if(num==0) { EnemyPos = new Vector3(-10, 8, 0); }else if(num==1) { EnemyPos = new Vector3(0, 8, 0); } else { EnemyPos = new Vector3(10, 8, 0); } CreateItem(item[3],EnemyPos,Quaternion.identity); }
每隔5s產生一波敵人
InvokeRepeating("CreateEnemy",4,5);
優化一下敵人AI
敵人AI碰到一塊兒時切換一次方向
private void OnCollisionEnter2D(Collision2D collision) { if(collision.gameObject.tag=="Enemy") { timeValChangeDirection = 4; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { //屬性值 public float moveSpeed = 3; private Vector3 bullectEulerAugles; public float timeVal; private float defendTimeVal=3; private bool isDefended=true; //引用 private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 public GameObject bullectPrefab; public GameObject explosionPrefab; public GameObject defendEffectPrefab; // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //保護是否處於無敵狀態 if(isDefended) { defendEffectPrefab.SetActive(true); defendTimeVal -= Time.deltaTime; if (defendTimeVal<=0) { isDefended = false; defendEffectPrefab.SetActive(false); } } //攻擊的CD if (timeVal>=0.4f) { //間隔大於0.4的時候纔有攻擊效果 Attack(); } else { timeVal += Time.deltaTime; } } private void FixedUpdate() { Move(); } //坦克的攻擊方法 private void Attack() { if(Input.GetKeyDown(KeyCode.Space)) { //子彈參數的角度:當前坦克的角度+子彈應該旋轉的角度 Instantiate(bullectPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bullectEulerAugles)); timeVal = 0; } } //坦克的移動方法 private void Move() { //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; bullectEulerAugles = new Vector3(0, 0, -180); } else if (v > 0) { sr.sprite = tankSprite[0]; bullectEulerAugles = new Vector3(0, 0, 0); } if (v != 0) { return; } //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); if (h < 0) { sr.sprite = tankSprite[3]; bullectEulerAugles = new Vector3(0, 0, 90); } else if (h > 0) { sr.sprite = tankSprite[1]; bullectEulerAugles = new Vector3(0, 0, -90); } } //坦克的死亡方法 private void Die() { if(isDefended) { return; } //產生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation); //死亡 Destroy(gameObject); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MapCreation : MonoBehaviour { //用來裝飾初始化地圖所需物體的數組 //0.老家 1.牆 2.障礙 3.出生效果 4.河流 5.草 6.空氣牆 public GameObject[] item; //已經有東西位置的列表 private List<Vector3> itemPositionList = new List<Vector3>(); private void Awake() { //實例化老家 CreateItem(item[0], new Vector3(0, -8, -0), Quaternion.identity); //用牆把老家圍起來 CreateItem(item[1], new Vector3(-1, -8, -0), Quaternion.identity); CreateItem(item[1], new Vector3(1, -8, -0), Quaternion.identity); for(int i=-1;i<2;i++) { Instantiate(item[1],new Vector3(i,-7,0),Quaternion.identity); } //實例化外圍牆 for(int i=-11;i<12;i++) { CreateItem(item[6], new Vector3(i, 9, 0), Quaternion.identity); } for(int i=-11;i<12;i++) { CreateItem(item[6], new Vector3(i, -9, 0), Quaternion.identity); } for(int i=-8;i<9;i++) { CreateItem(item[6], new Vector3(-11, i, 0), Quaternion.identity); } for(int i=-8;i<9;i++) { CreateItem(item[6], new Vector3(11, i, 0), Quaternion.identity); } //初始化玩家 GameObject go = Instantiate(item[3], new Vector3(-2, -8, 0), Quaternion.identity); go.GetComponent<Born>().createPlay = true; //產生敵人 CreateItem(item[3], new Vector3(-10,8,0),Quaternion.identity); CreateItem(item[3], new Vector3(0, 8, 0), Quaternion.identity); CreateItem(item[3], new Vector3(10, 8, 0), Quaternion.identity); //第一次調用CreateEnemy用4s,每隔5s開調用 InvokeRepeating("CreateEnemy",4,5); //實例化地圖 for (int i=0;i<60;i++) { CreateItem(item[1], CreateRamdomPosition(), Quaternion.identity); } for(int i=0;i<20;i++) { CreateItem(item[2], CreateRamdomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) { CreateItem(item[4], CreateRamdomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) { CreateItem(item[5], CreateRamdomPosition(), Quaternion.identity); } } private void CreateItem(GameObject createGameObject,Vector3 createPosition,Quaternion createRotate) { GameObject itemGo = Instantiate(createGameObject, createPosition, createRotate); itemGo.transform.SetParent(gameObject.transform); itemPositionList.Add(createPosition); } //產生隨機位置的方法 private Vector3 CreateRamdomPosition() { //不生成x=-10,10的兩列,y=-8和8這兩行的位置 while(true) { Vector3 createPosition = new Vector3(Random.Range(-9, 10), Random.Range(-7, 8),0); if(!HasThePosition(createPosition)) { return createPosition; } } } //用來判斷位置列表中是否有這個位置 private bool HasThePosition(Vector3 createPos) { for(int i=0;i<itemPositionList.Count;i++) { if(createPos==itemPositionList[i]) { return true; } } return false; } //產生敵人的方法 private void CreateEnemy() { int num = Random.Range(0, 3); Vector3 EnemyPos = new Vector3(); if(num==0) { EnemyPos = new Vector3(-10, 8, 0); }else if(num==1) { EnemyPos = new Vector3(0, 8, 0); } else { EnemyPos = new Vector3(10, 8, 0); } CreateItem(item[3],EnemyPos,Quaternion.identity); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Born : MonoBehaviour { public GameObject playerPrefab; public GameObject[] enemyPrefabList; //判斷是否產生敵人 public bool createPlay; // Use this for initialization void Start () { Invoke("BornTank",1f); Destroy(gameObject,1f); } private void Update() { } private void BornTank() { if (createPlay) { Instantiate(playerPrefab, transform.position, Quaternion.identity); } else { int num = Random.Range(0, 2); Instantiate(enemyPrefabList[num], transform.position, Quaternion.identity); } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Enemy : MonoBehaviour { //屬性值 public float moveSpeed = 3; private Vector3 bullectEulerAugles; private float v; private float h; //引用 private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 public GameObject bullectPrefab; public GameObject explosionPrefab; //計時器 public float timeVal; public float timeValChangeDirection=4; // Use this for initialization void Start() { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update() { //攻擊的時間間隔 if (timeVal >= 0.3f) { //間隔大於0.4的時候纔有攻擊效果 Attack(); } else { timeVal += Time.deltaTime; } } private void FixedUpdate() { Move(); } //坦克的攻擊方法 private void Attack() { //子彈參數的角度:當前坦克的角度+子彈應該旋轉的角度 Instantiate(bullectPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bullectEulerAugles)); timeVal = 0; } //坦克的移動方法 private void Move() { if(timeValChangeDirection>=4) { int num = Random.Range(0,8); if(num>5) { v = -1; h = 0; }else if (num == 0) { v = 1; h = 0; }else if (num > 0 && num <= 2) { h = -1; v = 0; }else if (num > 2 && num <= 4) { h = 1; v = 0; } timeValChangeDirection = 0; } else { timeValChangeDirection += Time.fixedDeltaTime; } //監聽玩家垂直軸輸入 transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; bullectEulerAugles = new Vector3(0, 0, -180); } else if (v > 0) { sr.sprite = tankSprite[0]; bullectEulerAugles = new Vector3(0, 0, 0); } if (v != 0) { return; } //監聽玩家水平軸輸入 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); if (h < 0) { sr.sprite = tankSprite[3]; bullectEulerAugles = new Vector3(0, 0, 90); } else if (h > 0) { sr.sprite = tankSprite[1]; bullectEulerAugles = new Vector3(0, 0, -90); } } //坦克的死亡方法 private void Die() { //產生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation); //死亡 Destroy(gameObject); } //優化敵人AI private void OnCollisionEnter2D(Collision2D collision) { if(collision.gameObject.tag=="Enemy") { timeValChangeDirection = 4; } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Explosion : MonoBehaviour { // Use this for initialization void Start () { //坦克銷燬後0.167秒銷燬爆炸特效 Destroy(gameObject,0.167f); } // Update is called once per frame void Update () { } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Heart : MonoBehaviour { private SpriteRenderer sr; public GameObject explosionPrefab; public Sprite BrokenSprite; // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } private void Die() { sr.sprite = BrokenSprite; Instantiate(explosionPrefab,transform.position,transform.rotation); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Bullect : MonoBehaviour { public float moveSpeed = 10; public bool isPlayerBullect; // Use this for initialization void Start () { } // Update is called once per frame void Update () { transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World); } //子彈觸發碰撞檢測 private void OnTriggerEnter2D(Collider2D collision) { switch(collision.tag) { case "Tank": if(!isPlayerBullect) { collision.SendMessage("Die"); Destroy(gameObject); } break; case "Heart": collision.SendMessage("Die"); Destroy(gameObject); break; case "Enemy": if(isPlayerBullect) { collision.SendMessage("Die"); Destroy(gameObject); } break; case "Wall": //銷燬自身和牆 Destroy(collision.gameObject); Destroy(gameObject); break; case "Barrier": Destroy(gameObject); break; default: break; } } }
玩家狀態管理
遊戲中添加空物體PlayerManager對象
添加遊戲的屬性值
public int lifeVale = 3; public int playerScore = 0; public bool isDead;
坦克的死亡方法
private void Die() { if(isDefended) { return; } PlayerManager.Instance.isDead = true; //產生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation); //死亡 Destroy(gameObject); }
玩家狀態管理類監聽玩家狀態,當玩家被子彈擊中時,生命值開始下降
void Update () { if(isDead) { Recover(); } } private void Recover() { if (lifeVale < 0) { //遊戲失敗,返回主界面 SceneManager.LoadScene("Game"); } else { lifeVale--; GameObject go = Instantiate(born,new Vector3(-2,-8,0),Quaternion.identity); go.GetComponent<Born>().createPlay = true; isDead = false; } }
遊戲源代碼
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { //屬性值 public float moveSpeed = 3; private Vector3 bullectEulerAugles; public float timeVal; private float defendTimeVal=3; private bool isDefended=true; //引用 private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 public GameObject bullectPrefab; public GameObject explosionPrefab; public GameObject defendEffectPrefab; // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //保護是否處於無敵狀態 if(isDefended) { defendEffectPrefab.SetActive(true); defendTimeVal -= Time.deltaTime; if (defendTimeVal<=0) { isDefended = false; defendEffectPrefab.SetActive(false); } } } private void FixedUpdate() { if(PlayerManager.Instance.isDefeat) { return; } Move(); //攻擊的CD if (timeVal >= 0.4f) { //間隔大於0.4的時候纔有攻擊效果 Attack(); } else { timeVal += Time.fixedDeltaTime; } } //坦克的攻擊方法 private void Attack() { if(Input.GetKeyDown(KeyCode.Space)) { //子彈參數的角度:當前坦克的角度+子彈應該旋轉的角度 Instantiate(bullectPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bullectEulerAugles)); timeVal = 0; } } //坦克的移動方法 private void Move() { //監聽玩家垂直軸輸入 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; bullectEulerAugles = new Vector3(0, 0, -180); } else if (v > 0) { sr.sprite = tankSprite[0]; bullectEulerAugles = new Vector3(0, 0, 0); } if (v != 0) { return; } //監聽玩家水平軸輸入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); if (h < 0) { sr.sprite = tankSprite[3]; bullectEulerAugles = new Vector3(0, 0, 90); } else if (h > 0) { sr.sprite = tankSprite[1]; bullectEulerAugles = new Vector3(0, 0, -90); } } //坦克的死亡方法 private void Die() { if(isDefended) { return; } PlayerManager.Instance.isDead = true; //產生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation); //死亡 Destroy(gameObject); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class PlayerManager : MonoBehaviour { //屬性值 public int lifeVale = 3; public int playerScore = 0; public bool isDead=false; public bool isDefeat; //引用 public GameObject born; //單例 private static PlayerManager instance; public static PlayerManager Instance { get { return instance; } set { instance = value; } } public void Awake() { Instance = this; } // Use this for initialization void Start () { } // Update is called once per frame void Update () { if(isDead) { Recover(); } } private void Recover() { if (lifeVale < 0) { //遊戲失敗,返回主界面 SceneManager.LoadScene("Game"); } else { lifeVale--; GameObject go = Instantiate(born,new Vector3(-2,-8,0),Quaternion.identity); go.GetComponent<Born>().createPlay = true; isDead = false; } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MapCreation : MonoBehaviour { //用來裝飾初始化地圖所需物體的數組 //0.老家 1.牆 2.障礙 3.出生效果 4.河流 5.草 6.空氣牆 public GameObject[] item; //已經有東西位置的列表 private List<Vector3> itemPositionList = new List<Vector3>(); private void Awake() { //實例化老家 CreateItem(item[0], new Vector3(0, -8, -0), Quaternion.identity); //用牆把老家圍起來 CreateItem(item[1], new Vector3(-1, -8, -0), Quaternion.identity); CreateItem(item[1], new Vector3(1, -8, -0), Quaternion.identity); for(int i=-1;i<2;i++) { Instantiate(item[1],new Vector3(i,-7,0),Quaternion.identity); } //坦克一開始就向下太難了,就直接給老家前面加了一頂牆 CreateItem(item[2], new Vector3(0, -4, -0), Quaternion.identity); //實例化外圍牆 for (int i=-11;i<12;i++) { CreateItem(item[6], new Vector3(i, 9, 0), Quaternion.identity); } for(int i=-11;i<12;i++) { CreateItem(item[6], new Vector3(i, -9, 0), Quaternion.identity); } for(int i=-8;i<9;i++) { CreateItem(item[6], new Vector3(-11, i, 0), Quaternion.identity); } for(int i=-8;i<9;i++) { CreateItem(item[6], new Vector3(11, i, 0), Quaternion.identity); } //初始化玩家 GameObject go = Instantiate(item[3], new Vector3(-2, -8, 0), Quaternion.identity); go.GetComponent<Born>().createPlay = true; //產生敵人 CreateItem(item[3], new Vector3(-10,8,0),Quaternion.identity); CreateItem(item[3], new Vector3(0, 8, 0), Quaternion.identity); CreateItem(item[3], new Vector3(10, 8, 0), Quaternion.identity); //第一次調用CreateEnemy用4s,每隔5s開調用 InvokeRepeating("CreateEnemy",4,5); //實例化地圖 for (int i=0;i<60;i++) { CreateItem(item[1], CreateRamdomPosition(), Quaternion.identity); } for(int i=0;i<20;i++) { CreateItem(item[2], CreateRamdomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) { CreateItem(item[4], CreateRamdomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) { CreateItem(item[5], CreateRamdomPosition(), Quaternion.identity); } } private void CreateItem(GameObject createGameObject,Vector3 createPosition,Quaternion createRotate) { GameObject itemGo = Instantiate(createGameObject, createPosition, createRotate); itemGo.transform.SetParent(gameObject.transform); itemPositionList.Add(createPosition); } //產生隨機位置的方法 private Vector3 CreateRamdomPosition() { //不生成x=-10,10的兩列,y=-8和8這兩行的位置 while(true) { Vector3 createPosition = new Vector3(Random.Range(-9, 10), Random.Range(-7, 8),0); if(!HasThePosition(createPosition)) { return createPosition; } } } //用來判斷位置列表中是否有這個位置 private bool HasThePosition(Vector3 createPos) { for(int i=0;i<itemPositionList.Count;i++) { if(createPos==itemPositionList[i]) { return true; } } return false; } //產生敵人的方法 private void CreateEnemy() { int num = Random.Range(0, 3); Vector3 EnemyPos = new Vector3(); if(num==0) { EnemyPos = new Vector3(-10, 8, 0); }else if(num==1) { EnemyPos = new Vector3(0, 8, 0); } else { EnemyPos = new Vector3(10, 8, 0); } CreateItem(item[3],EnemyPos,Quaternion.identity); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Born : MonoBehaviour { public GameObject playerPrefab; public GameObject[] enemyPrefabList; //判斷是否產生敵人 public bool createPlay; // Use this for initialization void Start () { Invoke("BornTank",1f); Destroy(gameObject,1f); } private void Update() { } private void BornTank() { if (createPlay) { Instantiate(playerPrefab, transform.position, Quaternion.identity); } else { int num = Random.Range(0, 2); Instantiate(enemyPrefabList[num], transform.position, Quaternion.identity); } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Enemy : MonoBehaviour { //屬性值 public float moveSpeed = 3; private Vector3 bullectEulerAugles; private float v=-1; private float h; //引用 private SpriteRenderer sr; public Sprite[] tankSprite; //上 右 下 左 public GameObject bullectPrefab; public GameObject explosionPrefab; //計時器 public float timeVal; public float timeValChangeDirection=0; // Use this for initialization void Start() { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update() { //攻擊的時間間隔 if (timeVal >= 0.3f) { //間隔大於0.4的時候纔有攻擊效果 Attack(); } else { timeVal += Time.deltaTime; } } private void FixedUpdate() { Move(); } //坦克的攻擊方法 private void Attack() { //子彈參數的角度:當前坦克的角度+子彈應該旋轉的角度 Instantiate(bullectPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bullectEulerAugles)); timeVal = 0; } //坦克的移動方法 private void Move() { if(timeValChangeDirection>=4) { int num = Random.Range(0,8); if(num>5) { v = -1; h = 0; }else if (num == 0) { v = 1; h = 0; }else if (num > 0 && num <= 2) { h = -1; v = 0; }else if (num > 2 && num <= 4) { h = 1; v = 0; } timeValChangeDirection = 0; } else { timeValChangeDirection += Time.fixedDeltaTime; } //監聽玩家垂直軸輸入 transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World); if (v < 0) { sr.sprite = tankSprite[2]; bullectEulerAugles = new Vector3(0, 0, -180); } else if (v > 0) { sr.sprite = tankSprite[0]; bullectEulerAugles = new Vector3(0, 0, 0); } if (v != 0) { return; } //監聽玩家水平軸輸入 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); if (h < 0) { sr.sprite = tankSprite[3]; bullectEulerAugles = new Vector3(0, 0, 90); } else if (h > 0) { sr.sprite = tankSprite[1]; bullectEulerAugles = new Vector3(0, 0, -90); } } //坦克的死亡方法 private void Die() { PlayerManager.Instance.playerScore++; //產生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation); //死亡 Destroy(gameObject); } //優化敵人AI private void OnCollisionEnter2D(Collision2D collision) { if(collision.gameObject.tag=="Enemy") { timeValChangeDirection = 4; } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Explosion : MonoBehaviour { // Use this for initialization void Start () { //坦克銷燬後0.167秒銷燬爆炸特效 Destroy(gameObject,0.167f); } // Update is called once per frame void Update () { } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Heart : MonoBehaviour { private SpriteRenderer sr; public GameObject explosionPrefab; public Sprite BrokenSprite; // Use this for initialization void Start () { sr = GetComponent<SpriteRenderer>(); } private void Die() { sr.sprite = BrokenSprite; Instantiate(explosionPrefab,transform.position,transform.rotation); PlayerManager.Instance.isDefeat = true; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class Bullect : MonoBehaviour { public float moveSpeed = 10; public bool isPlayerBullect; // Use this for initialization void Start () { } // Update is called once per frame void Update () { transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World); } //子彈觸發碰撞檢測 private void OnTriggerEnter2D(Collider2D collision) { switch(collision.tag) { case "Tank": if(!isPlayerBullect) { collision.SendMessage("Die"); Destroy(gameObject); } break; case "Heart": collision.SendMessage("Die"); Destroy(gameObject); SceneManager.LoadScene("Game"); break; case "Enemy": if(isPlayerBullect) { collision.SendMessage("Die"); Destroy(gameObject); } break; case "Wall": //銷燬自身和牆 Destroy(collision.gameObject); Destroy(gameObject); break; case "Barrier": Destroy(gameObject); break; default: break; } } }