이는 누군가를 위한 학습 관련 블로그가 아닌 개인의 평범한 공부일지로써 틀리거나 애매모호한 부분이 있을 수 있습니다. 만약 틀린 부분을 발견시 댓글을 달아주신다면 감사하겠습니다.
1. Physics Fundamentals
| Physics 101 | Movement | Rotation | Gravity, Friction, Drag |
Physics 101
게임 개발을 위한 물리에 대해 알고 싶다면 다음과 같은 책을 읽어보는 것이 도움이 될 수 있다.
Physics for Game Developers, David Bourg (2002)
Movement
- Velocity and Acceleration
Position (위치)은 말 그대로 해당 Object이 위치한 좌표를 나타내며 특정한 구간에 고정해 있게 됨으로 하나의 Vector값만을 가지게 된다.
e.g.) p = (x, y, z)

Velocity (속도)는 시간의 지남의 따른 Position의 변화를 나타내며 시간의 차원이 추가되어 Position 값에서 미분한 결과를 가지게 된다.
e.g.) v = (dx/dt, dy/dt, dz/dt)

Acceleration (가속도)은 시간의 따른 Velocity의 변화를 나타내며 Velocity 값에서 또 한번 미분한 결과를 가지게 된다.
e.g.) a = dvx/dt, dvy/dt, dvz/dt)

- Force
Force (힘)는 Mass (질량)에서 Acceleration (가속도)을 곱한 값으로 Mass는 Acceleration에 반비례 함으로 동일한 Force로 더욱 무거운 Object를 가했을 때 Acceleration 값이 줄어드는 것을 알 수 있다. 반면 가벼운 Object에게 가해지는 Acceleration 값은 더욱 커진다. Force는 뉴턴의 제 2법칙의 따라 F = ma와 같은 공식을 통해 계산된다.
Force = mass * acceleration
이 때 상기해야 할 것은 Force도 또한 Acceleration과 동일하게 시간이 지남에 따라 작동된다.
- Components
우리는 Force를 Object 안에서의 Component들로 분해할 수 있다. Object에 포함된 Total Force는 각각의 Force를 모두 더한 것과 값이 같다. 그렇게 됨으로써 아래와 같은 Object 안에서 각기 다른 방향의 Force가 가해지면 이를 더한 값이 총 Force의 결과값이 된다. 이는 마치 Vector의 계산과 동일하게 작동된다.

Object에 가해지는 Velocity의 값이 기존보다 늘어날 수록 Force는 Velocity의 방향대로 진행되며 이를 통해 Acceleration을 생성할 수 있다. 반대로 Object에 가해지는 Velocity의 값이 기존보다 줄어들 수록 Force는 Velocity의 반대 방향으로 진행되어 이를 통해 Decelration을 생성하게 된다.

만약 Force가 Velocity의 방향과 수평이 아닌 수직이라면 Circular Motion (원 운동)을 유도한다. 이 때 중요한 사실은 원운동을 할 수록 Velocity와 Force의 방향만이 바뀌게 됨으로 Object은 Rotate (회전)하지 않음으로 Object의 주체는 그대로인 것을 알 수 있다

- Impulse
Impulse (충격량)은 Object의 Velocity의 급격한 변화를 나타내며 Mass와 비례하여 좌지우지 되는 것을 알 수 있다. 아래의 식에서 Δ은 델타 함수로써 해당 값의 변화량를 나타낸다. Δv는 v (Final Velocity)에서 u (Initial Velocity)를 뺀 값과 같다.
I = mΔv
- Force vs Impulse
우리는 시간에 지남에 따라 Object에 Acceleration (가속도)를 적용하고 싶을 때에 Force를 사용한다.
반대로 우리는 Object의 Velocity값에 급격한 변화를 적용하고 싶을 때에 Impulse를 사용한다.
이는 Force를 사용하여 나타낸 시간이 지남에 따른 Velocity의 변화로써 서서히 Velocity의 값이 늘려나가 지는 것을 알 수 있다.


