캐릭터를 조종하는 방법
1. Character Controller
- Move
- SimpleMove
2. Rigidbody
- position
- MovePosition
3. Transform
1. Character Controller
Character Controller는 물리적 특성을 사용하지않는 1인칭 3인칭 플레이어 제어에 사용
자체적으로 Collider가있다.
Slope Limit | 콜라이더가 표시된 값 이하의 기울기만을 오르도록 제한 |
Step Offset | 표시된 값보다 지면에 가까운 경우에만 캐릭터가 계단을 오름 |
Skin width | 두 콜라이더가 Skin Width와 동일한 깊이에서 서로 관통 |
Min Move | Distance 캐릭터가 표시된 값 미만으로 움직이려 해도 움직이지 않음 |
Center | 캡슐 콜라이더의 중심 위치 |
Radius | 캡슐 콜라이더 반경 |
Height | 캐릭터의 Capsule Collider 높이 |
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Controller : MonoBehaviour
{
CharacterController controller;
float Speed = 5.0f;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Debug.Log(h + " " + v);
Vector3 move = new Vector3(h, 0, v);
//controller.Move(move * Speed * Time.deltaTime);
//controller.SimpleMove(move * Speed);
}
}
Move() | SimpleMove() |
![]() |
![]() |
특성 중력 계산 x float 인자 (방향 * 속도 * deltaTime) |
특성 중력 계산 o float 인자 (방향 * 속도) 단점 Y축 속도가 무시된다. |
여기서 점프를 구현하려면 조금 더 복잡해진다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Controller : MonoBehaviour
{
CharacterController controller;
float Speed = 5.0f;
float Gravity = -9.8f;
float JumpSpeed = 10.0f;
Vector3 velocity;
void Start()
{
controller = GetComponent<CharacterController>();
velocity = new Vector3(0f, 0f, 0f);
}
void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 move = new Vector3(h, 0, v);
if (move != Vector3.zero)
transform.forward = move;
velocity.y += Gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
Debug.Log(controller.isGrounded);
if (controller.isGrounded && velocity.y < 0)
velocity.y = 0f;
if (Input.GetButtonDown("Jump") && controller.isGrounded)
velocity.y += Mathf.Sqrt(JumpSpeed * -2f * Gravity);
controller.Move(move * Speed * Time.deltaTime);
}
}
controller에 중력을 추가해주고 땅에 닿았을때는 중력을 다시 끄며 물리적 연산을 직접 구현해주어야한다.
콘솔 창은 isGrounded값인데 버그가 좀 많아서 잘 안쓰고 Raycast를 사용하여 체크한다고한다.
-> Character Controller는 경사면 제어에있어서 유리하지만 물리연산을 일일히 구현해 주어야하기때문에 양이 많아진다.
2. RigidBody
RigidBody가 부착된 GameObject는 물리적 제어 하에 동작하게된다.
Mass | 오브젝트의 질량 설정 (상대적) |
Drag | 오브젝트의 저항력 0이면 공기 저항이 0이고, 무한대면 오브젝트는 즉시 움직임을 멈춤 |
Angular Drag | 오브젝트의 회전에 대한 저항력 0이면 공기 저항이 0이고, 높을수록 회전을 더 많이 늦춤 이 값을 무한대(infinity)로 설정하는 것만으로는 오브젝트의 회전을 즉시 중지할 수 없다는 점에 유의해야 한다. |
Use Gravity | 활성화하면 오브젝트는 중력의 영향을 받는다. |
Is Kinematic | 활성화하면 오브젝트는 물리적 효과를 받지않음 (물리 엔진에 의해 주도되지 않으며, Transform에서만 조작될 수 있다. ) |
Interpolate | Rigidbody의 움직임이 어색할 때 다음 옵션 중 선택할 수 있다. - None 보간을 적용하지 않는다. - Interpolate 이전 프레임의 Transform에 따라 Transform 스무딩. - Extrapolate 다음 프레임의 Transform에 따라 Estimated Transform 스무딩. |
Collision Detection | 충돌 감지 방법 - Discrete 정상 충돌에 사용된다. - Continuous 동적 충돌 자 (강체가 있는 경우)와 정적 MeshColliders (강체가 없는 경우)에 대한 연속 충돌 감지를 사용하여 개별 충돌 감지를 사용한다. - Continuous Dynamic 연속 및 연속 동적 충돌로 설정된 개체에 대해 연속 충돌 검색을 사용한다. 또한 고정 된 MeshColliders (rigidbody없이)에 대해 지속적인 충돌 감지를 사용한다. 빠르게 움직이는 물체에 사용된다. |
Constraints |
rigidbody의 동적 제한 - Freeze Position Rigidbody가 world 좌표의 X, Y 및 Z 축을 선택적으로 이동하는 것을 막는다. - Freeze Rotation Rigidbody가 로컬 X, Y 및 Z 축을 중심으로 회전하는 것을 막는다. |
Update() - 화면 갱신 주기
FixedUpdate() - 물리 갱신 주기
물리적 연산은 고정된 시간간격의 호출인 FixedUpdate에서 더 적합하다고 한다.
이 두 함수는 똑같은 만큼 움직일 것이다.
void Update()
{
rigidBody.MovePosition(rigidBody.position + move * Speed * Time.deltaTime);
}
void FixedUpdate()
{
rigidBody.MovePosition(rigidBody.position + move * Speed * Time.fixedDeltaTime);
}
하지만 불규칙한 호출의 Update는 물리엔진 충돌 검사가 제대로 되지않을수도있으므로 사용하는걸 지양한다.
키 입력은 Update(), 물리 효과 검사는 FixedUpdate()
isGrounded는 raycast혹은 Physics.CheckSphere 등을 이용하여 검사할수있다. (이 코드에선 생략)
public class Controller2 : MonoBehaviour
{
Rigidbody rigidBody;
float Speed = 5.0f;
float Gravity = -9.8f;
float JumpSpeed = 10.0f;
Vector3 move;
void Start()
{
rigidBody = GetComponent<Rigidbody>();
}
void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
move = new Vector3(h, 0, v);
if (move != Vector3.zero)
transform.forward = move;
if (Input.GetButtonDown("Jump"))
{
// 질량 무시하는 순간적인 힘 (프레임에 종속되지않음)
rigidBody.AddForce(Vector3.up * Mathf.Sqrt(JumpSpeed * -2f * Gravity), ForceMode.VelocityChange);
}
}
void FixedUpdate()
{
rigidBody.MovePosition(rigidBody.position + move * Speed * Time.fixedDeltaTime);
}
}
Character Controller과 비교하였을때 두 스크립트 모두 점프하는 코드지만 물리적 힘이 적용될때는 RigidBody가 훨씬 구현하기 쉬울것이다.
Rigidbody의 Position 과 MovePosition 의 자세한 차이는 이 블로그를 통해 공부하였다.
[출처] [유니티]Rigidbody. position과 MovePosition()의 차이와 성능. 그리고 결론?|작성자 sabotduke
[유니티]Rigidbody. position과 MovePosition()의 차이와 성능. 그리고 결론?
스크립트 최적화에 간단히 쓸 생각이었다가 깜박 잊었다. 처음 유니티 배울 때 position과 MovePosition(...
blog.naver.com
-> rigidbody.position을 사용할 때는 순간이동 , MovePosition은 이동
3. Transform
Transform.position같은경우는 오브젝트를 움직일때 연결된 모든 콜라이더들이 rigidbody의 위치를 다시계산한다고한다.
위의 참조한 블로그에서 어느 개발자가 50만번을 실행한 결과
Object with NO Collider and NO rigidbody:
transform.position: 2.540ms
Object with Collider and NO rigidbody:
transform.position: 11.296ms
Object with Collider and Rigidbody:
transform.position: 20.429ms
rigidbody.position: 1.689ms
rigidbody.MovePosition(): 1.701ms
정말 부득이한 상황아니면 rigidbody가 붙어있을때는 position(순간이동)과 MovePosition(이동)을 사용하도록하는것이 성능면에있어서 좋다.
'유니티' 카테고리의 다른 글
유니티 Input System (0) | 2025.02.18 |
---|---|
Atan (0) | 2025.01.06 |
Coroutine (0) | 2022.04.07 |
Photon Animator View (Trigger) (0) | 2022.04.06 |
오브젝트 풀링 (Object Polling) (0) | 2022.03.16 |