【Roblox】Character Controller について
はじめに
今回は、RobloxのCharacter Controllerについて紹介します。
Robloxバージョン: 0.665.0.6650685
Character Controllerとは
Character Controllerとはキャラクターの物理挙動を管理するシステムです。
Humanoidでキャラクターを動きを管理するのに対して、Character Controllerは物理挙動(例:走る、跳ぶ、歩くなど)を管理・カスタマイズすることができます。
物理挙動システムを自作したい場合や、乗り物の挙動を作成したい場合などに使用できます。
準備
今回はCreator Storeから取得したModelをCharacter Controllerを用いて移動できるようにします。
今回は試しにCreator Storeから「Pony」を取得します。
名称を「StarterCharacter」に変更しStarterPlayer直下に配置することで、ゲームプレイ中に操作できます。
このPony改めStarterCharacter以下にはHumanoidが存在しているので、この状態ですでに移動やジャンプが行えます。
Humanoid.EvaluateStateMachine
ここまでの準備の段階では、通常のキャラクターと同じでHumanoidをベースとして移動しています。
Character Controllerで物理挙動をカスタマイズするにはHumanoidの物理挙動をオフにしなければいけません。
Humanoidでは、物理挙動やステートマシンを無効化するHumanoid.EvaluateStateMachineというプロパティが用意されています。
これを変更するLocalScriptを作成し、StarterCharacterScriptsに配置します。
-- Service
local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer
local Character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()
local humanoid = Character:FindFirstChildWhichIsA("Humanoid")
humanoid.EvaluateStateMachine = false
Humanoid.EvaluateStateMachineをオフにした場合は以下の効果があります。
-
力が加わらないので、移動ができなくなる。
-
床や梯子などを検知しなくなる。
-
Humanoidがキャラクターのパーツの衝突状態を変更しなくなる。
-
HumanoidStateが自動的に変更されなくなる。(スクリプト経由で変更は可能)
-
HumanoidStateをスクリプト経由で変更した場合でも、ChagedイベントとStateイベントは呼ばれる。
- → アニメーションを管理するAnimateスクリプトは引き続き動作する。
-
HumanoidDescription、衣服、アクセサリーやその他Humanoidのレンダリング動作は無効になる。
-
Humanoidとカメラのリンクはそのままなので、カメラ挙動は引き続き動作する。
-
Humanoid.MoveDirectionは引き続き入力に応じて変更されるので、移動などで使用できる。
ざっとこのような効果があります。
Character Controllerを使用する際は物理挙動をカスタマイズしたい場合が多いと思うので、Humanoid.EvaluateStateMachine
はオフにしましょう。
今回はHumanoidがすでにエクスプローラーにあるので、プロパティから変更することもできます。
ControllerManager
ControllerManagerはCharacter Controllerを構築するために必要なインスタンスです。
ControllerManagerはRootPartを指定する必要があります。
このRootPartを基準にシミュレーションを管理するのでPartを作成しRootPartに設定します。
今回は分かりやすいように、胴体のTorsoパーツと同じ大きさ、座標の物を用意しTorsoにWeldします。
RootPartを作成しWeldする
ControllerManagerのRootPartプロパティに作成したRootPartを設定
ControllerPartSensor
ControllerPartSensorとは、Humanoidが床やはしご(TrussPart)を検出するように、他のBasePartでも検出を可能とするインスタンスです。
検出した結果をCharacter Controllerに送信する目的で使用します。
これを用いて、接地判定とはしごを検出するセンサーを作成します。
ControllerPartSensorをRootPart下に作成し、名前を分かりやすいように"GroundSensor"と"ClimbSensor"に変更します。
ControllerPartSensor.SensorModeプロパティはFloorとLadderの2種類があり、LadderはHumanoidのはしごを検出する仕組みを実行し、FloorはHumanoidの床を検出する仕組みを実行します。
GroundSensorはFloorに、ClimbSensorはLadderに変更します。
ControllerPartSensorのSearchDistanceプロパティは、ControllerPartSensorインスタンスの親のBasePartが他のBasePartを検出する距離を設定できます。
今回はRootPartの高さや大きさを考慮して、GroundSensor・ClimbSensor両方のSearchDistanceを2に設定しておきます。
Controllerの設定
先ほど設定したControllerPartSensorの親パーツとワールドのやり取りを指示するには、GroundControllerやClimbControllerのようなControllerの設定が必要です。
ControllerManagerの子オブジェクトとして、GroundControllerとClimbControllerを作成します。
GroundControllerのプロパティでは摩擦や入力終了時から停止するまでの時間など、物理挙動における各種パラメータを細かく設定できます。
今回はGroundOffsetの値をRootPartの高さを考慮して1.5に設定します。
GroundControllerのプロパティ
ControllerManagerにリンクさせる
ここまでで、RootPart、ControllerPartSensor、GroundController、ClimbControllerを作成しました。
これらをControllerManagerのプロパティにリンクさせる必要があります。
ActiveControllerプロパティをGroundControllerインスタンスにリンクします。
RootPartプロパティをRootPartという名前のパーツにリンクします。
ClimbSensorプロパティをClimbSensorインスタンスにリンクします。
GroundSensorプロパティをGroundSensorインスタンスにリンクします。
BaseMoveSpeedプロパティとBaseTurnSpeedは移動時の速度や方向切り替えの速度を変更できます。
必要があれば変更しましょう。
実際に移動させてみる
ここまでで、CharacterControllerのおおまかな設定が完了しました。
この時点では移動はできないので、移動処理を作成します。
ControllerManagerにはMovingDirectionというプロパティがあります。
この値をHumanoid.MoveDirectionと同じにすることで、入力方向に対してControllerManager.BaseMoveSpeedの速度で移動させることができます。
先ほど作成した、LocalScriptに追加でコードを記載します。
-- Service
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local LocalPlayer = Players.LocalPlayer
local Character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()
local humanoid = Character:FindFirstChildWhichIsA("Humanoid")
local ControllerManager = Character:FindFirstChildWhichIsA("ControllerManager")
-- Humanoidの初期化
humanoid.EvaluateStateMachine = false
humanoid:ChangeState(Enum.HumanoidStateType.Running)
local function onUpdate(deltaTime: number)
local desiredDirection = humanoid.MoveDirection
ControllerManager.MovingDirection = desiredDirection
if desiredDirection.Magnitude > 0 then
ControllerManager.FacingDirection = desiredDirection
else
ControllerManager.FacingDirection = ControllerManager.RootPart.CFrame.LookVector
end
humanoid:ChangeState(Enum.HumanoidStateType.Running)
end
RunService.RenderStepped:Connect(onUpdate)
RunServiceのRenderSteppedでControllerManager.MovingDirection
をHumanoid.MoveDirection
と同期させています。
また、HumanoidStateをRunningに変更することで、もともとあるアニメーションを再生するようにしています。
はしご(TrussPart)の検知
このままでは、はしご(TrussPart)の検知はできません。
理由は、CharacterManager.ActiveControllerがGroundControllerのままだからです。
CharacterManager.ActiveController
は現在使用してるControllerになります。
検知されたBasePartは、ControllerPartSensor.SensedPartから読み取ることができるので、ClimbSensor.SensedPart
が存在する場合は、ActiveControllerをClimbControllerに切り替えることではしごの昇り降りが可能になります。
さきほどのコードを、Controllerの切り替えを考慮した形に修正します。
-- Service
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local LocalPlayer = Players.LocalPlayer
local Character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()
local humanoid = Character:FindFirstChildWhichIsA("Humanoid")
local ControllerManager = Character:FindFirstChildWhichIsA("ControllerManager")
local GroundController = ControllerManager:FindFirstChildWhichIsA("GroundController")
local ClimbController = ControllerManager:FindFirstChildWhichIsA("ClimbController")
-- Humanoidの初期化
humanoid.EvaluateStateMachine = false
humanoid:ChangeState(Enum.HumanoidStateType.Running)
local function checkGround()
return ControllerManager and
ControllerManager.GroundSensor.SensedPart ~= nil and
not (ControllerManager.ActiveController == GroundController and GroundController.Active)
end
local function checkClimbing()
return ControllerManager and
ControllerManager.ClimbSensor.SensedPart ~= nil and
not (ControllerManager.ActiveController == ClimbController and ClimbController.Active)
end
local function updateActiveController()
if checkClimbing() then
ControllerManager.ActiveController = ClimbController
humanoid:ChangeState(Enum.HumanoidStateType.Climbing)
elseif checkGround() then
ControllerManager.ActiveController = GroundController
humanoid:ChangeState(Enum.HumanoidStateType.Running)
end
end
local function onUpdate(deltaTime: number)
local desiredDirection = humanoid.MoveDirection
ControllerManager.MovingDirection = desiredDirection
if desiredDirection.Magnitude > 0 then
ControllerManager.FacingDirection = desiredDirection
else
ControllerManager.FacingDirection = ControllerManager.RootPart.CFrame.LookVector
end
updateActiveController()
end
RunService.RenderStepped:Connect(onUpdate)
これにより、はしごの昇り降りが可能になりました。
(昇降のアニメーションは人用のアニメーションになっているので変になっていますが、正常に動作しています。)
今回はサンプルなので省きましたが、上記のコードにはまだ問題点があります。
接地判定とはしご判定が同時に存在する場合に毎フレームControllerが変更されたり、はしごを登り切った後に上に行けないなどです。
修正点もありますが、こういった詳細な点もカスタマイズ可能なのがCharacter Controllerの良い点だと思います。
さらに機能を追加する
今回は長くなるので割愛しましたが、GroundControllerのようにAirController、SwimControllerも存在します。
ジャンプをした際の空中にいる状態や、水に落ちた時の水中の状態などを設定する際は同様に作成可能です。
また、ControllerPartSensorにはUpdateTypeというプロパティが存在します。
今回の例やデフォルトではOnReadになっており、センサーで内部的にプロパティが上書きされています。
このUpdateTypeをManualにすることでセンサーによる内部的な感知を停止させることができます。
接地判定などをRaycastなどで独自に判断したい場合はManualにしましょう。
まとめ
-
Character Controllerとはキャラクターの物理挙動を管理・カスタマイズできるシステムである。
-
Humanoid.EvaluateStateMachine
をオフにすることで、Humanoidの物理挙動をオフにでき移動も停止させることができる。 -
ControllerManagerはCharacter Controllerを構築するために必要で、ControllerManager.MovingDirectionにVector3を入れることで、
ControllerManager.BaseMoveSpeed
を基準にした移動を行うことができる。 -
ControllerPartSensorは床やはしご(TrussPart)を検知するのに使用する。
-
ControllerPartSensor.SensedPartから検知しているBasePartを取得することが可能。
-
GroundController、ClimbController、AirController、SwimControllerはControllerPartSensorの親パーツとワールドのやり取りを指示するのに必要。
-
ControllerManagerのプロパティにてRootPartやSensorなどをリンクさせる必要がある。
-
ControllerPartSensor.UpdateTypeでは内部的にセンサーを検知するOnReadと、自作のRaycastなどで検知するManualを設定することができる。
以上がCharacter Controllerについての紹介でした。
もともと移動やジャンプなどは自動で行えますが、自作する場合は非常に詳細にカスタマイズができ便利だと思います。
ぜひCharacter Controllerを使用してみてください。
参考

当社ではRobloxを活用したゲームの開発、 また企業の商品やサービスの認知度拡大に寄与する3Dワールドの制作など、 Robloxにおける様々な活用支援を行っております。 Robloxのコンテンツ開発をご検討されている企業様は、お気軽にご相談ください。 landho.co.jp/
Discussion