본문 바로가기
Godot

[GodotDocs][Step by step] 5. 시그널 사용(GDScript)

by 채식금지 2024. 1. 4.
728x90

본 게시글은 고도엔진 공식문서에 작성된 Using signals를 정리하였습니다.

신호(Signal)

  • 버튼을 누르는 것과 같은 특정 상황이 발생했을 때 노드가 보내는 메시지
  • 게임 오브젝트가 서로 참조하지 않고도 다른 오브젝트의 변화에 반응할 수 있게 해준다.
  • 유니티의 이벤트와 유사한 역할을 한다.

 

씬 설정

  • [GodotDoc][Step by step] 3. 첫 번째 스크립트 만들기(GDScript) 에서 이어서 작업한다.
  • 상단 메뉴에서 Scene>New Scene를 선택하여 새로운 씬을 추가한다.
  • Scene 도크에서 2D Scene를 선택하여 Node2D 노드가 새로 만든 씬의 루트 노드가 되도록 만든다.
  • 이전 작업에서 만들었던 sprite_2d.tscn 씬을 새로 만든 씬의 자식 노드로 배치한다.
  • [GodotDoc][Step by step] 2. 인스턴스 생성 참고
  • Scene 도크에서 루트 노드를 선택한 후, ➕아이콘을 선택하여 새로운 자식 노드를 추가한다.
  • Create New Node 팝업창이 열리면 검색창(Search:)에 Button이라고 입력한다.
  • Button 노드를 선택한 후 Create 버튼을 선택하여 Button 노드를 추가한다.
  • Scene 도크에서 새로 추가된 Button 노드를 선택한다.
  • 뷰포트에서 Button 노드의 크기를 조절한다.
  • Inspector 도크의 Text 속성 아래있는 텍스트 입력창에 Toggle motion라고 입력한다.
  • 작업했던 씬은 node_2d.tscn 으로 저장한다.
  • FileSytem 도크에서 node_2d.tscn 씬을 우클릭한다.
  • Scene as Main Scene를 선택하여 node_2d.tscn 씬을 메인 씬으로 설정한다.

 

에디터에서 시그널 연결

  • Scene 도크에서 Button 노드를 선택한 후 Inspector 도크 옆에 있는 Node 도크를 선택한다.
  • Node 도크에서 pressed() 시그널을 더블 클릭한다.
  • Connect a Signal to a Method 팝업창이 열리면서 Sprite2D 노드가 자동으로 선택된다.
  • 자동으로 선택되지 않았다면 직접 선택한다.
  • Connect 버튼을 선택하면 my_sprite_2d.gd
    스크립트에 자동으로 _on_button_pressed 함수가 생성된다.

  • 앞으로 버튼을 누르면 _on_button_pressed 함수가 자동으로 호출된다.
  • _on_button_pressed 함수에 아래 내용을 추가한다.
func _on_button_pressed():
    set_process(not is_processing())
  • set_processfalse를 입력하면 is_processing 함수는 false를 반환하게 되고, 매 프레임마다 _process를 호출하지 않아 Sprite2D 노드는 움직이지 않는다.
  • set_processtrue를 입력하면 is_processing 함수는 true를 반환하게 되고,매 프레임마다 _process를 호출하여 Sprite2D 노드가 움직인다.
  • not 키워드를 이용하면 is_processing의 반대값을 반환하게되어, 버튼을 누를 때마다 Sprite2D 노드의 움직임을 제어할 수 있다.

 

타이머 추가

  • FileSystem 도크에서 spite_2d.tscn 씬을 불러온다.
  • Scene 도크에서 Sprite2D 노드를 선택한 후 버튼을 추가하였을 때와 동일한 방식으로 Timer 노드를 자식 노드로 추가한다.
  • Scene 도크에서 Timer 노드를 선택한다.
  • Inspector 도크에서 Autostart 속성 옆의 체크 박스를 체크한다.
  • sprite_2d.tscn 씬을 저장한다.

 

코드에서 시그널 연결

  • 에디터 대신 코드에서 시그널을 연결할 수도 있다.
  • my_sprite_2d.gd 스크립트에 아래 내용을 추가한다.
func _ready():
    var timer = get_node("Timer")
    timer.timeout.connect(_on_timer_timeout)

func _on_timer_timeout():
    visible = not visible
  • _ready는 노드가 준비 상태가 되었을 때 한번 호출된다.
  • get_node("Timer") 는 자식 노드로 추가했던 Timer 노드를 반환한다.
  • timeoutTimer 노드에서 설정한 시간이 되었을 때 동작하는 시그널이다.
  • timer.timeout.connect(_on_timer_timeout)을 입력하면 timeout
    시그널이 동작하면 _on_timer_timeout 함수를 자동 호출하게 된다.
    • visibletrue일 경우 노드가 화면에 출력되고, false일 경우 화면에 출력되지 않는다.

 

커스텀 시그널

  • 스크립에서 원하는 시그널을 직접 선언할 수 있다.
  • my_sprite_2d.gd 스크립트 맨 윗 줄의 extends Sprite2D 바로 아래에 시그널을 선언한다.
signal process_enabled
signal visiblity_changed(is_visible: bool)
  • signal process_enable 처럼 신호만 발생시킬 수도 있고, signal visiblity_changed 처럼 필요한 변수를 함께 전달할 수도 있다.
  • my_sprite_2d.gd 스크립트를 저장한 후 Node 도크를 확인하면 선언한 시그널을 확인할 수 있다.
  • 선언한 시그널은 emit 함수를 이용하여 신호를 발생시킨다.
  • my_sprite_2d.gd 스크립트에서 _on_button_pressed
    함수와 _on_timer_timeout 함수에 각각 emit 함수를 호출하도록 수정한다.
func _on_button_pressed():
    set_process(not is_processing())
    if is_processing():
        process_enabled.emit()

func _on_timer_timeout():
    visible = not visible
    visiblity_changed.emit(visible)
  • 추가한 커스텀 시그널들은 다른 노드에 연결하여 사용할 수 있다.

 

완성된 스크립트

var speed = 400
var angular_speed = PI

func _init():
    print("Hello, world!")

func _ready():
    var timer = get_node("Timer")
    timer.timeout.connect(_on_timer_timeout)

func _process(delta):
    rotation += angular_speed * delta    
    var velocity = Vector2.UP.rotated(rotation) * speed
    position += velocity * delta

func _on_button_pressed():
    set_process(not is_processing())
    if is_processing():
        process_enabled.emit()

func _on_timer_timeout():
    visible = not visible
    visiblity_changed.emit(visible)