본문 바로가기
유니티 게임 개발

[유니티 강좌] 2D RPG 게임 만들기 - 4 / 적과 체력바 만들기

by 호일이 2020. 5. 11.

 

공유 폴더에 체력바 그림 추가했습니다. 이미 다른 체력바 그림이 있으시다면 다른 것으로 사용해도 문제없습니다.

 

RPG 만들기 - Google 드라이브

 

drive.google.com

1. 체력바 불러오기

점점 파일이 많아지니 폴더를 정리하겠습니다.

Resources 폴더를 만들어 그림 파일들을 넣었습니다.

 

 

2. 체력바 생성

Hierarchy 창에서 우클릭 -> UI -> Image를 누르면 캔버스와 그 안에 Image가 생성됩니다.

Image 밑에 하나 더 Image를 만들어줍니다.

 

구분하기 쉽게 이름을 변경해줍니다.

 

bghp_bar

체력바의 모양처럼 Width와 Height를 수정해주고 

bghp_bar의 image에 체력바의 배경을 넣어줍니다.

 

hp_bar

좌우 확장되는 그림으로 클릭해서 바꿔주고 Left Top Right Bottom 전부 0으로 설정합니다.

간단히 설명하면 저 그림은 부모 오브젝트의 크기와 좌표를 똑같이 한다는 뜻입니다.

 

체력바 그림을 넣어주고 

Image Type을 바꿔줍니다.

 

Game 화면

Scene 화면

Canvas의 오브젝트들은(UI) 기존의 월드 좌표가 아니라 스크린 좌표에 따라 위치됩니다.

Scene 화면에서 UI를 확인하고 싶다면 UI 오브젝트를 두 번 클릭하면 됩니다.

 

3. 체력바 이동

bghp_bar의 좌표 그림(Anchor Presets)을 누르고

Shift + Alt + 클릭을 하면 원하는 좌표로 체력바를 이동할 수 있습니다.

Shift + Alt 를 눌렀을 때

Alt + 클릭으로도 이동이 가능하지만 중심점 설정이 안 된 상태로 이동이 되기 때문에 좌표 수치가 깨끗하지 않습니다.

 

이동하고 약간 여백을 주면

 

체력바 이동 완료

위치는 상관없으니 원하는 곳으로 이동시켜도 됩니다.

 

 

소드맨 체력바 체력에 따라 줄어들기

다음 포스팅에서 적과 함께 한 번에 적겠습니다.

 

4. 적  생성

적의 애니메이션을 저장할 폴더를 생성합니다.

 

Idle 0부터 19까지 선택하고 Scene창에 드래그 앤 드롭하면 애니메이션 생성 경로를 지정하는 창이 뜹니다.

아까 만든 폴더에 저장합시다.

 

적과 소드맨의 애니메이션 차이

소드맨의 애니메이션은 각 부위의 위치, 회전, 크기 값을 바꾸면서 표현하는 방식이었다면

의 애니메이션은 여러 장의 그림을 빠르게 바꾸면서 애니메이션을 표현하는 방식입니다.

 

소드맨은 3D쪽에서 사용되는 방식에 가깝고

적은 보통 2D에서 사용하는 방식입니다.

 

5. 체력바 따라다니기

할 게 조금 많으니 천천히 해주시기 바랍니다.

HP_Bar에 Prefab 폴더를 생성하고

Canvas 안에 있는 체력바(bghp_bar)를 Project창으로 드래그 앤 드롭 해 프리펩으로 만들어줍니다.

프리펩을 클릭하고 Pivot을 x, y 둘 다 0.5로 수정합니다. (중심점 중앙으로)

 

Scripts 폴더 안에 Enemy 스크립트 파일을 만듭니다.

 

Enemy 스크립트

체력바 따라다니기 코드

일단 적에게 스크립트를 붙이고 차근차근 설명하겠습니다.

 

적에게 붙였다면 prfHpBar, canvas, height가 나옵니다.

셋 다 위에서 public으로 선언했기 때문입니다.

 

prfHpBar에는 프리펩 체력바를

canvas는 Canvas 오브젝트를 넣어주고 실행해봅시다.

 

실행화면

체력바가 적의 위에 생기긴 했지만 약간 오른쪽으로 가있는데요.

 

이유는 그림파일안의 화면에서 캐릭터가 약간 왼쪽에 있기 때문입니다.

 

해결방법

빈 오브젝트를 생성하고

위치를 적의 중앙쯤에 위치시킵니다.

빈 오브젝트의 이름을 Enemy1으로 변경하고

안에 적을 넣습니다.

붙였던 Enemy 스크립트를 제거하고

새로 만든 Enemy1에 붙입니다.

※Enemy 스크립트가 2_enemies_1_idle_000에 있으면 체력바가 이동되지 않습니다.

 

