Godot3遊戲引擎入門之三:移動我們的主角
一、前言
說明:我目前使用的 Godot 3.1 預覽版,所以會與 Godot 3 的版本有一些區別,介面影響不大,如果要使用我上傳的 Github Demo 程式碼,記得去官網下載 3.1 預覽版(或者等之後正版釋出)然後就可以正常開啟執行 Demo 了。
二、正文
本篇目標
- 瞭解圖片材質在 Godot 中的匯入功能
- 建立簡單的場景,調整節點渲染次序,給節點新增指令碼
- 簡單的 GDScript 指令碼功能介紹和使用
建立場景
首先是建立我們的遊戲主場景,相比上一節,這個場景會更加簡單,首先場景尺寸我在專案設定中設成了 600x600 ,新增一個 Node2D 節點作為根節點,並改名為 Game ,然後新增兩個子節點,一個是我們的主角 Sprite 節點,命名為 Knight ,再新增一個 Sprite 節點作為遊戲中的地面,單擊,命名為 Ground ,接著修改相應的圖片材質屬性。這裡的操作有幾點需要注意:
1. 圖片的匯入
如果你滾動滑鼠滾輪,放大我們的視窗,你會發現我們的主角:騎士的圖片放大後有點模糊,這裡我希望能像有些畫素遊戲一樣能夠清晰地顯示圖片各個畫素( 2D 遊戲中一般叫完美畫素: Pixel Perfect ),那樣即使圖片很小,畫素化後依然顯得更加逼真,如何在 Godot 中實現呢?非常簡單, Godot 已經為我們預製好了,選中圖片,在屬性面板上方匯入設定中進行相應的設定即可,非常簡單,記得設定好之後一定要點選 Reimport 重新匯入:
經過畫素設定,我們的主角影象放大後像素更加清晰,是不是感覺更加 2D 了?熟悉 Unity 的同學知道,其 2D 場景是偽 3D 場景打造所以並沒有 Pixel Perfect 功能。想深入瞭解 Godot 中更多關於圖片壓縮模式的知識,可以參考官方的壓縮文件:
2. 重鋪圖片匯入
接著是地面的圖片設定,還是使用上一節中的圖片,之前我已經提到了如何設定普通圖片材質的平鋪屬性,不過,之前的設定在重新開啟後會丟失,如果儲存平鋪設定?我們需要在圖片匯入的時候進行相關的設定,儲存並重新匯入即可,相關設定如下圖:
大致的步驟就是:先選中圖片,啟用 Repeat 功能,最後點選 Reimport 重新匯入圖片材質,接著選中地面 Ground 節點,開啟圖片的 Region 區域設定,設定高度和圖片原高度相等,為 256 ,寬度設定為你想要的寬度,比如我設定的是 800 (或者更高)。最後你會發現我們的地面圖片在寬度方向上會沿著 X 軸方向自動平鋪, OK ,完美解決!
3. 節點渲染順序
有一個小問題是在我們添加了兩個子節點後,移動位置,我們的場景顯示是這樣的:
主角幹嘛躲在草叢後面啊?別慫,出來幹啊!哈哈,其實原因在上圖我已經說明了,這是由於 Godot 中節點的渲染順序引起的,越在上面的節點,渲染順序越前,所以下面的節點會最後渲染,造成的結果就是:可能會覆蓋之前渲染的上面的一些節點。解決方案很簡單,移動一下地面和主角節點的次序就可以了。
新增指令碼
簡單的場景打造好了,接下來就是如何使用鍵盤輸入控制騎士的位置移動了,學習 GDScript 指令碼語言的最佳時機到來,本篇作為指令碼開場白,僅僅做一個簡單的介紹,然後編寫程式碼實現一些簡單的功能。
在瞭解 GDScript 指令碼之前,我想比較一下 Godot 與 Unity 指令碼的一些共同點,如果你有遊戲開發經驗,你會發現他們有很多相似點。首先,我們選中 Game 根節點,然後在右上角點選新增指令碼,建立一個簡單的指令碼檔案,寫上一些方法( # 號代表註釋,和其他語言裡的 // 一樣):
# 節點啟用後執行該方法
func _ready():
print('ready!')
# 每幀執行此方法
func _process(delta):
print('process with delta time: ', delta)
# 處理物理引擎的方法
func _physics_process(delta):
print('physics process with delta time: ', delta)
# 處理裝置輸入的方法
func _input(event):
print('input event: ', event)
# 處理裝置輸入的另一個方法
func _unhandled_input(event):
print('unhandled input event: ', event)
上面的程式碼通過方法名字和我的註釋說明應該能明白它的含義了,現在看下 Unity 中 C# 指令碼元件的語法:
void Awake()
{
Debug.Log("Awake");
}
void Start()
{
Debug.Log("Start");
}
void Update()
{
Debug.Log("Update: " + Time.deltaTime);
}
void LateUpdate()
{
Debug.Log("LateUpdate: " + Time.deltaTime);
}
void FixedUpdate()
{
Debug.Log("FixedUpdate: " + Time.deltaTime);
}
驚人的相似,不是嗎?所以說,開發遊戲有時候只是軟體不同,思路大體還是相同的,正所謂道不同、理相同!好的,裝逼到此結束!開始拿起筆頭編寫指令碼吧,這裡我把基本完工的指令碼貼出來,你可以從英文單詞釋義或者我的註釋中得到每一行程式碼的功能是什麼樣的,具體如下:
# 繼承於Node2D
extends Node2D
# 常量,表示速度(畫素)
const SPEED = 200
# 定義一些變數,不需要型別
var maxX = 600 # 角色運動右邊界
var minX = 0 # 角色運動左邊界
var knight # 騎士節點
# 節點進入場景開始時呼叫此方法,常用作初始化
func _ready():
# 獲取節點並賦值給變數knight
knight = self.get_node("Knight")
# 每一幀執行此方法,delta表示每幀間隔
func _process(delta):
# Input表示裝置輸入,這裡D和右光標表示往右動
if Input.is_key_pressed(KEY_D) or Input.is_key_pressed(KEY_RIGHT):
moveKnightX(1, SPEED, delta)
elif Input.is_key_pressed(KEY_A) or Input.is_key_pressed(KEY_LEFT):
moveKnightX(-1, SPEED, delta)
# 自定義函式,direction表示方向,speed表示速度,delta是幀間隔
func moveKnightX(direction, speed, delta):
if direction == 0:
return
# position屬性為節點當前置,Vector2向量簡單乘法
knight.position += Vector2(SPEED, 0) * delta * direction
# 越界檢測
if knight.position.x > maxX:
knight.position = Vector2(maxX, knight.position.y)
elif knight.position.x < minX:
knight.position = Vector2(minX, knight.position.y)
OK ,大功告成,執行我們的遊戲,效果是這樣的:
不過……有點問題啊:主角顯然能置身於場景之外啊,而且往左移動的時候居然是邁克爾傑克遜附身——沒有轉身!別急,解決方法非常簡單:
第一個:場景邊界問題,在 _ready()
方法中的最後加入程式碼:
# get_rect方法獲取節點邊框
maxX -= knight.get_rect().size.x / 2
minX += knight.get_rect().size.x / 2
第二個:左移轉身問題,只需在 moveKnightX(...)
方法的最後加入程式碼:
# 節點的scale屬性為縮放向量
# 縮放向量x值為1就是往右,-1表示往左縮放
knight.scale = Vector2(direction, 1)
終於完工,儘管沒有真正的角色跑步動作(後續文章會講解如何使用 Godot 強大的動畫工具建立角色動畫),但是我們的移動功能算是完整了,看圖,最終結果:
三、總結
本篇講解到的知識點:
- 圖片材質的匯入模式
- 節點渲染順序
- 最基礎的 GDScript 指令碼入門
- 使用指令碼獲取節點屬性,偵聽輸入控制主角移動
PS: 我使用的是 Godot 3.1 版本,原始碼已經上傳到 Github ,如果需要在 Godot 3.0 版本上執行你可以自行建立節點,把圖片和程式碼複製過去即可,建議使用最新 3.1 預覽版,因為 3.1 即將釋出!哦吼!