[유니티2D 물리] 움직이는 물체가 서로 밀리지 않게 하기

Prevent rigidbodies from pushing each other

목표

게임을 만들다 보면, 플레이어와 적의 충돌이 일어나게 됩니다. 이 때 유니티 물리를 이용해 이동 로직을 구현했다면 (Rigidbody2D와 BoxColider2D 사용) 서로 밀리게 되는데, 이 때 서로 밀리지 않게 하는 방법을 고민해보고, 도출된 해결방법을 기록합니다. 

아이디어

일반적인 Player vs Enemy Collision을 생각해보고, Rigidbody body타입의 특성을 생각하면서 아이디어를 떠올립니다.

Kinematic 타입을 켜게 되면, Dynamic 타입의 오브젝트가 와서 충돌해도 움직이지 않습니다. 즉 밀리지 않습니다.

(단, Kinematic 타입이 Dynamic에 충돌하면 그냥 pass합니다.)

그래서 움직이는 오브젝트들에게 자식으로 빈 오브젝트를 만들고, 거기에 부모와 같은 크기의 Colider를 만든 뒤, rigidbody type을 Kinematic으로 해보았습니다.

red는 black의 child object입니다.

위 그림과 같이 구현하게 되면, 테스트를 해보기도전에 오브젝트가 날아가 버립니다.

부모, 자식 오브젝트가 서로 충돌해서 black(parent) 오브젝트가 날아가게 되는데요, 최대한 코드 없이 해결해 보려 했지만, 딱 한줄만 부모 오브젝트에 코드를 추가합니다.

해당 코드는 본인과 자식의 충돌을 무시하도록 합니다.

//Insert this code inside Awake()
Physics2D.IgnoreCollision(GetComponent<BoxCollider2D>(), GetComponentsInChildren<BoxCollider2D>()[1]);

그리고 실행시켜주면, 여전히 밀립니다. 이는 플레이어와 적의 black끼리 서로 충돌하기 때문인데요, black 간의 충돌을 에디터에서 꺼줍니다.

다른 레이어들은 신경쓰지 않으셔도 됩니다.

이제는 black이 아니라, 각각 Player, Enemy 레이어 그리고 red가 아니라 각각 Rigidbody_child_Player, Rigidbody_child라고 부르겠습니다. 여기까지 하시면, 플레이어와 적이 충돌했을때 서로 밀지 않고 제자리에 있게 됩니다.

Enemy vs Enemy 충돌은?

Dynamic 타입인 Enemy가 이동하다가 다른 Enemy의 child와 닿게되고, child는 Kinematic이기 때문에 밀리지 않습니다. Enemy vs Enemy 충돌만 에디터에서 꺼주도록 합니다.

Player,Enemy vs Wall 충돌은?

Dynamic 타입인 P or E가 Static Type인 Wall에 닿으면, 밀리지 않습니다. child 오브젝트와 Wall 충돌은 불필요하므로 에디터에서 꺼주도록 합니다.

Player,Enemy vs Bullet, HitableObject 충돌은?

정상적으로 작동합니다. 다만 불필요한 연산을 피하기 위해 최종적으로 다음과 같이 Layer Collison Matrix를 설정하겠습니다.

프로젝트에 따라 설정 변경을 할 수도 있습니다.

정리

유니티가 제공하는 물리엔진으로 구현 한 2D 게임에서, 움직이는 오브젝트가 서로 밀지 않도록 구현했습니다.

다만 제 방법은 한 오브젝트가 2개의 충돌체를 가진다는 점이 게임 퀄리티 면에서 얼마나 부하를 줄지 모르는게 단점입니다. 그래서 최대한 불필요한 물리 연산을 줄이기 위해, Rigidbody type을 적극적으로 이용하고, Collision Matrix를 최적화 해 보았습니다. Kinematic type에 대한 깊은 이해를 할 수 있었습니다.

https://github.com/Dripmaster/UnityPhysics

깃허브에 올려둔 프로젝트를 참조하세요.

 

Dripmaster/UnityPhysics

Test Unity Physics. Contribute to Dripmaster/UnityPhysics development by creating an account on GitHub.

github.com