關於Unity的入門游戲飛機大戰的開發(下)


 開發思路:

1: 修改測試模式,去掉開始按鈕方便開發,加入敵機的資源
2: 創建敵機 添加剛體,碰撞器組件,添加幀動畫播放組件;
3: 創建敵機出現的隊形;
4: 根據隊形隨機 生成我們的敵機,調整敵機的速度,和敵機出去后,刪除;
5: 碰撞配置分組,TAG 標記不同對象, 剛體加上trigger;
6: 玩家被敵人擊中,爆炸與恢復;
7: 子彈打死敵人后刪除自己,敵人也要做爆炸;
8: 加上玩家得分的情況;
9: 打開menu主頁, 做好GUI 適配

 

 

步驟一>>>>>>修改測試模式,去掉開始按鈕方便開發,加入敵機的資源

1.把menu_root節點隱藏起來,在game_scene腳本里面的Start函數里直接調用on_start_click()函數,這樣游戲就不用菜單的開始按鈕觸發,而是自己觸發開始了,比較好調試。

2.在Resources文件夾下面的tex文件夾中,添加進敵機的資源(9種)和敵機爆炸的動畫資源文件夾dead

 

 

步驟二>>>>>>創建敵機 添加剛體,碰撞器組件,添加幀動畫播放組件

1.創建一個叫enemy_root的敵機空節點,作為Canvas節點的子節點。節點大小設置為0。

2.給enemy_root創建一個叫e1的Image子節點,把敵機e1的貼圖拖進去,set native size,縮放設置為X為2,Y為2。

3.由於有很多敵機(8種)要添加碰撞形狀和物理剛體組件,所以可以手動添加組件,也可以用腳本代碼實現組件的添加,比較輕松。

4.創建一個叫enemy的腳本用來對每個敵機添加剛體和碰撞組件,以及對他們進行一些初始化,記得是先寫好腳本再掛載到e1到e8下面,不然先掛載再寫腳本這里會出錯。

using UnityEngine;
using System.Collections;
using System;

//用代碼添加剛體組件和形狀碰撞組件
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(BoxCollider2D))]

public class enemy : MonoBehaviour {
    public int e_type; // 敵機的類型;

    private BoxCollider2D box;
    private Rigidbody2D body;
   
    // Use this for initialization
    void Start () {
        
        this.body = this.GetComponent<Rigidbody2D>();
        this.box = this.GetComponent<BoxCollider2D>();

     //設置敵機碰撞器的形狀的大小
        RectTransform r_trans = (RectTransform) this.transform;
        r_trans.localScale = new Vector3(2, 2, 1);//放大節點兩倍
        Vector2 size = r_trans.sizeDelta;//取出節點的大小

        this.box.size = size;//設置好碰撞器大小
        this.box.isTrigger = true; // 只做碰撞觸發;只觸發不產生碰撞效果
        this.body.freezeRotation = true; // 不讓他旋轉;剛體不旋轉
    }
    
    // Update is called once per frame
    void Update () {
     
    }
}

5.記得把Rigidbody2D組件的Is Trigger打鈎,只做碰撞觸發,其實不打鈎也沒事,在腳本里面有寫。

6.給每個敵機創建一個節點,把自己的貼圖拖進自己的貼圖屬性中,set native size,記得填寫enemy腳本的公開屬性E_type,第幾個類型的就填第幾編號。

7.由於等下要生成非常多的敵機,所以要把這些敵機設置成預制體,就在prefabs文件夾下面再創建一個叫enemies的文件夾,然后把e1到e8的敵機節點拖進enemies變成藍色預制體,刪除原來的e1到e8節點。

 

 

步驟三>>>>>>創建敵機出現的隊形

1.開始排飛機的隊形,在enemy_root下面創建一個group1的空子節點,然后把prefabs里面的前三個敵機預制體拖進group1,修改三個敵機的坐標位置,排成一排或者其他的。

