Godot 4のコンポーネント指向開発シリーズ、今回は操作感(Game Feel)の要となる**「SurfaceFriction (摩擦制御)」**です。
アクションゲームで、キーを離した瞬間にピタッと止まるキャラと、少し滑って止まるキャラでは、プレイ感覚が全く違います。このコンポーネントを使えば、「氷の床」や「泥沼」といった地形による滑り具合を、移動コードとは独立して管理できるようになります。
このコンポーネントは、親ノードが「床にいる時」だけ、横方向の速度(velocity.x)を徐々に 0 に近づけます。つまり、ブレーキ担当の部品です。
1. コンポーネントのコード (Full Code)
以下のコードをコピーして、SurfaceFriction.gd という名前で保存してください。
class_name SurfaceFriction
extends Node
## 床の上にいる時、自動でブレーキ(摩擦)をかけて減速させるコンポーネント
## 親ノードは CharacterBody2D を想定しています。
# --- 設定パラメータ ---
@export_group("Friction Settings")
@export var friction: float = 1000.0 ## 摩擦力(1秒間に減速する速度量)
@export var enabled: bool = true ## 有効/無効の切替(空中などでOFFにしたい場合用)
# --- 内部変数 ---
var _parent: CharacterBody2D
func _ready() -> void:
_parent = get_parent() as CharacterBody2D
if not _parent:
push_error("SurfaceFriction: 親が CharacterBody2D ではありません。")
set_physics_process(false)
func _physics_process(delta: float) -> void:
if not enabled: return
# 床にいて、かつ速度が出ている場合のみ処理
if _parent.is_on_floor() and _parent.velocity.x != 0:
# move_toward は、現在の値を目標値(0)に向かって、指定量(friction * delta)だけ近づける関数
# これにより、滑らかかつ正確に0で止まります。
_parent.velocity.x = move_toward(_parent.velocity.x, 0, friction * delta)
2. 使い方チュートリアル
このコンポーネントの最大の利点は、**移動スクリプトから「止まる処理」を削除できる(または上書きできる)**点です。
手順①:プレイヤーの準備
CharacterBody2Dのプレイヤーを用意します。- 移動用のコンポーネント(
KeyboardMoverなど)がついている前提で進めます。
手順②:移動スクリプトの修正(重要!)
もし、移動用のスクリプト(KeyboardMoverなど)の中に「キーを離したら velocity = Vector2.ZERO にする」という記述があると、このコンポーネントの出番がありません(一瞬で止まってしまうため)。
摩擦コンポーネントを活かすには、移動側は「加速」だけを担当し、「減速」はこのコンポーネントに任せる構成が理想です。
(例:KeyboardMoverのパラメータ調整)
第1回で紹介した KeyboardMover を使っている場合、そのインスペクター設定にある Friction を 0 にしてください。
そうすると KeyboardMover はブレーキをかけなくなり、代わりに今回追加する SurfaceFriction がブレーキを担当するようになります。
手順③:コンポーネントのアタッチ
- プレイヤーの子ノードとして
Nodeを追加し、名前をSurfaceFrictionにします。 - スクリプト
SurfaceFriction.gdをアタッチします。
シーン構成図:
Player (CharacterBody2D)
├── Sprite2D
├── CollisionShape2D
├── KeyboardMover (加速担当: Frictionは0にしておく)
└── SurfaceFriction (減速担当) <-- 今回追加!
手順④:パラメータ調整と実行
インスペクターで Friction の値をいじってテストしてみてください。
- Friction = 1000: 通常のアスファルトや土の上。キュッと止まります。
- Friction = 100: 氷の上。キーを離してもツルツルと長く滑ります。
- Friction = 3000: 粘着床や泥沼。一瞬で止まります。
3. 応用:地形ごとに滑り具合を変える
このコンポーネントを独立させたことで、**「エリアに入ったら摩擦を変える」**というギミックが簡単に作れます。
「氷の床エリア」を作る
Area2D を使い、プレイヤーが入ってきたら SurfaceFriction の値を書き換えるギミックです。
# IceZone.gd (氷エリアのスクリプト)
extends Area2D
func _on_body_entered(body: Node2D):
# プレイヤーが持つ摩擦コンポーネントを探す
var friction_comp = body.get_node_or_null("SurfaceFriction")
if friction_comp:
friction_comp.friction = 100.0 # ツルツルにする!
func _on_body_exited(body: Node2D):
var friction_comp = body.get_node_or_null("SurfaceFriction")
if friction_comp:
friction_comp.friction = 1000.0 # 普通に戻す
これを床に配置するだけで、プレイヤーの移動コードを一切書き換えることなく、スーパーマリオのような「氷のステージ」が実装できます。
空中制御との兼ね合い
今回のコードは is_on_floor() のチェックを入れているため、**「空中では空気抵抗(摩擦)がかからない」**ようになっています。
これにより、「ジャンプ中は慣性が残り、着地した瞬間にブレーキがかかる」という、アクションゲームとして自然な挙動が自動的に実現できています。
