源代碼下載: learngdscript-cn.gd
GDScript 是一種動態類型的腳本語言,專門為免費開源遊戲引擎 Godot 製作。 GDScript 的語法類似 Python。 它的主要優點是易於使用和與引擎深度集成。 它非常適合遊戲開發。
基礎
# 單行註釋使用 # 號書寫。
"""
多行
註釋
是
使用
文檔字符串(docstring)
書寫。
"""
# 腳本文件本身默認是一個類,文件名為類名,您也可以為其定義其他名稱。
class_name MyClass
# 繼承
extends Node2D
# 成員變量
var x = 8 # 整型
var y = 1.2 # 浮點型
var b = true # 布爾型
var s = "Hello World!" # 字符串
var a = [1, false, "brown fox"] # 數組(Array) - 類似於 Python 的列表(list),
# 它可以同時保存不同類型的變量。
var d = {
"key" : "value",
42 : true
} # 字典包含鍵值對。
var p_arr = PoolStringArray(["Hi", "there", "!"]) # 池數組只能包含單一類型。
# 放入其他類型會被轉換為目標類型
# 內置向量類型:
var v2 = Vector2(1, 2)
var v3 = Vector3(1, 2, 3)
# 常量
const ANSWER_TO_EVERYTHING = 42
const BREAKFAST = "Spam and eggs!"
# 枚舉
enum { ZERO, ONE , TWO, THREE }
enum NamedEnum { ONE = 1, TWO, THREE }
# 導出的變量將在檢查器中可見。
export(int) var age
export(float) var height
export var person_name = "Bob" # 如果設置了默認值,則不需要類型註解。
# 函數
func foo():
pass # pass 關鍵字是未書寫的代碼的佔位符
func add(first, second):
return first + second
# 打印值
func printing():
print("GDScript ", "簡直", "棒呆了")
prints("這", "些", "字", "被", "空", "格", "分", "割")
printt("這", "些", "字", "被", "制", "表", "符", "分", "割")
printraw("這句話將被打印到系統控制枱。")
# 數學
func doing_math():
var first = 8
var second = 4
print(first + second) # 12
print(first - second) # 4
print(first * second) # 32
print(first / second) # 2
print(first % second) # 0
# 還有 +=, -=, *=, /=, %= 等操作符,但並沒有 ++ 和 -- .
print(pow(first, 2)) # 64
print(sqrt(second)) # 2
printt(PI, TAU, INF, NAN) # 內置常量
# 控制流
func control_flow():
x = 8
y = 2 # y 最初被設為一個浮點數,
# 但我們可以利用語言提供的動態類型能力將它的類型變為整型!
if x < y:
print("x 小於 y")
elif x > y:
print("x 大於 y")
else:
print("x 等於 y")
var a = true
var b = false
var c = false
if a and b or not c: # 你也可以用 &&, || 和 !
print("看到這句説明上面的條件判斷為真!")
for i in range(20): # GDScript 有類似 Python 的 range 函數
print(i) # 所以這句將打印從 0 到 19 的數字
for i in 20: # 與 Python 略有不同的是,你可以直接用一個整型數開始循環
print(i) # 所以這行代碼也將打印從 0 到 19 的數字
for i in ["two", 3, 1.0]: # 遍歷數組
print(i)
while x > y:
printt(x, y)
y += 1
x = 2
y = 10
while x < y:
x += 1
if x == 6:
continue # continue 語句使 x 等於 6 時,程序跳過這次循環後面的代碼,不會打印 6。
prints("x 等於:", x)
if x == 7:
break # 循環將在 x 等於 7 處跳出,後續所有循環不再執行,因此不會打印 8、9 和 10
match x:
1:
print("match 很像其他語言中的 switch.")
2:
print("但是,您不需要在每個值之前寫一個 case 關鍵字。")
3:
print("此外,每種情況都會默認跳出。")
break # 錯誤!不要在 match 裏用 break 語句!
4:
print("如果您需要跳過後續代碼,這裏也使用 continue 關鍵字。")
continue
_:
print("下劃線分支,在其他分支都不滿足時,在這裏書寫默認的邏輯。")
# 三元運算符 (寫在一行的 if-else 語句)
prints("x 是", "正值" if x >= 0 else "負值")
# 類型轉換
func casting_examples():
var i = 42
var f = float(42) # 使用變量構造函數強制轉換
var b = i as bool # 或使用 as 關鍵字
# 重載函數
# 通常,我們只會重載以下劃線開頭的內置函數,
# 但實際上您可以重載幾乎任何函數。
# _init 在對象初始化時被調用。
# 這是對象的構造函數。
func _init():
# 在此處初始化對象的內部屬性。
pass
# _ready 在腳本節點及其子節點進入場景樹時被調用。
func _ready():
pass
# _process 在每一幀上都被調用。
func _process(delta):
# 傳遞給此函數的 delta 參數是時間,即從上一幀到當前幀經過的秒數。
print("Delta 時間為:", delta)
# _physics_process 在每個物理幀上都被調用。
# 這意味着 delta 應該是恆定的。
func _physics_process(delta):
# 使用向量加法和乘法進行簡單移動。
var direction = Vector2(1, 0) # 或使用 Vector2.RIGHT
var speed = 100.0
self.global_position += direction * speed * delta
# self 指向當前類的實例
# 重載函數時,您可以使用 . 運算符調用父函數
# like here:
func get_children():
# 在這裏做一些額外的事情。
var r = .get_children() # 調用父函數的實現
return r
# 內部類
class InnerClass:
extends Object
func hello():
print("來自內部類的 Hello!")
func use_inner_class():
var ic = InnerClass.new()
ic.hello()
ic.free() # 可以自行釋放內存
訪問場景樹中其他節點
extends Node2D
var sprite # 該變量將用來保存引用。
# 您可以在 _ready 中獲取對其他節點的引用。
func _ready() -> void:
# NodePath 對於訪問節點很有用。
# 將 String 傳遞給其構造函數來創建 NodePath:
var path1 = NodePath("path/to/something")
# 或者使用 NodePath 字面量:
var path2 = @"path/to/something"
# NodePath 示例:
var path3 = @"Sprite" # 相對路徑,當前節點的直接子節點
var path4 = @"Timers/Firerate" # 相對路徑,子節點的子節點
var path5 = @".." # 當前節點的父節點
var path6 = @"../Enemy" # 當前節點的兄弟節點
var path7 = @"/root" # 絕對路徑,等價於 get_tree().get_root()
var path8 = @"/root/Main/Player/Sprite" # Player 的 Sprite 的絕對路徑
var path9 = @"Timers/Firerate:wait_time" # 訪問屬性
var path10 = @"Player:position:x" # 訪問子屬性
# 最後,獲取節點引用可以使用以下方法:
sprite = get_node(@"Sprite") as Sprite # 始終轉換為您期望的類型
sprite = get_node("Sprite") as Sprite # 這裏 String 被隱式轉換為 NodePath
sprite = get_node(path3) as Sprite
sprite = get_node_or_null("Sprite") as Sprite
sprite = $Sprite as Sprite
func _process(delta):
# 現在我們就可以在別處使用 sprite 裏保存的引用了。
prints("Sprite 有一個全局位置 ", sprite.global_position)
# 在 _ready 執行之前,使用 onready 關鍵字為變量賦值。
# 這是一種常用的語法糖。
onready var tween = $Tween as Tween
# 您可以導出這個 NodePath,以便在檢查器中給它賦值。
export var nodepath = @""
onready var reference = get_node(nodepath) as Node
信號(Signals)
信號系統是 Godot 對觀察者編程模式的實現。例子如下:
class_name Player extends Node2D
var hp = 10
signal died() # 定義一個信號
signal hurt(hp_old, hp_new) # 信號可以帶參數
func apply_damage(dmg):
var hp_old = hp
hp -= dmg
emit_signal("hurt", hp_old, hp) # 發出信號並傳遞參數
if hp <= 0:
emit_signal("died")
func _ready():
# 將信號 "died" 連接到 self 中定義的 _on_death 函數
self.connect("died", self, "_on_death")
func _on_death():
self.queue_free() # 死亡時銷燬 Player
類型註解
GDScript 可以選擇性地使用靜態類型。extends Node
var x: int # 定義帶有類型的變量
var y: float = 4.2
var z := 1.0 # 使用 := 運算符根據默認值推斷類型
onready var node_ref_typed := $Child as Node
export var speed := 50.0
const CONSTANT := "Typed constant."
func _ready() -> void:
# 此函數不返回任何東西
x = "string" # 錯誤!不要更改類型!
return
func join(arg1: String, arg2: String) -> String:
# 此函數接受兩個 String 並返回一個 String。
return arg1 + arg2
func get_child_at(index: int) -> Node:
# 此函數接受一個 int 並返回一個 Node
return get_children()[index]
signal example(arg: int) # 錯誤!信號不能接受類型參數!
延展閲讀
- Godot's Website
- Godot Docs
- Getting started with GDScript
- NodePath
- Signals
- GDQuest
- GDScript.com
有建議?或者發現什麼錯誤?在Github上開一個issue,或者發起pull request!
原著Wichamir,並由0個好心人修改。
Translated by: ShiftWatchOut
© 2022 Wichamir
本作品採用 CC BY-SA 3.0 協議進行許可。