2.排好之后先把這三台敵機取消預制體形態,還原成普通節點GameObject-->Break Prefab Instance,然后把整個group1拖進prefab文件夾里面當作一個預制體。

3.每次制作好預制體之后,都可以把原來的那個節點刪除,這樣重復制作組合大概5、6組就可以。

4.最后只剩一個enemy_root空節點,下面什么也沒有。

 

 

步驟四>>>>>>根據隊形隨機 生成我們的敵機,調整敵機的速度,和敵機出去后,刪除

我們首先是做了敵機的group,這個group下面可能有三駕敵機e1e2e3,每駕敵機都有相對於group相對偏移的位置pos1pos2pos3,接下來把所有的group都從一個很高很高的位置如(0,912,0)開始,當我們產生敵機的時候,把敵機的初始位置設置為(0,912,0)

保證了敵機可以從那個高度開始移動,接下來我們遍歷每個group下面的孩子,有幾個孩子就產生幾個enemy,每個enemy的位置就是912+pos,這樣再把新創建的enemy加到enemy_root空節點下面,這樣我們就生成了一個group實例。所以我們在enemy_root下其實是不直接生成group實例,因為group里面的每一個enemy位置都是寫死的,我們希望里面的每個敵機的位置是隨機的。所以我們新產生一個enemy,位置等於grooup的初始位置912+每個敵機相對group的偏移位置pos。

 

1.有了隊形之后就是怎么隨機產生這些隊形和移動這些隊形,以及最后超出屏幕后刪除的操作。

2.寫一個腳本gen_enemy掛載在enemy_root節點下面實現第一點

3.打開gen_enemy腳本,其實里面對預制體的實例化並不是對group的實例化,而是對一個一個enemy敵機的實例化。

  而且產生的飛機的位置也是隨機的,隊形是一個一個隨機的,而且具體哪個位置哪台飛機是隨機的。並不是我剛開始以為的對整個group進行實例化。如果那樣的話位置和飛機就會對應,不靈活。

