概要
Godotの移動処理では、move_and_slide()
で物理的な移動を行い、move_toward()
で速度の変化を制御します。特にノッ クバック処理では、この組み合わせが効果的です。
ノックバックの実装で最初につまずいたのは、「敵に当たった瞬間に吹き飛ばされるけど、すぐに通常速度に戻ってしまう」という問題でした。move_toward()
を使うことで、「じわじわと復帰する」感覚が出せるようになり、ゲームの手触りが格段に良くなりました。

各関数の役割
move_and_slide()
- 役割: CharacterBody2Dの主力移動関数
- 機能: velocityに基づいて移動し、衝突を自動処理
- 特徴: 壁や床でスライド、物理演算を考慮
move_toward(current, target, delta)
- 役割: 現在値から目標値へ段階的に変化
- 機能: 指定した量(delta)だけ目標に近づく
- 用途: 滑らかな加速・減速、慣性の表現
なぜノックバック処理にmove_towardが必要か
問題:直接代入では効果が消える
# 問題のあるコード
func move_player():
var move_vector = Input.get_vector("move_left", "move_right", "move_up", "move_down")
velocity = move_vector * move_speed # 直接代入
# ノックバック後、入力があると即座に通常速度に戻る
func apply_knockback(direction: Vector2, strength: float):
velocity += direction * strength # ノックバック適用
解決:move_towardで段階的に復帰
@export var acceleration: float = 500.0 # 1秒間に500ピクセル/秒の加速
func move_player():
var move_vector = Input.get_vector("move_left", "move_right", "move_up", "move_down")
var target_velocity = move_vector * move_speed
# 段階的変化:現在の速度から目標速度へ少しずつ近づく
velocity = velocity.move_toward(target_velocity, acceleration * delta)
func apply_knockback(direction: Vector2, strength: float):
velocity += direction * strength # velocityに直接力を加える
具体的な動作例
ノックバック時のフレーム単位の変化
初期状態: velocity = (100, 0) # 右に移動中
攻撃直後: velocity = (300, 0) # 右に吹き飛ばされる
以降のフレーム(acceleration = 500, delta = 0.016秒):
- フレーム1: velocity = (292, 0)
- フレーム2: velocity = (284, 0)
- フレーム3: velocity = (276, 0)
- ...約25フレーム後: velocity = (100, 0) # 通常速度に復帰
完全な実装例
プレイヤーの移動とノックバック
extends CharacterBody2D
@export var move_speed = 200.0
@export var acceleration = 500.0
@export var knockback_strength = 300.0
func _physics_process(delta):
# 移動処理
move_player(delta)
# 物理演算を適用
move_and_slide()
func move_player(delta):
var input_vector = Input.get_vector("move_left", "move_right", "move_up", "move_down")
var target_velocity = input_vector * move_speed
# move_towardで段階的に目標速度へ
velocity = velocity.move_toward(target_velocity, acceleration * delta)
func take_damage(damage_amount: int, from_position: Vector2):
# ダメージ処理
health -= damage_amount
# ノックバック方向を計算
var knockback_direction = global_position - from_position
knockback_direction = knockback_direction.normalized()
# ノックバックを適用
apply_knockback(knockback_direction, knockback_strength)
func apply_knockback(direction: Vector2, strength: float):
velocity += direction * strength
敵AIでの活用
# Enemy.gd
extends CharacterBody2D
@export var chase_speed = 150.0
@export var chase_acceleration = 300.0
var target: Node2D = null
func _physics_process(delta):
if target:
chase_target(delta)
move_and_slide()
func chase_target(delta):
var direction = global_position.direction_to(target.global_position)
var target_velocity = direction * chase_speed
# ノックバック効果を保持しつつ、段階的に追跡速度へ変化
velocity = velocity.move_toward(target_velocity, chase_acceleration * delta)
move_towardの3つの効果
- ノックバック保持: 即座に消えず、段階的に復帰
- 制御可能な復帰速度: accelerationで調整可能
- 滑らかな操作感: 急激な方向転換を避け、慣性を表現
パラメータ調整の指針
パラメータ | 効果 | 推奨値 |
---|---|---|
acceleration(小) | ゆっくり復帰、重い動き | 200-400 |
acceleration(中) | バランス型 | 400-800 |
acceleration(大) | 素早い復帰、機敏な動き | 800-1500 |
トラブルシューティング
ノックバックが効かない
velocity
の直接代入を避けるmove_toward
を使用しているか確認
動きがカクカクする
delta
を掛け忘れていないか確認acceleration
の値が大きすぎないか確認
実装して学んだこと
move_toward()
の存在を知るまでは、ノックバックの実装に本当に苦労しました。「一瞬だけ吹き飛び、すぐに通常移動に戻る」という動きは、プレイ感覚を損 ないます。
特に印象的だったのは、accelerationの値を調整することで、キャラクターの「重さ」を表現できることです。重たいキャラクターは小さいacceleration、軽いキャラクターは大きいaccelerationとすることで、ゲームプレイに多様性が生まれます。
また、この手法はノックバックだけでなく、氷上での滑りやすい動き、風の影響など、様々な環境効果にも応用できることがわかりました。