작업 중 물체(GameObject)의 위치가 제대로 초기화되지않는 현상이 발견돼서, 소규모로 테스트를 만들어서 실행해보았다.
public class TransformTest : MonoBehaviour
{
public Rigidbody2D _rb2D;
public bool isRgMove;
private void OnEnable()
{
SetPosition(Vector2.down);
}
private void OnDisable()
{
SetPosition(Vector2.up * 5);
}
protected void SetPosition(Vector2 newPosition)
{
if (isRgMove)
{
//_rb2D.position = newPosition;
_rb2D.MovePosition(newPosition)
}
else
{
transform.position = newPosition;
}
}
}
물체를 enable/Disable 시에 isRgMove가 뭐던간에 게임오브젝트의 위치가 바뀌는것이 내가 생각한 정상적인 결과였다.
isRgMove가 true인 경우에는 생각한 대로 작동했지만 리지드바디를 사용한 이동은 약간의 지연이 있었다. 지연이 항상 있는것도 아니고, 10번에 3번정도 지연이 있었다. 그래도 그 작은 지연때문에 큰 버그가 생기는 중이었다.
transform.position = newPosition;
이 코드는 물체의 Position 을 직접 바꿔주는 코드다.
"이동시킨다" 보다는 순간이동에 가까운 코드다. 물리엔진을 우회하는 행위다.
순간이동 시에 게임오브젝트의 "위치"만 순간이동하기 때문에 Rigidbody나 Collider같은 물리적인 요소들은 같이 이동되지않고,뒤늦게 따라오게 되면서 리지드바디의 위치를 다시 계산해야한다.
(위의 컴포넌트가 없는 물체는 상관없다.)
_rb2D.position = newPosition
이 코드도 Transform이 아닌 리지드바디를조작하기는 하지만, 결국 포지션을 덮어씌움으로 물리엔진을 우회하고있다. transform.position보다는 빠르지만 안정적인 코드는 아니라고 알고있다.
그래서 RigidBody를 가진 물체를 이동시킬때에는 위의 두 코드보다,
아래의 코드가 빠르고 물리적으로 안정적이다.
_rb2D.MovePosition(newPosition)
이 친구는 Position을 직접 바꿔주는 코드처럼 물체를 순간이동 시키는 것이 아니라,
지정된 위치로 충돌,물리적 상호작용등을 고려해서 "이동"을 하는것이다.
굉장히 빠르고 안정적이라고 알고있다. 하지만 이것도 지연은 똑같이 있었다..
(위의 테스트 말고) 실제 게임 내에서 문제가 됐던부분은
[물체 스폰 -> 순간이동] 의 흐름이 원활하지 않았던 것이다.
물리를 가진 물체를 순간이동 시키면 물리를 우회하고 안정적이지 않은 코드라고 앞서 말했었다.
그런데 게임오브젝트를 껐을때에는 물리도 같이 꺼진다.
그래서 스폰되기 전에 게임오브젝트가 꺼진 상태에서 transform.position을 사용해서 위치를 강제로 옮긴 후 게임오브젝트를 켰다.
[순간이동 -> 물체스폰] 의 순서로 바뀐것이다. 이것은 물리요소가 뒤따라오지도, 다시 계산할 필요도 없다고 한다.
_rb2D.MovePosition 을 사용해서 해결한 것은 아니지만 좋은 함수인것은 분명하다.
https://discussions.unity.com/t/there-is-a-delay-when-changing-rigidbody2d-position/1516558/2
한밤중에 궁금해서 이곳저곳 찾아보던 중 UnityDiscussion 커뮤니티에 가입해서 직접 질문해봤는데,
유니티 2D물리 담당 개발자분까지 나서서 답변을 성심성의껏 해주셨다.
해결방법은 너무 간단했지만, 과정중에 2D물리 이동에 대해서는 정말 찐하게 찾아보고 공부해본것같다.
감사합니다 Kurt-Dekker , MelvMay 선생님들...
Kurt-Dekker
https://discussions.unity.com/u/kurt-dekker/summary