11
12

이제 플레이어가 피해야할 적을 만들 시간이다.


우리가 만들 적은 그렇게 어렵게 움직이지 않는다. 적들은 화면의 바깥에서 생성되고, 랜덤 방향으로 일직선을 그리며 이동한다.

 

이렇게 만든 적은 Mob 이라는 이름의 씬에 저장한다.

우리는 이 과정에서 instance를 활용해 여러 개의 독립적인 몹들을 생성하게 될 것이다.

 


1. Mob 노드 설정

우선 탭 메뉴에서 Scene > New Scene을 만들어 새 씬을 생성하고 다음 구조대로 노드를 배치해보자.

 

 

RigidBody2D (이름: Mob)

  • AnimatedSprite2D
  • CollisionShape2D
  • VisibleOnScreenNotifier2D

 

Player씬에서 그랬듯 자식 노드를 클릭해도 그들이 선택될 수 없게 만들어주는 걸 잊지말자. (그룹화)

 

Mob 노드에서 RigidBody2D 노드를 찾아보자. 그 안에는 Gravity Scale이라는 프로퍼티가 있는데, 이걸 0으로 맞춰서 바닥에 떨어지지 않도록 한다.

 

또한, rigidbody2D 바로 밑의 CollisionObject2D 부분에서 Collision 이라 되어있는 부분을 펼쳐보자.


그리고 Mask 프로퍼티의 1을 꺼준다. 이걸 통해서 몹들은 서로 충돌하지 않을 수 있다.


(layer는 단순히 rigidbody2D에 붙는 이름표에 가깝고, Mask에서 켜준 번호와 레이어 번호가 같으면 서로 충돌하는 모양이다. 유니티 시스템과 비슷하다.)

 

 

AnimatedSprite2D는 Player를 생성했을 때와 똑같이 진행해준다. 다만 이번엔 fly, swim, walk 3가지의 애니메이션이 있을 뿐이다. 각 애니 스프라이트 파일은 art 폴더 안에 있다.

 

애니메이션 설정 시 FPS를 설정해줄 수도 있다. FPS는 알다시피 1/n초마다 프레임을 바꾸겠다는 뜻이다.

이번 애니메이션 각각에 FPS 값(Animation Speed)을 3으로 맞춰주자.

 

참고로 Play Animation 버튼을 누르면 애니메이션이 어떻게 보이는지 구경할 수도 있다.

 

크기가 너무 큰 것 같으므로 해당 스크립트의 스케일도 낮춰준다. x, y 값 0.75, 0.75가 적당하다.

 

 

또, 잊지 말고 collision 설정도 해주도록 하자. CollisionShape2D에 New CapsuleShape2D를 지정해준다.


근데 이때 캡슐의 방향이 정해져 있으므로 회전값을 넣어서 이미지에 맞게 돌려준다. 이건 인스펙터 안의 "Transform>Rotation"값을 조정하면 된다.

 

당연한 이야기지만, Animation이 바뀌더라도 collisionShape2D는 공유하고 있기 때문에 모두 같은 모양의 콜리전을 공유하게 된다. 애니메이션마다 콜리전을 다르게 하려면 어떻게 해야할까?

 

 

 

Mob 씬 자체를 저장해주는 것도 잊지말자.

 


2. Mob 스크립트 작성

이제는 Mob(rigidbody2D) 노드에 스크립트를 생성해주자.

 

extends RigidBody2D

 

 

 

Mob은 RigidBody2D를 베이스로 삼는 만큼 해당 노드를 상속받고 있다는 걸 잊지말자.

 

 

우리는 _ready() 안에서 앞서 만들어준 3가지 애니메이션 중 하나를 랜덤으로 선택한 뒤, 플레이해줄 것이다.
일단 완성된 코드를 보자.

 

func _ready():
	var mob_types = $AnimatedSprite2D.sprite_frames.get_animation_names()
	$AnimatedSprite2D.play(mob_types[randi() % mob_types.size()])
  1. AnimatedSprite2D의 "sprite_frames" 속성에서, 애니메이션 이름 리스트를 받아온다. 받아온 리스트는 mob_types 리스트에 저장한다.
    GDScript 문법으로는 이런 배열로 저장된다. ["walk", "swim", "fly"]

    덤: 이걸 확인하려면 _ready() 안에 print(mob_types)를 추가해보자.
  2. 이제 우리는 3가지 중 하나를 선택하는 랜덤 수가 필요하다. 배열은 0부터 수를 세므로 0, 1, 2 셋 중 하나면 되는 것이다.
    이럴 때 randi() % n 라고 작성하면 0부터 n-1 까지의 값중 정수 1개를 선택해준다. mob_types.size()는 해당 배열이 갖고 있는 자식의 개수를 리턴한다.

 

여기까지 작업되었다면 오른쪽 위 Run Current Scene을 실행시켜서 현재 씬을 실행도 시켜보자.

 

 

Mob 오브젝트의 위치값이 0,0이라 화면 위에 잘려보이지만, 실행할 때마다 애니메이션 파일이 바뀌는 걸 확인할 수 있다.

 

 

마지막으로 작업해줄 부분은 몹들이 스크린 밖으로 넘어가면, 자동으로 사라지게끔 만들어주는 것이다.


VisibleOnScreenNotifier2D 노드에서 screen_exited() 신호를 찾아 Mob 스크립트에 연결한다.

 

 

그리고 다음과 같이 코드를 입력한다.

func _on_visible_on_screen_notifier_2d_screen_exited():
	queue_free()

 

완료 후 저장해준다. 이제 Mob 작업 역시 끝이다.

 

 


 

이즈음 진행해보니 좀 궁금해진 것

  1. 노드를 자식으로 두는 기준이 있나? 하나의 씬 안에 자식의 자식을 많이 만드는 것도 괜찮은건가?
  2. 게임 매니저 같은 것이 그럼 아예 필요가 없나?
  3. 여러 이벤트(카메라, 라이팅, 캐릭터 움직임 등)를 동시에 진행하려면 어떻게 관리를 해야하나?
  4. 자체 데이터 베이스 생성?

 

플레이어와 몹이 준비되었으니, 다음 장에선 새 씬을 생성해 이 둘을 배치하는 작업을 진행해 볼 것이다.

이제 플레이할 수 있는 게임이 되기까지 머지 않았다!

COMMENT