プレイヤーを動かすときは move_and_slide()、HPバーをなめらかに動かすときは move_toward()。どちらも「動く」ように見えるので、最初は同じ種類の関数に見えます。
しかし実際には、役割がかなり違います。move_and_slide() は キャラクターを物理ワールドの中で動かす処理、move_toward() は 値を目標へ少しずつ近づける処理 です。
ノック バックでは、この2つを組み合わせます。壁との衝突は move_and_slide() に任せ、吹き飛びの勢いを弱めるところに move_toward() を使います。
この記事でわかること
move_and_slide()とmove_toward()の役割の違い- CharacterBody2Dで
positionを直接動かすと危ない理由- ノックバック中に入力を止める考え方
velocityをmove_toward()で減衰させる実装- UIやカメラでは
move_toward()をどう使うか
2つは同じ「移動関数」ではない
まず、2つの役割を分けて考えます。

move_and_slide() は、CharacterBody2D の velocity をもとに、物理フレームで移動と衝突処理を行います。壁に当たれば止まったり、壁沿いに滑ったりします。
move_toward() は、値を目標値へ近づけるだけです。壁や床を知りません。Vector2 に使えばベクトルを近づけられますし、数値に使えばHPバーやゲージの値を近づけられます。
| 使うもの | 主な役割 | 得意な場面 |
|---|---|---|
move_and_slide() | 物理ワールドでキャラクターを動かす | プレイヤー、敵、壁との衝突、坂や床 |
move_toward() | 値を目標へ一定量近づける | velocityの減衰、HPバー、カメラ追従、UI |
つまり、ノックバックでは「どちらか一方を選ぶ」のではありません。
- キャラクターを実際に動かす:
move_and_slide() - ノックバックの勢いを弱める:
move_toward()
この分担で考えると、コードの役割がかなり読みやすくなります。
move_and_slide()は物理キャラクターを動かす
move_and_slide() は、CharacterBody2D のための移動処理です。基本は、毎物理フレームで velocity を決めてから呼び出します。
extends CharacterBody2D
const SPEED := 220.0
func _physics_process(delta: float) -> void:
var input_vector := Input.get_vector(
&"move_left",
&"move_right",
&"move_up",
&"move_down"
)
# このフレームで進みたい速度を決める
velocity = input_vector * SPEED
# 実際の移動と衝突処理はGodotに任せる
move_and_slide()
Godot 4では、move_and_slide() は velocity プロパティを使って移動します。壁に当たったときの滑りや衝突応答も、この呼び出しの中で処理されます。
ここで大事なのは、move_and_slide() を「座標を変える便利関数」として見るのではなく、物理ワールドへ移動を申請する処理 として見ることです。
position += direction * speed * delta のように座標を直接動かすと、物理エンジンが衝突を解決する前に位置だけが変わってしまいます。その結果、壁抜けやめり込みの原因になります。
move_toward()は値を目標へ近づける
move_toward() は、物理を動かす関数 ではありません。現在の値を、目標値へ一定量だけ近づける関数です。
たとえば、HPバーを現在値へなめらかに追従させるなら、物理は関係ありません。
var displayed_hp := 100.0
var actual_hp := 40.0
func _process(delta: float) -> void:
# 表示用HPを、実際のHPへ少しずつ近づける
displayed_hp = move_toward(displayed_hp, actual_hp, 80.0 * delta)
hp_bar.value = displayed_hp
Vector2 にも使えます。ノックバックでは、吹き飛びの速度を少しずつ Vector2.ZERO へ近づけます。
var knockback_velocity := Vector2(500.0, 0.0)
func _physics_process(delta: float) -> void:
# ノックバックの勢いを0へ近づける
knockback_velocity = knockback_velocity.move_toward(
Vector2.ZERO,
1200.0 * delta
)
ここでは move_toward() がキャラクターを動かしているわけではありません。あくまで「次に使う速度の値」を計算しています。
実装例: ノックバックを状態で分ける
ノックバック処理で一番大事なのは、通常移動と被弾中の移動を混ぜないことです。

通常時はプレイヤー入力で velocity を決めます。ノックバック中は入力を一時的に無視し、外から与えられた吹き飛び速度で動かします。
extends CharacterBody2D
enum PlayerState {
MOVE,
KNOCKBACK,
}
const SPEED := 220.0
const KNOCKBACK_DECAY := 900.0
const KNOCKBACK_END_SPEED := 20.0
var current_state := PlayerState.MOVE
var knockback_velocity := Vector2.ZERO
func _physics_process(delta: float) -> void:
match current_state:
PlayerState.MOVE:
update_move()
PlayerState.KNOCKBACK:
update_knockback(delta)
# どの状態でも、最後の移動と衝突処理はここに集める
move_and_slide()
func update_move() -> void:
var input_vector := Input.get_vector(
&"move_left",
&"move_right",
&"move_up",
&"move_down"
)
# 通常時はプレイヤー入力で速度を決める
velocity = input_vector * SPEED
func update_knockback(delta: float) -> void:
# ノックバック中は入力を見ず、吹き飛び速度だけを使う
velocity = knockback_velocity
# 次のフレームへ向けて、吹き飛びの勢いを弱める
knockback_velocity = knockback_velocity.move_toward(
Vector2.ZERO,
KNOCKBACK_DECAY * delta
)
if knockback_velocity.length() <= KNOCKBACK_END_SPEED:
knockback_velocity = Vector2.ZERO
current_state = PlayerState.MOVE
func apply_knockback(source_position: Vector2, power: float) -> void:
# 攻撃してきた位置から、自分が離れる方向を作る
var direction := source_position.direction_to(global_position)
knockback_velocity = direction.normalized() * power
current_state = PlayerState.KNOCKBACK
このコードでは、move_and_slide() を最後に1回だけ呼んでいます。通常移動でもノックバックでも、最終的に velocity を決めてから物理移動へ渡す、という形です。
ノックバック中に入力を完全に無視するか、少しだけ操作を残すかはゲーム性によって変えられます。アクションRPGなら短時間だけ操作不能にすると被弾感が出ますし、ツインスティックシューターならノックバック中も少し入力を混ぜた方が気持ちよく動くことがあります。
変えるならどこか
- 吹き飛びを強くしたい:
powerを大きくする - すぐ止まりたい:
KNOCKBACK_DECAYを大きくする - 長くのけぞらせたい:
KNOCKBACK_DECAYを小さくする - 小さな揺れを早めに止めたい:
KNOCKBACK_END_SPEEDを大きくする
数字だけを調整するより、「入力を止める時間」「勢いが弱まる速度」「復帰する条件」を別々に考えると、ゲームごとの手触りを作りやすくなります。
よくある失敗: positionを直接動かす
初心者がつまずきやすいのは、CharacterBody2Dを position で直接動かしてしまうことです。
