공격#1

CJB_ny·2021년 12월 25일
0

Mini_MMO_RPG

목록 보기
6/16
post-thumbnail

오늘의 작업은 왼클릭은 한번하게 되면 몬스터에게 다가가서 한번 때리는 작업을 해보도록 할 것이다. 클릭을 한상태에서 계속 누르고 있으면 패는 모션 만들어 볼 것이다.

일단 PlayerController로 돌아가서 코드를 좀 정리를 할 필요가 있다.


이부분을 보게되면 딱히 플레이어와 관계가 없다고 봐도 될정도로 PlayerController에 왜 있는지 의문이 든다.

거의 독립적으로 실행이 되고있는 함수이다.

그래서 따른 컨트롤러로 따로 빼놓도록 하자.


이렇게 새 스크립트 함 파주고


일단 PlayerController에 있는 UpdateCursor함수에 있는거 커서컨트롤러의 Update문안에 이동을 시키자
(지금 빨간줄은 안가져 온것들 때문에 가져올 것들이 많다. 그리고 UpdateMouseCursor함수 없애주도록 하자)

또한 옮겼던 부분들(Update문안에 함수 없애기)


이부분은 복사를 해서 CursorController로 옮기자


그리고 이부분들도 다 보내버리자


Start에서도 로딩하는 부분들 옮기자

그리고 이제 분리는 다 됬으니까
유니티로 돌아가서 테스트를 해보자.


그래서 지금 CursorController를 어디다가 붙일지 고민이 되기는 하는데
유니티짱에 붙여도되고 게임씬에 붙여도된다.
일단 게임씬에다가 붙여 놓도록 하자.


이게 GameScene부분인데 처음에 init을 하는 순간에


이 주인님한테 CursorController를 붙여주는 작업을 하도록 하자.


그러면 실행하기 전인데 실행을 하면은 아래처럼


이렇게 불러와진다.

그러면 이제 동작은 제대로 잘 되고있다.


지금 우리는 Idle과 Moving 밖에 사용을 안하고있었는데

PlayerController맨 아래로 내려서 보면은

OnMouseEvent는 사실 Idle인 상태와 Moving인 상태에서 들어오는 녀석이다.


그리고 switch로 PointerDown, Press, PointerUp인 상태일때도 들어온다.

PointerDown은 마우스를 처음 한번 딱 눌렀을때,

레이캐스팅을 딱 해가지고 몬스터를 눌렀냐 아니면 땅을 눌렀냐에 따라서 현재 상태를 바꿔주고 있다.

그리고 계속 누르는 상태인 Press

에서는 누르는 대상을(== _lockTarget이 null이 아닐때 == 몬스터일때) _destPos를 바꿔주고 있는 중이다.
_destPos = _lockTarget Or hit.point로 바꿔주고 있는 상황이다.

그런데 우리가 만약에 몬스터한테까지 다가 가가지고 특정거리 == 나의 공격 사정거리 까지 갔으면은 이제 "전투 상태"로 바꾸어 주어야 한다는 말인데

그부분을 어디서 해야할까??
(-> 내생각은 일단 enum PlayerState에 Attack추가하고 Switch문의 PoinetDown, Press안에서 if문으로 추가 해야 할거같다.)


지금 이부분에서 UpdateMoving이 이동을 처리하는 부분이였다.


이 함수가 이동함수인데

지금 Vector3 dir = _destPos - transform.position으로 해주고
if(dir.magnitude < 0.1f)는 이동하는 부분까지 거의 도달을 했으면
_state = PlayerState.Idle; 로 멈추게 해주고

그게 아니라면

계속 이동을 하게 해주었었다.


그래서 타겟이 있을때만 로직이 실행될 수 있도록 해주자

나와 그 아이의 거리가 어느정도 가까워 지면은 _state를 공격인 상태로 바꿔 주면 될 것이다.

그래서 나와 몬스터의 거리는
_destPos - transform.position 하면 나온다


그래서 (_destPos - transform.position).magnitude를 해주게되면 나와 대상간의 거리가 나오게 되는데

이것을 float로 들고 있도록 하자.

