做自己的Pokemon Go:Unity Location-Based Game遊戲製作教學(I)

【寫在前面】這篇教學主要是提供給小樽本學年 (105上學期) 教授AR/VR課程的寶貝學生們使用,教學中使用的Unity軟體與SDK會有因為版本差異而產生問題,因此修課同學初接觸沒有把握時,請先使用小樽在課程社團內提供的素材,等熟悉操作後可以在自行更換版本操作,因此因為版本不同而產生的問題,小樽不一定都能解答(因為組合太多種),可以先搜尋對應的官方資料來確認版本相容性,通常只要有Bug都會有人討論,google一下也能找到唷。

特別感謝:強者 Yi-Wei 學弟協助

Last update:

2017/1/11:加入教學2連結與GitHub資源網址

2017/1/10:將程式碼顯示從圖片改成文字

軟體版本:Unity 5.5.0f3  MapNav1.3.4 (如要發佈製手機Android SDK/JDK請自行安裝好)

快速跳轉:做自己的Pokemon Go:Unity Location-Based Game遊戲製作教學(II)

1.開一個新的專案,匯入MapNav 1.3.4.unitypackage (最新版本有些尺寸自適應修改,如果沒有把握自行排除異動,請使用小樽提供的版本)

2.在Hierachy的地方建立一個空物件(Create Empty),在本教學中將之命名為GoogleMap,並將Layer設定為GoogleMap,設定Layer方式如下:

2-1 選擇該物件,並且在其屬性面板找到Layer的下拉選單,按Add layer新增我們要自定義的Layer

2-2 在可以輸入的Layer欄位輸入我們要建立的Layer名稱,等等程式會透過這個地方來辨識攝影機要顯示的內容,因此後面只要使用到都要注意大小寫

2-3 確認我們這個空遊戲物件(Game Object)的Layer已經選擇成剛剛建立的GoogleMap

3.在Hierachy的地方將攝影機Main Camera移至GoogleMap底下(變成其子物件,方便我們群組管理),並設定參數如下圖:請將攝影機的Layer也設定成GoogleMap,並將Clear Flags改成Depth Ony(讓攝影機背景只顯示深度),Culling Mask選擇的就是GoogleMap這個Layer–意思就是讓這台攝影機只顯示屬於GoogleMap這層Layer的東西,其他不顯示(Render)

4.到專案(Project)視窗的Assets底下,找到步驟1匯入的MAPNAV資料夾,將其子資料夾Prefabs底下的2D_Pointer及Map兩個物件拖移至GoogleMap底下,如下圖:

5.將2D_Pointer (代表使用者的游標) 的Layer也設定到GoogleMap,這樣這一層的攝影機才能正確顯示它,並且把Position(位置)的Y座標設定為0.1,其用意只是確保游標是在地圖(Y座標0)之上,你想改其他數字嘗試看看也是ok滴

6.接著我們要設定如果遊戲沒有讀取到GPS時預設的GPS座標起點,所以我們必須先取得一組我們自己想要的經緯度數值,例如:可以透過 Google Map 做選取,只要在你想作為預設起點的地方按下滑鼠右鍵,選擇”這是哪裡?”就可以取得一組經緯度數值如下:

7.點選Map物件,把Layer設定到GoogleMap,其他配置如下,GPS Emulator可以等要發佈到手機時在取消,下方的GUI按鈕與允許使用者觸控手勢的功能可以先關閉:

8.到上面步驟我們基本的定位環境功能已經完成,按下Play執行看看,代表使用者的游標會出現在我們起始設定的位置,並且可以使用鍵盤的W/A/S/D來試著控制游標:

接著我們希望達成當使用者走到特定位置的時候,可以觸發地圖上對應的圖案產生變化的效果,類似Pokemon Go裡走到Stop Station/道場位置時,會有展開的動畫那樣的概念,因此我們需要先定義出這些可以互動的地點。

9.在Assets的地方按滑鼠右鍵,用Import New Assets功能匯入一張帶透明的png檔 (本教學中是檔名為 Dot.png 的一張驚嘆號圖檔) ,匯入後點選這張圖檔,在其屬性的欄位中把Texture Type改成Sprite後按下Apply套用,這個步驟是將png圖檔轉成一個2D的遊戲物件,這樣我們才能在專案中正常的使用它。

10.接下來先在 Hierachy 中的 GoogleMap底下建立一個空的遊戲物件DOT (Create Empty)

10-1.首先在Tag (標籤) 的地方(下圖橘框處),新增一個叫Dot的標籤並賦予給他,這是稍後我們撰寫Script (程式腳本) 時會用到的名稱,所以也請注意大小寫,它和Hierarchy上的名稱沒有直接關係,只是方便我們辨識所以取一樣,Layer選取到GoogleMap如下圖紅框處。

10-3.Unity預設攝影機是水平視角,但由於MAPNAV外掛中的攝影機會被改成由上往下的鳥瞰視角,因此這個視角會看不到Dot,所以將Rotation X旋轉90度讓圖片物件平躺就可以被看到,如下圖紫框處。

10-4.在DOT被選取的狀態下,於屬性面板欄位下方,按一下Add Component,在出現的選單中選擇 Physics > Capsule Collider ,建立一個膠囊狀的碰撞器,如下圖淡黃框範圍,並且把其Is Trigger打勾,如黃框的標示。

10-5.在碰撞器建立完後,在其下方再按一下Add Component,在出現的選單中選擇 MAPNAV>Set Geolocation,如下圖淡籃框範圍,使用Google Map或其他定位工具找到你希望放置這個互動點的經緯度,將其數值輸入如下圖藍框處,scale X/Y/Z是設定這個點的範圍大小,其數值會直接對應到Transform的Scale值,所以用手動拉也可以(快速鍵:w移動/e旋轉/r縮放),在本教學中是取0.36的大小,讓他大約跟圖片視覺上吻合。完成上述設定後按下Apply套用。

