2020. 6. 22. 16:54ㆍDEFOLD/튜토리얼
이 Tutorial은 작은 게임 구조를 만드는데 필요한 단계를 진행합니다. Defold에 대한 어떤 사전 경험도 필요하지 않지만, 만약 당신이 Lua, Javascript, Python 또는 이와 비슷한 곳에서 프로그래밍을 했다면, 그것은 도움이 될 것입니다.
당신은 빈 프로젝트부터 시작하지만 우리는 당신을 위해 필요한 Asset들을 추가했다. 빌드 및 실행(또는 메뉴에서 Project build Build)을 선택하여 프로젝트가 비어 있는지 확인할 수 있다. 이것은 게임을 시작할 것이고 당신은 검은 화면만 볼 수 있을 것이다.
Draw the game map
게임에는 설정과 지도가 필요합니다. 지도는 타일로 만들어질 것이고, 모자이크처럼 모아진 작은 이미지들은 더 큰 이미지로 만들어질 것이다. Defold는 이러한 이미지를 타일 맵이라고 한다. 타일 맵을 생성하려면 다양한 타일이 포함된 이미지 파일이 필요하다. 그런 다음 타일, 여백 및 패딩의 크기와 타일 소스라는 유형의 파일에 사용할 이미지 파일을 지정해야 한다.
1. main 폴더에서 우클릭해서 New > Title source를 클릭합니다. 이름은 map.tilesource로 만듭니다.
2. 새로 만든 tilesource 파일이 편집기에서 자동으로 열립니다. tilesource의 Image속성을 이미지 파일 /assets/map.png로 설정하십시오. 가장 쉬운 방법은 Image 속성으로 리소스 선택기를 클릭하여 리소스 선택기를 불러오는 것입니다. 그런 다음 /assets/map.png파일을 선택하십시오:
타일은 여백이나 패딩이 없는 16X16 픽셀 이므로 titlesource의 기본 속성들을 변경할 필요가 없습니다.
3. main 폴더에서 우클릭 해서 New > tile map을 눌러 타일맵을 생성하자 이름은 map으로 한다. 생성이 이상없이 성공하면 자동으로 열린다.
4. tile source 속성을 /main/map.tilesource로 설정한다.
5. outline에서 layer1을 선택한다
6. 메뉴에서 Edit > Select Tile... 또는 Spacebar를 누르면 tile palette가 표시된다.
7. 풀 타일을 클릭하십시오. 클릭된 타일을 현재 브러시로 선택한다. 그런 다음, 풀 타일에 맞는 것처럼 타일 맵 레이어를 칠하십시오. 다른 그래픽을 그릴 타일 팔레트에서 다른 타일을 선택하십시오.
8. Shift키를 누른 상태에서 클릭하고 끌어서 현재 타일 맵 계층에서 선택하십시오. 그러면 선택이 새로운 브러시가 된다. 이것은 여러 개의 타일로 구성된 붓으로 그림을 그리는 데 유용한 방법이다.
맵을 다 만들었으면 이제 게임에 추가를 해야 합니다.
Add the map to the game
Defold는 당신이 만든 모든 것을 컬렉션에 저장한다. 컬렉션은 게임 오브젝트와 다른 컬렉션의 계층 구조를 만드는 데 사용되는 파일이다. "game.project" 파일에서 게임을 시작할 때 로드되는 특정 컬렉션을 지정하십시오. 이것은 처음에 "/main/main.collection" 파일로 설정된다.
1. main.collection 파일을 여세요.
2. Outline에서 Root Collection하위에 게임 오브젝트를 생성하세요
3. 게임 객체(오브젝트) ID 속성을 map으로 변경하세요.
4. id가 map인 게임 객체에 마우스 우클릭 후 Add Component File을 선택하자
5. /main/map.tilemap파일을 선택하자. 이것은 tilemap 파일을 기반으로 게임 객체에 새로운 컴포넌트를 만든다. 성공시 아래와 같이 화면에 표시가 된다.
6. 게임을 실행하고 이상없이 동작하는지 확인하자.
참고: 게임을 실행할 때 "Out of tiles to render" 오류가 발생하면 사용자가 만든 타일 맵이 구성된 최대 타일 수보다 크다는 의미. game.project 파일에서 Tailmap->Max Tail Count 값을 늘리면 이 문제를 해결할 수 있다.
Create the player animation
1. Assets안에 Main폴더를 만들고 Atlas 파일을 생성하자, 이름은 sprites로 만든다. Atlas는 더 큰 택스쳐로 만들어지는 이미지(PNG 또는 JPEG)의 모음입니다. Defold는 성능과 메모리 때문에 단일 이미지 파일 대신 Atlas를 사용한다. 새로운 Atlas는 에디터에서 열어야 한다.
2. Outline에서 Root 노드를 우클릭해서 Add Animation Group을 선택한다. ID는 player-down으로 한다
3. player-down을 우클릭하고 add Image...를 선택한다. 리소스 선택 창에서 /assets/infantry/down/1.png ~ 4.png 까지 선택한다.
4. player-down 애니메이션 그룹을 선택후 view > play나 spacebar를 눌러서 애니메이션을 확인하자, 60 프레임으로 되어있어서 너무 빠르게 동작하니 fps 속성을 8로 하자
Create the player game object
Defold 게임 오브젝트는 id, 위치, 회전 및 구성요소를 저장하는 컴포넌트을 가진 오브젝트다. 그들은 플레이어 캐릭터, 총알, 게임의 룰 시스템 또는 레벨 로더/언로드러와 같은 것들을 창조하는데 사용된다. 컴포넌트는 게임에서 게임 객체를 시각, 청각 및/또는 로직 표현을 제공하는 실체다.
1. main.collection을 연다.
2. outline에서 root collection에 게임오브젝트를 만들고 해당 게임오브젝트 ID는 player로 하자
3. player 게임객체의 Z Position 속성을 1.0으로 한다. map 게임 객체가 Z Position이 0이므로 player 게임객체가 상단에 있으려면 해당 값이 0보다 커야 한다.
4. player 게임 객체에 sprite를 추가하자.
5. sprite의 image 속성을 /main/sprites.atlas로 설정하자
6. Default Animation은 player-down으로 하자
게임을 실행하고 player가 애니메이션화 되었는지 확인해라.
플레이어 게임객체는 현재 게임세계에서 시각적으로 표현된다. 다음 단계는 플레이어 게임객체에 스크립트 구성요소를 추가하는 것이다. 이를 통해 움직임과 같은 행동을 만들 수 있다. 하지만 그것은 사용자 입력에 따라 다르므로, 먼저 그것을 설정해야 한다.
Add input binding
기본적으로 매핑된 입력이 없으므로 플레이어 캐릭터에 대한 입력 작업을 추가하십시오.
1. /input/game.input_binding 파일을 연다. 이 파일은 입력 소스(키보드, 터치스크린, 게임패드등)의 입력 동작들의 매핑정보를 설정하는 곳이다. 여기서 특정 입력과 동작을 연관시키는 설정을 해보자
2. up, down, left, right를 아래와 같이 Key Triggers에 추가하자.
Create the player script
player 게임객체에 직접 추가한 sprite 컴포넌트와 달리 스크립트 컴포넌트는 별도의 파일을 만들어야 한다. 이 스크립트 파일은 스크립트 구성 요소의 템플릿으로 사용된다 :
1. main 폴더안에 script를 생성하고 이름은 player로 한다. 이상없이 성공시 init, final 함수등 기본적인 함수들이 들어있는 파일을 만들어 준다.
2. main.collection을 열고 player 게임 오브젝트에 /main/player.script를 추가하자
우리는 player 게임객체에서 실행되는 스크립트를 만들어 보았다. 하지만 아무런 동작하지를 않으며 이제 이동에 관한 로직을 만들어보자.
program the player movement
8개의 방향에서 캐릭터 움직임을 만드는 데 필요한 코드는 길지 않지만, 완전히 이해하는 데는 약간의 시간이 필요할 수 있다. player.script의 각 기능에 대한 코드를 아래 코드로 교체하고, 게임을 실행한 후, 아래 코드 주석을 주의 깊게 읽어 보자
function init(self) -- (1)
msg.post(".", "acquire_input_focus") -- (2)
self.moving = false -- (3)
self.input = vmath.vector3() -- (4)
self.dir = vmath.vector(0, 1, 0) -- (5)
self.speed = 50 -- (6)
end
function final(self) -- (7)
msg.post(".", "release_input_focus" -- (8)
end
function update(self, dt) -- (9)
if self.moving then
local pos = go.get_position() -- (10)
pos = pos + self.dir + self.speed * dt -- (11)
go.set_position(pos) -- (12)
end
self.input.x = 0 -- (13)
self.input.y = 0
self.moving = false
end
function on_message(self, message_id, message, sender)
end
function on_input(self, action_id, action) -- (14)
if action_id == hash("up") then
self.input.y = 1 -- (15)
elseif action_id == hash("down") then
self.input.y = -1
elseif action_id == hash("left") then
self.input.x = -1
elseif action_id == hash("right") then
self.input.x = 1
end
if vmath.length(self.input) > 0 then
self.moving = true -- (16)
self.dir = vmath.normalize(self.input) -- (17)
end
end
function on_reload(self)
end
(1) init() 함수는 게임 엔진에서 스크립트 컴포넌트 살아나면 호출된다. 이 함수는 대부분 게임 객체 상태의 초기 설정시 사용된다.
(2) "acquire_input_focus"라는 메시지를 현재의 게임 오브젝트(".")에 보낸다. 이것은 엔진에 이 게임객체에 입력 동작을 보내라고 하는 시스템 메시지다. 동작은 이 스크립트 구성요소의 on_input() 함수에 도달한다.
(3) self는 현재 컴포넌트 인스턴스에 대한 참조변수다. 컴포넌트 인스턴스에 로컬인 상태 데이터를 자체로 저장할 수 있다. 도트 표기법으로 테이블 필드 변수를 인덱싱하여 루아 테이블처럼 사용한다. moving 변수는 플레이어가 이동하는지 여부를 추적하는 데 사용된다.
(4) input은 vector3이며, vector3은 현재 8개 입력 방향 중 하나를 가리키는 세 가지 구성 요소인 x, y, z를 가진 벡터다. 그것은 플레이어가 화살표 키를 누를 때 바뀔 것이다. 이 vector의 Z성분은 사용하지 않기 때문에 값 0으로 유지된다.
(5) dir는 플레이어가 향하는 방향을 포함하는 또 다른 vector3이다. dir vector는 입력이 없고 플레이어 캐릭터가 움직이지 않으면 여전히 방향을 향해야 하기 때문에 input vector와 분리되어 있다.
(6) speed는 초당 픽셀 단위로 표시되는 이동속도다
(7) 게임에서 스크립트 구성요소가 삭제되면 final()함수가 호출된다. 이는 컨테이너 게임객체("player")가 삭제되거나 게임이 종료될 때 발생한다.
(8) 이 스크립트는 입력 포커스를 명시적으로 해제하여 엔진에 더 이상 입력을 원하지 않는다는 것을 알린다. 게임객체를 삭제할 때 입력 포커스가 자동으로 해제되므로 이 라인은 필요하지 않지만 여기에 포함되어 있어 명확하다.
(9) update() 함수는 각 프레임마다 한 번씩 호출된다. 게임은 초당 60프레임으로 진행되기 때문에 기능은 1/60초 간격으로 호출된다. 파라메터 변수 dt에는 현재 프레임 간격 --- 함수에 대한 마지막 호출 이후 경과된 시간(초)이 포함되어 있다. 보통 1/60의 값이 들어가 있다.
(10) moving 값이 참이면 현재 게임객체의 위치를 얻으십시오. go.get_position() 함수는 포지션을 얻기 위해 게임객체의 ID인 선택적 파라메터를 갖는다. 파라메터가 주어지지 않으면 현재 게임 객체의 위치가 반환된다.
(11) 현재 방향 Vector를 현재 위치에 추가한다.
(12) 게임객체를 계산된 새로운 위치로 설정한다.
(13) 계산이 끝나면 input vector값을 초기화 하고 moving값을 false로 한다.
(14) on_input() 함수는 활성화 된 모든 매핑된 입력에 대해 모든 프레임에서 호출됩니다. action_id 인수는 입력 바인딩 파일에 설정된 action을 포함합니다. 파라메터 action은 입력에 대한 세부 사항이있는 Lua 테이블입니다.
(15) 각 입력 방향에 대해 입력 Vector의 X 또는 Y 성분을 자체로 설정한다. 사용자가 위쪽 화살표와 왼쪽 화살표 키를 동시에 누르면 엔진이 이 기능을 두 번 호출하고 입력 벡터는 (-1, 1, 0)으로 설정된다.
(16) 사용자가 화살표 키를 누르면 입력 vector의 길이가 0이 아니다. 그렇다면 플레이어가 이동될수 있도록 moving 플래그를 설정하십시오. 스크립트가 on_input() 함수에서 플레이어를 이동시키지 않는 이유는 각 프레임의 모든 입력을 수집하여 update()에서 실행하는 것이 더 간단하기 때문이다.
(17) dir Vector는 입력의 정규화된 값으로 설정된다. 예를 들어 입력 벡터가 (1, 1, 0)인 경우, 벡터 길이는 1(2의 제곱근)보다 크다. 벡터를 정상화하면 정확히 1의 길이가 된다. 정규화되지 않으면 대각선 이동이 수평 및 수직 이동보다 빠를 것이다. 엔진이 update() 기능을 실행할 때, 사용자 입력은 플레이어의 움직임을 유발하는 dir 벡터에 영향을 줄 것이다.
게임을 실행해보자 이제 캐릭터가 움직일 것이다. 이제 로켓 발사 기능을 추가 해보자.
Create a rocket game object
로켓은 사용자가 키를 누르면, 로켓을 발사해야 하야 한다. 얼마든지 로켓을 발사할 수 있어야 한다. 이것을 구현하기 위해 "main.collection"에 로켓 게임객체만을 추가할 수 없다. 단지 그것은 하나의 로켓일 뿐이며 진짜로 필요한 것은 로켓 게임 객체의 청사진을 만들고 그 청사진을 바탕으로 새로운 게임 객체를 즉석에서 만들어 내는 Factory이다.
먼저 게임 객체의 Blueprint(청사진) 파일을 생성한다:
1. main 폴더에서 새로운 게임객체를 만들고 이름은 rocket으로 하자
2. sprites.atlas를 열고 새로운 애니메이션 그룹 rocket을 만들자
3. rocket 에니메이션 그룹에 /assets/buildings/turret-rocket을 추가하고 fps속성은 알아서 적어주자
4. rocket.go를 열고 outline의 root에 sprite 컴포넌트를 추가하자
5. Image 속성에 /main/sprites.atlas를 설정하고 Default Animation을 rocket으로 설정하자
이제 기본적인 로켓 게임 객체 청사진을 파일에 저장해 놓으셨습니다. 다음 단계는 이 Blueprint 파일을 기반으로 게임 개체를 생성하는 기능을 추가하는 것이다. 이를 위해 Factory 컴포넌트를 사용하십시오. 당신은 또한 사격하는 플레이어에 대한 새로운 입력 동작을 추가할 필요가 있다.
Spawn rockets
1. main.collection 파일을 열고 player 게임 객체 하위에 Factory를 추가한다.
2. factory id를 rocketfactory로 하고 prototype속성을 /main/rocket.go로 설정한다.
3. /input/game.input_binding 파일을 연다
4. 미사일 발사를 위한 키 트리거를 하나 추가하고 action을 fire로 설정한다.
5. main/player.script를 열고 init()함수에 미사일 발사에 관련한 flag 변수를 추가 한다.
function init(self)
msg.post(".", "acquire_input_focus")
self.moving = false
self.firing = false -- 플레이어가 미사일 발사할때마다 true로 설정된다.
self.input = vmath.vector3()
self.dir = vmath.vector3(0, 1, 0)
self.speed = 50
end
6. update() 함수에서 fire가 true일때 수행할 작업을 추가합니다. factory 컴포넌트는 새로운 게임 객체를 생성합니다.
function update(self, dt)
if self.moving then
local pos = go.get_position()
pos = pos + self.dir * self.speed * dt
go.set_position(pos)
end
if self.firing then
factory.create("#rocketfactory") -- (1)
end
self.input.x = 0
self.input.y = 0
self.moving = false
self.firing = false
end
(1) firing 플래그 변수가 참이면, 새로운 게임 오브젝트를 생성하기 위해 방금 생성 한 "rocketfactory"라는 팩토리 컴포넌트를 알려줍니다. 뒤에 오는 것이 컴포넌트의 ID임을 나타내는 문자 '#'에 주목하십시오.
(2) firing flag를 false로 설정 합니다. 이 플레그 변수는 사용자가 fire키(space에 매핑)를 누를때마다 on_input()에 매핑 됩니다.
7. on_input()함수에 fire관련 로직을 작성한다.
function on_input(self, action_id, action)
if action_id == hash("up") then
self.input.y = 1
elseif action_id == hash("down") then
self.input.y = -1
elseif action_id == hash("left") then
self.input.x = -1
elseif action_id == hash("right") then
self.input.x = 1
elseif action_id == hash("fire") then -- (1) 로직 추가
self.firing = true
end
if vmath.length(self.input) > 0 then
self.moving = true
self.dir = vmath.normalize(self.input)
end
end
이제 스페이스바를 누르면 로켓이 표시되는 것을 확인 할 수 있다.
Set the direction of the rocket
로켓이 생성되면 현재 플레이어 방향으로 향하지 않습니다. 그리고 곧바로 비행하고 짧은 간격 후에 폭발해야 합니다.
1. player.script를 열고 update() 함수에 아래 코드를 작성하세요
function update(self, dt)
if self.moving then
local pos = go.get_position()
pos = pos + self.dir * self.speed * dt
go.set_position(pos)
end
if self.firing then
local angle = math.atan2(self.dir.y, self.dir.x) --(1)
local rot = vmath.quat_rotation_z(angle) -- (2)
local props = { dir = self.dir } -- (3)
factory.create("#rocketfactory", nil, rot, props) -- (4)
end
...
end
(1) 플레이어의 현재 움직임을 이용해 각도(radian)을 계산 및 반환 합니다.
(2) Z축 주위로 각 회전에 대한 쿼터니언(x,y,z,w) 값을 만든다
(3) 로켓으로 전달할 속성값이 포함될 변수를 생성, 플레이이어의 방향은 로켓에게 필요한 유일한 데이터
(4) 명시적 위치 (아니면 로켓이 플레이어의 위치에 스폰 됨), 회전(계산 된 쿼터니언) 및 속성값을 이용해 로켓을 스폰합니다.
로켓은 게임객체 회전(rot)외에 이동 방향이 필요하다는 점에 유의한다. 로켓이 회전을 바탕으로 이동 벡터를 계산하게 하는 것은 가능하겠지만, 두 값을 분리하는 것이 더 쉽고 유연하다. 예를 들어, 별도의 회전을 통해 회전 흔들림을 로켓의 이동 방향에 영향을 주지 않고 추가할 수 있다.
2. main폴더 안에 Script를 생성한다, 이름은 rocket으로 하자. 그리고 아래 코드를 넣자
go.property("dir", vmath.vector3()) -- (1)
function init(self)
self.speed = 200 -- (2)
end
function final(self)
end
function update(self, dt)
local pos = go.get_position() -- (3)
pos = pos + self.dir * self.speed * dt -- (4)
go.set_position(pos) -- (5)
end
function on_message(self, message_id, message, sender)
end
function on_input(self, action_id, action)
end
function on_reload(self)
end
(1) dir라는 새로운 스크립트 속성을 정의하고 빈 벡터값 vmath.vector3()으로 속성을 초기화하십시오. 기본값은 factory.create() 함수에 값을 전달하여 재정의할 수 있다. 현재 속성 값은 self.dir로 접근할 수 있다. 이것은 단위 벡터 (길이 1)가 될 것으로 예상된다.
(2) 초당 픽셀로 이동할 로켓 속도 값
(3) 현재 로켓의 위치
(4) 이전 위치, 이동할 방향, 속도를 바탕으로 새로운 위치를 계산한다.
(5) 새로운 위치를 설정한다.
3. rocket.go 파일을 열고 방금전 만든 rocket.script를 추가한다.
4. 이제 게임을 실행해보자. 미사일은 발사 되지만 180도 반대로 나가버린다. 이제 이것을 수정해보자
5. sprites.atlas를 열고 roket 에니메이션을 선택한 후 Flip Horizontal 속성을 체크한다.
6. 게임을 실행하고 이상없이 미사일이 날라가는지 확인하자.
Make the rockets explode (로켓 폭팔 만들기)
로켓이 잠시후 폭발 하는 것을 만들어 보자.
1. sprites.atlas를 열고 explosion이름을 가진 에니메이션 그룹을 만들자.
2. explosion 그룹에 /assets/fx/explosion의 9개의 이미지를 추가하고 fps속성은 알아서 설정한다. 그리고 playback을 One Forward로 한다.
3. rocket.script를 열고 init()함수에 아래와 같이 코드를 작성한다.
function init(self)
self.speed = 200
-- 로켓의 수명을 추적하는 타이머 역할을 할 속성 추가
self.life = 1
end
4. 아래 update()함수에 아래와 같이 코드를 작성하자
function update(self, dt)
local pos = go.get_position()
pos = pos + self.dir * self.speed * dt
go.set_position(pos)
self.life = self.life - dt --(1)
if self.life < 0 then -- (2)
self.life = 1000 -- (3)
go.set_rotation(vmath.quat()) -- (4)
self.speed = 0 -- (5)
msg.post("#sprite", "play_animation", {id=hash("explosion")}) -- (6)
end
end
(1) delta time으로 시간을 줄인다, 초당 1.0씩 감소된다.
(2) self.life가 0에 도달할때
(3) 이 코드가 후속 update()함수 호출시 실행되지 않도록 큰 값으로 세팅한다
(4) 게임 객체 rotation을 0으로 설정하지 않으면 폭발 에니메이션이 회전해버린다.
(5) 이동 속도를 0으로 하지 않으면 폭발 에니메이션이 움직인다.
(6) 게임 객체의 "sprite" 컴포넌트에서 "explosion"애니메이션을 재생시키는 메세지를 보낸다.
5. on_message 함수에 아래 코드를 작성하자.
function on_message(self, message_id, message, sender) -- (1)
if message_id == hash("animation_done") then -- (2)
go.delete() -- (3)
end
end
(1) 이 스크립트 컴포넌트에 메세지가 전달될때 on_message()함수가 호출된다.
(2) 전달받는 메세지에 animation_done이 있는제 확인한다. 엔진 실행시 이 스크립트에서 play_animation으로 시작된 sprite 애니메이션이 완료될 때마다 이 메세지를 전송한다.
(3) 에니메이션이 완료되면 게임 객체를 삭제 한다.
Create a tank game object
1. main 폴더에 tank.go라는 게임객체를 만들자.
2. sprites.atlas안에 tank-down이라는 에니메이션 그룹을 만들자.
3. tank-down에 /assets/units/tank/down아래 이미지를 추가하고 fps는 알아서 설정하자.
4. tank.go를 열고 sprite를 추가하자 그리고 Image속성에 /main/sprites.atlas를 Default animation에 tank-down을 설정하자.
5. main.collection을 열고 tank.go를 추가하자. 한 3개 정도 추가하고 모두 position의 z를 1.0으로 설정해서 map위에 랜더링 되도록 설정하자.
게임 실행시 탱크가 추가 되었음을 알수 있다.
Add collision object (충돌 객체 추가)
탱크와 로켓사이에 충돌을 추가하자
1. tank.go를 열고 Add Component > Collision Object를 눌러서 충돌 객체를 만들자
2. type 속성을 Kinematic으로 설정하자. 이것은 물체에 대한 중력이나, 충돌을 시뮬레이션 하지 않음을 뜻한다. 대신 충돌만 감지하고 응답을 코딩하도록 해준다.
3. group 속성을 tanks로 설정하고 mask를 rockets로 설정한다.
4. 방금 만든 collisionobject에 Add Shape > box를 만들고 탱크모양과 일치하도록 모양 및 크기를 설정하자
5. rocket.go를 열고 Collision Object를 추가하자. 그리고 type은 Kinematic으로 설정하자.
6. Group 속성을 rockets으로 Mask는 tanks로 설정하자, rocket.go는 Mask가 rocket으로 설정된 tanks그룹의 객체데 대한 충돌을 감지합니다. 이제 rockets와 tanks 사이의 그룹과 마스크가 서로 일치하여 물리엔진이 상호 작용시 이를 감지한다.
7. collisionobject에 box를 추가하고 로켓 모양과 일치하도록 설정한다.
물리엔진은 충돌하는 게임객체에 메세지를 보낸다. 이제 해당 메세지에 반응 하는 코드를 만들어 보자.
code a reaction to the collisions (충돌에 대한 반응 코드 작성)
1. rocket.script를 열고 update() 함수에 코드를 작성하자.
local function explode(self) -- (1)
self.life = 1000
go.set_rotation(vmath.quat())
self.speed = 0
msg.post("#sprite", "play_animation", {id = hash("explosion")})
end
function update(self, dt)
local pos = go.get_position()
pos = pos + self.dir * self.speed * dt
go.set_position(pos)
self.life = self.life - dt
if self.life < 0 then
explode(self) -- (2)
end
end
function on_message(self, message_id, message, sender)
print(message_id)
if message_id == hash("animation_done") then
go.delete()
elseif message_id == hash("collision_response") then -- (3)
explode(self) -- (4)
go.delete(message.other_id) -- (5)
end
end
(1) 타이머가 다 떨어지거나 rocket이 탱크에 다을 경우 폭팔 에니메이션을 동작해야 하므로 중복코드 제거를 위해 해당 기능을 별도 함수로 분리 했다. 이 함수는 local로 선언 되어 있기 때문에 rocket 스크립트에서만 사용가능하다.
(2) 전에 존재하던 코드들이 explore()함수로 이동 되었다.
(3) 물리엔진은 group과 mask가 맞으면 shape가 충돌시 collision_response라는 메시지를 보낸다.
(4) 충돌이 있을 경우 폭발 기능을 호출 한다.
(5) 마지막으로 탱크를 삭제 한다. other_id변수를 통해서 로켓과 충돌한 게임객체의 ID를 구할 수 있다.
게임을 실행해보자.
Create the scoreing GUI
1. main 폴더에 text라는 font를 추가하자.
2. font를 열고 Font 속성에 /assets/fonts/04font.ttf를 설정한다.
3. main 폴더에 ui.gui를 만들자. 여기서는 점수 카운터를 배치할 예정이다.
4. ui.gui에 아까 만든 /main/text.font를 추가하자.
5. Nodes에 text를 추가하자
6. Text의 id속성엔 score, Text 속성엔 SCORE: 0을 font 속성엔 아까 만든 text를 넣는다.
7. text위치를 좌상단에 놓자
8. main에 gui script를 추가하자. 이름은 ui로 한다.
9. ui.gui를 열고 Script 속성에 방금전에 만든 ui.gui_script를 설정하자. 이제 gui를 게임객체에 컴포넌트로 추가하면 GUI가 표시되고 설정한 스크립트가 실행될 것이다.
10. main.collection을 열자
11. game object를 추가하자. 그리고 생성한 게임 오브젝트 아래에 /main/ui.gui를 추가하자. 추가된 ui.gui는 아이디가 ui로 자동으로 설정 되어 있을 것이다.
이제 점수 카운터가 표시된다. 이제 점수를 업데이트 할 수 있도록 GUI 스크립트에 기능을 추가하자
Code the scoring update
1. ui.gui_script를 연다
2. 아래 코드를 작성하자
function init(self)
self.score = 0 -- (1)
end
function final(self)
end
function update(self, dt)
end
function on_message(self, message_id, message, sender)
if message_id == hash("add_score") then -- (2)
self.score = self.score + message.score -- (3)
local scorenode = gui.get_node("score") -- (4)
gui.set_text(scorenode, "SCORE: " .. self.score) -- (5)
end
end
function on_input(self, action_id, action)
end
function on_reload(self)
end
(1) self.score에 초기 점수를 초기화
(2) add_score 메세지에 대해 처리할 분기 로직
(3) 메세지에 전달된 값을 self.score에 추가한다
(4) gui의 score text노드를 찾는다
(5) score text node에 "SCORE: " + 추가된 점수 값을 넣는다.
3. rocket.script를 열고 on_message() 함수에 아래 코드를 추가하자
function on_message(self, message_id, message, sender)
print(collision_response)
print(message_id)
if message_id == hash("animation_done") then
go.delete()
elseif message_id == hash("collision_response") then
explode(self)
go.delete(message.other_id)
msg.post("/gui#ui", "add_score", {score = 100}) -- (1)
end
end
(1) main.collection에 있는 게임객체 gui의 ui 컴포넌트에 add_score 메세지를 보낸다. 메세지 내용으로 score:100 값이 들어잇는 값을 전달한다.
4. 게임을 실행해보자.
Practice
우리는 네가 이 튜토리얼을 재미있게 봤기를 바라며 그것이 도움이 되었기를 바란다. Defold에 대해 더 잘 알기 위해, 우리는 당신이 이 작은 게임으로 계속 일하기를 제안한다. 제안된 몇 가지 연습:
플레이어 캐릭터에 대한 방향 애니메이션을 추가하십시오.
Tip, update_animation(self)이라는 기능을 update() 함수에 추가하고 self.dir 벡터의 값에 따라 애니메이션을 변경한다. 또한 각 프레임을 스프라이트에 "play_animation" 메시지를 보내면 애니메이션이 처음부터 다시 시작되므로 각 프레임은 애니메이션이 바뀌어야 할 때만 "play_animation"을 보내야 한다는 것을 기억할 필요가 있다.
플레이어 캐릭터에 "아이들" 상태를 추가하여 이동할 때 보행 애니메이션만 재생하도록 하십시오.
탱크가 동적으로 생성되도록 하십시오. 로켓이 어떻게 생성되는지를 보고 탱크에 대해 비슷한 설정을 한다. 탱크 산란 기능을 제어하는 스크립트로 메인 컬렉션에 새로운 게임 개체를 만들고 싶을 것이다.
탱크들이 지도를 순찰하게 해 한 가지 간단한 옵션은 탱크가 지도에서 임의의 지점을 선택해서 그 지점을 향해 이동하게 하는 것이다. 점으로부터 짧은 거리 내에 있을 때, 새로운 점을 선택한다.
탱크가 선수를 뒤쫓게 한다. 한 가지 옵션은 구형 모양으로 탱크에 새로운 충돌 물체를 추가하는 것이다. 플레이어가 충돌 물체와 충돌할 경우 탱크를 플레이어를 향해 이동시키십시오.
선수에게 탱크를 발사한다.
음향 효과를 추가한다.
'DEFOLD > 튜토리얼' 카테고리의 다른 글
3. Colorslide tutorial (0) | 2020.06.18 |
---|---|
2. Movement tutorial (0) | 2020.06.18 |
1. Walking astronaut tutorial (0) | 2020.06.18 |