사용자:Senouis/고도3 도큐먼트/GDScript vs Python 3

리버티게임, 모두가 만들어가는 자유로운 게임

고도 엔진에서 사용하는 GDScript는 파이썬(Python) 3 프로그래밍 언어를 게임 제작 용도로 개조한 것이 아닐까 싶을 정도로 스크립트 문법이 매우 유사합니다.

그러나 차이가 없는 것은 아니며, 파이썬 3 문법과 비교했을 때 GDScript는 엄연히 독자 구현한 언어인 만큼 중요한 차이가 있으며 구체적으로 다음과 같습니다.

주요 차이점

변수 선언

  • 파이썬 3에서는 변수 이름을 지정할 때 그냥 변수 이름만 쓰고 거기에 뭘 대입하면 됩니다. 아래는 0 값을 집어넣어 초기화한 variable1 변수입니다.
 variable1 = 0
  • 그러나 GDScript는 자바스크립트처럼 변수 이름 앞에 'var'를 넣어줘야 합니다.
var variable1 = 0
  • 전역 변수(global variable)에 한해, 고도 엔진 에디터에 변수 값을 지정하는 항목을 만들어주는 특수한 접두어 export까지 앞에 합치면, 에디터에서 GDScript 변수에 들어갈 초기 값을 지정할 수 있습니다.
# 이러면 고도 엔진 에디터에 'var exported'라는 항목이 노드 속성 창에 나타나며, 처음에 값이 3으로 설정됩니다.
export var var_exported = 3
@export var var_exported2 = 4 # 고도 엔진 4에서는 @export 어노테이션으로 변경
  • 또, GDScript는 고도 엔진 구조 상 변수 초기화를 onready 접두어로 _ready() 콜백 함수의 호출 시점까지 미룰 수 있습니다. _init() 콜백 호출 시점에서 정해지지 않는 '부모 노드나 자식 노드에 접근하는 변수'는 이 접두사를 붙여줍니다.
onready var var_onready = get_parent().get_node_or_null("Godot3_Node1")
@onready var var_onready2 = get_node("Godot4_Node2") # 고도 엔진 4에서 @onready 어노테이션으로 변경
  • GDScript는 역시 자바스크립트처럼 const 키워드로 변경 불가능한 값을 가지는 상수(constant)의 지정이 가능합니다.
# 변경 불가능한 상수 constvar2
const constvar2 = 3

함수/메서드 선언

파이썬 3은 함수 이름 앞에 'def'를 붙여 함수를 선언하고 정의하지만, GDScript는 'def' 대신 'func'을 사용합니다. 파라미터 정의는 타입 강제 지정 방법까지 전부 똑같습니다.

  • GDScript 함수 선언 및 정의
func function1(param1 : int):
  # 놀랍게도 pass가 GDScript에도 먹힙니다.
  pass

파이썬 모듈 사용법 vs GDScript 씬 사용법

  • GDScript는 파이썬의 'import' 같이 모듈 역할을 하는 다른 씬의 기능을 직접 불러와 합치는 기능이 없습니다. 대신 자바/C#/자바스크립트처럼 단일 루트 계층(Singly rooted hierarchy)을 사용하여, 원하는 기능이 있는 부모 씬을 직접 extends로 확장하여 가져와야 합니다. 가령 Node2D를 확장하여 2D 씬을 만든다면 가장 위에 다음과 같이 적습니다.
extends Node2D
  • 이 때 씬의 클래스 명칭을 class_name으로 따옴표 없이 지정할 수 있습니다. 그러면 지정한 class_name을 에디터가 인식하고 클래스명 자동 완성에 넣어줍니다. 예를 들어 Class1이라는 클래스 이름을 지정하려면 다음과 같이 적습니다.
class_name Class1

오브젝트 생성/해제

파이썬 3에서는 클래스를 인스턴스화하여 RAM에 오브젝트로 올려 실체화할 때, 클래스 생성자 메서드를 사용하지만, GDScript는 load 함수로 불러온 씬을 엔진 버전에 따라 instance()나 instantiate() 메서드로 실체화하거나, 노드 혹은 클래스에 new() 메서드를 붙여 만든 빈 오브젝트에 속성을 일일이 지정하는 방법을 사용합니다.

  • 파이썬 3 오브젝트 생성법
 variable1 = Class1() # 클래스 Class1의 생성자 호출로 오브젝트 variable1 생성
  • GDScript 오브젝트 생성법
variable1 = Node2D.new() # 지정이 속성값이 전혀 없는 내장 Node2D 클래스에서 오브젝트 variable1 생성
variable2 = Class1.new() # 프로그래머가 만든 클래스 Class1에서 오브젝트 variable2 생성
variable3 = load("res://scene_folder/scene_type1.tscn").instance() # 고도 엔진 3에서 scene_type1.tscn 씬을 불러와 인스턴스화하여 오브젝트 variable3 생성
variable4 = load("res://scene_folder/scene_type1.tscn").instantiate() # 고도 엔진 4에서 scene_type1.tscn 씬을 불러와 인스턴스화하여 오브젝트 variable4 생성

