본문 바로가기
Godot

[GodotDocs][Your First 2D Game] 3. 플레이어 코딩(GDScript)

by 채식금지 2024. 2. 6.
728x90

본 게시글은 고도엔진 공식문서에 작성된 Your first 2D game를 정리하였습니다.

 

스크립트 추가

 

  • res://Player.tscn을 선택한다.
  • Scene 도크에서 Player 노드를 선택한다.
  • Attach Script 아이콘을 클릭한다.

 

  • Attach Node Script 팝업창이 열리면 Path에서 파일명을 res://player.gd라고 입력한다.
  • GDScript는 파이썬과 유사한 코딩 스타일을 권장한다.(GDScript style guide)
  • Create 버튼을 클릭하여 스크립트를 생성한다.

 

플레이어 이동구현

 

  • player.gd 파일을 연다.
  • extends Area2D 아래 줄에 변수를 선언한다.
extends Area2D

@export var speed = 400
var screen_size
  • @export 키워드를 사용하면 해당 변수를 Inspector 도크에서 설정할 수 있게 된다.
  • 스크립트를 저장한 후 Player.tscn 씬을 열고, Player 노드를 선택하면 Inspector 도크에 Speed 속성이 추가되어 있는 것을 확인 할 수 있다.
  • 처음 스크립트를 추가하면 _ready() 함수와 _process(delta) 함수는 이미 추가되어 있다.

 

  • _ready() 함수 안에 아래의 코드를 추가한다.
func _ready():
    screen_size = get_viewport_rect().size
  • _ready() 함수는 Player 노드 씬 트리에 등록되었을 때(초기화 되었을 때) 한 번 호출된다.
  • get_viewport_rect() 함수를 이용하여 게임 화면의 크기를 불러와 screen_size 변수 안에 저장한다.

 

  • _process(delta) 함수 안에 아래의 코드를 추가한다.
func _process(delta):
    var direction = Vector2.ZERO
    if (Input.is_action_pressed("move_right")):
        direction.x += 1
    if (Input.is_action_pressed("move_left")):
        direction.x -= 1
    if (Input.is_action_pressed("move_down")):
        direction.y += 1
    if (Input.is_action_pressed("move_up")):
        direction.y -= 1    
  • move_right, move_left, move_down, move_up[GodotDocs][Your First 2D Game] 1. 프로젝트 설정에서 미리 키보드 A, D, S, W와 미리 입력 시켜 두었다.
  • Input.is_action_pressed 함수는 특정키를 누르고 있을 때 true를 반환한다.
  • Input.is_action_pressed 함수 안에 move_right, move_left, move_down, move_up을 넣어 사용하면 키보드 A, D, S, W를 누르고 있을 때 true를 반환한다.
  • 키보드를 누를 때 이동할 방향을 direction 변수에 저장한다.

 

  • 고도 엔진의 2D 좌표는 가로는 X축, 세로는 Y축이다.
  • 따로 카메라를 추가하지 않았다면 화면 기준으로 왼쪽 상단 좌표가 (0, 0)이다.
  • 오른 쪽으로 갈 수록 X축 값이 증가하고, 아래 쪽으로 내려갈 수록 Y축 값이 증가한다.

 

  • _process(delta) 함수 안에 아래의 코드를 더 추가한다.
var velocity = Vector2.ZERO
if direction.length() > 0:
    velocity = direction * speed
    $AnimatedSprite2D.play()
else:
    $AnimatedSprite2D.stop()
  • direction.length() 함수는 벡터의 거리를 계산하는 함수이다. 키보드를 누를 경우 0이 아닌 값을 반환한다.
  • velocity = direction * speed 는 키보드를 누를 경우 direction 방향으로 speed 만큼의 속력으로 이동한다는 의미가 된다. 하지만 실제 노드의 좌표를 변경하지 않았기 때문에 이것 만으로 노드가 이동하지 않는다.
  • $AnimatedSprite2D는 GDScript에서 제공하는 기능이다. get_node("AnimatedSprite2D")와 같은 역할을 한다.
  • $AnimatedSprite2D.play()는 등록된 SpriteFrame에 맞춰 스프라이트 애니메이션을 재생 시키는 함수이다.

 

  • _process(delta) 함수 안에 아래의 코드를 더 추가한다.
position += velocity * delta
position = position.clamp(Vector2.ZERO, screen_size)
  • positionvelocity를 더해 노드가 velocity 만큼 이동하게 된다.
  • 컴퓨터의 사양과 관계없이 동일한 시간에 동일한 거리를 이동하도록 처리하기 위해 velocitydelta를 곱해준다.
  • clamp 함수는 입력된 값의 범위를 벗어나지 않게 보정해준다.
  • position.clamp(Vector2.ZERO, screen_size)를 적용하면 노드가 화면 밖으로 이동하지 않도록 보정해준다.

 

  • _process(delta) 함수 안에 아래의 코드를 더 추가한다.
