본문 바로가기

3D_FPS

08_11 (코루틴의 전반적인 설명, Damage() 코루틴으로 구현)

목차

 

 

 


Die 애니메이션 끝나고 바닥으로 사라지게 하기

 

죽는 애니메이션이 끝나고 나면 바닥으로 사라지도록 하고싶다.

 

Die 애니메이션

바로사라지기 전에 

 

고고고

여기서

여기서 currentTime = 0 을 넣어주면 안됨!

 

 


코루틴 관련 설명 (Thread 와 Task)

 

 

 

하나의 App 을 실행할 떄의 단위를 Task 라고 하는데, 여러개를 하는게 Multi-Task 이다!

 

앱 하나한에서 일어날는 동작을 Thread 라고 함!

 

그러면 이 쓰레드는 여러개가 있어야 겠네?

 

여러개의 앱을 실행 하는건 멀티 테스크!

하나의 앱 안에서 여러개의 동작을 하는걸 멀티 쓰레드 라고 함!

 

Bottle neck 현상

처음께 내려가지 않으면 그 다음껀 기다리고 있을 수 밖에 없음

 

그래서 여러개를 하려면 어떻게 해? 병렬 처리를 하자!

멀티 쓰레드!

이게 코루틴의 원리 이기도 함!

 

Thread 는 고급 개발자가 써야함 위험하기 때문!

 

데이타를 건들일때 동시에 건들이면?

 

비주얼 스튜디오에 여러명이  들어와서 한 코드를 동시에 코딩 하는 느낌?

이게 진짜 위험함. 누가 쓴걸 지우고 할 수도 있으니까

 

그래서 나만 쓸 수 있게 세팅하는 작업이 필요함.

이걸 락킹 한다고 함. Locking!

 

근데 또 락킹해놓고 안에서 잠들어버리면 데드락이라고 함.

 

여튼 되게 위험함.

 

유니티가 비전공자도 할 수 있게 해놨는데

바로 최근까지는 내부적으로 돌리는 물리엔진이나, 이런걸 옮겨놨는데

사용자한테는 싱글쓰레드만 쓸 수 있게 해놨음

 

파일 다운로드하면서 모래시계라도 돌려야 하는데, 이걸 막아 놓은거임

 

코딩의 어려움때문에 원쓰레드만 쓰게 해놨는데 이러면 어떡하냐?

 

하나의 처리 단위를 함수라고 했을 때, 

함수 => Routine

싱글 쓰레드는 이 함수가 끝나야 다른 함수가 돌아간다는 거임!

 

그래서 같이 돌자는 느낌으로 Coroutine 이라고 함!

 

그래서 양보해준다고 한다. 그래서 yield 가 따라다님

 

그러면 얼마나 양보해야 함?

 

유니티에서는 시간이라는걸 씀. 

시간을 쪼개서 양보하면서 쓴다는게 코루틴의 핵심임!!

 

A() 를 계속 호출할 수 있는것 처럼

코루틴을 잘못 쓰면, 여러개가 등록 되서 예약 걸어놨던게 계속 일어남

그래서 죽었어야 되는 캐릭터가 갑자기 일어나서 또 터지고

죽이고 또 터지고.

그러면 어떻게 해?

계속 실행시키면 안되니까, 멈추고 실행 시켜야 함

 

A()  함수 실행시킬때 는 A(); 하면 되지만,

코루틴은

StartCoroutine();

StopAllCoroutine(); 

 

이런식으로 호출 함!

 

남발하면 이상해지니까, 딱 필요할 때만 쓰자!

 

쓰레드나 태스크는 OS 와 관련된 내용임!! 찾아보자

 


A() 라는 함수가 끝나지 않았는데 다른애가 실행되는 구조임!

 

코루틴을 제어를 잘 못하면 큰 문제가 생김..!

 

작업관리자에서

작업관리자 세부정보 모습

여기서 유휴시간 프로세스 => Idle 상태

 

지금 대기중인게 96 이면 성능이 96만큼이나 쓸 수 있는거임!

 

언제든지 사용할 수 있게 남겨두고 있는건데, 

 

멀티로 많이 쓰면 Idle  CPU 할당이 낮아지고, 그러면 성능이 저하됨!

 


 

 

알람의 방식

