게임 엔진에서 가장 중요하고도 명확히 정해지지 않으면 진행할 수 없는 것이 시간 소스이다.
시간 소스는 프레임마다 발행되는 틱으로 구성되며, 일반적으로 고정 간격과 가변 간격으로 나뉜다.
- 고정 간격은 일정한 시뮬레이션이 필요할때 사용되어야 하며,
- 가변 간격은 프레임간 매끄러운 애니메이션이 필요할때 사용되어야 한다.
그런데 두가지 다 필요하다면 어떻게 해야 하나?
고정 간격 시간의 특성상 일정한 간격으로 시뮬레이션을 수행하므로 시뮬레이션 해상도가 항상 같다.
그러므로 시간에 따라 시뮬레이션 결과가 달라지지 않는다.
이것은 항상 같은 결과를 내어야 하는 룰 엔진에 적합하다.
하지만 비주얼 프레임은 항상 가변 간격으로 렌더링된다.
여기에 딜레마가 발생한다. 룰은 고정 간격으로 돌리면서 가변 간격의 프레임에 맞추어 렌더링을 수행하면
애니메이션을 매끄럽게 할 수 없다.
프레임 간격이 넓어지면서 1.8틱이나 2.5틱의 룰을 수행해야 하는 경우가 생긴다.
성능상 서브틱단위로 계산할 수는 없다. 하지만 틱마다 간격을 달리할 수도 없다.
2.5틱의 경우 2틱과 3틱을 교대로 수행할 수도 있지만, 애니메이션이 오차가 더 커져서 매끄럽지 못하게 된다.
연속적으로 2틱이나 3틱으로 적당히 조정할 수 있지만 이렇게하면 실제 시간과 싱크가 맞지 않아 실시간 흐름이 이상하게 느껴진다.
결론은, 고정 간격 시간이나 가변 간격 시간 어느 한쪽으로 일정한 시뮬레이션과 매끄러운 애니메이션 양쪽을 동시에 구현할 수는 없다. 이 모두가 필요하다면 이 두 가지 시스템을 같이 채용하고, 필요에 따라 적절히 조정해여 병용해야 한다.
기본적으로 두 가지 시간을 모두 발행하고, 룰 계산은 고정 간격을 쓴다.
렌더링은 가변 간격을 쓴다. 애니메이션은 모두 curve로 지정되어 연속적인 수치로 표현할 수 있게 해야 한다.
실수로 표현된 진행 시간에 기반해 매끄럽게 애니메이션되도록 말이다.
모든 종류의 출력이 시간/수치 커브에 기반해 연속적으로 표현 가능해야 한다는 것이 핵심이다.
(차후에 네트워크 지연에 따른 에러 보정을 할 때도 편하게 된다)
구체적으로는 애니메이션 구현은 이렇다.
모든 애니메이션은 시간/수치 커브로 나타낼 수 있다. 3차벡터의 경우 개별적인 x/y/z 축에 대한 시간/수치 커브로 표현가능하다. 이 수치 커브를 함수화해 사용하는 것이다.
어떤 수치가 변화하는 것이라면 모두 이렇게 표현할 수 있다.
예를 들어 시간이 지나면서 차오르는 진행 상태 바 같은 경우 이런식으로 쉽게 표현 가능하다.
SRT(크기/회전/이동)라는 기본 애니메이션은 틱 기반의 누적 애니메이션으로 구현해야 한다고 생각하기 쉽지만 그렇게 해서는 안된다. 항상 시작 상태와 최종 상태가 정해지고, 애니메이션은 이 사이가 보간되는 형식으로 구현해야 한다.
주의할 것은, S와 T는 단순한 벡터 보간으로 쉽게 되지만 R은 쿼터니언 회전 보간을 사용해야 한다.
카메라의 경우는 위치나 FOV등의 개별 패러미터를 각각 수치 커브로 보간하는 것으로 구현 가능하다.
이 때, 룰 계산이 출력(애니메이션 표현 등)과 같거나 앞서 가는 것이 중요하다.
왜냐면 수치 함수에 기반해 예측된 미래값은 잘못된 결과일 수 있기 때문이다.
잘못된 미래를 예측하기보다는 느리더라도 올바른 결과를 보여주어야 한다.
또한, 대부분의 수치 함수는 유효입력범위(보통 0~1)를 벗어나면 결과가 바르지 않다.
지난 프레임 시간이 0.3틱이라고 하면 0틱(룰이 진행되지 않는다)으로 생각할 수 있지만 이 룰에서 사이에 특정 유닛이 삭제될 수도 있고, 패스 진행이 오버되어 유닛이 길을 지나쳐 허공에 떠있을 수도 있게 된다.
이 경우 출력은 바르지 않다. 일단 1틱을 진행시키고 그 중 0.3만큼만 진행했다고 표시하는 것이 올바르다.
유저는 0.7만큼의 진행정보를 잃게 되어 0.7의 지연시간을 느끼게 된다. 하지만 지연시간이 있는 쪽이 낫다.
이것은 네트워크 지연시간과는 구분되어야 한다. 네크워크 지연시간을 생각하기 이전에 출력이 최소한의 올바른 범위 안에 있다는 것이 보장되어야 유저가 잃는 몰입감을 최소화할 수 있기 때문이다. 네트워크 지연시간때문에 왼쪽으로 가던 유닛이 사실은 아직 오른쪽에 있다는 사실을 발견할 수도 있지만, 최소한 유닛은 길 위에 있어야 하는 것이다.
룰 계산과 출력의 타이밍은 이렇게 어긋나게 된다.
입력은 어떨까?
룰 계산은 고정 간격으로 틱단위 계산된다. 그러므로 이 틱간에는 어떤 변화가 생기더라도 룰 자체에는 영향이 없다.
그러므로 입력은 즉시 수행되어도 좋다.
하지만 어떤 입력은 여러 프레임에 걸쳐 수행된다.
드래그나 키홀딩 같은 입력이 그러하다. 특히 드래그는 여러 프레임에 걸쳐 이산적인 좌표들로 구성된 입력값이다. 문제는 이 입력 프레임들의 간격은 항상 가변이라는 것이다.
사실 이 입력을 그대로 써도 별 문제는 없다. 약간의 입력 오차만이 발생할 뿐이며, 어떤 유저들은 이러한 입력에 익숙하기도 하다.
문제가 생길 경우에는 각 입력값을 보간해 매끄럽게 한 뒤 필요한 수치를 사용하면 된다. 이 경우 최소한의 바른 범위의 보간을 위해 최소한의 샘플이 필요하게 되며, 이만큼의 지연 시간이 생긴다. 어느쪽을 선택할지는 게임의 디자인에 달려 있다.