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


每個組件都是一個類的實例,要獲得某個組件,要先創建一個同類型的組件類實例,然后把實例傳引用過去,就可以對想要的組件實例進行操作。

做游戲一般創建一個邏輯節點,里面只管邏輯,再創建一個動畫節點,里面有好多動畫節點。一般我們把邏輯節點作為動畫節點的父節點。

 

 

開發步驟:

1: 搭建unity項目工程;
2: 資源整理好;
3: 配置好我們的canvas;
4: 做一個開始界面;
5: 做一個總的游戲的控制腳本game_scene;
6: 點擊開始按鈕,讓這個開始界面消失;
7: 讓這個飛行射擊類游戲背景滾動起來;
8: 創建一個飛機,能讓它被自由的移動和拖動;
9: 創建一個子彈,能夠在物理引擎的控制下發射出去;
10: 產生一個預制體,讓這個飛機不斷的射擊;
11: 修改開始,讓玩家獲得開始消息;

 

 

步驟一和步驟二>>>>>>搭建unity項目工程>>>>>>資源整理好

1.創建一個2D的Unity項目

2.創建好scenes,resources,scripts文件夾

3.在resources文件夾下再創建一個tex文件夾

4.把要用到的圖片資源放進tex文件夾中

5.保存場景到scenes文件夾

 

 

步驟三>>>>>>配置好我們的canvas

1.創建一個Canvas節點

2.把Canvas節點的Canvas組件中的Render Mode設置為Screen Space-Camera,並把Main Camera節點拖進Render Camera屬性

3.把Canvas節點的Canvas Scaler組件的UI Scale Mode設置為Scale With Screen Size,並把Refernces Resultion設置為和Game視圖分辨率一樣的640X960

4.創建兩個空節點game_root和menu_root作為Canvas節點的子節點,game_root是用來放游戲的節點,menu_root是用來放菜單的節點。由於還沒有講場景跳轉,所以這里需要這兩個節點。

 

 

步驟四>>>>>>做一個開始界面

1.給menu_root創建一個叫menu_bg的Image子節點,把背景拖進去,set native size。

2.給menu_root創建一個叫start_button的button子節點,,把按鈕貼紙拖進去,set native size,把它自帶的Text子節點刪除。

 

 

步驟五>>>>>>做一個總的游戲的控制腳本game_scene

1.創建一個叫game_scene的腳本掛載在Canvas下面作為游戲總控制的腳本。

 

 

步驟六>>>>>>點擊開始按鈕,讓這個開始界面消失

1.打開game_scene腳本,編寫一個游戲開始函數,on_game_start_click(){}

using UnityEngine;
using System.Collections;

public class game_scene : MonoBehaviour {
   //設置一個開始游戲的標志
    bool is_started = false;

    // Use this for initialization
    void Start () {
  
    }
//刪除菜單節點函數   private void delete_menu() { MonoBehaviour.Destroy(GameObject.Find("Canvas/menu_root")); } //游戲開始按鈕點擊,菜單按鈕點擊后的響應函數,記得要設置為public權限才能關聯按鈕 public void on_game_start_click() {      //防止重復點擊  if (this.is_started) { return; } this.is_started = true;      //執行一個定時器(自帶的),讓刪除節點的函數過一會再執行,過渡效果 this.Invoke("delete_menu", 0.2f); }    // Update is called once per frame void Update () { } }

2.寫好按鈕事件函數后,可以直接在Inspector視圖里面關聯相應的按鈕,就是在按鈕的屬性視圖的最下面。

 

 

步驟七>>>>>>讓這個飛行射擊類游戲背景滾動起來

1.先把menu_root節點隱藏起來,像ps里面的把眼睛關掉

2. 給game_root創建一個叫sky的Raw Image子節點(有UVRect屬性,只有它才能動態修改紋理坐標),,用來做游戲地圖滾動背景。再把sky的貼圖屬性改成Texture(只有這種模式才能repeat紋理),我這個版本沒有Texture屬性,只有一個Default屬性,兩者效果一樣的。再把Wrap Mode改成repeat,最后Apply。

3.把背景地圖拖進sky節點的貼圖屬性,set native size。設置大小(512X1024)和縮放比例(X:1.25 Y:1.25),只要覆蓋Canvas節點就行,沒必要太大,影響性能。

4.創建一個叫sky的腳本掛載在sky下面,用來實現地圖滾動效果。

5.打開sky腳本,主要是拿到Raw Image組件,並且拿到UVRect屬性,進行動態修改地圖紋理坐標移動,又因為Repeat的特效,會讓地圖一直重復。

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

public class sky : MonoBehaviour {
  //背景圖片移動的速度設置
    public float speed = 0.1f;

  //創建一個RawImage用來操作組件實例
    private RawImage img;

    // Use this for initialization
    void Start () {
        this.img = this.GetComponent<RawImage>();
    }
    
    // Update is called once per frame
    void Update () {
        float sy = this.speed * Time.deltaTime;
        Rect uvrect = this.img.uvRect;//不是傳引用
        uvrect.y += sy;
        this.img.uvRect = uvrect;
    }
}

 

 

步驟八>>>>>>創建一個飛機,能讓它被自由的移動和拖動

1.給game_root創建一個叫plane的空子節點,在plane節點下面創建一個叫anim的Image類型的動畫子節點。

2.把飛機貼圖拖進anim節點,set native size,節點大小設置大一點,讓飛機大一點。

3.創建一個叫plane的腳本掛載在plane節點下面,用來實現飛機被鼠標自由的移動和拖動的效果。

4..打開plane腳本,先實現飛機被鼠標自由的移動和拖動;的效果

using UnityEngine;
using System.Collections;

public class plane : MonoBehaviour {
  //飛機隨着鼠標運動需要定義飛機坐標和鼠標坐標
    Vector3 start_plane_pos; // 按鈕按下的時候飛機的起始坐標
    Vector3 start_mouse_pos; // 鼠標的起始坐標;

    // Use this for initialization
    void Start () {
        
    }

    //這里有一個問題就是鼠標不按在飛機上,飛機也會跟着移動,這是還沒有處理碰撞的原因,后面會改
    //屏幕坐標轉世界坐標我的理解是把攝像機拍的二維平面坐標,也就是我們鼠標點擊的那個坐標,轉化為三維世界的坐標,三維世界的坐標才能做一些動作。
    // 響應我們的鼠標事件,GetMouseButton(0)
    
    // Update is called once per frame
    void Update () {
        if (Input.GetMouseButtonDown(0)) { // 鼠標按下的情況
            // 世界坐標來記錄
            // 記錄一下當前鼠標的位置,獲得鼠標的初始點擊位置
            this.start_mouse_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            // 記錄一下當前我們飛機的位置,獲得飛機的初始位置
            this.start_plane_pos = this.transform.position;
        }
        else if (Input.GetMouseButton(0)) {  // 鼠標在滑動的情況
            Vector3 w_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            Vector3 offset = w_pos - this.start_mouse_pos;//獲得偏移量
            this.transform.position = this.start_plane_pos + offset;//設置飛機偏移后的位置
        }
    }
}

5.修改

上次說過,這里有一個問題就是鼠標不按在飛機上,也可以移動飛機,這是因為沒有在鼠標控制飛機前判斷鼠標是否點在飛機上,所以這里的代碼修改如下

打開plane腳本

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

public class plane : MonoBehaviour {
    //飛機隨着鼠標運動需要定義飛機坐標和鼠標坐標
    Vector3 start_plane_pos;
    Vector3 start_mouse_pos;

    //-----修改-----
    private bool is_touch = false;//是否點到飛機

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    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;
     }
   }
}

 

 

步驟九>>>>>>創建一個子彈,能夠在物理引擎的控制下發射出去

1.給game_root創建一個叫bullet_root的空子節點,在bullet_root節點下面創建一個叫plane_bullet的Image類型的子節點,Hierarchy視圖中把bullet_root節點移動到plane節點的上面,這樣子彈不會跑到飛機上面去。

2.把plane_bullet節點的大小設置為width:10,height:14,顏色為紅色。

3.准備要給子彈添加剛體組件和碰撞形狀組件,所以要先進行物理引擎設置edit --> ProjectSetting -->Physices 2D;設置重力為0

4.給子彈添加Rigidbody 2D剛體組件,打鈎Freeze Rotation,不然子彈在碰撞過程中旋轉。又因為子彈的碰撞是連續的(比較特殊),所以Collision Detection設置為Continuous

5.給子彈添加碰撞形狀檢測器組件,設置碰撞檢測器的大小,再在物理引擎設置器中設置碰撞檢測器的邊界框的顏色,再打鈎always show coll總是顯示邊界框。

6.創建一個叫plane_bullet的腳本掛載在plane_bullet節點下面,用來實現子彈飛行和飛出半個屏幕后消失的效果。

using UnityEngine;
using System.Collections;

public class plane_bullet : MonoBehaviour {
   //設置子彈的速度
    public float speed = 8; // 子彈的飛行速度
  
//什么時候刪除我們的子彈,因為設計分辨率是640X960,但是如果改變了分辨率, //就不會還是半個屏幕的時候子彈消失,所以要轉換設計分辨率的屏幕的高成具體的分辨率高, //有一個scale比例,轉換完再乘0.5f就可以取一半屏幕高    private float dead_line_y;

   Rigidbody2D body;
// Use this for initialization void Start () { this.body = this.GetComponent<Rigidbody2D>(); Vector2 v = new Vector2(0, this.speed);      //剛體的運動會帶動與它相連接的整個節點的運動 this.body.velocity = v; float scale = 640.0f / (float)Screen.width; this.dead_line_y = Screen.height * scale * 0.5f; //Debug.Log("this.dead_line_y: " + this.dead_line_y); } // Update is called once per frame void Update () { // 找准已給時機來刪除我們的子彈;這里原點是屏幕中心,所以只要超過一半屏幕的高度就刪除子彈。 if (this.transform.localPosition.y >= this.dead_line_y) { MonoBehaviour.Destroy(this.gameObject); } } }

 

 

步驟十>>>>>>產生一個預制體,讓這個飛機不斷的射擊

1.為了飛機不斷地射擊,不斷地產生子彈,需要把子彈變成預制體,就是把剛才設計的子彈變成一個模板,后面可以不斷地用這個模板生成子彈。

2.在Resources文件夾下面創建一個prefabs文件夾,里面存放子彈預制體,也就是直接把plane_bullet節點拖動到prefabs文件夾下面,原節點名字變藍。

3.打開飛機節點下的plane腳本,里面添加讓飛機不斷通過子彈預制體產生子彈的實現代碼

要添加三個public的Inspector視圖屬性,一個放預制體,一個放目標父節點,也就是生成的一大堆子彈等下放在哪里,一個是子彈發射的頻率,這里分別拖進plane_bullet和bullet_root和自定義頻率數值。

4.打開plane腳本

using UnityEngine;
using System.Collections;

public class plane : MonoBehaviour
{
    //飛機隨着鼠標運動需要定義飛機坐標和鼠標坐標
    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;//是否點到飛機

    // Use this for initialization
    void Start()
    {

    }

    void shoot_bullet()
    {
        //使用預制體生成一顆子彈
        GameObject bullet = GameObject.Instantiate(this.bullet_prefab);
        // 注意這個參數要使用false,和Canvas的實現機制有關,false意思是不用世界坐標
        bullet.transform.SetParent(this.bullet_root, false);

        //使用localPosition是因為子彈和plane都有相同的父節點,兩者之間是相對坐標 
        Vector3 offset = new Vector3(0, 64, 0);
        //之所以用localPosition是因為子彈和飛機都是同一個父節點的子節點
        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();
    }
}

5.然后可以把願來Hierarchy視圖里面藍色名字的子彈節點plane_bullet刪除

 

 

步驟十一>>>>>>修改開始,讓玩家獲得開始消息

1.給總的游戲控制腳本game_scene添加游戲開始的代碼,就是點擊按鈕后觸發游戲開始,飛機開始發射子彈。

2.打開game_scene腳本

using UnityEngine;
using System.Collections;

public class game_scene : MonoBehaviour {
  
   //設置一個開始游戲的標志
   bool is_started = false;    

    //定義plane腳本,為了等一下執行里面的start_game方法,這個方法可以讓子彈開始發射
    private plane player_ctrl;

    // Use this for initialization
    void Start () {
     //獲得plane腳本
        this.player_ctrl = this.transform.Find("game_root/plane").GetComponent<plane>();
    }

   //執行plane腳本里面的start_game函數開始發射子彈
    private void game_realy_started() {
        this.player_ctrl.start_game();//開始發射子彈
    }
 
   //刪除菜單節點函數
    private void delete_menu() {
        MonoBehaviour.Destroy(GameObject.Find("Canvas/menu_root"));
    }

    //菜單按鈕點擊后的響應函數,記得要設置為public權限才能關聯按鈕
    public void on_game_start_click() {
        if (this.is_started) { // 防止重復點擊
            return;
        }
        this.is_started = true;
        //執行一個定時器(自帶的),讓刪除節點的函數過一會再執行,場景過渡效果
        this.Invoke("delete_menu", 0.2f);
        this.Invoke("game_realy_started", 1.0f);
    }

    // Update is called once per frame
    void Update () {
    
    }
}

3.打開plane腳本,里面添加游戲開始的觸發函數

using UnityEngine;
using System.Collections;

public class plane : MonoBehaviour
{

    //飛機隨着鼠標運動需要定義飛機坐標和鼠標坐標
    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;//是否點到飛機

    // Use this for initialization
    void Start()
    {

    }

    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();
    }
}


免責聲明!

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



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