記得在enemy_root的Inspector面板里面把對應的屬性綁定好,自己手動拖進去。

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class gen_enemy : MonoBehaviour {
public GameObject[] group_set; // 敵機組的集合 public GameObject[] enemy_set; // 敵機的集合 // Use this for initialization void Start () { }
public void start_gen_enemy() { this.Invoke("gen_one_group", 3); }
  
void gen_one_group() { // [0, this.group_set.Length) 隨機數,生成一個0到敵機組總數-1的隨機數 int group_index = Random.Range(0, this.group_set.Length); //設置一個初始位置,敵機組從這里生成並開始移動 Vector3 start_pos = new Vector3(0, 912, 0); // 循環遍歷group下面的孩子數目;遍歷隨機到的那一個敵機組,遍歷里面的每一個敵機 for (int i = 0; i < this.group_set[group_index].transform.childCount; i++) {        //生成一個0到敵機總數-1的隨機數,隨機取1到8敵機類型的一種類型        int e_type = Random.Range(0, this.enemy_set.Length);        //獲得孩子的位置,獲得當前指定敵機的位置 Transform group_enemy = this.group_set[group_index].transform.GetChild(i); // 隨機的生成了一個敵人,開始隨機生成一架敵機 GameObject e_item = GameObject.Instantiate(this.enemy_set[e_type]); e_item.transform.SetParent(this.transform, false); Vector3 pos = start_pos + group_enemy.localPosition; e_item.transform.localPosition = pos; } // [0.0, 3.0f] this.Invoke("gen_one_group", 3 + Random.Range(0.0f, 3.0f)); }   // Update is called once per frame void Update () { } }

4.在enemy腳本中,由於每一個敵機我們給它一個向下的初速度,這個速度的設置是寫在原來的enemy腳本中的Start函數里面

this.body.velocity = new Vector2(0, -8);

還要寫實現敵機飛出屏幕后刪除的代碼,這個和子彈刪除的原理是一樣的

 

void Start () {

  ...

  float scale = 640.0f / (float)Screen.width;
  this.dead_line_y = -(Screen.height * scale * 0.5f + 100);

}

void Update () {
  if (this.transform.localPosition.y < this.dead_line_y) {
  MonoBehaviour.Destroy(this.gameObject);
  }
}

 

5.在game_scene腳本中,為了開始生成敵機隊列,首先要在里面的Start函數中獲得enemy_root下的腳本

 this.gen_enmey_ctrl = this.transform.Find("game_root/enemy_root").GetComponent<gen_enemy>();

然后在game_realy_started函數里面調用gen_enmey腳本里面的start_gen_enemy函數開始生成敵機

 this.gen_enmey_ctrl.start_gen_enemy();//記得要在gen_enmey腳本中把start_gen_enemy函數的權限改為public才可以訪問

 

 

步驟五>>>>>>碰撞配置分組,TAG 標記不同對象, 剛體加上trigger

1.給plane添加碰撞器形狀組件,大小設置為飛機的大小128X128,為了准確也可以做一個多邊形的Collider,那樣就必須使用Polygon Collider 2D組件,然后編輯。

2.把Box Collider 2D的Is Trigger打鈎,表示不發生碰撞效果,但是還是有碰撞響應。

3.編輯右上角的層,把游戲內的物體分成3個層,plane,plane_bullet,enemy,給每個節點這里設置plane節點及其子節點和resources/prefabs/enemies里面所以預制體和resources/prefabs/plane_bullet預制體都設置對應的層。

4.對每個層的碰撞情況進行編輯,Edit-->project Settings-->Physics 2D,在Layer Collision Matris碰撞矩陣里面編寫打鈎碰撞的情況,不打鈎的意思是連碰撞響應都不發生。

5.編輯左上角的標記,把游戲內的物體進行標記,這里分成3個標記plane,plane_bullet,enemy,給每個節點和預制體都設置對應的標記,有了標記后面才能知道是誰和誰在碰撞。

 

 

步驟六>>>>>>玩家被敵人擊中,爆炸與恢復

1.由於plane,plane_bullet,enemy的碰撞類型都是trigger,所以我們要在相應的腳本里面寫Trigger的響應函數。

2.我們還需要一個幀動畫的組件,在第22的文件里面,里面的frame_anim.cs,把它拷貝到項目的scripts文件夾下面

3.在飛機plane節點下面添加frame_anim.cs組件,因為飛機爆炸有7張圖,屬性size就寫7,並把每一張爆炸圖都拖進去。

4.在OnTriggerEnter2D函數里面調用frame_anim.cs的play_once函數,記得把play_once改成public才能調用,而且我們還要改寫一下frame_anim.cs的函數play_once,使得它變成一個回調函數,這樣爆炸結束的時候還能自動調用別的函數。

改寫的frame_anim.cs

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System;

// 我們當前代碼強制要求要加入一個Image組件,
// 如果沒有Image組件,那么自動加上,如果有就使用;
// 如果你的代碼要求這個節點必須掛某個組件,那么
// 使用RequireComponent
[RequireComponent(typeof(Image))]

public class frame_anim : MonoBehaviour {
    // 我們這個動畫所需要的畫面;
    public Sprite[] sprite_frames;
    // 幀動畫的間隔時間
    public float duration = 0.1f;
    // 是否循環播放
    public bool is_loop = false;
    // 是否在加載的時候開始播放;
    public bool play_onload = false;

    private float played_time;
    private bool is_playing = false;

    private Image img;
    Action end_func = null;//----補充----加一個結束的動作


    // Use this for initialization
    void Start () {
        this.img = this.GetComponent<Image>();
        if (this.play_onload) {
            if (this.is_loop) {
                this.play_loop();
            }
            else {
                this.play_once(null);//----補充----改寫成傳遞參數的調用
            }
        }
    }

    // 只播放一次
    public void play_once(Action end_func) {//----補充----改寫成傳遞參數的調用
        if (this.sprite_frames.Length <= 1) {
            return;
        }

        this.end_func = end_func;//----補充----賦值

        this.played_time = 0;
        this.is_playing = true;
        this.is_loop = false;
    }

    // 循環播放
    void play_loop() {
        if (this.sprite_frames.Length <= 1) {
            return;
        }
        this.played_time = 0;
        this.is_playing = true;
        this.is_loop = true;
    }
    // 停止當前的動畫播放
    void stop_anim() {
        this.is_playing = false;
    }
    // Update is called once per frame
    void Update () {
        if (this.is_playing == false) {
            return;
        }

        // 
        float dt = Time.deltaTime;
        this.played_time += dt;
        // 向下取整;
        int index = (int)(this.played_time / this.duration);
        if (this.is_loop == false) {
            // 結束了
            if (index >= this.sprite_frames.Length) { // 停止播放
                this.is_playing = false;
                this.played_time = 0;
                if (this.end_func != null) {//----補充----停止播放的時候執行結束函數
                    this.end_func();
                } 
            }
            else {
                this.img.sprite = this.sprite_frames[index];
            }
        }
        else {
            // 超過了范圍,減掉一個周期
            while (index >= this.sprite_frames.Length) {
                this.played_time -= (this.duration * this.sprite_frames.Length);
                index -= this.sprite_frames.Length;
            }

            this.img.sprite = this.sprite_frames[index];
        }
        // end 
    }
}

 

改寫的plane.cs

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

//定義兩個飛機的狀態用來后面判斷是否播放爆炸動畫
enum State
{
    NORMAL = 0,
    DEADED = 1,
};

public class plane : MonoBehaviour
{
    //播放幀動畫要用的變量
    private frame_anim bomb_anim;
    public Sprite ship_idle;
    private Image ship_icon;
    private State state;

    //碰撞器
    private BoxCollider2D box;
    //飛機隨着鼠標運動需要定義飛機坐標和鼠標坐標
    Vector3 start_plane_pos; // 按鈕按下的時候飛機的開始的坐標
    Vector3 start_mouse_pos; // 鼠標開始的坐標;

    //子彈預制體
    public GameObject bullet_prefab;//預制體子彈節點
    public Transform bullet_root;//預制體子彈節點的父節點
    public float shoot_rate = 0.2f; // 子彈發射的頻率;我感覺是一個時間間隔,設定的子彈發射時間間隔
    private float shoot_time = 0.0f; // 距離上一次發射過去的時間
    private bool is_shooting = false;//是否處於發射子彈的狀態

    //-----優化-----
    private bool is_touch = false;//是否點到飛機
    private bool is_super = false;//是否處於無敵狀態

    // Use this for initialization
    void Start()
    {
        //幀動畫播放初始化
        this.bomb_anim = this.transform.Find("anim").GetComponent<frame_anim>();
        this.ship_icon = this.bomb_anim.GetComponent<Image>();
        this.state = State.NORMAL;

        //獲得碰撞器
        this.box = this.GetComponent<BoxCollider2D>();
    }

    public void start_game()
    {
        this.is_shooting = true;

    }

    void shoot_bullet()
    {
        //使用預制體生成一顆子彈
        GameObject bullet = GameObject.Instantiate(this.bullet_prefab);
        // 注意這個參數要使用false
        bullet.transform.SetParent(this.bullet_root, false);

        //使用localPosition是因為子彈和plane都有相同的父節點,兩者之間是相對坐標
        Vector3 offset = new Vector3(0, 64, 0);
        bullet.transform.localPosition = this.transform.localPosition + offset;
    }

    // 響應我們的鼠標事件,GetMouseButton(0)
    void Update()
    {
        //鼠標按下的情況
        if (Input.GetMouseButtonDown(0))
        {
            //-----修改-----
            this.is_touch = false;//每次鼠標點下去,不管有沒有點到飛機,初始化為沒點到
            Ray myRay = Camera.main.ScreenPointToRay(Input.mousePosition);//從攝像機發出一條射線
            RaycastHit2D hit = Physics2D.Raycast(new Vector2(myRay.origin.x, myRay.origin.y), Vector2.zero);//射線從鼠標點擊屏幕的那個點出發,射到以當前點擊位置為原點的坐標系中的垂直於(0,0)的位置,
                                                                    //如果從3D的視角看就是攝像機的射線垂直射到Canvas上
            if (hit.collider)//如果碰到有Collider2D組件的物體,就做一些事情
            {
                if (hit.transform.gameObject.name == "plane")//如果碰到的是飛機
                {
                    //Debug.Log(hit.transform.name);//打印出碰撞到的節點的名字
                    this.is_touch = true;//點到飛機
                }
            }

            if (is_touch)//如果點到飛機
            {
                //獲得鼠標的初始點擊位置
                this.start_mouse_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                //獲得飛機的初始位置
                this.start_plane_pos = this.transform.position;
            }
        }

        //鼠標滑動的情況
        else if (Input.GetMouseButton(0) && this.is_touch)
        {
            Vector3 w_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            //獲得偏移量
            Vector3 offset = w_pos - this.start_mouse_pos;
            //設置飛機偏移后的位置
            this.transform.position = this.start_plane_pos + offset;
        }

        // 子彈發射邏輯控制,update里面嵌套自定義的update,自定義刷新函數
        this.shoot_update(Time.deltaTime);
    }

    void shoot_update(float dt)
    {
        if (!this.is_shooting)
        {
            return;
        }

        this.shoot_time += dt;
        if (this.shoot_time < this.shoot_rate)
        {
            return;
        }

        this.shoot_time = 0;
        this.shoot_bullet();
    }

    //寫一個觸發器來響應碰撞
    void OnTriggerEnter2D(Collider2D c)
    {
        if (this.state == State.DEADED)
        {
            return;
        }

        if (!is_super)//飛機不是超級狀態
        {
            this.state = State.DEADED;

            this.box.enabled = false;// 把物理碰撞區域給隱藏,這樣他就不會觸發碰撞了。
            this.is_shooting = false; // 不能發射子彈了

            this.bomb_anim.play_once(this.on_bomb_anim_ended);//回調函數
        }
    }

    //寫一個爆炸后調用的函數
    void on_bomb_anim_ended()
    {
        //Debug.Log("on_bomb_anim_ended called");
        this.bomb_anim.gameObject.SetActive(false);//把飛機的形狀隱藏起來,不參與碰撞,也可以把剛體隱藏起來,也不參與碰撞
        this.Invoke("plane_relive", 3.0f);
    }

    //寫一個爆炸后調用的函數的定時函數
    void plane_relive()
    {
        this.state = State.NORMAL;
        this.is_shooting = true;
        this.shoot_time = 0;

        this.ship_icon.sprite = this.ship_idle;//圖像
        this.bomb_anim.gameObject.SetActive(true);//把飛機的形狀顯示出來,參與碰撞
        this.ship_icon.color = Color.red;//圖像顏色變紅
        this.is_super = true;//設置為超級狀態
        this.box.enabled = true;//顯示碰撞器
        this.Invoke("enable_collider", 3.0f);// 允許3秒的無敵狀態,3秒后再打開我們的碰撞無敵區域
    }

    //寫一個爆炸后調用的函數的定時函數的定時函數
    void enable_collider()
    {
        this.is_super = false;//再設置回正常狀態
        this.ship_icon.color = Color.white;//圖像顏色變原色
    }
}

 

 

步驟七>>>>>>子彈打死敵人后刪除自己,敵人也要做爆炸

1.由於子彈要在碰到敵機后馬上刪除,所以它自己也要寫一個OnTriggerEnter2D的函數,在發生碰撞的時候調用,在plane_bullet.cs里面寫OnTriggerEnter2D函數並直接Destroy自己的節點。

    // 子彈如果碰到了敵機,那么馬上刪除;
    void OnTriggerEnter2D(Collider2D c) {
        MonoBehaviour.Destroy(this.gameObject);
    }

2.由於敵機要在碰到子彈后自爆,所以它自己也要寫一個OnTriggerEnter2D的函數,在發生碰撞的時候調用。

3.在敵機e1到e8預制節點下面分別添加frame_anim.cs組件,因為敵機爆炸有7張圖,屬性size就寫7,並把每一張爆炸圖都拖進去。

改寫后的enemy.cs

using UnityEngine;
using System.Collections;
using System;

//用代碼添加剛體組件和形狀碰撞組件
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(BoxCollider2D))]