요런 느낌임.


그리고 나중에는 사정거리라는 변수로 따로 빼와서 distance <= 변수 뭐 이런식으로 해주어야 되겠지만 일단은 1로 해주도록 하자.

그래서 아무튼 distance가 1보다 작다면

이렇게 PlayerState를 Skill로 바꿔주도록하자.

그리고 이렇게 했으면 아래는 더 실행을 할 필요가 없으니까 return; 때려주자.

그래서 if문을 만족을 하여서 Skill이 되면 다음에는 이제
UpdateMoving이 아니라 UpdateSkill로 들어오게 될 것인데..

만들어 둔 기억이 없으니 Update문을 수정을 해주자

일단 이렇게 만들어 주고 UpdateSkill()함수를 구현을 해주어야 한다.


바로 위에다가 맨들어 주고
뭐 별다른 이상이 없으니 테스를 해보도록 하자.


뜨기는 잘뜨는데 한번만 누르면 뜨지는 않고 뭐 더블클릭이나 조금더 클릭을 하면 그때서야 로그가 찍힌다.

그래서 한번만 눌렀을때는 처리가 잘못된다는 그런 결론을 내릴 수 있다. 지금은.

한번만 눌렀을 때는 왜 처리가 안되는지 한번 살펴 보도록하자.

지금 현재 OnMouseEvent에서 switch문에서

_lockTarget이 null로 변경 되니까 한번 클릭으로 안되는 것이다.

왜냐하면 UpdateMoving에서

_lockTarget이 null이 아닐때, float distance가 <= 1일때 _state가 PlayerState가Skill로 되니까 Update문 안에서 Update를 받게 되는 것이기 때문에 _lockTarget을 null로 하면 한번 클릭시 로그가 안찍힌다.

그래서 일단 저 switch문을 주석처리를 하고 유니티 실행을 하면은 한번 클릭시 로그가 잘 찍히기는 한다.

그래서 이제는 로그를 찍을것이 아니라 애니매이션을 재생을 해보도록 하겠다.

애니매이션 재생은
여기 PlayerAnimController로 가가지고


Knight의 Attack애니매이션 넣어주는데

이제 여기서가 고민의 시작인데
어떻게
이 ATTACK이라는 녀석을 관리를 해주어야 할것인가?


wait <-> run 은 speed라는 녀석으로 관리를 해주었는데

ATTACK은 일단 attack이라는 bool을 나두어서 일단은 관리를 하면 될거 같다라는 생각이 든다.


가만히 있는 상태에서도 전투에 돌입 할 수 있으니까 일단 이렇게 만들어 주자.


그리고 각각의 Exit Time은 꺼두도록하자
ATTACK 애니매이션이 끝났다고 바로 WAIT로 돌아갈 것은 아니니까.

그다음에 이제
condition을 넣어주기 시작하여야 하는데

ATTACK이 true면은 ATTACK실행하고 false이면은 ATTACK -> RUN으로 가는 방식이다.

WAIT <-> ATTACK도 똑같다.

그래서 코드만 추가를 해주면 되는데 기존의 Idle을 보면은

이런 상태이다.

그래서 똑같이 UpdateSkill도

true라고 해주면은 넘어 갈 것이다.
일단 돌아오는 것은 생각하지 않고 때리는 모션이 잘 실행이되는지 보도록하자.

모션이 그냥 한번 실행이되고 크래쉬가 난다. (한번 실행은됨)


일단
이런 경고창이 뜬다.. 다른 경고창도 일단 뜨는 중이다.

이거 한번 예전에 살펴본 기억이 있었다고한다.(나는 기억이 안난다.)

애니매이션이랑 때리는 순간에 이벤트를 발생시키기 위한 그런 방안으로

해당 애니매이션으로 간다음음에 Event라는 것이 있었는데

이렇게

Attack_1의 경우

여기에 뭔가가 추가가 되어있다.


일단 크래쉬는 안난다 아까처럼 Attack_1에러 메세지는 안뜸.
그리고 달릴때 에러뜨던것도 Event드가서 delete 해주니까 해결이 되었다.