어떤 일이 끝났을 떄를 알기위해 2가지의 방법이있음

1. 1초마다 체크하던지

2. 알람을 맞춰놓던지

 

알람을 맞춰놓고 다른일을 하다가 오는게 더 효율적이지 않을까? 그것에 관한 내용임!


코루틴 호출방법

 

1. StartCoroutine("A");

 

-인자가 있을 때는 뒤에 , 를 추가해서 

-Ex) StartCoroutine("A" , a , b);

 

2. StartCoroutine(A());

 


Damage() 를 코루틴함수로 재구현해보기

 

이제 우리는, Damage() 함수의 내용을 코루틴으로 바꿔 볼 것이다!

 

Damage() 함수

이걸 코루틴으로 바꿔보자!

 

사진을 보면, 지금 이 Damage() 안의 함수는 

넉백을 당하면서, 시간이 같이 흐르고 있는 상태임

시간이 다 흐르면 Idle 로 바뀌고!

 

이걸 코루틴으로 구현해보자!

 

void => IEnumerator 로 바꾼모습

함수를 void Damage() 에서 IEnumerator 

 

넉백 부분은 주석처리 해준 모습

아직 동시에 코루틴을 돌리게 하는건 헷갈리니까, 넉백부분은 일단 지워놓고 시작하자!

 

 

 

Damage 함수 주석처리한 모습

Damage 함수는 Update 에서 호출되고있었는데 여기서 이렇게 사용 안할거임 이제!

 

코루틴은 Update 가 한바퀴 돌 때, 다른데 가서 돌다가 오는건데, Update 에 있으면,

이게 다른데 가서 돌다가 와! 라는 예약을 계에에에속 걸어 놓는 것이기 때문에 없애준다!

 

코루틴 함수호출을 넣어준 모습

그러면 코루틴 함수호출을 어디에 넣어야 함??

 

딱 맞았을 때, Damage 상태로 돌아가지는 그 순간에 들어가야 하니까

 

OnDamageProcess() 의 else 문 안에 넣자!

=> 맞았을 때, hp 가 0 이하가 된( Die ) 상태가 아니라면, Damage 코루틴을 실행 시키겠다 라는 말임!

 

StartCoroutine 을 마지막에 넣어준 모습

이 코루틴 호출은 순서가 중요하다.

 

코드가 위에서 내려오는 상태로 진행 될 텐데, 이 코루틴은 어디 다른데 가서 거기서 실행시키다가 오는것임!

 

애니메이션 실행되기 전에 다른데 갔다오면 안되니까, 애니메이션도 실행 되면서 실행하게 해야함!

 

knockBackpos 도 받아야 하니까, StartCoroutine 을 마지막에 넣어준다!

 

또 다른 방법

아니면, 그냥 저것들을 코루틴 함수 안에 넣어도 됨!

 

이렇게 했을 때, 데미지 입고,  다시 Idle 로 되고 나한테 오면 됨.

 

그렇게 되긴 하는데,

 


이렇게 하면 되긴 함.

되긴 하는데,

 

Player 가 연발로 Enemy 한테 계속 쏘면 죽는 애니메이션까지 나오고 쓰러지긴 하는데,

죽지않고 Move 만 된 모습

나중엔 죽어서 땅 밑으로 내려가지도 않고  Move state 에서만 돌고 있네?!

이상태에서 Move 가 됨

Move 에서 계속 돌고있는것도 서러운데,

 

Move 상태인데도 저상태로 안움직이지 조차도 않음.. 왜?

 

움직이지 않는건 죽고나서, Character Controller 를 꺼버려서 그런거임..!

 

그러면 Move 에서 계속 돌고있는건 왜 그럴까..?

 

연발로 쏘면서, StartCoroutune 이 계속 예약이 걸리기때문에, 

IEnumerator Damage() 가 끝나도 다음 코루틴이 계속 실행 되서 그런거임!

 

그러니까 맞을때, 코루틴이 계속 예약이 걸리면 안되니까, Stop 시키고 또 다시 시작시키면 됨!!

스탑 추가해준 모습

이제 스탑을 추가해줬다.!!

 

 

 

그런데,, 이렇게 해도, 위와 똑같음....

될 줄 알았는데, 비슷한 현상이 또 생김.. 왜??

StopAllCoroutunes(); 의 위치 때문!!

 