public class enemy : MonoBehaviour {
    //敵機爆炸所需要的變量
    private frame_anim bomb_anim;
    //委托
    public event Action dead_event;  

   //敵機的類型
   public int e_type; 

    private BoxCollider2D box;
    private Rigidbody2D body;
    private float dead_line_y;

  // Use this for initialization
    void Start () {
        
        this.body = this.GetComponent<Rigidbody2D>();
        this.box = this.GetComponent<BoxCollider2D>();

      //設置敵機碰撞器的形狀的大小
      RectTransform r_trans = (RectTransform)this.transform;
      r_trans.localScale = new Vector3(2, 2, 1);//放大節點兩倍
      Vector2 size = r_trans.sizeDelta;//取出節點的大小

      this.box.size = size;//設置好碰撞器大小
      this.box.isTrigger = true;//只觸發不產生碰撞效果
      this.body.freezeRotation = true;//剛體不旋轉
      this.body.velocity = new Vector2(0, -8);//給敵機一個初始向下的速度

      //敵機飛出屏幕后刪除
      float scale = 640.0f / (float)Screen.width;
      this.dead_line_y = -(Screen.height * scale * 0.5f + 100);

      //獲得播放動畫的組件
      this.bomb_anim=this.GetComponent<frame_anim>();

    }
    