Rotation
Object은 Mass의 중심을 중심으로써 회전하게 된다. 만약 Object의 Mass가 Component에 따라 모두 고루 분포되어 있다면 Object의 중심이 Object의 회전축으로 작동 할 것이다. 만약 그렇지 않고 Object의 Mass가 고르지 않게 분포되어 있다면 조금 더 무거운 쪽의 Component 위치가 회전축으로 작동할 것이다.

Rotation은 Velocity의 방향과 무관하게 작동하며 독립적이다. 그렇게 됨으로 Velocity의 방향이 계속해서 동일하더라도 Rotation을 추가하여 Object이 회전되게끔 만들어 줄 수 있다.

- Velocity and Acceleration
Euler Angle
Euler Angle은 Rotation이 각각의 X/Y/Z 축을 기준으로 회전하는 것을 나타내며 이를 통해 Quaternion보다 더욱 쉽게 Angle을 유저가 알기 쉽게 조절할 수 있다.
r = (θx, θy, θz)

Angular velocity
Angular Velocity는 시간의 지남의 따른 Rotation의 변화를 나타내며 시간의 차원이 추가되어 Euler Angle 값에서 미분한 결과를 가지게 된다.
ω = (dθx/dt, dθy/dt, dθz/dt)
Angular Acceleration
Angular Acceleration는 시간의 지남의 따른 Angular Velocity의 변화를 나타내며 Angular Velocity 값에서 미분한 결과를 가지게 된다.
α = (dwx/dt, dωy/dt, dωz/dt)
- Torque & Angular Impulse
Torque (돌림힘)은 Rotation 상에서의 Force와 동일하며 식으로는 다음과 같이 작성된다.
Torque = mass * angular acceleration
Angular impulse는 Rotation 상에서의 Impulse와 동일하며 식으로는 다음과 같이 작성된다.
Angular Impulse = mass * change in rotation
Torque는 Force와 동일하게 시간이 지남에 따라서 발생하며 Angular Impulse는 Impulse와 동일하게 급작스럽게 발생한다.
Gravity
Gravity (중력)는 Object의 mass와 비례한 값을 가지는 아래를 향한 일종의 Force이다. 이 때 Gravitational Force는 9.8이라는 지구의 중력을 나타내는 Constant (상수)를 곱하여 계산할 수 있다.
G = 9.81m
즉 Gravity로 인한 Acceleration값은 Constant (상수)이며 이는 다음과 같은 식을 통해 계산되어진다.
a = G/m = 9.81m/s2
그렇게 됨으로 더욱 무거운 Object은 Gravitational Force의 값이 더욱 커지게 되는 결과를 낳게 되고 이는 Acceleration의 감소를 나타낸다.
Friction
Friction (마찰력)은 velocity의 반대 방향으로 발생하는 Force로써 Object이 Surface 위에 움직일 때 생겨난다. Friction은 Normal Force (수직항력)과 비례하며 이때 Normal Force는 Object이 Surface를 향하여 가하는 Force를 뜻한다. Friction을 구하는 식은 다음과 같으며 아래의 μ은 Coefficient of Friction (마찰 계수)을 뜻한다. 그리고 이는 Surface의 재질에 따라 각기 다르게 된다.
Ff ≤ μFn

- Static & Dynamic Friction
Friction은 총 두가지의 종류로 이루어져 있으며 Static Friction은 Object이 움직이지 않을때 가해지는 Friction이다. 반면 Dynamic Friction은 Object이 움직일때 가해지는 Friction으로써 보통 Static Friction을 위한 Coefficient (계수)는 Dynamic Friction을 위한 Coefficient보다 더욱 높아 Static Friction의 값이 보통적으로 더 큰것을 알 수 있다. 이는 마치 이미 굴러가는 물체를 미는 것보다 멈춰있는 물체를 밀기 시작하는 것이 더욱 힘이드는 것과 마찬가지이다.

Common Forces
- Drag
Friction과 동일하게 Drag (항력)는 또한 Object의 Movement를 저항하는 Force중 하나이다. Drags는 보통적으로 공기 저항을 나타내며 Drag의 값은 또한 Velocity와 같이 상승하며 (비례하며) 식은 다음과 작성할 수 있다. 아래의 μd은 Drag Coefficient (항력 계수)이며 Object의 모양에 따라 값이 바뀌어 진다. 마치 구깃구깃한 종이와 빳빳한 새 종이를 위에서 동시에 떨어뜨렸을때 떨어지는 속도가 다른 현상으로 이를 대변할 수 있다.
Fd = μd |v|2

