2020. 6. 18. 10:54ㆍDEFOLD/튜토리얼
이 초보자 자습서에서는 플레이어 입력을 캡처하고 캐릭터를 움직이고 애니메이션으로 만드는 방법을 배웁니다.
그 과정에서 Defold의 핵심 구성 요소 인 게임 객체, 컴포넌트 및 컬렉션에 대해 소개합니다.
이 튜토리얼 프로젝트에는 필요한 모든 Assets이 사전 설정되어 있습니다. Project > build(Ctrl + b)를 눌러서 확인 기동 시켜보세요.
"/main/main.collection"을 여십시오.
에디터에 보이는 것은 Collection 파일입니다. Defold 엔진이 시작되면 "game.project" 설정 파일에 지정된대로 부트스트랩 컬렉션을 로드 합니다. 이 특정 컬렉션 파일은이 프로젝트의 부트스트랩 컬렉션이므로 게임을 실행할 때 그 내용을 볼 수 있습니다.
이 컬렉션에는 두 개의 게임 오브젝트를 가지고 있습니다. 그리고 두 게임 오브젝트(astronaut, level)는 각각 컴포넌트를 가지고 있습니다.
컬렉션(COLLECTION) : 컬렉션 파일에는 게임 오브젝트 및 기타 컬렉션(하위 컬렉션)이 포함됩니다. 컬렉션 파일에 게임 오브젝트를 추가하여 구성합니다. 컬렉션을 사용하여 플레이어 캐릭터 또는 보스와 같은 작은 것을 만들고 전체 레벨과 같은 큰 것을 만드는 데 사용합니다.
게임의 오브젝트(GAME OBJECT) : 게임 홀드 스프라이트, 사운드, 3D 모델, 타일 또는 스크립트(프로그램 된 동작을) 객체. 게임 오브젝트에는 위치, 회전 및 스케일이 있습니다. 게임이 실행되는 동안 이러한 속성을 조작하는 스크립트 코드를 작성할 수 있습니다. 일반적인 게임 오브젝트는 총알, 픽업 개체 또는 레벨 로더입니다.
컴포넌트(COMPONENT) : 컴포넌트는 화면에 그려 지거나 소리가 나거나 상호 작용이 이루어지는 것입니다. 컴포넌트는 자체적으로 존재하지 않으며 게임 오브젝트 안에 배치됩니다. 일부 컴포넌트에는 런타임시 조작 할 수 있는 속성이 있으며 대부분의 컴포넌트를 켜거나 끌 수 있습니다 (활성화 및 비활성화). 많은 컴포넌트 유형은 아틀라스 이미지 파일, 사운드 파일, 애니메이션 파일 등과 같은 별도의 리소스 파일에서 콘텐츠를 제공합니다.
Main.collection 파일에는 뭐가 있을까요?
"main.collection" 파일을 열면 중앙에 콜렉션의 시각적 컨텐츠를 표시합니다. 오른쪽 개요 창에서 컬렉션 내용은 트리 구조로 표시됩니다. 컬렉션에는 두 가지 게임 개체가 있습니다.
-
ID 「astronaut」가 있는 우주 비행사 게임 오브젝트. 그 하위에는 Sprite 컴포넌트와 Script 컴포넌트가 포함되어 있습니다. 그리고 "/main/astronaut.go"라는 게임 오브젝트 파일은 메인 컬렉션에 추가되었습니다.
-
ID가 "level"인 배경 레벨 게임 오브젝트입니다. 여기에는 Tilemap 컴포넌트가 포함되어 있습니다. 이 게임 오브젝트는 컬렉션 파일에 직접 임베드 되어 별도의 파일이 없습니다. 그러나 tilemap 구성 요소는 "/main/level.tilemap"이라는 별도의 파일에서 타일 맵 데이터를 제공합니다.
컬렉션에 직접 임베드된 게임 오브젝트(level) 또는 블루 프린트 파일을 기반(astronaut)으로 하는 게임 오브젝트 사이에는 차이가 없습니다. 게임 오브젝트가 하나의 인스턴스에만 존재하는 경우 블루 프린트 파일을 사용하면 실질적인 이점이 없지만 동일한 오브젝트의 사본을 여러 개 만들려면 블루 프린트 파일을 사용하면 모든 인스턴스를 한 번에 변경할 수 있으므로 매우 편리합니다.
astronaut 게임 오브젝트
"/main/astronaut.go"를 열어 "main.collection"에서 우주 비행사 인스턴스를 작성하는데 사용되는 블루 프린트 파일을 보십시오. 컬렉션과 마찬가지로 에디터는 게임 오브젝트의 내용을 중앙 편집기 보기에 표시하고 오른쪽의 개요 보기에는 구조가 표시됩니다. 이 게임 오브젝트 파일은 두 가지 구성 요소로 구성됩니다.
1. Script : "/main/astronaut.script" 스크립트 컴포넌트
2. Sprite : 우주비행사 이미지 컴포넌트
Sprite 컴포넌트를 클릭하여 선택합니다. 오른쪽 하단의 속성 보기에 Sprite 컴포넌트와 관련된 모든 속성이 나열됩니다.
Sprite에는 자체 Id, Position 및 Rotation 속성이 있습니다. 이것들은 컴포넌트를 포함하는 게임 오브젝트와 관련이 있습니다. Sprite에 표시 할 이미지 또는 애니메이션을 지정하는 속성도 있습니다.
Image : 이 속성은 Sprite 그래픽의 소스로 사용되는 이미지 리소스를 가리 킵니다. 이미지 리소스는 Atlas 또는 Tilesource 파일입니다. Atlas 파일은 효율성을 위해 더 큰 이미지로 변환한 별도의 이미지 모음입니다. 여기서 속성은 "/main/astronaut.atlas"파일로 설정됩니다.
Default Animation: 이 속성은 이미지 리소스에서 사용해야 할 특정 이미지 또는 애니메이션을 나타냅니다. 여기서 속성은 "idle" 애니메이션으로 설정됩니다.
게임을 다시 실행하십시오. astronaut Sprite가 Idle 애니메이션을 통해 반복됩니다. 이제 애니메이션이 어떻게 설정되어 있는지 살펴 보겠습니다.
Atlas Animation
"/main/astronaut.atlas"파일을 여십시오. 중앙의 편집기 보기에는 아틀라스에 추가된 각 이미지가 표시됩니다. 개요 전체보기 쇼 이미지와 애니메이션이 어떻게 구성되어 있습니다.
애니메이션 그룹은 지정된 재생 속도에 지정된 순서로 재생되는 이미지의 목록입니다. 현재 하나의 애니메이션 그룹 만 있습니다. "Idle"이라고 하며 5개의 개별 이미지로 구성됩니다. "Idle" 애니메이션을 선택하고 메뉴에서 View ▸ Play(Space)를 선택 하여 애니메이션을 미리 볼 수 있습니다.
Outline에서 Atlas에 마우스 우클릭해서 새로운 애니메이션 그룹을 만들어 봅시다.
이미지를 추가하면 기본적으로 애니메이션 프레임은 60으로 되어 있는데 너무 빠르므로 15로 설정 합니다. 그리고 동일한 방식으로 "right", "front", "back"이라는 애니메이션 그룹을 만들어 봅시다.
astronaut script 컴포넌트
우주 비행사 게임 오브젝트는 "/main/astronaut.script"파일을 기반으로 하는 스크립트 컴포넌트가 있습니다.
"/main/astronaut.script"를 열어 Lua스크립트 파일을 보십시오. 보시다시피, 스크립트 파일에는 비어있는 함수들이 있습니다. 함수들은 다음과 같습니다.
init(self) : 이 함수는 컴포넌트가 초기화 될 때 화면에 표시되기 전에 호출됩니다. 이 기능을 사용하여 몇 가지 사항을 설정합니다.
final(self) : 이 함수는 컴포넌트가 제거 될 때 호출됩니다, 게임 오브젝트가 삭제되거나 엔진이 게임을 종료하기 직전에.
update(self, dt) : 이 함수는 각 프레임마다 한 번씩 호출됩니다. 실시간으로 발생해야 하는 조작 및 계산을 수행하는 데 유용합니다. 이 함수를 사용하여 입력에 따라 게임 오브젝트를 이동합니다.
on_message(self, message_id, message, sender) : 이 함수는 메시지가 스크립트 구성 요소로 전송 될 때마다 호출됩니다. 메시지 전달은 Defold의 핵심 기능이지만이 여기서는 수행하지 않습니다.
on_input(self, action_id, action) : 이 함수는 입력이 스크립트 컴포넌트로 전송 될 때마다 호출됩니다. 입력 액션은 "/input/game.input_binding"파일에 정의되어 있습니다. 이 프로젝트에는 "left", "right", "front"및 "back"화살표 버튼에 대한 바인딩이 이미 설정되어 있으며이 기능을 사용하여 입력에 반응합니다.
on_reload(self) : 이 함수는 현재 스크립트 컴포넌트가 실행중인 게임에 핫 리로드 될 때마다 호출 됩니다. 이것은 재로드시 게임 오브젝트의 상태를 검사하거나 조작하여 테스트하거나 디버깅하는 데 매우 유용합니다.
Programming the astronaut movement
이제 애니메이션을 재생하고 우주 비행사 게임 객체를 움직이기 위해 약간의 Lua 코드를 작성할 준비가되었습니다. 먼저 init()함수 의 내용을 다음과 같이 변경하십시오.
function init(self)
-- acquire_input_focus는 사용자의 입력을 받기위해 준비하라는 의미
msg.post(".", "acquire_input_focus") -- 현재 게임 오브젝트에 acquire_input_focus 메세지 전송
self.dir = vmath.vector3() -- 스크립트 인스턴스에 dir속성을 추가 하고 거기에 백터 값을 가질수 잇도록 한다.
end
다음은 on_input 함수를 변경합니다.
function on_input(self, action_id, action)
if action_id == hash("front") then -- (1)
self.dir.y = -1
elseif action_id == hash("back") then
self.dir.y = 1
elseif action_id == hash("left") then -- (2)
self.dir.x = -1
elseif action_id == hash("right") then
self.dir.x = 1
end
end
(1) 입력 바인딩 파일에 정의된 값으로 action_id매개 변수 로 전송됩니다 . 사용자가 "front" 또는 "back" 버튼을 누르면 이동 방향 벡터의 Y 구성 요소를 설정합니다.
(2) 사용자가 "left" 또는 "right"버튼을 누르면 이동 방향 벡터의 X 구성 요소를 설정합니다.
플레이어가 "front"와 "left"를 동시에 누르면 두 번의 호출이 수행되고 on_input() 방향 벡터의 X 및 Y 구성 요소가 모두 변경됩니다.
셋째, update()함수 의 내용을 변경하십시오 .
function update(self, dt)
if vmath.length_sqr(self.dir) > 1 then -- (1)
self.dir = vmath.normalize(self.dir)
end
local p = go.get_position() -- (2)
go.set_position(p + self.dir * speed * dt) -- (3)
self.dir = vmath.vector3() -- (4)
end
(1) update() 함수가 호출되면 엔진은 이미 모든 입력을 처리한 상태이다. 즉 방향 벡터가 설정되었다는 뜻이다. 대각선 이동의 경우 이동 벡터의 길이가 1보다 크다. normalize(정규화)는 벡터의 방향은 유지하고 크기는 1을 유지하는 벡터로 만드는 과정이며 이렇게 해야지 대각선 이동시 계산하기가 편하다.
(2) 현재 게임 오브젝트의 위치를 파악하십시오. go라는 이름은 현재의 게임 오브젝트을 지칭하지 않는다. 모든 게임 오브젝트 기능을 담고 있는 루아 모듈의 이름이다.
(3) 현재 게임 오브젝트의 위치를 이전 위치값과 이동을 위한 값에 속도 상수(speed) 및 dt 를 곱해서 이동을 시킨다. dt는 현재 게임이 실행되는 프레임의 1프레임에 속하는 시간을 반환한다. 보통 게임이 60프레임으로 동작한다면 dt는 1초 / 60값 0.0166666xx값을 가지게 된다. 왜 dt를 곱하냐면 update는 60프레임 기준으로 1초에 60번을 호출하게 되며 해당 1프레임당 움직이는 거리 크기는 1 / 60 * speed 값이 되기 때문이다. 여기서 1 / 60이 dt이며 1프레임당 이동할 크기를 계산하기 위해서 사용한다.`
(4) 방향을 위한 벡터가 각 프레임에 설정되어 있으므로 다시 초기화 해야한다.
게임을 다시 실행해보고 이상없이 움직이는지 확인해보자.
Adding animations to the movement
마지막으로 이동 방향에 따라 재생되는 애니메이션을 변경해보자. 이를 위해 먼저 현재 애니메이션을 보유한 변수를 추가해야 합니다.
function init(self)
-- acquire_input_focus는 사용자의 입력을 받기위해 준비하라는 의미
msg.post(".", "acquire_input_focus") -- 현재 게임 오브젝트에 acquire_input_focus 메세지 전송
self.dir = vmath.vector3() -- 스크립트 인스턴스에 dir속성을 추가 하고 거기에 백터 값을 가질수 잇도록 한다.
self.current_anim = nil -- (1)
end
(1) 실행중인 애니메이션을 저장하기 위한 속성 추가
그리고 update()에서 방향에 따라 에니메이션을 변경하는 코드를 추가하자
function update(self, dt)
if vmath.length_sqr(self.dir) > 1 then -- (1)
self.dir = vmath.normalize(self.dir)
end
local p = go.get_position() -- (2)
go.set_position(p + self.dir * speed * dt) -- (3)
-- animation 기능 추가 시작
local anim = hash("idle") -- (a1)
if self.dir.x > 0 then -- (a2)
anim = hash("right")
elseif self.dir.x < 0 then
anim = hash("left")
elseif self.dir.y > 0 then
anim = hash("back")
elseif self.dir.y < 0 then
anim = hash("front")
end
if anim ~= self.current_anim then -- (a3)
msg.post("#sprite", "play_animation", {id=anim}) -- (a4)
self.current_anim = anim -- (a5)
end
-- animation 기능 추가 종료
self.dir = vmath.vector3() -- (4)
end
(a1) 초기 애니메이션 id를 가질 로컬 변수
(a2) 이동 방향에 따라 사용할 에니메이션 id를 설정
(a3) 이동방향에 맞는 애니메이션이 현재 동작하는 에니메이션 id와 틀릴 경우 분기
(a4) sprite에 새로운 애니메이션 전달 메세지 전송
(a5) 새롭게 변경된 에니메이션 ID을 (a3) 비교를 위해서 self.current_anim속성에 저장
게임을 다시 실행하고 이상없이 움직이고 에니메이션이 동작하는지 확인
'DEFOLD > 튜토리얼' 카테고리의 다른 글
4. War battles tutorial (0) | 2020.06.22 |
---|---|
3. Colorslide tutorial (0) | 2020.06.18 |
2. Movement tutorial (0) | 2020.06.18 |