즉, 3대를 맞았을 때는 

else 문으로 들어가지 않고, if(hp <= 0)  으로 들어간다.

즉, Die 상태로 들어가는 조건문으로 들어가는데,

 

앞에서 Damage() 가 실행되고있는 중이다

 

즉, 2대까지는 괜찮게 코루틴이 멈췄다가 다시 실행되게 해놨는데,

3대부터, 이제 조건문이 다른곳으로 들어가면서 코루틴을 멈추게 해놓지 못했다!

 

그렇기 때문에 StopAllCoroutines 를 조건문 위에 배치해서,

그냥 맞으면 무조건 코루틴 다 멈추게 구현하자!

 

[문제는 즉, Enemy 가2대까지는 괜찮은데 Damage 함수가 끝나기 전에 한대 더 맞으면,

  HP가 0 이되서 Die 로 갈려고 함. 근데 ? 끝나지 않은  Damage 함수가 계속 돌고 있는 상태 인거임.]

 

그러니까, StopAllCoroutines 를 위로 놓는다.

 StopAllCoroutines 를 조건문 위에 배치해서, 일단 피격당하면 코루틴이 멈추게 해놓는다.


IEnumerator Damage() 에 넉백 기능 추가

 

 

지금까지는

IEnumerator Damage()

딱 이렇게 damageDelayTime 지나고 Idle 상태로 전환만 코루틴으로 연습한 상태임!

 

그럼 넉백은 이제 어떻게 해줄까?

 

IEnumerator Damage() 에 넉백 을 넣어보자


여기서 중요한 참고

 

코루틴 함수 안에서

while(true)
{
	yield return null;
}

이 while 문과, 한 프레임을 넘기는 코루틴의 기능을 넣으면

 

이 while 문은 Update() 의 기능을 한다!!

원래 while 문은 반복을 한번에 돌리는 것이지만 한프레임씩 양보해주는 저 코드가 들어가있음으로써,

Update() 문으로 쓰일 수있게 함!


그러면

이렇게 Lerp 에 Time.deltaTime 을 넣어도 자신의 기능을 할 수 있는건, 이 while 문이 Update 문이 됬기 때문!

while 문 안에서 넉백을 구현한 코드


지금까지 원래구현했던 방식이 아닌 코루틴의 방식으로

2초기다리고 Idle 상태로 가는것,

넉백되는것

 

을 구현해봤음

 

근데, 이렇게 되면 안되고,

 

넉백되는것 따로, 2초 기다리는것 따로 하는게 아니라,

 

넉백되고있으면서 2초가 같이 흐르게 해야함!

 

즉, 지금은 넉백이 되고 나서, 2초가 흘러야 Idle 로 가게 되어있는것임

근데 이게 아니라, 넉백이 되면서 2초가 같이 흘러야 함! 

 

어떻게 할까??

 

나의 답

while(true) 문이 Update 문이 되었으니, 여기서 curTime 을 흘려보내주게 했음

 

 

 

강사님의 답

 

엄청 깔끔함..

 

while 문에 직접 조건을 걸어주고

시간 흐르게 해주고

넉백 해주고있으면서

 

2초가 끝나면 그냥  Enemy 의 위치를 knockBackPos 에 가져다 뒀음


(참고) 코루틴을 끝내고 싶을때?

 

 


코루틴으로 상태머신을 구현 하는 법

 

Start 함수를 코루틴으로 쓰려고 시도

스타트 함수를 코루틴으로 써보자!

void 를 IEnumerator 로 바꾼 모습

스타트를 IEnumerator 로 만들어보리자

 

Idle 함수도 코루틴으로 바꿈

이렇게 하면 2초지나게 하는걸 그냥 코드 한줄로 할 수 있음

 

이렇게 이런식으로 쓸 수도 있는데 코루틴을 잘못 쓰면 오류가 났을때 답도 없어짐..

이런 방법도 있다~ 하고 알고 넘어가자

 

나중에 잘쓸 수 잇으면 쓰자!ㅎㅎ


1인칭인 캐릭터를 3인칭으로 바꿔보기

 

캐릭터는 지금 1인칭인데, 3인칭으로 바꿔보도록 하자!

3인칭으로도 바꾸고, 