[2021/04/13 추가 설명

위의 그림과 같이 Pivot으로 되어있지 않고, Center로 되어있으면 빈 오브젝트를 생성해서 중앙에 놓고, Enemy를 안에 넣어도 좌표 표시가 제대로 안 되는 현상을 볼 수 있습니다.

 

Center

  • 오브젝트의 경계의 중앙을 기준점으로 표시
  • 부모 오브젝트의 경우 자식 오브젝트의 전체적인 경계의 중앙을 기준점으로 표시
  • 오브젝트의 정확한 중앙값을 알아내서 회전하거나 이동할 때 사용함

Pivot

  • Transform의 position의 좌표 그대로 표시

어느 것으로 하든 표시되는 기준점이 바뀌는 것이고, 실제 Position 좌표값이 바뀌지는 않습니다만, 헷갈리지 않도록 Pivot으로 둔 상태로 진행하면 되겠습니다.

Pivot과 Center의 기준점 차이

2021/04/13 추가 설명 끝]

 

실행화면

 

코드 설명

체력바를 생성하되 canvas의 자식으로 생성하고, 체력바의 위치 변경을 쉽게 하기 위해 hpBar에 저장한다.

 

위 코드는 여러 가지가 합쳐져서 설명이 좀 깁니다.

 

Instantiate(게임오브젝트, 부모의 transform);

Instantiate는 게임오브젝트를 생성하는 함수입니다.

체력바가 따라다니게 하려면 우선 체력바가 게임 내에 존재해야 하기 때문에 먼저 생성을 했습니다.

단, UI는 Canvas 안에 있어야 합니다.

2번째 파라미터에 transform 값을 주면 그 transform의 안으로 들어가게 됩니다.

그냥 Instantiate(게임오브젝트) 하면 맨 밑에 생성되기 때문에 canvas.transform을 썼습니다.

 

이렇게 생성된 체력바 오브젝트의 위치를 움직여야 하는데

그 전에는 움직이기 위해 transform.position의 값을 변경했었습니다.

 

하지만 UI는 transform이 아닌 RectRansform을 사용하므로 GetComponent로 RectTransform을 받았습니다.

GetComponent란?

GetComponent 예시

GetComponent<컴포넌트 이름>();

GetComponent로 게임오브젝트에 붙어있는 컴포넌트들을 받아올 수 있습니다.

위의 그림에서 RectTransform, Canvas Renderer, Image 모두 컴포넌트입니다.

 

Camera.main.WorldToScreenPoint(월드 좌표 값);

월드 좌표를 스크린 좌표 즉, UI좌표로 바꿔주는 함수입니다.

 

height는 체력바를 적의 머리 위에 위치시키기 위해 추가했습니다.

 

스크린 좌표로 바꾼 값으로 체력바를 이동시켰습니다.

 

 

 

추가 설명

 

UI의 좌표란?

0, 1080  y  1920, 1080         

x

0, 0          1920, 0

이렇게 왼쪽 아래가 0,0인 좌표계입니다.

가운데가 0,0인 월드 좌표와 다르고 수치도 차이가 많이 나서

좌표계가 다를 때는 변환해주는 함수를 꼭 써야 합니다.

 

GetComponent 관련

1) hpBar = Instantiate(prfHpBar, canvas.transform).GetComponent<Transform>();

Transform을 써도 이동은 할 수 있습니다.

다만 Width, Heigth 등 RectTransform 고유의 다른 설정은 할 수 없습니다.

 

2)

Start

{

    hpBar = Instantiate(prfHpBar, canvas.transform);

}

Update

{

    hpBar.GetComponent<RectTransform>().position = _hpBarPos;

}

이런 방식으로 해도 실행은 문제없습니다만

Update에서 매 프레임마다 GetComponent를 사용하는 건 성능에 있어서 좋지 않습니다.

 

최적화에 대해 자세히는 모르지만 아는 것은 기회가 있다면 쓸 테니 가볍게 보시면 좋겠습니다.

 

3) Camera.main.~~

Camera.main도 최적화할 수 있습니다.

Start

{

    Camera camera = Camera.main;

    혹은 GetComponent로 얻어오는 방법

}

이렇게 비용을 줄일 수 있습니다.

 

꼭 public GameObject로 에디터에서 불러와야만 하는지

GameObject.Find("게임오브젝트명"); 으로 오브젝트를 불러오거나

Resource.Resources.Load("폴더명/파일명") as 타입; 으로 에셋의 리소스를 불러올 수 있습니다.

다만 코드를 최대한 간결하게 쓰려다 보니 쓰지 않게 되었습니다.

 

잘못된 점이 있다면 지적 환영입니다.

 

읽어주셔서 감사합니다.

반응형

댓글