博客 / 詳情

返回

Y 分鐘速成 GDScript

源代碼下載: 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 協議進行許可。

user avatar fyuanlove 頭像 liujunqi 頭像 xiaodaigua_ray 頭像 mianduijifengba_59b206479620f 頭像
4 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.