給貓看的遊戲AI實戰(一)Unity俯視角遊戲初步
前言
大家好,如題目所說的,我在知乎專欄開了一個坑,專門講講和遊戲AI有關的內容。難度不高,會從非常非常基礎開始,假定用戶是我家的大貓 (′?ω?`) 。
現在Unity方面的教程和視頻可以說是汗牛充棟,為了找到有特點的角度作者我也是煞費苦心。機緣巧合最近在做一些遊戲AI相關的內容,於是就開了這個坑。
廢話不說,第一節作為適應課程(讓我適應專欄寫作),內容相對很少,但是之後有不少例子是基於這種俯視角遊戲的,俯視角遊戲在觀察AI行為方面很直觀很好用,所以要先搭一個學慣用的工程。沒基礎的同學跟著自己做一下就能搞定,有基礎的同學可以一遍掃過去毫無壓力。
一、場景搭建
按照上圖所示,搭建一個簡單的場景
1、創建一個平面作為地板,地板放大一些,3倍左右,地板默認有Mesh Collider組件。
2、放幾個方塊Cube作為障礙物,Cube默認有碰撞體Box Collider組件。
3、創建一個膠囊體代表玩家,正面最好加上一個彩色的方塊以區分正面在哪。下面有主角特寫,感覺有點像小黃人。
4、創建材質可以用來改變貼圖的顏色。在Assets目錄里創建Material,然後調個顏色,拖到物體上即可。下面有截圖。
5、為方便起見,給主角加上Rigid Body剛體組件,這是一種物理有關的組件。有了它就可以用速度、力等方法控制角色了。但是這裡注意取消重力,也就是取消Use Gravity。
前面的步驟非常基本,我家的貓已經做完了。接下來要寫點代碼控制主角的移動。
6、在Project窗口Assets文件夾點擊右鍵——Create新建——C# Script,創建一個新的C#腳本,命名為Player,拖拽到場景里的Player上(膠囊體)。
7、雙擊這個腳本,開始編輯吧。我們的代碼都經過了簡化,力求簡單。
public class Player : MonoBehaviour { // 用於控制移動速度,public變數方便在編輯器里修改 public float moveSpeed = 6; // 代表剛體組件的變數 Rigidbody myRigidbody; // Player GameObject初始化時調用 void Start() { // 在這裡給myRigidbody變數賦值,方便後面的使用。 // 如果不用這個變數也可以,那每次都需要GetComponent<Rigidbody>,會很麻煩。 myRigidbody = GetComponent<Rigidbody>(); } // 每幀被引擎調用一次,下面詳細說明 void Update() { // 後面添加 }}
8、我們打算用滑鼠+鍵盤控制Player的移動,和大量流行的俯視角射擊遊戲是一樣的,滑鼠用來指方向、開火。鍵盤的WASD用來移動。首先解決滑鼠指哪,主角就轉向哪的問題:
根據滑鼠位置,創建一個射線:
// 說明:滑鼠在屏幕上有一個位置Input.mousePosition,這個位置和遊戲無關// 就是你windows滑鼠的位置而已// 通過Camera.main,也就是主攝像機的,就可以把滑鼠位置轉換到遊戲中去,製造一條射線// 這個射線很好理解,你拿一根針,垂直屏幕,戳在滑鼠的位置,就是這條射線ray了。Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
我們拿著這個射線讓它往垂直屏幕的方向射過去,就會碰到物體(準確的說是有Collider碰撞組件或者Rigid Body剛體組件的物體),然後碰撞的交點就是我們輸入的點:
// 先創建一個RaycastHit變數,也就是射線碰撞信息,在下面一句用到。 RaycastHit hitt = new RaycastHit();// 這句話的意思:讓射線ray打出去,距離100(很長的距離),把碰撞結果返回到hitt變數中。// out參數就是用來輸出結果的,是C#特有的寫法。Physics.Raycast(ray, out hitt, 100, LayerMask.GetMask("Ground"));
如果不嚴謹地做,最後的LayerMask.GetMask("Ground")參數是不需要的,不寫的話如果滑鼠當前位置正好是Player或者障礙物,就可能會造成偏差。所以我們限定射線只能和地板碰撞,穿過其他東西。這裡需要設置一下地板的Layer,如下圖操作:
在任意一個空白的Layer上寫上Ground,就創建了一個Ground層。然後把地板的Layer設置為Ground層即可。
接著寫代碼:
// 列印Log,方便查看碰撞是否成功了。如果不成功八成是Layer設置的問題 Debug.Log("hitt", hitt.transform);// 如果碰撞到了東西 if (hitt.transform != null) {// 讓當前物體(也就是掛著這個腳本的Player)轉向目標點。注意目標點的寫法。 transform.LookAt(new Vector3(hitt.point.x, transform.position.y, hitt.point.z)); }
Update函數整個代碼如下:
void Update() { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hitt = new RaycastHit(); Physics.Raycast(ray, out hitt, 100, LayerMask.GetMask("Ground")); Debug.Log("hitt", hitt.transform); if (hitt.transform != null) { transform.LookAt(new Vector3(hitt.point.x, transform.position.y, hitt.point.z)); } }
9、經過步驟8的詳細說明,我們已經可以能讓主角跟隨滑鼠轉動了,播放一下,看看效果。
10、之後添加用WASD移動的代碼,很簡單只有一句,加在Update函數的最後面一句即可:
myRigidbody.velocity = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).normalized * moveSpeed;
這一句對新手很不友好,可以解釋為以下N句:
// 獲得輸入的H軸和V軸,也就是橫軸和縱軸,也就是W、S鍵或是A、D鍵的狀態。 float input_h = Input.GetAxisRaw("Horizontal"); float input_v = Input.GetAxisRaw("Vertical"); // 輸入是一個-1~+1之間的浮點數,把它轉化成方向向量 Vector3 vec = new Vector3(input_h, 0, input_v); // 當W鍵和D鍵同時按下時,vec會比單按W鍵要長一些,你可以想想為什麼。 // 所以這裡要把輸入歸一化,無論怎麼按鍵,vec長度都要一致。 vec = vec.normalized; // 乘以moveSpeed可以讓調整vec的長度 vec = vec * moveSpeed; // 把vec賦值給剛體的速度,就可以讓剛體運動起來了 myRigidbody.velocity = vec;
以上兩種方法,任選一種,初學者建議把後面這段,粘貼到Update函數裡面,最後的位置。
11、這樣,我們的主角就動起來咯~~
小結
本節課程基礎到沒朋友,前半部分我真懷疑大猩猩經過訓練也能做出來 o(*≧▽≦)ツ┏━┓
主要是讓我自己也熟悉一下,下節課就開車咯,大家要親手做一下才能上車。
————————————————————————————————————
對遊戲開發感興趣的同學,歡迎圍觀我們:【皮皮關遊戲開發教育】 線下教育自不必說,還會定期更新各種教程,乾貨。在你學習進步的路上,有皮皮關陪你!~
我們的官網地址:http://levelpp.com/
我們的遊戲開發技術交流群:610475807
我們的微信公眾號:皮皮關
推薦閱讀:
※半年之後國家態度出來了。給《Pokemon GO》洗地的諸位臉疼么?
※可配置的有限狀態機
※GameMaker: Studio 中文教程 #8: 惡魔行者與AI
※GDC2017: 《Lone Echo》中的VR動畫
※如何開發一款老陰逼射擊遊戲?