    // Update is called once per frame
    void Update () {
        if (this.transform.localPosition.y < this.dead_line_y) {
            MonoBehaviour.Destroy(this.gameObject);
        }
    }

    //寫一個觸發器來響應碰撞,碰到子彈后自爆,碰到飛機一點事情都沒有
   void OnTriggerEnter2D(Collider2D c) {
        // 敵人碰到玩家的子彈,敵人碰到玩家,敵人不爆炸,玩家爆炸,敵人碰到子彈,敵人爆炸
        if (!c.gameObject.tag.Equals("plane_bullet")) { // 飛機碰到玩家,玩家爆炸;
            return;
        }
        //  敵機就不能有碰撞區域
        this.box.enabled = false;
        // 子彈打到敵人
        this.bomb_anim.play_once(this.on_bomb_anim_end);
        // end 
    }

  //寫一個回調函數來等觸發函數執行后來調用
    void on_bomb_anim_end() {
        this.dead_event(); // 觸發事件
        MonoBehaviour.Destroy(this.gameObject);
    }
}

 

 

步驟八>>>>>>加上玩家得分的情況

1.我們需要一個統計分數的節點,我們在Canvas節點下面再創建一個空節點叫game_ui,Hierarchy視圖中要放在game_root和menu_root之間。

2.把game_ui的節點大小設置為640X960,同時把菊花分開,讓父親有多大,孩子就有多大。

