[미리보기]
이번 편에서 할 것: 플레이어 애니메이션과 움직임 구현
[환경 세팅]
https://godotengine.org/ 에서 최신 버전 고도를 다운로드한다.
* 스팀에서도 설치가능 (godot 로 검색 후 설치)
[프로젝트 생성하기]
godot 를 실행하고 [+새로 만들기] 버튼으로 프로젝트를 생성한다.
* 새로 만들 프로젝트 이름을 적어주고 프로젝트 이름 인풋 옆에 [폴더 만들기] 로 폴더를 먼저 만들어줘야 한다.
그 후 프로젝트 설정을 하면 되는데 앱용으로 게임을 만들것이기 때문에 세로 뷰로 창을 설정한다.
세로로 게임화면 설정하기
1. [프로젝트 설정]으로 들어간다.
[창] 탭을 선택하고 아래 설정을 해준다.
- 뷰포트 너비 480 / 높이 720
- ‘스트레치' 에서 ‘모드'를 canvas_items 으로 설정
- ‘양상' 을 keep 으로 설정 (이렇게 하면 게임창 크기 조절되어도 비율이 유지되어 조정되거나 변형되지 않는다.)
[씬 생성]
왼쪽에 [씬] 탭에 + 로 노드를 추가해 줄 것이다.
2D 게임을 만들 것이고 다른 노드와의 중첩을 감지할 수 있어야 하기 때문에 Area2D 를 검색해서 생성해 준다.
그리고 이 노드는 Player 관련 설정을 해줄 것이라 이름을 Player 로 변경해 준다.
(왼쪽 하단 [파일 시스템]을 보면 .tscn 확장자로 생성되었을 텐데, t 는 텍스트라는 뜻이고 고도의 씬 용 파일형식이다.)
[애니메이션]
Area2D 는 충돌 감지할 수 있지만, 그 자체로는 모양이 없다. 그래서 이미지를 표시하는 노드가 필요하다.
아까 만든 Area2D 노드 아래에 이번에는 AnimatedSprite2D 를 만들어준다.
----
AnimatedSprite2D에는 SpriteFrames 이라는 리소스가 필요하다.
우측 패널에 [인스펙터] 탭에서 Animation/Sprite Frames 속성을 찾고 empty 를 클릭해서 드롭다운을 연 후 ‘새 SpriteFrames’선택한다.
그럼 하단에 애니메이션 창이 생기는데, 여기에 Player의 동작인 run, idle, hurt 를 만들어준다.
그리고 애니메이션으로 만들 이미지를 끌어와서 추가해 주면 애니메이션이 완성된다.
그리고 세 가지 종류의 애니메이션 중에 기본으로 실행될 애니메이션을 설정할 수도 있는데, 휴지통 오른쪽에 있는 아이콘인 '불러오면 자동 재생'을 클릭해서 idle이 기본 애니메이션으로 실행되게 해 주자.
- 애니메이션 속도를 빠르게: 프레임을 증가시키기
- 이미지 크기: 우측 [인스펙터] 에서 Scale 키우기
- 이미지의 중앙을 (0,0) 좌표로 조정: Offset 조정
[콜리전 모양]
[스크립트 작성]
코드를 추가해 주기 위해 필터 인풋 오른쪽에 있는 ‘새 스크립트’ 아이콘을 클릭해서 스크립트도 추가하자.
스크립트 파일에서 변수 앞에 @export 어노테이션을 붙이면 [인스펙터] 창에 속성이 추가되고 다른 기본 속성처럼 조절할 수 있게 된다.
extends Area2D
@export var speed = 350
플레이어 이동
고도에는 이동 방향을 알아내는 Input.get_vector() 함수가 있다.
이를 이용해 vector 값을 얻어서 오브젝트의 position을 업데이트할 수 있다.
또 clamp()라는 함수로 플레이어의 위치를 화면 밖으로 벗어나지 못하게 해 줄 수도 있다.
func _process(delta):
#1. 키보드 입력, 2. 방향으로 이동. 3. 애니메이션 재생
velocity = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
position += velocity * speed * delta
# 화면 밖으로 벗어나지 못하게 막는
position.x = clamp(position.x, 0, screensize.x)
position.y = clamp(position.y, 0, screensize.y)
게임 개발할 때 많이 쓰이는 delta라는 값이 있다.
delta는 '이전 프레임 이후 경과된 시간'이다.
만약 프레임 당 10 픽셀씩 움직이게 했다면 1초에 600 픽셀을 이동할 것이다.
그런데 프레임이 오래 걸리면 1초 50 프레임이 될 수도 있어 오브젝트의 이동이 그만큼 느려질 수가 있다.
그래서 이 delta 값을 사용한다. 약 0.016초로, 만약 초당 600 픽셀에 delta 값을 곱하면 10픽셀의 움직임 얻을 수 있는데 delta가 증가하면 오브젝트는 18픽셀을 이동한다. 그래서 결과적으로 이동속도는 프레임 속도과 관계없이 유지될 수 있게 된다.
스크립트를 작성했으면 오른쪽 최상단에 '현재 씬 실행'으로 직접 플레이어를 움직여서 문제가 없는지 확인하기.
[실행될 애니메이션 선택]
이번엔 입력에 따라 idle 혹은 run 애니메이션을 보여주자.
또, 오른쪽/왼쪽 이동 방향에 따라 애니메이션을 좌우로 뒤집어줘야 한다.
좌우 뒤집기는 [인스펙터]의 flip_h에서 직접 토글 해볼 수도 있다.
# 어떤 애니메이션 보여줄 지 결
if velocity.length() > 0:
$AnimatedSprite2D.animation = "run"
else:
$AnimatedSprite2D.animation = "idle"
# 방향 이동에 따라 수평 뒤집기
if velocity.x != 0:
$AnimatedSprite2D.flip_h = velocity.x < 0
[$ 표기법]
노드 이름은 스크립트 실행하는 노드에 대해 상대적.
$Node1/Node2 의 뜻? 스크립트 실행하는 노드 0의 자식노드인 노드 1의 자식노드인 노드 2를 가리킴.
[시작 & 종료]
set_process() 함수로 고도에 프레임 호출 시작/중지를 알릴 수 있다.
인자로 true/false 를 전달해 시작과 종료를 할 수 있도록 코드를 작성한다.
func start():
set_process(true)
position = screensize / 2
$AnimatedSprite2D.animation = "idle"
func die():
$AnimatedSprite2D.animation = "hurt"
set_process(false)
[시그널]
고도에 시그널이라는 기능이 있는데 이는 노드가 다른 노드에 메시지를 보내서 특정 동작을 할 수 있도록 해준다.
플레이어가 아이템에 닿았을 때랑 장애물에 닿았을 때 보낼 커스텀 시그널을 만들자.
스크립트의 윗부분에 시그널을 추가해 준다.
signal pickup ## 동전에 닿았을 때 보낼 시그널
signal hurt ## 장애물에 닿았을 때 보낼 시그널
이렇게 코드를 추가해 주면 오른쪽 패널 중 [노드]에 시그널이 추가된 걸 볼 수 있다.
방금 만든 커스텀 시그널을 아래 이미지처럼 시그널로 확인할 수 있다.
이 다음에 만들게 될 동전 오브젝트도 Area2D 노드가 될 것이라서 플레이어와 동전이 닿았는지에 대한 시그널은 area_entered 시그널을 이용하는게 좋다.
이 시그널을 우클릭해서 '연결'을 선택하고 연결 설정을 해준다.
이러면 스크립트 하단에 _on_area_entered()가 자동으로 추가된다.
func _on_area_entered(area):
if area.is_in_group("coins"):
area.pickup()
pickup.emit()
if area.is_in_group("obstacles"):
hurt.emit()
die()
다른 오브젝트랑 플레이어가 중첩되면 중첩된 영역은 area 라는 파라미터로 전달될 것이다.
상황에 맞게 해당하는 시그널을 발신해준다.
'토이프로젝트' 카테고리의 다른 글
고도 엔진으로 게임 만들기 #3: 유저 인터페이스 (10) | 2024.09.18 |
---|---|
고도 엔진으로 게임 만들기 #2: 동전씬과 메인씬 (2) | 2024.09.14 |
[Dart] Mac에서 Dart 설치하기 (0) | 2023.10.13 |
[React] 개발과 배포시 cors에러 해결 기록(with. heroku cors-anywhere) (0) | 2022.02.26 |
[공공데이터 활용] HTML canvas태그: 시간별 기온 차트 만들기 #2 (0) | 2022.02.01 |