- Terminal Velocity
Drag는 Velocity와 함께 값이 증가하며 Drag Force (항력)를 Drive Force (추진력)와 동일하게 값을 설정하면 Acceleration이 가해지지 않게 된다는 것을 알 수 있다. 그렇게 되면 설정된 일정한 Velocity의 값으로써 Object이 Position을 변경하게 되는데 이를 Terminal Velocity라고 부른다. 이는 왜냐하면 각기 다른 방향의 Drag와 Drive Force들이 동일한 값을 가지게 되어 두 Force들의 차를 구하였을때 남는 값이 없기 때문에 일정한 속도를 유지하게끔 설정되기 때문이다.

2. Movement & Frame-rate
| Movement should be scaled based on frame duration |
| Simulating at different frame-rates can affect the outcomes |
- Moving at constant velocity
예전 강의에도 언급되었듯이 우리들은 Frame-rate을 독립적으로 작성하여 어느 기기에서 동일한 속도의 Object Movement를 구현하게끔 세팅해주어야 한다.
public class Move : MonoBehaviour
{
public Vector3 velocity = new Vector3 (10, 0, 0); // m/s
void Update ()
{
// 특정 velocity의 값의 방향으로 distance variable을 설정
Vector3 distance = velocity * Time.deltaTime;
// distance의 방향으로 Object을 움직이게끔 만들어라
transform.Translate (distance);
}
}
프레임은 즉 FPS에 따라 얼마나 프레임이 1초안에 분포되는지 달라지게 되는데 이를 Diagram으로 표현하자면 다음과 같다.

- Moving with acceleration
Acceleration을 적용시킨 Velocity를 Object에 적용하게끔 코드를 작성하려면 다음과 같이 작성할 수 있다.
public class Accelerate : MonoBehaviour
{
public Vector3 acceleration = new Vector3 (10, 0, 0);
private Vector3 velocity = new Vector3 (0, 0, 0);
void Update ()
{
// velocity에 acceleration값을 프레임이 흐를수록 계속 더함
velocity += acceleration * Time.deltaTime;
Vector3 distance = velocity * Time.deltaTime;
transform.Translate (distance);
}
}
프레임은 즉 FPS에 따라 얼마나 프레임이 1초안에 분포되는지 달라지게 되는데 이때 Acceleration이 적용된 결과를 Diagram으로 표현하자면 다음과 같다.