3.在tex文件夾下面創建一個美術字資源create-->Custom Font,把它的名字命名地和我們的字體資源一樣的名字,是win_score.fontsettings。這個資源需要有個材質屬性。於是我們創建一個字體材質create-->Material,名字命名地和字體資源的名字是一樣的,叫win_score.mat。把材質的Shader設置為Mobile/Diffuse,然后把我們的原始字體資源win_score.png文件拖進去,再把材質球win_score.mat拖進剛才創建的Custom Font字體資源win_score.fontsettings。

4.我們還需要導入字模,在第24的文件夾里面,在Resources文件夾下面創建一個叫做Editor的文件夾,表示里面的東西是對Unity編輯器的擴展。然后把24里面的CreateFontEditor.cs腳本拷貝進去。

5.對win_score.fnt文件右鍵-->create-->CreateFBMFont,然后字模就導入進剛才的字體資源文件了,注意這里的文件是那個全是字的文件,不是我們剛才創建的win_score.fontsettings文件。

6.在game_ui節點下,創建一個Text類型的叫score的UI節點,把它的菊花設置為左上角對齊,然后設置具體坐標位置讓它在左上角x,y(32,-32)

7.在enemy_root節點下的gen_enemy腳本里面寫一個public的score對象屬性,然后把剛才的score節點拖進去綁定。(綁定我的理解是:綁定不是賦值,而是引用,所以會同步發生變化)

