의식의 흐름대로 게임 만들기 12. 플레이어 체력

2023. 7. 26. 23:58GAME/Unity

이제 적과 플레이어가 충돌했을경우 플레이어의 체력을 감소시키면 좋겠습니다.
 
이것도 전에 했던 내용과 다를게 없죠.. 이래서 기초가 가장 중요합니다.
 
PlayerHP 스크립트를 하나 만듭니다.

그리고 초라하지만 Hp 하나를 만듭니다 ㅎ
 
 
적이 플레이어와 충돌했을때 적을 파괴시키고 플레이어의 체력을 -1 하는 코드를 만들어보죠.
그러면 일단 충돌이 일어난 시점으로 갑시다.
 
OntriggerEnter2d로 갑니다.
 

그렇다면 충돌한게 Player인지 구분을 해 주어야 하겠죠... 어떻게 구분을 할까요? 방법은 여러가지가 있습니다.
 
먼저 위에 함수의 매개값으로 들어온 collision에 충돌 정보가 담깁니다. 여기서 정보를 빼오면 됩니다.
 
가장 첫번째로 생각할 수 있는 방법은... 스크립트 입니다. Player 스크립트를 불러오고 -를 해주는 방법이죠 
 
일단 설명으로는 모르겠으니 한번 코드로 봅시다.
 

결국에는 Player는 PlayerHp라는 컴포넌트가 있기 때문에 충돌한 놈에게서 PlayerHp 컴포넌트를 찾아서 Hp-1을 해주는겁니다..
 
하지만 이것은 성능적으로도 약간 문제가 될 수 있고 간접적으로 Player를 알아내는 방식입니다.
 
플레이어를 알아내는 방법 중 Tag 라는것이 있습니다.
 
GameObject에 Tag를 붙여서 너가 Player 태그니? 라고 물어보는것이죠.
 

플레이어를 클릭하시고 Inspactor 창 상단에 Untagged라고 되어있는데 이것을 클릭하시면 
 

이러한 창이 나오게 되죠.. Add Tag를 해주면
 

+버튼을 누르시고

Player를 입력합니다.
 

마지막으로 Tag에 Player를 추가하시면 완성입니다.
 
이제 태그가 붙여졌고요.. 적이 물어봐야겠죠.
 

이런식으로 tag == "player" 로 비교가 가능합니다. (CompareTag라는 메서드로도 가능)
 
피격 처리는 되었습니다. 이제 플레이어의 체력이 일정 범위 이하면 죽음 처리를 했으면 좋겠습니다...
 
우선 지금으로서는 적에다 해 봅시다.
 

플레이어인지 검증하고 플레이어의 체력을 1 깎는 코드 밑에
플레이어가 체력이 0이 될경우 게임오버가 되는 코드를 작성했습니다. (단순 기능 확인용입니다)
 
암튼 이제 충돌을 하려면 또 플레이어에 Collider랑 Rigidbody가 있어야합니다.
 
빨리 붙여주고....
 

 
collider 를 trigger로, rigidbody의 gravity는 0으로는 생략하겠습니다.
이제 플레이어와 적이 충돌을 하면 Hp가 깎이고
플레이어의 색상이 검은색으로 변하면서 게임 오버가 됬다는 사실을 알 수 있습니다.
 
하지만 이건 좀 이상합니다. 왜 플레이어의 죽음 처리를 적에서 하는걸까요?
 
개선을 해야할듯 합니다.. 하지만 오히려 지금이 날수도 있습니다.
왜일까요? 한번 보도록 하죠. 그러면 Player에서 죽음 처리를 직접 해 봅시다.
 

Player Hp
Enemy

 
이렇게 분리를 했더니 보기좋아졌습니다. 하지만 내부적으로는 오히려 문제가 더 커집니다.
 
왜 그러냐... Update의 특성을 저번에 말했었죠. 1초에 60번정도 실행이 됩니다.
 
하지만 Hp를 1초에 60번 체크를 할 필요가 있을까요? 그럴정도로 많이 호출을 해야할 일은 아니라고 봅니다...
이건 성능 낭비입니다!!
 
자 그렇다면 어떻게 해야할까요? 
 