if direction.x != 0:
    $AnimatedSprite2D.animation = "walk"
    $AnimatedSprite2D.flip_v = false
    $AnimatedSprite2D.flip_h = direction.x < 0
elif direction.y != 0:
    $AnimatedSprite2D.animation = "up"
    $AnimatedSprite2D.flip_v = direction.y > 0
  • walk, up[GodotDocs][Your First 2D Game] 2. 플레이어 씬 제작에서 미리 만들어둔 애니메이션이다.
  • $AnimatedSprite2D.animation 값을 수정하여 미리 만들어둔 애니메이션을 선택할 수 있다.
  • X축으로 이동할 때는 walk, Y축으로 이동할 때는 up 애니메이션을 선택한다.
  • $AnimatedSprite2D.flip_htrue일 경우 X축을 기준으로 이미지를 반전 시킨다.
  • $AnimatedSprite2D.flip_vtrue일 경우 Y축을 기준으로 이미지를 반전 시킨다.
  • 플레이어가 오른쪽으로 이동하면 X축을 기준으로 이미지를 반전 시키고, 아래로 내려갈 경우 Y축을 기준으로 이미지를 반전 시킨다.

 

  • 지금까지 작업한 내용은 에디터 오른쪽 상단의 Run Current Scene 버튼을 클릭하여 테스트할 수 있다.

 

충돌처리 준비

 

  • 적과 충돌하였을 때 처리를 미리 구현한다.
  • extends Area2D와 선언한 맴버변수 사이에 시그널을 선언한다.
signal hit

 

  • Scene 도크에서 Player 노드를 선택한다.
  • 에디터 오른쪽에 있는 Node 도크를 선택한다.
  • body_entered(body: Node2D) 시그널을 더블 클릭한다.

 

  • Connect a Signal to a Method 팝압창이 열리면 바로 Connect 버튼을 눌러 시그널과 연결된 함수를 추가한다.

 

  • 자동으로 추가된 _on_body_entered(body) 함수 안에 아래 내용을 추가한다.
func _on_body_entered(body):
    hide()
    hit.emit()
    $CollisionShape2D.set_deferred("disabled", true)
  • 적과 충돌하게 되면 _on_body_entered(body) 함수가 자동으로 호출된다.
  • hide() 함수를 호출하면 노드가 화면에 출력되지 않는다.
  • emit() 함수를 호출하면 미리 정의해둔 hit 시그널의 신호가 발생한다.
  • CollisionShape2D를 바로 비활성화하면 고도엔진이 충돌처리를 하는 도중에 오류가 발생할 수 있다.
  • set_deferred 함수를 이용하면 안전하게 CollisionShape2D를 비활성화할 때까지 대기하도록 고도엔진에 지시하게 된다.

 

  • start(pos) 함수를 새로 추가한다.
  • start(pos) 함수는 게임을 시작할 때 플레이어를 초기화하기 위해 호출한다.
func start(pos):
    position = pos
    show()
    $CollisionShape2D.disabled = false

 

완성된 스크립트

extends Area2D

signal hit

@export var speed = 400
var screen_size


func _ready():
    screen_size = get_viewport_rect().size


func _process(delta):
    var direction = Vector2.ZERO
    if (Input.is_action_pressed("move_right")):
        direction.x += 1
    if (Input.is_action_pressed("move_left")):
        direction.x -= 1
    if (Input.is_action_pressed("move_down")):
        direction.y += 1
    if (Input.is_action_pressed("move_up")):
        direction.y -= 1    

    var velocity = Vector2.ZERO
    if direction.length() > 0:
        velocity = direction * speed
        $AnimatedSprite2D.play()
    else:
        $AnimatedSprite2D.stop()

    position += velocity * delta
    position = position.clamp(Vector2.ZERO, screen_size)

    if direction.x != 0:
        $AnimatedSprite2D.animation = "walk"
        $AnimatedSprite2D.flip_v = false
        $AnimatedSprite2D.flip_h = direction.x < 0
    elif direction.y != 0:
        $AnimatedSprite2D.animation = "up"
        $AnimatedSprite2D.flip_v = direction.y > 0


func _on_body_entered(body):
    hide()
    hit.emit()
    $CollisionShape2D.set_deferred("disabled", true)


func start(pos):
    position = pos
    show()
    $CollisionShape2D.disabled = false