8.字體顏色設置為白色,字體居中,把剛才我們創建的那個字體資源文件win_score.fontsettings拖進去Text組件的Character的Font屬性中。

8.寫一個事件委托,在enemy里面敵機爆炸的那個函數里面,觸發事件,然后在gen_enemy腳本里面對事件進行響應,調用add_score函數,每次有事件發生就調用add_score函數。

改寫后的gen_enemy腳本

using UnityEngine;
using System.Collections;
using UnityEngine.UI;


public class gen_enemy : MonoBehaviour {
    public GameObject[] group_set; // 分組的集合
    public GameObject[] enemy_set; // 敵人的集合

    //分數統計
    public Text score;
    int score_value;

    // Use this for initialization
    void Start () {
        this.score.text = "0";
        this.score_value = 0;
    }

    //開始生成敵機的函數
    public void start_gen_enemy() {
        this.score.text = "0";
        this.score_value = 0;
        this.Invoke("gen_one_group", 3);
    }
  
void gen_one_group() { // [0, this.group_set.Length) 隨機數,生成一個0到敵機組總數-1的隨機數 int group_index = Random.Range(0, this.group_set.Length); //設置一個初始位置,敵機組從這里生成並開始移動 Vector3 start_pos = new Vector3(0, 912, 0); // 循環遍歷group下面的孩子數目;遍歷隨機到的那一個敵機組,遍歷里面的每一個敵機 for (int i = 0; i < this.group_set[group_index].transform.childCount; i++) {        //生成一個0到敵機總數-1的隨機數,隨機取1到8敵機類型的一種類型        int e_type = Random.Range(0, this.enemy_set.Length);        //獲得孩子的位置,獲得當前指定敵機的位置 Transform group_enemy = this.group_set[group_index].transform.GetChild(i); // 隨機的生成了一個敵人,開始隨機生成一架敵機 GameObject e_item = GameObject.Instantiate(this.enemy_set[e_type]); e_item.transform.SetParent(this.transform, false); Vector3 pos = start_pos + group_enemy.localPosition; e_item.transform.localPosition = pos;              //-----非常重要的一句話-----這句話就是把委托和響應函數進行了關聯        e_item.GetComponent<enemy>().dead_event += this.add_score; } // [0.0, 3.0f] this.Invoke("gen_one_group", 3 + Random.Range(0.0f, 3.0f)); } //增加分數的函數 void add_score() { this.score_value ++; this.score.text = "" + this.score_value; }   // Update is called once per frame void Update () { } }

 

改寫后的enemy腳本在步驟7里面,上次寫的超前了

 

 

步驟九>>>>>>打開menu主頁, 做好GUI 適配

1.把步驟1里面的對menu_root的隱藏顯示出來,打鈎。再注釋掉game_scene里面的Start函數的this.on_game_start_click();這樣只有按了按鈕之后才會真正地開始游戲。

2.把menu_root節點的菊花也是設置為最右下角那個圖案,使得父節點怎么變化,子節點就怎么變化。

3.把menu_root節點下面的menu_bg背景圖節點的菊花設置為正下方那個圖案,使得它可以隨着分辨率的變化而上下拉伸。

4.屏幕適配完成。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM