每個組件都是一個類的實例,要獲得某個組件,要先創建一個同類型的組件類實例,然后把實例傳引用過去,就可以對想要的組件實例進行操作。
做游戲一般創建一個邏輯節點,里面只管邏輯,再創建一個動畫節點,里面有好多動畫節點。一般我們把邏輯節點作為動畫節點的父節點。
開發步驟:
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(); } }