11.將步驟9建立好的2D Sprite(DOT)拖曳到Hierachy中的空物件DOT下方,使其成為子物件,並且確認Layer有設定成Google Map如下圖,也注意一下Transform的數值沒有跑掉,這樣他才能乾淨的繼承空物件上剛剛設定好的屬性,正確顯示在地圖上:

12.點選2D_Pointer,在屬性欄位下方點選 Add Component>New Script,命名一個叫Player 的 C sharp 程式腳本,完成後如下圖紅框處。

13.雙擊上圖紅框第二行Script後方的Player,會開啟Unity的程式編輯器,裡面已經有預設填好的程式碼,由於偵測是否到達正確地點是透過判斷游標與地點碰撞器是否發生碰撞事件 ,因此請將下面的程式碼打在void Update () {  }後方:

[code lang=”csharp”]

void OnTriggerStay(Collider other){
if(other.tag == "Dot"){
other.gameObject.transform.GetChild(0).GetComponent<Renderer>().material.color = Color.green;
}
}

void OnTriggerExit(Collider other){
if(other.tag == "Dot"){
other.gameObject.transform.GetChild(0).GetComponent<Renderer>().material.color = Color.white;
}
}

[/code]

這段程式碼的意思就是當2D_Pointer這個游標碰到並停留在觸發器上(OnTriggerStay)時,tag標籤名為Dot的遊戲物件,他的第一個子物件(GetChild(0)) 顯示(Renderer)疊加顏色改成綠色 (Color.green),而當游標離開觸發器(OnTriggerExit)時,顯示疊加的顏色改成原色 (Color.white)

到上面步驟完成後存檔,Play執行看看,是不是當控制游標碰到紅色驚嘆號後,紅色驚嘆號就會變成綠色,如果是就沒問題啦~可喜可賀!

為了讓效果更明顯,並且接續我們下一個教學 [ Unity Location-Based Game遊戲製作教學(II) ],我們再來加一點效果,呈上面的內容,我們希望當使用者觸發事件後,不但圖片會變色,還會出現文字提示,由於我們希望中文文字的效果能夠稍微好看一點,因此建議用製作圖片的方式將文字在外部製作好再導入Unity使用,在本教學中可以先使用素材W.png,接下來步驟如下

14.參照步驟9的方法,把W.png導入Assets變成2D Sprite,拖放到空物件DOT底下,並且排在Sprite DOT底下變成第二個子物件,可以手動稍微調整一下位置與大小,以本教學為例,調整了Y軸的位置於-1.5,是為了讓它顯示再DOT驚嘆號圖片的下方,確認Layer設定成GoogleMap以後,把Activity狀態的勾勾取消,讓物件預設是不可見狀態,如下圖。

15.回到2D_Pointer再次雙擊Script的Player,並在上一次撰寫的基礎上新增程式碼如下:

[code lang=”csharp”]

void OnTriggerStay(Collider other){
if(other.tag == "Dot"){
other.gameObject.transform.GetChild(0).GetComponent<Renderer>().material.color = Color.green;
other.gameObject.transform.GetChild(1).gameObject.SetActive(true);
}
}

void OnTriggerExit(Collider other){
if(other.tag == "Dot"){
other.gameObject.transform.GetChild(0).GetComponent<Renderer>().material.color = Color.white;
other.gameObject.transform.GetChild(1).gameObject.SetActive(false);
}
}

[/code]

這段程式碼的意思就是,當游標與碰撞器接觸時,標籤為Dot的物件的第二個子物件(GetChild(1))的狀態(SetActive)要變成啟動(true),當碰撞觸發事件解除後,狀態(SetActive)又變回取消(false),執行看看結果吧~

本教學到此告一段落,為了怕有初學的同學/朋友不確定自己Script是否輸入正確,小樽將完整的Script (Player.cs)也截圖附上,有時候程式有錯誤可能是少了個分號(;)或者大括號{},也有可能是宣告的名稱大小寫沒有對上以至於程式找不到目標 (例如Tag),如果有錯誤就是仔細檢查一下吧

[code lang=”csharp”]

using UnityEngine;
using System.Collections;

public class Player : MonoBehaviour {
// Use this for initialization
void Start () {
}

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

void OnTriggerStay(Collider other){
if(other.tag == "Dot"){
other.gameObject.transform.GetChild(0).GetComponent<Renderer>().material.color = Color.green;
other.gameObject.transform.GetChild(1).gameObject.SetActive(true);
}
}

void OnTriggerExit(Collider other){
if(other.tag == "Dot"){
other.gameObject.transform.GetChild(0).GetComponent<Renderer>().material.color = Color.white;
other.gameObject.transform.GetChild(1).gameObject.SetActive(false);
}
}

}

[/code]

如果要新增其他互動點,方法有很多種,如果是初學嘗試,可以試著建立不同的空物件並給予觸發器,放置在不同的位置並且給予不同的Tag,這樣程式碼可以基於不同的Tag來作判別,再命令各自的子物件做變色或開關,如果對程式語言已經有一定熟悉度的同學,就可以嘗試共用標籤的寫法,希望大家都能做出自己滿意的成果唷。

接續  做自己的Pokemon Go:Unity Location-Based Game遊戲製作教學(II)

本教學中所有程式碼小樽都放在GitHub上,需要請自取 https://github.com/skyhunter/LocationBasedGame