그러면 이제 공격을 끝낸 다음에 원상태로 돌아가고싶은데 RUN이나 WAIT로 돌아가고싶다.

이것은 애니매이션이랑 좀 맞출 필요가 있을것이다. 때리는데 1초가 걸린다고 했을때 1초 기다렸다가 상태를 바꾸어야 할텐데..

사실은 그것은 애니매이션 이벤트로 제어할 수 있었다.


아까 삭제했었던 부분에서 다시 이벤트를 넣어주고(적절한 시간에)
OnHitEvent라고 만들어 주자.

그다음에 이제 코드로 돌아가서 OnHitEvent를 받아주는 부분을 구현을 해야한다.


이렇게 구현을 해준다음에 이것이 잘 실행이 되는지 유니티에서 테스트를 해보도록 하자.

그래서 애니매이션은 잘 구현이 되는데 뭔가 이상하다. 때리면서 잠깐 RUN인 상태여서 뛰다가 Idle인 상태로 바뀐다.

왜그렇지...??

애니매이션대로 좌표 이동하기 싫을때

이것은 그냥 애니매이션 자체가 앞으로 살짝 대쉬를 하도록 해서 만들어 진거같은데..이것이 애니매이션대로 좌표를 이동하기 싫으면은...

방법이 하나 있는데

애니매이터를 들고있는 오브젝트에서

Apply Root Motion을 해제를 하면은 된다.

그러면은 이제 "애니매이션을 따라가지 않겠다"라고 되가지고 이제 잘 때리게 될것이다. 근데 살짝 뛰는 모션이 있는데 쉬발 뭐지..??
(일단 나중에)

계속 공격하는 애니매이션 구현

그리고 일단은 누르고 있으면 계속 공격을 해야하는데 이부분을 어떻게 할지 다시 고민이다.

일단 코드로 돌아와서 이부분을 어떻게 구현을 할지 생각을 해보도록하자.

(내 생각에는 아마 계속 누르는 상태인 switch의 Press에서

이부분에서 뭔가를 손봐야 할거같은디..


이부분에 _state를 Skill로하니 몬스터와의 거리가 많이 떨어져 있어도 계속Skill모션을 행한다...)


Skill애니매이션이 완료 될 때쯤이면 다시 PlayerState를 Idle로 돌려놓았었다.

그리고 Idle상태에서

OnMouseEvent를 계속 받아서(마우스로 클릭시)


이렇게 switch문 안에서 PointerDown일때 _state를 Moving으로 바꾸어서 PlayerController의 Update문안에서 UpdateMoving이 호출되어 특정거리(distance <= 1일때) Skill이라는 애니매이션이 실행이 되도록 하였다.

아무튼 Moving으로 바꾸는 조건은 raycastHit을 해가지고 해당 조건을 만족을 해야지만 _state가 Moving으로 바뀌었다.

그런데 문제는 지금 PointerDown이라는 애가 마우스를 누르고 있으면 계속 뜨는게 아니라 처음에 마우스를 한번 눌렀을 때 뜬다는 문제점이 있다.

그래서 지금 상태로는

이녀석은 발생을 절대 안하고

Press상태에서

이녀석만 계속 뜨는 상태라서 Idle상태에서 더이상 바뀌지 않는 그런 문제점이 있다.

그러면 조금 꼼수를 써가지고

OnHitEvent에서 Idle상태로 놔두는 것이 아니라 Moving인상태로 놔두면 어떨까라는 생각이 든다.(먼말이고??)


그러면 누르는 상태일때(Press)일때 연속해서 때리기는 하는데
애니매이션 블렌딩 때문에 때렷다가 뛰었다가 바로 또 떄렷다가 이런식으로
굉장히 어색하게 동작한다.

SKill애니매이션 문제 해결방법

디아블로에서는 이딴 식으로 만들지 않을테니

결국에는 OnHitEvent가 발생을 했을때, 마우스를 쭉 누르고 있었냐 아니냐에 따라서 쭉 누르고 있었다면 Skill상태를 다시한번 호출 해서 한방더 때리게 하고 그게 아니라고 하면은 Idle상태로 넘어가게 만들면 해결이 될거같다라는 생각이 든다.