우리의 목적은 결국 Hp가 감소될때만 체크를 하고싶습니다.
 
하지만 Hp를 변수로만 관리한다면 감소될때를 체크하기 어렵습니다.
 
따라서 Hp가 감소(변동)하는것을 기능...즉 함수로 만들고
 
Hp가 감소되는 [함수]
밑에다 게임오버 체크를 하면 되겠죠..
 

이렇게 Hp를 직접 접근하지 않고 함수로 접근해서
 
Hp가 조정될때는 결국 이 함수가 호출될때니까 이 함수가 실행될때 검증을 하면 되죠. 
 
마지막으로 다른곳에서 접근을 할수 없도록 Hp 자신에게는 public을 빼 줍니다.
 

public은 접근제한자중 하나인데 다시말하지만 이 블로그에는 프로그래밍 기초는 다루지 않습니다. 너무 길어집니다 ㅠㅠ
 
그러면 이제 충돌 체크로 가봅시다.
 

아까는 보지 못했던 빨간줄이 뜨는데요, public을 뺀다는것은 공개하지 않겠다! 라는 의미라고 받아들이시면 됩니다.
 
그래서 Hp를 다른 컴포넌트에 공개하지 않기 때문에 접근이 불가합니다.
하지만 저희가 만들어둔 Get과 Set 메서드는 public이죠? 다 이유가 있습니다.
 

이런식으로 할수가 있죠. ph.GetHP 메소드는 PlayerHp에 있는 Hp를 리턴하는 메소드고
리턴된 값을 -1 해서 다시 PlayerHp의 Hp로 설정하죠.
 
그러면 이제 PlayerHp 컴포넌트에 Set 메서드에서 들어온 값이 Hp가 되고 게임오버 체크가 되는것이죠. 
 

이것을 전문용어로 말하자면 '객체지향의 캡슐화' 라고 합니다. 
 
본체(Hp)를 숨겨두고 Get,Set 메서드로 접근하는 행위입니다.
 
그렇다면 왜 할까요? 많은 이유가 있지만(보호,읽기,쓰기등)
지금은 아까 보셨다시피 변수 Hp를 직접 접근하면... 변화가 될때를 감지하지 못합니다. 따라서 Update문에서 계속 체크해야하는 문제가 생기는거죠.(성능상 문제)
 
자 이러한 원리를 깨닳으셨다면 한가지만 더 하고 끝내죠. 
 

이 코드를 보셨을때, 불---편 하시다면 지극히 정상입니다.
아니 Hp변수를 또만들고 함수를 여러번 실행하고....
 
네.. 하지만 그것도 개선이 가능하죠. 바로 '프로퍼티' 입니다.
 
일단 무작정 써 봅시다.
 

기능은 똑같습니다.
HP는 프로퍼티 이름이고요.. 그안에 get과 set이 있네요. 방금 썼던 get함수와 set 함수를 의미합니다.
 
한번 써 볼까요?

Hp에 ph.HP(프로퍼티)를 담습니다. 
 
그러니 아무 문제가 없죠? 분명 Get과 Set은 함수 아니였나요?
 
네 프로퍼티는 함수를 변수처럼 사용하는 기능입니다.

변수 HP = 3  이렇게 하면
이 HP 변수를 3으로 조정하겠다! 라는 의미가 되잖아요? 그니까 SETTER 가 실행이 되고

변수 HP만 불러올때 print(HP) 이거는 HP를 조정하지 않으니까 GETTER이죠.

지금은 int Hp라는 변수에 HP프로퍼티를 담으니까
누군가에게 내 정보를 주는것이죠?
그니까 GET 함수가 실행되겠죠.
아주 좋습니다.
 
그렇다면, 이것도 됩니다.
 

ph.HP를 Get해서 그걸 --함으로서 Set하는거죠. 완전 길이가 줄었네요! 
 
마지막으로 PlayerHp에서 기본 체력을 설정해줍시다.
 

주의할점은 Hp는 변수고 HP는 프로퍼티입니다. 이름에 주의하세용.
 

3번 맞으니 색이 변했네요!
 
생각보다 양이 길어져서... 빠르게끝냈네요 ;;
도움이 되면 좋겠습니다. 감사합니다.