게임을 시작했을때, 먼 곳에서 카메라가 슈우욱 하고 플레이어 뒷편으로 와서 게임을 시작하는 모습을 만들어 볼거임

그리고 캐릭터가 움직일 때 움직임의 때라 카메라의 움직임도 바뀔건데, Lerp 로 부드럽게 움직여 볼거임!

 

Player 에게 썬글라스도 끼게 하고, 카메라도 뒤로 빼자

 

카메라 CamRotate를  일단 꺼두자.

벽도 하나 만들고

 

 

1대1 대응되는게 마음에 안들어서, 부드럽게 따라다니게 하고싶다!

 

CamFollow 스크립트 생성!

Cam Follow.cs 생성해서 카메라에 넣자

 

메인카메라를 뒤로 했다 앞으로했다 할려면,(포지션의 움직임을 제어하려면)

플레이어와 분리해야함!

 

여기서 꿀팁.

 

 

바로 분리하지말고,

플레이어에게 붙어있는 이 Main Camera 에서

 

 

카메라에 빈 게임오브젝트를 생성 한다.

 

 

메인카메라 안에있던 CamPose 를 MainCamera 밖으로 빼자

(Player 안에는 있게)

 

그 다음 카메라를 빼자 (Player 밖으로 )

 

이렇게 하면, 카메라를 밖으로 빼면서 원래 있던 카메라 위치를

빈 게임오브젝트로 Player 에게 남겨줄 수 있다.!! 굿

 

 


이제 하려고 하는게

카메라가 뒤에서 보고있다가, 쭉 플레이어에게 가까워지게 할 거임

그 후, CamPos 를 따라다니게 할거임!

CamPos 의 위치

 

Main 카메라를 게임시작할때 먼곳에서 따라오게 할건데

그 먼곳을 지정해보자. 개인의 취향에 따라서.

 

 

메인카메라를 선택하고,Ctrl + Shift +F 눌러서 씬에서 원하는 위치에 배치


CamFollow 의 모습

이제 CamFollow 를 작성해보자.

 

컴포넌트 넣어준 모습

 

Lerp 로 따라가게 함

멀리 있다가 아까 만들어준 빈 오브젝트인 캠포지션에 럴프로 가게 하고,

카메라의 앞방향은 캠포지션의 앞방향으로

 

CamRotate.cs 의 모습

public bool bUseHorizontal

public bool bUseVertical 

을 선언해주고

 

조건문으로 저런식으로 만들어준다

에디터상의 모습

그러면 체크한거에 따라서, 좌우나 상하를 체크에 따라서 사용할 수 있다.

 

회전 부분

여기서 우리가 회전을 마우스에 따라 시키겠다는 의미인데,

아까 CamFollow 코드에서는 앞방향을 고정시켜놨었음!

이렇게 되면 충돌나니까 아까 것을 주석 처리해놓자

 


근데 게임시작하면

저 멀리서 카메라가 Campos 로 럴프로 쭉 오게 하려고 했잖아?

그거는 나중에 하자.

 

일단 귀찮으니까, campose 컴포넌트 복사해서

Main Camera 에 붙여넣자

캠포즈 복사
붙여넣기

 

 

이렇게 바로시작

 

Cam Rotate 집중

여기에 B Use Vertical 에만 체크 되어있으니까, 위 아래로만 움직이게 해놨음 일단!

 

더보기

플레이어 양옆으로 움직이려면 CamRotate 플레이어 한테 붙이고 Horizontal 체크 하면 됨!

근데 지금 은 안할거임

 


다음 할 부분

 

지금 까지 한건, 우리가 애니메이션을 확장 시켜서 써보려고 밑작업 한거였음

 

우리는 에너미에서 애니메이션 쓸 때 상태머신을 만들어 넣고 Trgger 로만 썼었음

 

근데 Player 는 상태머신에 따라서 애니메이션을 넣는게 아님!

 

그냥 우리가 조작에 따라 상태머신이 바뀜

 

이게 과연 Trigger 로만 가능 할까?

 

움직이는것과 움직이지 않는건 상태에 따라서가 아니라, 속도에 따라서 나눌 수 있다!

 

그러면 Trigger 로 하는게 아니라, float 이나 bool 같은 요소를 섞어서 쓸 수 밖에 없다.

 

이 부분을 내일 배워볼 거임!