- Moving and Turning
이 때 아래와 같이 Object이 움직이면서 회전을 하게끔 만드려면 아래와 같은 코드를 작성해 줄 수 있다.
public class Accelerate : MonoBehaviour
{
public Vector3 acceleration = new Vector3 (10, 0, 0);
private Vector3 rotation = 90; // degrees per second
void Update ()
{
Vector3 distance = velocity * Time.deltaTime;
transform.Translate (distance);
// angle variable에 rotation과 Time.deltaTime을 곱하여
float angle = rotation * Time.deltaTime;
// z축을 기준으로 angle값만큼 회전하게끔 세팅
transform.Rotate (new Vector (0, 0, angle);
}
}

- Physics Simulation
- 물리는 미적분에 기반하였으며 지속적인 variable (변수)들, 적분 그리고 미분과 함께 작동된다.
- 시뮬레이션은 지속적인 시스템의 근사치를 내기 위해 작고 별개의 타임 스텝 (프레임 사이의 시간)을 사용한다.
- 타임 스텝의 값이 클 수록 시뮬레이션의 정확성이 떨어지게 된다.
- 여러가지의 변화가 큰 Frame-rate은 한결같지 않은 결과를 나타내게되며 우리는 그러므로 고정된 타임스텝으로 시뮬레이션을 가동하는 것이 중요하다.
- 유니티는 기본적으로 50FPS로써 물리엔진을 가동시키는데 (하나의 물리 프레임은 0.02초가 걸림). 이는 실제 게임에서의 Frame-rate과는 별개로써 작동된다.
- FixedUpdate
FixedUpdate()는 Update()의 타임스텝이 제각각인 문제를 해결하기 위한 Event Method로써 각각의 프레임마다 일정한 타임스텝을 가지게 된다.
float time = 0;
float fixedTime = 0;
float fixedDeltaTime = 0.02;
DoFrame (float deltaTime)
{
time += deltaTime;
while (fixedTime < time)
{
FixedUpdate();
SimulatePhysics();
ReportCollisions();
fixedTime += fixedDeltaTime;
}
Update();
}
윗 코드로 생성된 Event Methods들의 순서는 다음과 같이 작동하게 되는 것을 파악할 수 있다.
Start of Frame -> FixedUpdate() -> Physics Simulation -> OnTriggerXXX() -> OnCollisionXXX() -> Update
이 때 아래와 같은 코드를 쓰게 되면 각기 time값에 차이가 생기는 것을 알 수 있다.
public class LogUpdate : MonoBehaviour
{
void FixedUpdate ()
{
Debug.Log ($"Fixed update: {Time.fixedTime}");
}
void Update ()
{
Debug.Log ($"Update: {Time.time}");
}
}

- FixedUpdate vs Update
모든 Physics 관련 코드는 FixedUpdate() Event안으로 가야만 한다. 그래야만 더욱 정확하고 자연스러운 결과를 얻을 수 있다.
반면 모든 물리와 관련 없는 코드는 Update() Event로 들어가야 한다.
// Remember that they don't synchronise
private float moveForce = 10;
private float jumpImpulse = 20;
private float movement = 0;
private bool jump = false;
private Rigidbody rigidbody;
void Update ()
{
// input is updated every frame
// Read and Store input values
movement = Input.GetAxis ("Horizontal");
jump = jump || jump = Input.GetButtonDown ("Jump");
}
void FixedUpdate ()
{
// Apply forces in FixedUpdate
rigidbody.AddForce (moveForce * movement * Vector3.right);
if (jump)
{
rigidbody.AddForce (jumpImpulse * Vector3.up, ForceMode.Impulse);
jump = false; // don't jump twice
}
}
- Time.fixedDeltaTime
FixedUpdate()에 모든 시간 관련 행동들은 Time.deltaTime 대신 Time.fixedDeltaTime으로 수정되어야 한다.
void FixedUpdate()
{
// Accelerate by directly changing rigidbody.velocity
rigidbody.velocity = rigidbody.velocity + acceleration * Time.fixedDeltaTime;
}
- Best practices
- 모든 물리 Update는 Update()가 아닌 FixedUpdate() Event method에 소속되어야 한다.
- FixedUpdate()에는 최대한 물리기반이 아닌 코드를 최소화해야 한다.
- Update()와 FixedUpdate()에서 동시에 일어나는 이슈들을 조심하여라
- Update()안에서는 Time.deltaTime을 활용하라
- FixedUpdate()안에서는 Time.fixedDeltaTime을 활용하여라.
3. Moving with Rigidbodies
| Kinematic Rigidbodies | Non-kinematic (physics-driven) rigidbodies: Movement & Rotation | Parameters | Best Practices |
Kinematic Rigidbodies
Kinematic Rigidbody는 Physics 즉 물리로 컨트롤 되는 시스템이 아니다. 하지만 Kinematic이 아닌 Object들과의 충돌은 여전히 감지하고 이를 Trigger로 인식할 수 있다. Kinematic Rigidbody는 Transform을 통해 움직여질수 있으며 Object의 움직임을 우리가 직접 컨트롤을 완전히 감당하고 싶은 동시에 Environment와 인터렉트하게끔 만들고 싶을때 이를 쓴다. (마치 캐릭터의 Movement를 우리가 직접 조절하면서 동시에 충돌 감지를 인식하게끔 하고 싶을때 - 실제적인 물리로써 움직이지 않는 아무 아바타같은 것을 구현하는데 쓰게 된다.) 이 때 알아야할 사실은 무조건적으로 Physics가 필요한 상황이 아니면 왠만하면 유니티에 내장되어있는 물리엔진을 사용하지 않는 것이다.
Non- Kinematic Rigidbodies
- Movement with Rigidbodies
우리들은 Rigidbody와 함께 여러가지 방법으로 특정 Object들을 움직여 줄 수 있다.
- 직접적으로 Position에 변화를 주기
- Velocity를 세팅하여주기
- Force를 이용하기
- Impulse를 이용하기
- Setting Position
Position을 세팅하는 방법은 두 가지의 방법이 있는데 이들은 다음과 같다.
- 만약 Object의 Position을 순간이동 시키고 싶다면 rigidbody.position의 값을 사용하여 구현할 수 있다.

- 만약 Object의 Position을 스무스하게 이동시키고 싶다면 rigidbody.MovePosition()이라는 Method를 사용하여 구현가능하다.

이때 MovePosition() Method가 작동되는 방식은 Interpolation setting에 의해 좌지우지되는 것을 알 수 있다.
- Setting velocity
rigidbody.velocity variable은 Object의 현재 velocity (World Coordinate)으로써 나타난다. 이 때 rigidbody의 velocity를 저 variable을 세팅하여 직접적으로 조절하는 방법이 있고 또한 이는 다음의 Physics Update에서 나타나는 movement에게로만 영향을 주고 이 때 Collision의 효과나 다른 forces들도 계속해서 적용된다.
- Applying forces
이 때 우리는 rigidbody.AddForce를 사용하여 object에 force를 추가하여 줄 수 있다. Force 파라미터는 World Space기반 vector의 값으로 가져지며 이 때 각기 다른 방향을 가진 force들의 종류들을 사용하여 여러가지의 force들의 합의 값으로써 object을 움직일 수 있다.
rigidbody.AddForce (drive * transform.forward); // forward의 방향으로 가는 force 구축
rigidbody.AddForce (drag * transform.back); // back의 방향으로 가는 force 구축
// total force applied = drive + drag - 총 force의 값은 drive와 drag을 더한 값이 됨
- Applying Impulse
Impulse는 Object의 momemtum의 변화를 나타낸 것으로써 식으로는 다음과 같이 계산된다. Impulse = velocity * mass
Impulse는 Object의 velocity의 즉각적인 변화로써만 생각할 수 있지만 실상은 Mass에 따라 값이 증가할지 아닌지가 결정된다. 각각의 Object들이 동일한 Impulse의 값으로 인해 가해졌을때 더욱 가벼운 Object이 무거운 Object보다 더욱 큰 변화를 나타내게 된다. (Velocity의 변화 - 이는 Mass는 Velocity와 반비례하기 때문이다). Impulse를 적용할 때에는 Force와 동일한 rigidbody.AddForce를 쓰지만 Impulse의 알맞는 값과 ForceMode.Impulse를 작성하여 구현하게 된다.
rigidbody.AddForce (impulse, ForceMode.Impulse);
- Force vs Impulse
Force는 시간이 갈 수록 계속해서 작동하게 되며 (e.g. Gravity) 지속적인 Acceleration을 생성한다.'
반면 Impulse는 즉각적으로 velocity의 값에 변화를 준다. (e.g. a collision)
그래서 특정 Single Frame안에서 큰 값의 Force를 object에다 적용하여 즉각적인 이동을 유도하는 것은 잘못된 방법이다. (대신 Impulse를 사용하여 구현해야 한다.)
아래 코드는 틀린 방법으로 작성되었고 잘못된 부분은 Jump는 즉각적인 Velocity의 변화임으로 Impulse가 적용되어야 하는데 그렇지 않고 되려 Force로 Jump가 한 프레임에서 큰 값으로 적용되게끔 식을 작성하였다는 점이다.
// Wrong
float jumpForce = 10000;
void FixedUpdate ()
{
if (Input.GetButtonDown ("Jump"))
{
rigidbody.AddForce (jumpForce * Vector3.up);
}
}
윗 코드의 문제점을 해결하기 위해 다음과 같이 rigidbody.AddForce에 ForceMode.Impulse를 곱해주었다.
// Wrong
float jumpImpulse = 10;
void FixedUpdate ()
{
if (Input.GetButtonDown ("Jump"))
{
rigidbody.AddForce (jumpImpulse * Vector3.up * ForceMode.Impulse);
}
}
- Rotation
Rotation은 방금전 본 Movement의 여러 물리기반 원리들과 동일하게 작동되며 다음과 같은 방식을 통해 만들어 줄 수 있다.
- rigidbody.rotation을 조절하여 특정 rotation을 서서히 나타나는 과정없이 순간적으로 회전을 구현할 수 있다.
- rigidbody.MoveRotation은 특정 rotation을 서서히 돌아가게끔 만들어 줄 수 있다.
- rigidbody.angularVelocity는 angular velocity를 지정해줄 수 있따. (단위는 radians로 계산된다.)
- rigidbody.AddTorque (torque)는 지속적으로 Torque를 가해 회전을 시켜줄 수 있다.
- rigidbody.AddTorque (impulse, ForceMode.Impulse)는 angular impulse를 생성하여 즉각적인 회전의 변화를 구축할 수 있다.
- Which one to use?
- Setting position (가장 직접적임)
- Setting velocity is more indirect (velocity를 세팅하는 것은 더 간접적이다)
- Adding Impulse
- Adding force (least direct) (제일 직접적이지 않고 간접적으로 Object의 position이나 rotation의 변화를 줌)
이들중에서 그렇다면 무엇을 이용해야 할까? 이는 개발자가 Object을 어떻게 컨트롤 하고 싶은지에 대해 달려있다. 즉 더욱 간접적이고 직접적으로 변화를 주지 않는 옵션으로써 다른 요인들 (e.g. gravity, friction, etc)로부터 받아지는 영향이 더욱 증가한다. (물리적으로 더욱 정확히 구현 가능케 만들 수 있다.)
여러 옵션들의 차이는 다음의 링크를 통해 뭐가 어떻게 작동하는지 직관적으로 관찰해보아 공부할 수 있다.
https://wordsonplay.itch.io/physics-test
3D Physics Test by wordsonplay
A test of Unity Physics
wordsonplay.itch.io
Parameters
유니티에서 몇몇의 UI 파라미터들은 시뮬레이션에 영향을 미치는데 다음과 같다.
- Gravity
- Drag
- Physics Material (Friction, Bounce)
- Constraints
- Interpolation
- Gravity
Rigidbody는 기본적으로 Gravity로부터 영향을 받는데 이 때 Rigidbody Component setting안에 Use Gravity라는 속성을 끄게 되면 Gravity로부터 영향을 받지 않게끔 세팅할 수 있다.
또한 이때 값과 방향의 대한 설정을 Project Settings -> Physics로 들어가 세부적으로 설정 할 수 있다.
- Drag
모든 Rigidbody는 Drag와 Angular Drag 세팅을 가져 Movement와 Rotation 각각을 위한 Drag를 실행시킬 수 있다. 유니티에서는 이에 관한 Documentation을 제공하지만 Drag의 어떠한 모델이 사용되었고 각기 파라미터들이 정확히 무엇을 의미하는지 언급하지 않는다. 그러므로 왠만하면 Drag는 직접 방정식을 구현하여 코드로써 제작하는 것이 더욱 유용하다.
- Physics Materials
Physics Material은 Object의 Coefficients of Friction을 명시하여 Bouncy의 정도를 직접 설정할 수 있게끔 한다.
Physics Material은 특정 Asset으로 제작하여 적용하려는 Object의 rigidbody의 값으로써 집어넣을 수 있다.
이 때 Friction은 두 Object 사이의 상호작용에서 나타나는 Force로써 제각기 다른 Coefficient를 가지게 된다. 그러므로 어떠한 값을 직접 써넣을건지 정확히 명시해야 보다 정확한 결과를 나타낼 수 있다. (Min, Max, Average, Multiply과 같은 방법으로 두 각기의 다른 값들을 하나로 만들어 직용할 수 있다.)
- Constraints
Rigidbody는 각 특정 Axis로 movement와 rotation이 생성되지 않게끔 조절할 수 있게끔 할 수 있다. 이때 각기 Position과 Rotation이 추구하는 Space의 특징이 다르다.
- Position Contraints는 World (Global) Space로써 적용되어 특정 축이 제한된다.
- Rotation Contraints는 Object (Local) Space로써 적용되어 특정 축이 제한된다.
Best Practices
- 만약 물리가 필요한 상황이 아니라면 물리를 이용하지 말아라. (e.g. 다른 Object과의 충돌을 할 필요가 없는 Object을 이동시키고자 할때)
- 만약 Object의 움직임을 조절하고 싶지만 동시에 특정 Object의 충돌을 감지하고 싶게끔 하려면 Kinematic Rigidbody를 사용하여라. 그리고 이를 Transform을 활용하여 움직여라. (transform.Translate()과 같은 Method)
- 만약 Object이 완전히 물리 기반으로 움직여지게끔 만들고 싶으면 non-kinematic rigidbody를 사용하여 물리의 법칙이 적용되게끔 하여라. (e.g. Obstacle로부터 바운스되는 상황). Rigidbody를 활용하여 이동시켜라. (rigidbody.AddForce()와 같은 Method)
- Non-kinemetic Rigidbody를 Transform을 사용하여 움직이지 말아라.
- 모델이 물리적인 시스템에 정확히 안착하여 작동될 때 까지 시간을 투자하여 시뮬레이션을 구현하기 위한 최고의 접근 방법을 찾아내어라.
- 물리 엔진은 가끔 예상치 못하는 순간으로 갈 수 있다. 왜 그리고 어떻게 해야 원하는 대로 작동하게끔 만드는지 실험하여라.
4. Physics Collisions
| Colliders | Collision Events | Collision Detection Mode |
Colliders
Physics Colliders는 IsTrigger 옵션이 꺼진 상태에서 나타낸다. (마치 두 Object들 끼리 부딪혔을 때 실제로 통과하지 못하게끔 만들어 줄 수 있다.) Trigger Collider과 동일하게 Physics Collider도 두 가지의 종류로 이루어져 있는데 다음과 같다.
- Static Colliders (Rigidbody가 없음) - 움직이지 않는 Object에 적용
- Dynamic Colliders (Rigidbody가 있음) - 움직이는 Object에 적용
Collision Events
Trigger Colliders와 동일하게 Physics Collider들도 다음과 같은 Method들로 호출하여 유니티에서 인식될 수 있다.
- OnCollisionEnter (Collision collision) - colliders가 첫번째 부딪혔을 때
- OnCollisionExit (Collision collision) - colliders들이 서로 헤어질 때
- OnCollisionStay (Collision collision) - colliders들이 매 프레임마다 접촉되는 모든 순간
이는 2D 물리에서도 동일하게 작동된다.
- Collisions
위에서 작성된 Event Handler들은 (Collider 자체를 받는 OnTrigger 계열 파라미터와는 다르게) Collision의 파라미터를 인식하고 값으로써 받는다.
Collision으로부터 생기는 물리의 관한 정보를 Collision은 포함하는데 다음과 같다.
- The point of collision (Collision의 포인트)
- The relative velocity of the two objects (두 Object의 관련된 velocity)
- The impulse applied (적용된 Impulse)
Collision Detection Mode
기본적으로 유니티는 오직 Collision을 물리 Frame에서 제일 마지막에 체크하게 되는데 이는 시간 안에서 Collider가 있는 Object을 부딪힐때 감지된다. 그말인즉슨 만약 object이 엄청 빠르게 이동하게 되면 Collider가 있는 장벽을 뚫고 지나갈 수 도 있다는 말이다.

그래서 만약 Collider에 Continuous Collision Detection (지속적 충돌 감지)를 켜넣는다면 유니티는 빠르게 움직이는 Object의 즉각적인 포지션들을 각 프레임마다 감지 할 수 있어 다른 옵션이었으면 놓쳣을 충돌을 감지 할 수 있게끔 만들 수 있다.
하지만 이는 CPU를 많이 활용하고 컴퓨터로써 무리를 줄 수 있어 오직 필요한 경우에만 켜넣길 바란다. (빠르게 움직이는 Object을 감지시키려 할 때)
