<a target=_blank href="http://weibo.com/DoubleIris">微博@捲毛的呈秀波</a>
上回我們已經建立了遊戲中的基本要素,這回我們要建立一個交互界面。
作爲一個塔防遊戲,他的互動要素有以下
- 點擊按鈕
- 在空地放置炮臺
簡言之就是操作界面的建立。
UI界面
我們來想一下UI界面的要素
- 按下按鈕之後可以創建炮臺
- 能在怪物的移動軌道之外建立炮臺
僞代碼可以寫成
if(buttonpressed == TRUE)
Tower.Render.enabled = true;
if(Tower.Render.enabled == true){
if(mousecontact.Object != path&&!=tower){
createTower(Pos(mouse.position));
Tower.Rander.enabled = false;
}
}
前期工作
要完成這兩個功能,我們需要了解幾個函數
Object.Instantiate()
這個函數是不是很眼熟,沒錯,這就是上一篇中我們用來複制Monster 的克隆函數,具體細則參照上一篇。
這個函數用來獲取鼠標按鍵的返回消息,參數分別對應左右中鍵。
這個函數用於生成GUI界面的按鈕,返回按鈕是否被按下。一共有六個重載,挑選自己所需要的使用就好
用來返回射線是否觸碰到物體
不太懂沒關係,接下來我們將會實際使用到。
首先將我們上次在場景中創建的Tower隱藏或者移除。
邏輯1
於Project-》Script下新建一個腳本,名爲createtower 。
首先我們要繪製GUI按鈕,在MonoBehavior中添加如下代碼
void OnGUI()
{
if(GUI.Button(new Rect(0,0,64,64),"點擊這裏”))
Debug.Log("click");
}
將它掛載到Main Camera上點擊播放,可以看見下圖
左上角出現了按鈕,並且點擊之後consle會輸出信息“click”
這裏就要了解OnGUI這個過程了,他是專門用來繪製GUI可見對象的一個函數。我們使用GUI。Button生成的按鈕在這裏會被調用。具體說明請戳我
而在這裏我們需要做的事情是,按下按鈕後,進入可以放置炮臺的狀態。所以我們要新建一個bool 類型的變量用來管理狀態。
bool isCreate = false;//默認關閉
然後修改我們的OnGUI
void OnGUI()
{
if(GUI.Button(new Rect(0,0,64,64),"點擊這裏"))
isCreate = true;
if (isCreate == true)
{
GUI.Button(new Rect(Input.mousePosition.x - 32, Screen.height - Input.mousePosition.y - 32, 64, 64), "這裏是模型");
Debug.Log("Click");
}
}
在這裏我們又生成了一個實時跟隨鼠標的GUIButton,用來告訴玩家當前處於可以創建炮臺的狀況= =因爲我沒模型所以用了String來代替。
檢查一下效果
邏輯2
現在我們擁有了可以操作的按鈕但是還是不能生成炮臺。
生成炮臺需要兩個判斷
- 是否處於可以創建炮臺的模式下
- 鼠標點擊的地方是不是path
第一個判斷我們已經使用bool變量來存儲了,現在要解決第二個判斷。這個就要用到之前出現的兩個函數Raycast和GetMBDown。
聲明兩個變量,Ray,和RayHit用於Raycast的調用
public Ray distance;
public RaycastHit hit;
還要聲明一個gameObject類,用來掛載Tower
然後在Update中添加下列代碼
void Update ()
{
distance = camera.ScreenPointToRay(Input.mousePosition);//獲取從攝像機的投影平面向鼠標位置發射的射線
if (isCreate == true)//前提需要能夠創建炮臺
{
if (Physics.Raycast(distance, out hit))//如果射線觸碰到了物體
{
if (hit.collider.tag != "path")//前提2不是怪物的路徑
{
if (Input.GetMouseButtonDown(0) && hit.collider.name != "Tower")//按下左鍵切鼠標觸碰到的碰撞體不是塔
{
Object.Instantiate(mTower, hit.collider.transform.position, Quaternion.identity);
isCreate = false;//把炮臺複製過來,並且關閉可以創建的狀態
}
}
}
}
}
然後運行一下
如果你和我的設置一樣會發下有兩個個問題
- 創建的炮塔都重複在中間,並且一個疊加在另一個上面
- 炮臺下沉在地面之下
第二個問題很簡單,因爲我們的圓柱本來就要上升0.5個單位,所以在Instantiate (的transform後面加Vec(0,0.5,0))就能夠讓炮臺準確的在地面上浮現了。
第一個問題好像完全不符合情理,我們已經在代碼中做了判定,卻依舊能夠在炮塔身上建立炮臺?
這個問題我們需要深究一下。
重新看我們的代碼:
if (Input.GetMouseButtonDown(0) && hit.collider.name != "Tower")
我們可以看見我們所做的判斷是判定射線觸碰到的物體名字是否爲Tower,但是實際觀察一下我們的組件欄
他的名字是Tower(Clone)!!! 你是不是完全沒有在意!
再看另一行代碼
Object.Instantiate(mTower, hit.collider.transform.position, Quaternion.identity);
這行代碼將我們的炮臺複製到的地方是射線觸碰到物體的位置(中心),這不符合常理,因爲地面是一個物體,我們不可能將所有炮臺都建立在地面中心。
關於這一點我們有兩種解決方案:
- 在地圖上建立一個個炮架,這樣炮臺就會建立在炮架上。
- 把炮臺的複製位置換成射線觸碰的點。
在這裏,加入選用第一種方案的話,勢必就要再給炮架添加一個判斷腳本,太繁瑣所以我們直接將hit.collider.transform.position改變成hit.point.position.
最後我們的代碼長成這個樣子
void Update ()
{
distance = camera.ScreenPointToRay(Input.mousePosition);
if (isCreate == true)
{
if (Physics.Raycast(distance, out hit))
{
if (hit.collider.tag != "path")
{
{ //getMouseDown(x) :x=0,left button;1,right button;2,middle button)
if (Input.GetMouseButtonDown(0) && hit.collider.name != "Tower(Clone)")
{
Object.Instantiate(mTower, hit.point + new Vector3(0f, 0.5f, 0f), Quaternion.identity);
isCreate = false;
Debug.Log(hit.point );
Debug.Log(hit.collider.name);
}
}
}
}
}
}
然後你就能看見下圖
耶,我們的塔防遊戲又完善了一步。
ps,筆者雜談
最近由於各種瑣碎的事情,導致上週的教程完全沒有更新,今天突然有一個讀者諮詢我教程,感覺自己的努力也是有回報的。
於是登陸了CSDN,看見還給我的博客頒發了持之以恆的徽章。頓時覺得只要你們能從筆者的簡陋教程中獲取一些知識,筆者再辛苦也是值得的。
我是妖哲,明天見~