3Dキャラクターを作る

前回の解説では、3Dオブジェクトのインポート方法とシーン内での配置方法について取り上げました。今回のチュートリアルでは、さらにオブジェクトを追加し、ユーザー操作可能なキャラクターも実装していきます。

シーンの構築

引き続き、パート2でダウンロードしたKenney Platformer Kitを使用します。すべてのblock*.glbファイルを選択し、インポートタブでそのルートの型StaticBody3Dに設定してください。ルート名プロパティはチェックを外しておき、再インポートをクリックします。blockLarge.glbを選択して新しい継承シーンを作成します。前回のチュートリアルと同様に、メニューからメッシュに対して 「Collision Shape Placement」で兄弟 オプションを使いましょう。これでシーンを保存できます。また別にフォルダを作成することをオススメします。なぜなら、すぐに様々な形状のプラットフォームパーツを表すシーンが大量に出来上がるからです。

前のステップで作成した「Ground」平面と木箱を含むシーンを開いてください。 まず、木箱を削除し、大型ブロックのインスタンスを追加してください。これらのブロックを整列させて配置できるようにしたいので、以下の手順を実行してください。 ビューポート上部の「Transform」メニューから「スナップ設定」を選択します → 移動スナップ0.5 に設定します。 次に、「スナップモード」ボタンをクリックするか(または Y キーを押す)ことでスナップモードを有効にします。これでブロックを複製し、ドラッグして配置できるようになります。

ご希望であれば、他のプラットフォームブロック用のシーンを追加し、 魅力的なレベルに構成してみます。創造力を発揮してください!

alt alt

キャラクターの追加方法

次に、プラットフォーム上を歩き回れるようにキャラクターを作成します。 新しいシーンを開き、“Character"という名前のCharacterBody3Dコンポーネントを追加してください。このPhysicsBodyノードは2D版とほぼ同じ動作をします(2Dチュートリアルはお済みですか?)。このコンポーネントにはmove_and_slide()メソッドが用意されており、これを使って移動と衝突検出を行います。

メッシュインスタンス3D用のカプセル型MeshInstance3Dと、それに対応させた衝突形状CollionShape3Dを追加してください。また、メッシュにStandardMaterial3Dを追加してアルベド/カラープロパティを設定すれば、色を変更できることも覚えておいてください。

カプセル自体は良好ですが、回転方向を正確に把握するのは困難です。そこで、もう一つのメッシュを追加してください。今回は CylinderMesh3D 形状を使用します。 Top Radius0.2Bottom Radius0.001Height を 0.5 に設定し、その後 x軸 回転を -90度に変更します。これで円錐形の形状が完成します。ボディから外側に向かって伸びるように、このメッシュを配置してください。その際、負方向z軸 に沿って配置します(ギズモの矢印が正方向に表示されている方が、マイナス方向です)。

alt alt

この画像では、さらにキャラクター性を高めるために、目用に2つの球状メッシュを追加しています。ご自由にお好みのディテールを追加してください。

シーンに Camera3D オブジェクトも追加してください。プレイヤーが移動すると追従するように設定します。キャラクターの後方かつ少し上方に配置し、わずかに下向きに角度を調整してください。「プレビュー」ボタンをクリックするとカメラ視点で確認できます。

スクリプトを追加する前に、「プロジェクト設定」を開き、「インプットマップ」タブで以下の入力を追加してください。

アクションキー
move_forwardW
move_backS
strafe_rightD
strafe_leftA
jumpSpace

それでは、ボディ部分にスクリプトを追加してください。

extends CharacterBody3D

var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
var speed = 4.0  # movement speed
var jump_speed = 6.0  # determines jump height
var mouse_sensitivity = 0.002  # turning speed


func get_input():
    var input = Input.get_vector("strafe_left", "strafe_right", "move_forward", "move_back")
    velocity.x = input.x * speed
    velocity.z = input.y * speed

func _physics_process(delta):
    velocity.y += -gravity * delta
    get_input()
    move_and_slide()

_physics_process()内のコードは非常にシンプルです。重力を加えて Y方向(下向き) に加速し、get_input()を呼び出して入力をチェックした後、move_and_slide()を使用して速度ベクトルの方向に移動させます。