GDScript에서 오브젝트로 RAM 메모리에 올린, 즉 인스턴스화(instantiate)를 한 씬은 반드시 queue_free()나 free() 메서드로 해제해야 합니다. 파이썬 오브젝트가 해제할 오브젝트 앞에 del을 붙이는 것과 차이가 큽니다.

  • 파이썬 3의 오브젝트 해제법
 del object1
  • GDScript 오브젝트 해제법
object1.queue_free() # 게임 프레임을 고려하여 적당한 때에 오브젝트를 해제하며, 게임 성능 저하가 적기에 추천합니다.
object2.free() # 즉시 오브젝트 해제, 남용하면 성능 저하가 심각해질 수 있습니다.

match

다른 언어에 있던 switch 키워드는 파이썬과 GDScript에 없으며 그 대신 match가 그 역할을 합니다. 파이썬 3.10부터 도입된 match와 GDScript의 match는 미묘한 차이가 있는데, match 대상이 가지는 경우의 수를 지정할 때 python은 case 키워드를 쓰지만, GDScript는 case 키워드를 사용하지 않습니다.

  • 파이썬 (3.10+)
 match condition_var1:
  case 1:
   return 0
  case 2:
   return 1
  case _: # 기본값
   return -1
  • GDScript
match condition_var1:
 1:
  return 0
 2:
  return 1
 _: # 기본값
  return -1

클래스 선언

Python의 클래스보다 GDScript의 씬이 조금 더 넓은 범위를 커버하며, Python의 클래스보다 GDScript의 내부 클래스가 적은 범위를 커버한다고 보면 됩니다.

단적으로, GDScript의 내부 클래스는 생성자(constructor)가 없습니다. 그냥 클래스 이름 선언한 줄 아래에 들여쓰고 바로 멤버 변수를 초기값과 함께 정의하면 됩니다. 또 GDScript의 내부 클래스는 파이썬과 달리 self를 첫 파라미터로 넣지 않습니다. 이런 점에서 GDScript의 클래스는 오히려 자바스크립트의 프로토타입(Prototype)에 가까운 편입니다.

  • 파이썬
 class PythonClass1:
  def __init__(self):
   self.member_var1 = -1
   self.member_var2 = 1
   self.member_var3 = 0
  def get_member(self, condparam):
   if condparam == 0:
    return self.member_var1
   elif condparam == 1972:
    return self.member_var2
   else:
    return self.member_var3
  • GDScript (내부 클래스)
class GDScriptClass1:
 var member_var1 = -1
 var member_var2 = 1
 var member_var3 = 0
 func get_member(condparam):
  if condparam == 0:
   return member_var1
  elif condparam == 1972:
   return member_var2
  else:
   return member_var3

특이 사항으로, GDScript 씬 클래스가 부모 씬을 extends로 확장하여 상속받을 때, 부모 씬의 _init( ) 생성자를 자식 씬의 _init( ) 생성자 옆에 .( )을 붙여서 가져올 수 있습니다. 이때 자식 생성자에 붙은 .( )에는 자식 생성자의 파라미터 전체 또는 일부가 부모 생성자에 맞게 들어갑니다.

# 고도 엔진 3.6 'GDScript basics' 문서에서 가져옴(CC BY 3.0)

# State.gd 파일 (상속하는 클래스)
var entity = null
var message = null

func _init(e=null):
    entity = e

func enter(m):
    message = m

# Idle.gd (State.gd 상속 받음)
extends "State.gd"

func _init(e=null, m=null).(e):
    # 먼저 부모 씬 클래스 State.gd에서 _init( )이 _init(e)의 형태로 호출됨(여기 e는 Idle.gd 생성자의 e 파라미터임)
    message = m # 자식 생성자가 m 파라미터를 가지고 동작

약한 참조(Weak reference)

Python은 weakref 모듈을 사용해 약한 참조를 지원하나, GDScript는 내장된 weakref() 메서드에 오브젝트를 파라미터로 넘겨 약한 참조를 만듭니다.

var weakref_obj1 = weakref(obj1)

프로퍼티 정의

클래스 멤버 변수를 조작하는 getter 메서드와 setter 메서드의 정의법이 다릅니다.

  • 파이썬
 class PythonClass1:
  def __init__(self):
   self.__member_var1 = 0
  
  # getter를 '@property' 어노테이션으로 정의
  @property
  def member1(self):
    return self.__member_var1
  
  # setter를 '@(프로퍼티 이름).setter' 어노테이션으로 정의
  @member1.setter
  def member1(self, value):
    self.__member_var1 = value
 
 obj1 = PythonClass1()
 obj1.member1 = 32
 print(obj1.member1) # 32를 콘솔에 출력
  • GDScript 씬 클래스
var variable1 = 7 setget var1_set, var1_get # setter, getter 모두 선언
var variable2 = 3 setget var2_set # setter만 선언
var variable3 = 2 setget ,var3_get # getter만 선언

func var1_set(value):
 variable1 = value

func var1_get():
 return variable1

func var2_set(value):
 variable2 = value

func var3_get():
 return variable3

참고 자료