Godot 엔진 2D게임에서 중력 적용하기
저번 글에서 배경과 플레이어 캐릭터, 플레이어가 디딜 땅까지 구현했으니, 이번에는 플레이어에게 중력을 적용해보려고 한다.
사실 단순 중력만 적용하면 플레이어 컨트롤이 상당히 어색하기 때문에 가속도와 마찰력 등 현실에서 겪는 물리력을 최대한 반영하고자 했다. 개인적으로 구현하기는 어려워 AI 서비스인 Grok3의 힘을 빌렸다.
![]() |
플레이어 노드에 추가된 물리 적용 스크립트 |
이전 글의 과정에서 플레이어 캐릭터를 만들 때 플레이어 노드에 스크립트를 추가했었는데, 해당 부분에 아래 코드를 붙여 넣으면 된다.
물리 적용 코드
extends CharacterBody2D
# 현실 물리 단위 (1m = 100px로 가정)
const METERS_TO_PIXELS = 100.0 # 1미터 = 100픽셀
# 물리 상수
@export var max_speed = 2.0 * METERS_TO_PIXELS # 최대 속도 (5 m/s → 500 px/s)
@export var ground_acceleration = 10.0 * METERS_TO_PIXELS # 가속도 (10 m/s² → 1000 px/s²)
@export var ground_friction = 30.0 * METERS_TO_PIXELS # 마찰력 (8 m/s² → 800 px/s²)
@export var air_drag = 0.02 # 공기 저항 계수 (속도에 비례)
@export var gravity = 9.8 * METERS_TO_PIXELS # 중력 (9.8 m/s² → 980 px/s²)
@export var jump_strength = -4.0 * METERS_TO_PIXELS # 점프 힘 (-5 m/s → -500 px/s)
@export var max_fall_speed = 20.0 * METERS_TO_PIXELS # 최대 낙하 속도 (20 m/s → 2000 px/s)
var input_direction = 0.0 # 입력 방향 (-1: 왼쪽, 1: 오른쪽, 0: 중립)
func _physics_process(delta):
# 입력 방향 계산
input_direction = 0.0
if Input.is_action_pressed("ui_right"):
input_direction += 1.0
if Input.is_action_pressed("ui_left"):
input_direction -= 1.0
# 수평 이동 (가속도와 마찰력/공기 저항 적용)
if is_on_floor():
# 바닥: 가속도와 마찰력 적용
if input_direction != 0:
# 입력이 있으면 가속
velocity.x += input_direction * ground_acceleration * delta
else:
# 입력이 없으면 마찰력으로 감속
var friction_force = -sign(velocity.x) * ground_friction * delta
if abs(velocity.x) > abs(friction_force):
velocity.x += friction_force
else:
velocity.x = 0.0
else:
# 공중: 공기 저항과 제한된 가속 적용
if input_direction != 0:
# 공중에서 방향 전환 시 제한된 가속
velocity.x += input_direction * ground_acceleration * 0.5 * delta
# 공기 저항 (속도에 비례)
velocity.x -= velocity.x * air_drag
# 최대 속도 제한
velocity.x = clamp(velocity.x, -max_speed, max_speed)
# 점프
if Input.is_action_just_pressed("ui_select") and is_on_floor():
velocity.y = jump_strength
# 중력 적용
if not is_on_floor():
velocity.y += gravity * delta
# 최대 낙하 속도 제한
if velocity.y > max_fall_speed:
velocity.y = max_fall_speed
# 이동 적용
move_and_slide()
# 현실 물리 단위 (1m = 100px로 가정)
const METERS_TO_PIXELS = 100.0 # 1미터 = 100픽셀
# 물리 상수
@export var max_speed = 2.0 * METERS_TO_PIXELS # 최대 속도 (5 m/s → 500 px/s)
@export var ground_acceleration = 10.0 * METERS_TO_PIXELS # 가속도 (10 m/s² → 1000 px/s²)
@export var ground_friction = 30.0 * METERS_TO_PIXELS # 마찰력 (8 m/s² → 800 px/s²)
@export var air_drag = 0.02 # 공기 저항 계수 (속도에 비례)
@export var gravity = 9.8 * METERS_TO_PIXELS # 중력 (9.8 m/s² → 980 px/s²)
@export var jump_strength = -4.0 * METERS_TO_PIXELS # 점프 힘 (-5 m/s → -500 px/s)
@export var max_fall_speed = 20.0 * METERS_TO_PIXELS # 최대 낙하 속도 (20 m/s → 2000 px/s)
var input_direction = 0.0 # 입력 방향 (-1: 왼쪽, 1: 오른쪽, 0: 중립)
func _physics_process(delta):
# 입력 방향 계산
input_direction = 0.0
if Input.is_action_pressed("ui_right"):
input_direction += 1.0
if Input.is_action_pressed("ui_left"):
input_direction -= 1.0
# 수평 이동 (가속도와 마찰력/공기 저항 적용)
if is_on_floor():
# 바닥: 가속도와 마찰력 적용
if input_direction != 0:
# 입력이 있으면 가속
velocity.x += input_direction * ground_acceleration * delta
else:
# 입력이 없으면 마찰력으로 감속
var friction_force = -sign(velocity.x) * ground_friction * delta
if abs(velocity.x) > abs(friction_force):
velocity.x += friction_force
else:
velocity.x = 0.0
else:
# 공중: 공기 저항과 제한된 가속 적용
if input_direction != 0:
# 공중에서 방향 전환 시 제한된 가속
velocity.x += input_direction * ground_acceleration * 0.5 * delta
# 공기 저항 (속도에 비례)
velocity.x -= velocity.x * air_drag
# 최대 속도 제한
velocity.x = clamp(velocity.x, -max_speed, max_speed)
# 점프
if Input.is_action_just_pressed("ui_select") and is_on_floor():
velocity.y = jump_strength
# 중력 적용
if not is_on_floor():
velocity.y += gravity * delta
# 최대 낙하 속도 제한
if velocity.y > max_fall_speed:
velocity.y = max_fall_speed
# 이동 적용
move_and_slide()
![]() |
물리 적용 테스트 플레이 |
저장한 뒤 'F5'를 누르면 플레이해서 테스트할 수 있다. 공중에서 방향 전환하려고 할 때 감속 걸리는 부분까지 만족스러운 수준에서 구현이 되었다.
적용된 물리 값을 바꾸고 싶을 경우, 스크립트의 물리 상수 값을 변경하고 테스트 하면서 적당한 값을 찾아가면 된다.
댓글
댓글 쓰기