오늘은 캐릭터 충돌 처리를 진행해 본다.
1. signal hit 생성
우리는 플레이어가 적과 부딪혔을 때를 탐지하려 한다. 아직 적은 만들지 않았지만 Godot의 signal 기능을 사용해 볼 수는 있다.
먼저 Player 스크립트의 extends Area2D 바로 다음 줄에 아래 스크립트를 넣어주자.
signal hit
이 작업을 통해 우린 Player 내부에 "hit"이라는 이름의 커스텀 시그널을 정의해 줬다.
스크립트 저장 후 godot 인스펙터 창 옆에 있는 Node 탭을 보자.
우리는 Area2D 노드를 통해 플레이어가 적과 충돌했는지 확인해 줄 것이다.
우리가 만들 적에게는 RigidBody2D라는 노드가 붙어있을 것이고, rigidbody2D 노드는 Area2D(플레이어)와 충돌할 때 body_entered() 신호를 방출한다.
사진 속 body_entered(body: Node2D) 부분에 오른쪽 마우스를 클릭하고, Connect를 눌러주자.
Method 기본 이름은 가능하면 건드리지 않는 걸 권장한다. 이 상태로 connect 버튼을 눌러 진행하면 Player 스크립트 최하단에 아래 같은 스크립트가 자동 생성된다.
_ready()가 게임 시작 시에, _process()가 한 프레임에 한 번씩 호출되는 함수라면, 이 함수에선 Area2D가 다른 오브젝트와 충돌했을 때 호출된다.
줄 번호 옆에 있는 초록색 아이콘을 보자. 이건 이 함수가 signal과 연결되어 있다는 뜻이다. 다시 말해, 이 함수는 기존 함수들처럼 스크립트 작성자가 자유롭게 호출할 수 있는 함수가 아니라, 게임 내에서 특정 상황이 발생하면 자동으로 실행되어주는 함수다.
그래서 function의 이름과 매개 변수가 연결된 signal과 매칭이 되어있는지 확인해야 한다.
초록색 아이콘을 클릭하면 이 함수가 제대로 연결되어 있는지도 확인할 수 있다.
어쨌든 이제는 이 함수를 채워보자.
func _on_body_entered(body: Node2D) -> void:
hide() # 플레이어를 화면에서 숨긴다
hit.emit() # "hit"이라는 이름의 신호 방출
$CollisionShape2D.set_deferred("disabled", true)
우리 게임에서 플레이어는 무언가와 충돌하면 바로 게임오버될 예정이므로 이런 구성으로 만들어줬다.
만약 충돌 뿐 아니라 hp가 있다거나... 몬스터마다 닿아도 되는 횟수가 다르다거나... 회복 아이템이 있다거나... 한다면 더 다양한 경우를 생각해봐야 할 것이다. _on_body_entered에서 몬스터를 종류별로 탐지할 수 있는 방법은 뭘까?
또 여기서 기억해야할 부분이 있다면, 단순히 충돌 여부를 탐지할 거라면 Area2D의 _on_body_entered()를 다른 스크립트에서 직접 받아서 사용하면 될 것 같은데, 굳이 hit이라는 커스텀 시그널을 따로 만들어서 관리해주고 있다는 점이다. 이런 식으로 이벤트의 상황을 여러 함수/케이스로 분리해주는 건 프로젝트가 커질수록 대단히 중요해진다.
참고할 점 : set_deferred()
area의 collision shape를 직접적으로 끄면 문제가 생길 수도 있다.(공식 문서에서는 physics properties라고 하는 듯)
왜냐하면 고도 엔진의 콜리전 계산과 충돌할 수 있기 때문이다. 그래서 대신 사용하는 것이 set_deferred() 다. 이걸 쓰면 안전하게 shape 자체를 끌 수 있다.
2. start 함수 생성
게임 시작 시 플레이어를 초기화해 줄 함수를 작성해 주자. 스크립트 어느 위치에든 작성해 주면 된다.
func start(pos):
position = pos
show()
$CollisionShape2D.disabled = false
또 게임을 처음 켰을 때 플레이어가 보이지 않게 하기 위해서 _ready 함수에 hide 커맨드도 넣어준다.
func _ready() -> void:
screen_size = get_viewport_rect().size
hide()
다음 시간에는 플레이어와 충돌해 줄 적을 만들어본다. (진짜로)