드디어.. 트레이서 시간 역행이 돌아왔다..
일단 개발에 들어가기 전에 트레이서가 시간 역행을 하면 어떤 일이 벌어지는지 분석해보자.
A. 트레이서 시간 역행 분석
직접 옵치에 들어가서 해본 결과..
역행을 하면 다음과 같은 일이 발생한다.
1. HP 회복
2. 장전
3. 역행할 때 이동, 기본 공격, 스킬 사용 불가
4. 카메라가 고정됨 (마우스로 움직일 수 없음)
HP 회복이나 장전 같은 경우에는 HP와 총을 개발한 후에 적용할 것이다.
이번 편에서는 역행하는 것만 구현하려고 한다.
B. 트레이서 시간 역행 구현
레퍼런스 1번에 따르면, 트레이서의 시간 역행은 3초 전으로 돌아간다고 한다. 역행이 걸리는 시간은 1.25초이다.
즉, E 스킬을 사용하면 1.25초 만에 3초 전의 트레이서로 역행하는 것이다.
레퍼런스 4번 영상을 보고 코루틴을 사용하기로 했다. 영상에서는 0.1초씩 정보를 수집하여 총 30개, 즉 3초간의 정보를 수집한다. 트레이서가 언제 시간 역행을 사용할지 모르니 항상 정보를 저장해줘야한다. 아직까지는 이게 큰 오버헤드가 될지 모르겠지만 일단 구현해보자.
먼저, 게임 중에 항상 트레이서의 position과 rotation을 기록해두어야한다.
CollectRecallInfo 코루틴을 사용하여 항상 0.1초마다 정보를 저장한다. 이 때, 3초 전까지만의 정보만 필요하므로 positions와 rotations list의 길이는 30으로 유지해준다. 정보 저장은 Queue에다가 한다.
GetInput 함수에서 E 키가 눌렸음을 감지하고,
Update 함수에서 E키가 눌렸을 때 정보 모으기를 Stop하고 Recall을 Start한다.
Recall 시에도 Blink와 같이 캐릭터 컨트롤러를 diable해준다.
그리고 Recall 도중에 마우스로 카메라를 움직일 수 없으므로 카메라를 컨트롤하는 PlayerLook도 disable해준다.
카메라의 rotation을 임의로 설정한 이유는 Recall시에 카메라가 항상 정면을 바라보게하기 위해서인데, 이건 또 다른 문제가 있어서 마지막에 언급할 예정이다.
정보 저장을 Queue에다가 했으니 Queue에서 바로 정보를 빼서 사용하면 가장 과거의 정보부터 빼내질 것이다. 그러나 우린 가장 최근의 정보부터 빼야한다. 따라서 Queue에 있는 정보들을 Stack에 옮겨준 후에 Stack에서 빼주면 우리가 원하는 대로 정보를 빼서 쓸 수 있다. 따라서 위 사진의 for문을 통해 Queue의 정보들을 Stack에 옮겨주었다.
그 후, 실제 정보들을 트레이서에 적용하는 것은 Recurse 코루틴을 통해서 진행한다.
원래는 for 문을 만들고 for 문 안에 waitforseconds를 넣어서 구현했는데 큰 문제가 발생했다. waitforseconds하는 동안 이미 다음 줄이 진행되기 때문에 완전히 꼬여버린다.. 이걸로 정말 헤매다가 발견했다.. 조만간 Trial&Error에서 다룰 예정..
따라서 recursive한 함수를 사용하게 되었다. Recursive하게 함수를 짰기 때문에 for문에 waitforseconds를 넣을 필요가 없어졌다. Waitforseconds가 필요한 이유는 recall시간을 1.25초에 맞춰야 하기 때문이다.
그렇게 recall이 끝나면 disable해놨던 캐릭터 컨트롤러와 카메라를 다시 enable해준 후, 정보 모으기 코루틴을 다시 시작한다.
C. 결과
정말정말 많은 시행 착오 끝에 완성..
Recall시 조금씩 끊기는 듯한 현상은 정보를 모으는 주기를 더 짧게 하면 해결이 될 것이다.
D. 문제점 발견
실제로 트레이서가 역행을 할 때 카메라 무빙은 다음과 같다.
잘 보면 리콜전에 어떻게 카메라 무빙을 했든 상관없다.
리콜 직전의 카메라 방향에서 정면의 방향으로 자연스럽게 움직인다.
이러한 자연스러운 카메라 회전을 다음 편에 구현할 예정이다. 이거도 아마 굉장히 어려울 것 같은 느낌...
그럼 다음편에.. 즐개~ (즐거운 개발이란 뜻...)
(노트노트)
for 문 안에 wait for seconds 들어가면 걍 망함
startcoroutine을 해서 해당 코루틴이 돌아도 다음줄은 계속됨. 코루틴 이후에 그 줄을 실행하고 싶으면 코루틴 함수 안에 그 줄을 넣으셈.
stop coroutine 은 string으로 할때 됨. 그냥 호출하면 안됨.
디테일: 카메라가 무조건 과거를 따르지 않고.. 카메라는 리콜직전 --> 정면으로 자연스럽게 이어짐.
Reference
1. https://overwatch-archive.fandom.com/wiki/Recall
2. https://answers.unity.com/questions/46745/how-do-i-find-the-frames-per-second-of-my-game.html
3. https://codingmania.tistory.com/172
4. https://www.youtube.com/watch?v=I7X8ysoPeiU
5. https://www.youtube.com/watch?v=eqlHpPzS22U
6. https://forum.unity.com/threads/how-to-cancel-and-restart-a-coroutine.435493/
7. https://answers.unity.com/questions/934490/stopcoroutine-is-not-stopping-my-coroutines.html
'Unity > 오버워치 따라잡기' 카테고리의 다른 글
[Unity] 플레이어 체력(HP바) 구현하기! (0) | 2023.03.20 |
---|---|
[Unity] 오버워치 따라잡기! 트레이서 편(5) - Recall 시간역행 (0) | 2023.03.17 |
[Unity] 오버워치 따라잡기! 트레이서 편(3) - Blink 점멸 (0) | 2023.03.16 |
[Unity] 오버워치 따라잡기! 트레이서 편(2) - Blink 점멸 (1) | 2023.03.15 |
[Unity] 오버워치 따라잡기! 트레이서 편(1) - 움직임 (0) | 2023.03.15 |