get_input() 関数では、押されたキーを確認し、対応する方向に移動します。プログラムを実行してテストしてみます。

alt alt

これは素晴らしい設定ですが、マウスで回転できるようにしたいですよね。キャラクターのスクリプトに以下のコードを追加してください。

func _unhandled_input(event):
    if event is InputEventMouseMotion:
        rotate_y(-event.relative.x * mouse_sensitivity)

これにより、x方向のマウス移動はすべて、y軸を中心とした回転に変換されます。

シーンを実行し、マウスを動かすとキャラクターが回転することを確認してください。

alt alt

しかし、問題があります。どちらの方向を向いていようと、W を押すとワールド座標の Z軸 に沿って移動してしまいます。したがって、現在の移動オブジェクトを進行方向に移動が必要です。

トランスフォームの力

ここで トランスフォーム が登場します。トランスフォームとは、オブジェクトの位置・回転・スケール情報をすべて含む数学的な 行列 です。Godotではこの情報は Transform データ型に格納されます。位置情報は transform.origin と呼ばれ、向きの情報は transform.basis に含まれます。

3Dギズモを『ローカル空間モード』に設定できることを思い出してください。このモードで動作させると、 ギズモのX/Y/Z 軸はオブジェクトそのものの座標系に沿って配置されます。これは変換の basis と同じ概念です。基底には x, y, z という3つの Vector3 オブジェクトが含まれており、これらが各方向を表します。この機能を利用することで、Wキーを押すと常にオブジェクトの進行方向に移動させることができます。

get_input()関数を次のように変更します

func get_input():
    var input = Input.get_vector("strafe_left", "strafe_right", "move_forward", "move_back")
    var movement_dir = transform.basis * Vector3(input.x, 0, input.y)
    velocity.x = movement_dir.x * speed
    velocity.z = movement_dir.z * speed

入力ベクトルに transform.basis を掛けることで、その変換をベクトルに『適用』します。基底はオブジェクトの回転を表すため、これにより前方方向と後方方向がオブジェクトのZ軸方向に、サイド移動キーがそのX軸方向に沿った向きに変換されます。

alt alt

ジャンプ動作

プレイヤーにさらに1つの動作を追加してください。ジャンプです。

以下の行を _unhandled_input() の最後に追加してください。

if event.is_action_pressed("jump") and is_on_floor():
    velocity.y = jump_speed

カメラ機能の改善

お気づきかもしれませんが、キャラクターが障害物近くに立っている場合、カメラが「オブジェクト内部に切り込む」(クリッピング現象)ことがあり、見た目が美しくありません。本格的な3Dカメラの実装は複雑なテーマですが、Godotに組み込まれたノードを活用することで、実用的な解決策を得ることができます。

キャラクターシーンから Camera3D を削除し、代わりに SpringArm3D を追加してください。このノードは移動可能なアームとして機能し、カメラを保持しながら衝突検知を行います。障害物がある場合は、カメラを障害物に近づけるように自動調整します。

プロパティ設定で、スプリング長さ5に、位置(0, 1, 0)に設定します。これはキャラクターの頭部に位置する値です。スプリング長さを示す黄色のラインに注意してください。カメラはこのラインに沿って移動します - 可能であれば終点まで進み、障害物がある場合はより近付く方向に動きます。

SpringArm3Dの子要素として再び Camera3D を追加し、再度ゲームを実行してみてください。スプリングアームを回転させて試してみることができます(例えばx軸を中心に少し下向きに調整するなど、好みの配置が見つかるまで自由に操作してください)。

ファーストパーソンはどう実装する?

ファーストパーソン視点での実装方法に興味がある場合は、基本FPSキャラクタ作成レシピを参照してください。先ほど書いたサードパーソン用スクリプトと共通点がありますね。

まとめ

このチュートリアルでは、より複雑なシーンの構築方法と、ユーザー操作キャラクター用の移動制御コードの書き方を学びました。また、3Dグラフィックスにおいて極めて重要な概念であるトランスフォームについても理解を深めました。これらは今後のプロジェクトで頻繁に活用する技術となるでしょう。