コントローラーの作り方
公式
事前準備
地面の準備
MainSceneのノード構成

上から空ノードのMain
子ノードのStaticBody3DのGround
孫ノードとして1つ目はCollisionShape3D(InspecterでBoxShape3Dを割り当て、箱アイコンをクリックしてSizeを設定)

孫ノード2つ目はMeshInstance3D
同じくBoxMeshを割り当てコリジョンと同じサイズを設定する

できたらGroundを選択し、TransformのY値を-1にする。


最後にMainの子要素にDirectionalLight3Dを配置
Y値のPositionとX軸の回転をいじって地面が照らされるようにする

キャラの用意
新しくPシーンを作る。

ルートノードはCharacterBody3Dノード(今回はPlayerと命名)。

その下にNode3Dを追加して(Pivotと命名)、更にその下にキャラの3Dモデルを配置する(今回は単純なMeshInstance3Dを使った)
ルートのPlayerノードの子要素として(Pivotと同階層)CollisionShape3Dノードを配置する。
右のInspecterパネルでShapeを割り当てる

TSCNファイルとして保存しておく。
入力システム設定
上部タブから Project – ProjectSettingと進む。
InuputMapタブを選択し、今回は前後左右の移動を作りたいのでAddのところにアクションを追加する

各アクションのプラスアイコンからキーボードなりパッドの入力を紐づける(ひとつのアクションに複数も可能)

動きのスクリプトを作る
Playerノードを右クリックし、AttachScriptを実行。
Templateのチェックを外して、スクリプトを保存する箇所と名前を適宜設定してCreateを実行、Script編集画面に移動する。


コードは公式の中に全部解説付きで記述されているのでコピペでも自力でも可。
一個前のInuputMapで作ったアクション名をコード内で使用するので、同じになっているかチェックしておく。違うなら修正する。
カメラの配置
MainSceneにカメラを配置する。
Mainノードの子要素としてまずMarker3Dノードを出し、CameraPivotと命名。
その子要素としてCamera3Dを設置
Viewの箇所で画面を分割する。
Camera3Dを選択するとPreviewというラベルが表示されるはずなので、片方にチェックを入れる。そうすると片方はカメラからの光景に

Camera3DのTransformをZ軸に少し動かす
CameraPivotをX軸に45度回転させる

実行
MainSceneを開き、Mainノードを右クリックしてInstantiateChildSceneを実行、Playerのtscnファイルを開く。
ノードの構成はこんな感じ

できたらF5か再生ボタンでゲームを起動してみる。
割り当てたキーで動くならOK(終わるときはF8)


一人称視点のコントローラー
単純に前後左右に動くようにする。今回はジャンプとかも省略
地面などは省略
構造としては親がメインシーン、子として地面シーン、プレイヤーシーン

プレイヤーシーンの設定
ノード構成

ルートはCharacterBody3Dノード。
子要素1はキャラの腕3Dモデル(なくてもOK)
子要素2はCollisionShape3D(形はカプセル)
子要素3はNode3Dで、その子要素にCamera3D(カメラの位置を目や頭のあたりに配置する)
スクリプトを追加する
ルートのCharacterBody3Dを右クリックしてAttachScript
今回はTemplateを使う

このテンプレートだと方向キーで動くようになっている。なのでWASDに変更する。
Godot上部タブのProject – Project Setting と進み、 input map タブを選択する 。
WASDをそれぞれAddする。

スクリプトに移動しui_left などの箇所をmove_ へ置き換えていく

候補を出してくれるので楽。
ジャンプなどをはしょるとこんな感じ。F5で再生して動くか確認
extends CharacterBody3D
const SPEED = 5.0
func _physics_process(delta: float) -> void:
var input_dir := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
関数を分けたり速度をInspector側で設定できるようにすると↓
extends CharacterBody3D
@export var SPEED = 5.0
func _physics_process(delta: float) -> void:
# charactermoving
player_move(delta)
#character moving func
func player_move(delta:float) -> void:
var input_dir := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
move_and_slide()“@export var SPEED = 5.0” とすることでInxpector上で速度を調整できるようになる

マウスで視点移動できるようにする
変更点
“@onready var head: Node3D = $Head” は左のヒエラルキーから Ctrolを押しながらスクリプト上にDragDropすると自動で記述される
_input関数内の “rotate_y(event.relative.x * sensitivity)” が左右の回転
“head.rotate_x(event.relative.y * sensitivity)”前後の回転(こっちはHeadノードを使っている)
3行目のclamp関数で回転の角度に制限をかける
extends CharacterBody3D
@export var SPEED = 5.0 #chara moving speed
@export var mouse_sensitivity = -0.002 # viewpoint rotation
@export var camera_rotation_limitation = 30 #camera rotation limit
@onready var head: Node3D = $Head
#mouse viewpoint movement / rotation
func _input(event: InputEvent) -> void:
if event is InputEventMouseMotion:
rotate_y(event.relative.x * mouse_sensitivity)
head.rotate_x(event.relative.y * mouse_sensitivity)
head.rotation.x = clamp(head.rotation.x,deg_to_rad(camera_rotation_limitation * -1),deg_to_rad(camera_rotation_limitation))
func _physics_process(delta: float) -> void:
# charactermoving
player_move(delta)
#character moving func
func player_move(_delta:float) -> void:
var input_dir := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
画面の端にいくとそれ以上視点操作ができなくなる
上の視点移動だと画面の端に行くとそれ以上ローテートすることができない。
下記コードを加えると、マウスポインタの位置に左右されず視点移動を継続できる
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
デフォルトの表示戻すには Input.MOUSE_MODE_VISIBLE