그래서 이부분을 고쳐보도록 하자.

그런데 그전에 잠깐 정말로 고치고싶은 부분이 있는데 뭐냐하면은

바로 이부분인데

잠깐 고치고 갈부분 (프로퍼티 생성)

지금 애니매이션을 Animator로 접근을 해가지고 GetComponent()로 들고와서 anim. 으로 컨트롤 하여서
_state를 PlayerState.Moving 이런식으로 애니매이션을 바꾸어 주었는데

이런 애니매이션을 컨트롤 하는 부분이랑 _state를 바꿔주는 부분이랑 따로따로 되어있다. 사실은 _state가 Moving으로 바뀌었으면은 Animator anim 이부분도 한번에 같이 맞게 바뀌어야 할 텐데

이런식으로 코드를 분리를 해놓으면
혹시라도 나중에

이녀석은 적어 놓았는데

_state를 구현을 안해놓는 다던가

아니면 반대로 _state는 Skill이나 Idle인상태로 해놓았는데 애니매이션 코드부분을 빼먹는 다던가 하는 "문제"가 자주 일어 날 수 있다.

그래서 이런식으로 따로따로 관리하는 것은 죄악이 될 것이고
이것을 하나로 관리를 할 수 있도록 뭉처놓도록 하자.


일단 이렇게 코드를 위로 올려서
유니티에서도 볼 수 있게

시리얼라이즈 필드를 추가를 해주고 그다음에 그 밑에다가 프로퍼티를 하나 만들어 줄 것인데

PlayerState를 사용하는 그런 프로퍼티이다.

get같은 경우에는 그냥 바로 _state를 반환하면 될것이고
set의 경우 _state는 value를 넣어준 다음에

_state = value; 밑에 애니매이션과 관련된 부분을 넣어 주도록 하자.

그래서 결국에는 이렇게

Animator를 가지고 와가지고

여기서 이제 우리의 _state가 무엇인지에 따라가지고 아까 넣던 값을 다 넣어주어야 한다.


그래서 이렇게 되는데 switch문안에서 각각의 상태에서 대해서 우리가 넘겨 주어야 할 값이 무엇인지 생각을 해보면은

UpdateMoving에서

해당 애니메이터를 들고와서 anim.SetFloat("speed", _stat.MoveSpeed)로 설정을 해주었는데

우리가 만든 State의 프로퍼티에서 Moving일때 저것을 구현을 해주어야 한다.

그래서 내가 만약 Moving상태였다면은

이렇게 될 것이고

만약 Idle상태일때라고하면은

코드가 이러니까 anim.SetFloat("speed", 0);부분을 프로퍼티에 추가를 하면 된다.

그래서 다시 올려서

이렇게 될 것이고

그리고 방금 우리가 한 Skill일 경우에는

UpdateSkill을 보면 이런식이니까

프로퍼티에서 추가를 해주면된다.

그리고 Skill상태가 아닐 경우(다른 상태 일경우) 조금 지저분 하기는 하지만


이런식으로 false로 바꿔 주도록 하자.
(밖으로 빼놓아서 따로 관리를 할 수도 있지만 일단은 이런식으로 가자)

그다음에는 이제 무엇을 챙겨야 하냐면은 _state를 직접 챙기면은 안되고

이제는 무조건 우리가 만든
이 프로퍼티를 이용해서 Player의 상태를 바꿔주어야 한다.

그러면 애니매이션도 딸려와서 같이 셋팅이 된다.


그래서 이렇게 _state = PlayerState.Skill이나 Idle이렇게 되있는 부분을

이런식으로 바꾸어 주어야한다.


이렇게 그냥 _state부분 다 State로 바꿔주자.

이렇게 다바꾸고나면은 이제 State랑 애니매이션이랑 같이 묶여서 작동을 하는 그런식으로 된 것이다.

_state -> State로 바꾸는 부분 다 잘 바꾸었으면

아까랑 똑같이 잘 작동을 한다.

굿

profile
https://cjbworld.tistory.com/ <- 이사중

0개의 댓글