3D 공간에서 오브젝트의 상하좌우를 움직이게 해볼 것이다.
완성본

1. 입력
using UnityEngine;
public class InputManager : MonoBehaviour
{
public Vector3 direction;
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
}
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxis("Vertical");
direction = new Vector3(h, 0f, v).normalized;
}
}
움직임을 위한 입력을 받는 방법
direction : 방향을 저장할 Vector
키 입력을 받는 것이기 때문에 Update에서 코드를 작성해야 한다.
h는 좌우(A키,D키, 왼쪽 방향키, 오른쪽 방향키)의 입력값을 받고,
v는 상하(W키,S키, 위쪽 방향키, 아래쪽 방향키)의 입력값을 받는다.
direction에 현재 입력값을 저장한다.
GetAxis / GetAxisRaw의 차이점
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
GetAxisRaw의 경우 가지는 값은 -1,0,1이다.
즉각적인 움직임에 유용하다.
양극의 키를 동시에 누르고 있다면 값은 0이 된다.
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
GetAxis의 경우 가지는 값은 -1f ~ 1f 이다
부드러운 움직임에 유용하다.
양극의 키를 동시에 누르고 있다면 동시에 누르고 있는 이후의 값 변동은 없다.
(d키를 눌러 값이 t가 되었을때 a키도 누른다면 t에서 값이 변경되지 않는다.)
즉각적인 반응이 필요한 게임에서 GetAxisRaw를 사용하는것이 적합하다
이 입력받는 경우 방향값을 가지기 때문에 즉각적인 값 변화를 사용한다.(GetAxisRaw)
normalized를 사용하는 이유
direction = new Vector3(h, 0f, v).normalized;
상하 키와 좌우 키를 동시에 눌렀을때, 방향은 대각선으로 나타나는데, 이때 한 축으로 이동하는 것보다 더 긴 거리를 이동할수 있기때문에 normalized를 사용해 방향 벡터로 만들어준다.
(방향이 한축(1,0)일 경우 거리는 1이지만
방향이 1,1일 경우 이 거리는 1.414(루트2)의 값을 가진다.
normalized를 사용하면 1.414였던 거리를 1로 변환한 뒤, 그에 맞는 방향값을 가진다. (0.71,0.71)
GetButton, GetKey등 입력을 받는 방법은 여러가지가 있지만 이 방법이 가장 편리한 것 같다.
2. 움직임
- Transform.Translate
- Rigidbody.MovePosition
- Rigidbody.Addforce
- Rigidbody.velocity (linearVelocity)
1. Transform.Translate
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
InputManager inputManager;
[SerializeField] float speed;
private void Awake()
{
inputManager = GetComponent<InputManager>();
}
void Update()
{
OnMovement();
}
void OnMovement()
{
transform.Translate(inputManager.direction * speed * Time.deltaTime);
}
}
현재위치에 이동할 좌표만큼 더해서 움직이는 단순한 방법이다.
이 방법은 벽을 뚫을수 있기 때문에 플레이어 이동에는 많이 사용되지 않는듯 하다.
주로 단순 이동이나 UI에서 사용한다
Time.deltaTime을 곱하는 이유
PC 성능에 따라 FPS(Frame Per Second)가 다르기 때문에 FPS가 높은 PC에서는 UPdate가 자주 실행되어서 더 빠르게 움직이는 버그가 발생하기 쉽다. 때문에 deltaTime(한 프레임에서 다음 프레임까지 걸리는 시간)을 곱하여 PC간의 차이를 없앤다.
ex)60프레임의 경우 deltaTime은 1/60의 값을 가진다.
ex)240프레임의 경우 deltaTime은 1/240의 값을 가진다.
1.1 Transform.positoin
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
InputManager inputManager;
[SerializeField] float speed;
private void Awake()
{
inputManager = GetComponent<InputManager>();
}
void Update()
{
OnMovement();
}
void OnMovement()
{
transform.position += inputManager.direction * speed * Time.deltaTime;
}
}
Translate와 똑같은 방법으로 현재 좌표에서 다음 좌표의 값을 더해 움직인다.
2. Rigidbody.MovePosition
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
InputManager inputManager;
[SerializeField] float speed;
Rigidbody rigidBody;
private void Awake()
{
inputManager = GetComponent<InputManager>();
rigidBody = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
OnMovement();
}
void OnMovement()
{
rigidBody.MovePosition(rigidBody.position + inputManager.direction * speed * Time.fixedDeltaTime);
}
}
Rigidbody를 이용하여 물리적으로 움직이는 방법
MovePosition 같은 경우 transform.position과 비슷하지만 물리적으로 움직이기 때문에 벽을 통과하는 일이 없다.
MovePosition은 월드좌표이기 때문에 rigidBody.position을 더하여 현재위치에서 좌표를 더하게 한다.
Rigidbody가 Kinematic(외부에서 가해지는 힘을 무시하는 오브젝트)일때 사용하면 좋다.
MovePosition은 텔레포트 이후 충돌 처리를 하는 방식이다.
FixedUpdate를 사용하는 이유
Rigidbody는 물리적인 연산은 하기 때문에 고정 시간 간격으로 프레임이 호출되는 FixedUpdate에서 호출해야 한다.
Time.fixedDeltaTime을 사용한 이유
FIxedUpdate에서 호출하는 함수에서는 fixedDeltaTime으로 적어야 한다. FixedDeltaTime으로 적어도 자동으로 변환되지만, 명확성과 가독성을 위해 이렇게 적는다.
3. Rigidbody.Addforce
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
InputManager inputManager;
[SerializeField] float speed;
Rigidbody rigidBody;
private void Awake()
{
inputManager = GetComponent<InputManager>();
rigidBody = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
OnMovement();
}
void OnMovement()
{
rigidBody.AddForce(inputManager.direction * speed, ForceMode.Force);
}
}
Rigidbody를 이용해 힘을 가하여 움직임
힘을 가하는 것이기 때문에 계속 누르게 되면 힘이 누적된다.
DeltaTime을 사용하지 않는 이유
AddForce의 경우 내부적으로 fixedDeltaTime을 고려하기 때문에 사용하지 않는다.
ForceMode
Force모드에는 4가지 모드가 존재한다.
1.Force : 질량 O , 지속적 가속 (자동차, 로켓추진)
2.Impulse : 질량 O , 순간적 가속 (총 반동, 점프)
3.Accleration : 질량 X , 지속적 가속 (바람 장애물, 중력)
4.velocityChange : 질량 X , 순간적 가속 (넉백, 폭발)
4. Rigidbody.velocity (linearVelocity)
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
InputManager inputManager;
[SerializeField] float speed;
Rigidbody rigidBody;
private void Awake()
{
inputManager = GetComponent<InputManager>();
rigidBody = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
OnMovement();
}
void OnMovement()
{
rigidBody.linearVelocity = inputManager.direction * speed;
}
}
Rigidbody를 이용하여 속도를 사용하여 움직임
유니티 6의 경우 linearVelocity로 사용한다.
속도를 직접 덮어쓰기 때문에 정밀한 조작이 가능하다.
deltaTime을 사용하지 않는 이유
velocity는 기본적으로 초당 이동속도를 의미하기 때문에 FPS의 영향을 거의 받지 않아 deltaTime을 사용하지 않는다.
| 움직임 방식 | 특징 | 장점 | 단점 |
|---|---|---|---|
| Transform | 위치 직접 이동 | 단순한 구현 | 충돌 불안정 |
| MovePosition | 물리 기반 이동 | 충돌 안전 | 힘과 혼합X |
| AddForce | 힘 가속 | 자연스러움 | 제어 어려움 |
| Velocity | 속도 제어 | 정밀 조작 | 힘 계산 우회 |
'Unity > Tutorial' 카테고리의 다른 글
| [Unity] Cinemachine (기초) (0) | 2026.02.24 |
|---|---|
| [Unity] Character Controller (3D) (0) | 2026.02.24 |
| [Unity] 1인칭 시점 카메라 (3D) (0) | 2026.02.22 |
| [Unity] 카메라 회전에 따른 플레이어 회전과 움직임 (3D) (0) | 2026.02.21 |
| [Unity] 3인칭 시점 카메라 (3D) (0) | 2026.02.20 |