キャラクターパスファインディング

*このコンテンツは、ベータ版のAI(人工知能)を使用して翻訳されており、エラーが含まれている可能性があります。このページを英語で表示するには、 こちら をクリックしてください。

パスファインディング は、キャラクターを論理的なパスに移動させるプロセスで、障害物や (オプションで) 危険な材料や定義された領域を避けます。

ナビゲーションビジュアライズ

パスファインディングレイアウトとデバッグを助けるために、Studio はナビゲーションメッシュと 変更者 レーベルをレンダリングできます。有効にするには、 ナビゲーションメッシュ と 変更者 レーベルを 2>ビジュアル化オプション2> ウィジェ

A close up view of the 3D viewport with the Visualization Options button indicated in the upper-right corner.

ナビゲーションメッシュを有効にすると、色付きのエリアは、キャラクターが歩水泳か、Swim する場所を表示し、色付きのエリアは、ジャンプして、AgentCanJump をAgentCanJump に設定した場合、パスを作成すると、小さな矢印が、キャラクターがジャンプし、 True</

Navigation mesh showing in Studio

パスファインドモジュール を有効にすると、テキストラベルは パスファインドモジュール を使用する際に考慮される特定の材料と領域を指し示します。

Navigation labels showing on navigation mesh

既知の限定

パスファインド機能は、効率的な処理と最高パフォーマンスを保証するための制限を特定します。

縦型配置の制限

パスファインド計算は、特定の垂直境界内のパーツだけを考慮します:

  • 境界下限 — 下位の Y 座標が -65,536 より小さいパーツは無視されます。
  • アッパーバウンドリー — 上限 Y コーディネートのパーツは、65,536スタッドを超えているため無視されます。
  • 垂直スパン — 最下部の底からの垂直距離 Y コーディネートから最上部のトップ Y コーディネートまでの垂直距離; 65,536スタッドを超えると、パス検索システムは、パス検索コンピューターのパス検索コンピューターでパス検索コンピューターを無視します。

検索距離制限

パスファインドから開始して最終点までの直接視界距離は 3,000 スタッドを超えてはなりません。この距離を超えると、NoPath ステータスが結果となりま状況。

パスを作成中

パス検索は、PathfindingService とその CreatePath() 機能を通じて始動されます。

ローカルスクリプト

local PathfindingService = game:GetService("PathfindingService")
local path = PathfindingService:CreatePath()

CreatePath() は、キャラクター (エージェント) がパスをどのように移動するかを調整するオプションのパラメーターのテーブルを受け入れます。

キー説明タイプデフォルト
AgentRadiusエージェント範囲、in studs。障害からの最小限の分離を決定するのに便利。整数2
AgentHeightエージェントの高さ、in studs。空きスペースがこの値より小さい、例えば階段の下のスペースのように、非乗り越え可能であることが示されます。整数5
AgentCanJumpパスファインド中にジャンプすることが許可されていますか。ブールーンtrue
AgentCanClimbパスファインド中に TrussParts をクライムすることが許可されています。ブールーンfalse
WaypointSpacingパス内のインターミディエートポイント間のスペース。如果math.huge を設定すると、中間のウェイポイントはありません。番号4
Costs材料の表または定義された PathfindingModifiers とそのコストで移動。 ユーザーエージェントが特定の材料/領域を他の領域より好むようにするのに便利。 「modifiers」で詳細を参照してください。テーブルnil
ローカルスクリプト

local PathfindingService = game:GetService("PathfindingService")
local path = PathfindingService:CreatePath({
AgentRadius = 3,
AgentHeight = 6,
AgentCanJump = false,
Costs = {
Water = 20
}
})

エージェントがパスファインド中に TrussParts をクライムすることがあります。これは、パスを作成するときに AgentCanClimbtrue に設定した場

Path going up a climbable TrussPart ladder
ローカルスクリプト - トラスの登りパス

local PathfindingService = game:GetService("PathfindingService")
local path = PathfindingService:CreatePath({
AgentCanClimb = true,
Costs = {
Climb = 2 -- 登り坂のコスト; デフォルトは 1
}
})

パスに沿って移動

このセクションでは、プレイヤーのキャラクターのために次のパスファインドスクリプトを使用します。読み込み中にテストするには:

  1. コードを LocalScript 内の StarterCharacterScripts にコピーします。
  2. 11行を Vector3 に編集し、プレイヤーキャラクターが到達できるデスティネーション。
  3. 次のセクションを通じて、パス計算とキャラクターの移動について学びましょう。
ローカルスクリプト - キャラクターパスファインド

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local path = PathfindingService:CreatePath()
local player = Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local TEST_DESTINATION = Vector3.new(100, 0, 100)
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local function followPath(destination)
-- パスを計算
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- パスウェイポイントを取得する
waypoints = path:GetWaypoints()
-- パスがブロックされるかどうかを検出
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- 障害物がパスをさらに下にあるかどうかチェック
if blockedWaypointIndex >= nextWaypointIndex then
-- パスが再計算されるまで、パスブロックを検出しないでください
blockedConnection:Disconnect()
-- 新しいパスを再計算するための関数を呼び出す
followPath(destination)
end
end)
-- 次の移動ポイントへの移動が完了したときに検出
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- ウェイポイントインデックスを増加し、次のウェイポイントに移動する
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- 最開始に 2番目のウェイポイントに移動します (最初のウェイポイントはパススタートです)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
followPath(TEST_DESTINATION)

パスを計算する

有効なパスを作成した後、CreatePath() を含む、必要なパスを計算する必要があります。 Datatype.Vector3 の両方の開始点と目的地の両方で、Path:ComputeAsync() を呼び出してください。

ローカルスクリプト - キャラクターパスファインド

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local path = PathfindingService:CreatePath()
local player = Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local TEST_DESTINATION = Vector3.new(100, 0, 100)
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local function followPath(destination)
-- パスを計算
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
end
Path start/end marked on series of islands and bridges

ウェイポイントを取得する

Class.Patパス が計算されると、 通路 が開始から終了までを追跡するシリーズの Path:GetWaypoints() が含まれます。これらのポイントは、1>Class.Patパス:GetWaypoints()1> 関数で集めることができます。

ローカルスクリプト - キャラクターパスファインド

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local path = PathfindingService:CreatePath()
local player = Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local TEST_DESTINATION = Vector3.new(100, 0, 100)
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local function followPath(destination)
-- パスを計算
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- パスウェイポイントを取得する
waypoints = path:GetWaypoints()
end
end
Waypoints indicated across computed path
計算されたパスに指定されたウェイポイント

パス移動

各ウェイポイントは、位置 ( Vector3 ) とアクション ( 2> Class.Humanoid:MoveTo

ローカルスクリプト - キャラクターパスファインド

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local path = PathfindingService:CreatePath()
local player = Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local TEST_DESTINATION = Vector3.new(100, 0, 100)
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local function followPath(destination)
-- パスを計算
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- パスウェイポイントを取得する
waypoints = path:GetWaypoints()
-- パスがブロックされるかどうかを検出
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- 障害物がパスをさらに下にあるかどうかチェック
if blockedWaypointIndex >= nextWaypointIndex then
-- パスが再計算されるまで、パスブロックを検出しないでください
blockedConnection:Disconnect()
-- 新しいパスを再計算するための関数を呼び出す
followPath(destination)
end
end)
-- 次の移動ポイントへの移動が完了したときに検出
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- ウェイポイントインデックスを増加し、次のウェイポイントに移動する
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- 最開始に 2番目のウェイポイントに移動します (最初のウェイポイントはパススタートです)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end

ブロックされたパスを処理する

多くの Roblox 世界はダイナミックです。部品が移動したり、床が落ちたりする可能性があります。これは、Path.Blocked イベントを接続し、キャラクターが目的地に到達するを防ぐことができます。これを処理するには、Class.Path.Blockedイベントを接続し、ブロックされたパスを再コンピュートします。

ローカルスクリプト - キャラクターパスファインド

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local path = PathfindingService:CreatePath()
local player = Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local TEST_DESTINATION = Vector3.new(100, 0, 100)
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local function followPath(destination)
-- パスを計算
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- パスウェイポイントを取得する
waypoints = path:GetWaypoints()
-- パスがブロックされるかどうかを検出
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- 障害物がパスをさらに下にあるかどうかチェック
if blockedWaypointIndex >= nextWaypointIndex then
-- パスが再計算されるまで、パスブロックを検出しないでください
blockedConnection:Disconnect()
-- 新しいパスを再計算するための関数を呼び出す
followPath(destination)
end
end)
end
end

パスファインディングの修正

デフォルトでは、Path:ComputeAsync() は、スタート地点と目的地の間の最短の パス を返しますが、ジャンプを避けようとします。これは、いくつかの状況で不自然に見えます - たとえば、水の上をジャンプするよりも、パスを水の上をジオメトリ的に短くするために移動することがありま

Two paths indicated with the shorter path not necessarily more logical

さらにパス検索を最適化するために、パス検索モディファイアーを実装して、さまざまな 素材 、領域 、または 2>障害物2> の周りでより賢いパスを計算できます。

素材コストを設定

Class.Terrain と BasePart 素材を使用しているときは、Costs テーブルを含めることができます。1>Class.PathfindingService:CreatePath()|CreatePath()1> 内のす

Costs テーブルにあるキーは、Enum.Material 名前を表示するストリング名でなければなりません。たとえば、Water は、1>Enums.Material.Water1> 名前のための4>Cost4>です。

ローカルスクリプト - キャラクターパスファインド

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local path = PathfindingService:CreatePath({
Costs = {
Water = 20,
Mud = 5,
Neon = math.huge
}
})

領域と協力

In some cases, 材料の好み は十分ではありません。たとえば、キャラクターが 定義された領域 を避ける必要がある場合などです。これは、PathfindingModifier オブジェクトを追加することで達成できます。

  1. 危険な領域周辺の Anchored パーツを作成し、CanCollide プロパティを false に設定します。

    Anchored part defining a region to apply a pathfinding modifier to
  2. 部品に PathfindingModifier インスタンスを挿入し、Label プロパティを見つけ、 危険ゾーン のような名前を割り当てます。

    PathfindingModifier instance with Label property set to DangerZone
  3. Inклюide a Costs table within CreatePath() containing a matching key and associating numeric value. A modifier can be defined as non-traversable by setting its value to math.huge .

    ローカルスクリプト - キャラクターパスファインド

    local PathfindingService = game:GetService("PathfindingService")
    local Players = game:GetService("Players")
    local RunService = game:GetService("RunService")
    local path = PathfindingService:CreatePath({
    Costs = {
    DangerZone = math.huge
    }
    })

障害物を無視する

場合により、実在しないと思われる障害物をパスファインドすることが便利です。これにより、特定の物理ブロックを通過するパスを計算でき、失敗した計算を完了することなく済みます。

  1. オブジェクトの周りに Anchored パーツを作成し、CanCollide プロパティを false に設定します。

    Anchored part defining a region to apply a pathfinding modifier to
  2. 部品に PathfindingModifier インスタンスを挿入し、PassThrough プロパティを有効にします。

    PathfindingModifier instance with PassThrough property enabled

    さあ、ゾンビ NPC からプレイヤーキャラクターへのパスが計算されると、パスはドアを超えて拡張され、ゾンビがそれをトラベルするように促します。ゾンビがドアを開けることができない場合でも、ドアの後ろのキャラクターを「聞こう」として反応します。

    Zombie NPC path passing through the previously blocking door

パスファインドリンク

通常は通過できない空間のパスを見つける必要があります。たとえば、渓谷のように。PathfindingLink オブジェクトを通じて、次の方位点に到達するカスタムアクションを実装できます。これは、Class.PathfindingLink オブジェクトを通じて実装できます。

上の島の例を使用すると、エージェントがすべての橋を歩く代わりにボートを使用できます。

PathfindingLink showing how an agent can use a boat instead of walking across all of the bridges

この例を使用して PathfindingLink を作成するには:

  1. 視覚化とデバッグをサポートするために、 パスファインドリンク をオプションビューポートの右上隅の ビジュアルオプション ウィジェットから切り替えます。

  2. ボートの座席に一つ、ボートの着陸ポイントの近くに一つの Attachments を作成します。

    Attachments created for pathfinding link's start and end
  3. ワークスペースに PathfindingLink オブジェクトを作成し、 アタッチメント0アタッチメント1 プロパティをスタートと終了のアタッチメントにそれぞれ割り当てます。

    Attachment0/Attachment1 properties of a PathfindingLink PathfindingLink visualized in the 3D world
  4. ボートの名前を含めた有意義な名前を UseBoat に、 Label プロパティに割り当てます。この名前は、パス検索スクリプトでフラグとして使用されて、エージェントが開始リンクポイントに到達すると、カスタムアクションをトリガーするようになります。

    Label property specified for PathfindingLink
  5. In include a Costs table within CreatePath() 含めて、Water キーとカスタムキーを含む、1> Class.PathfindingLink.Label|Label1> プロパティ名に一致するカスタムキーを含める。4> Water4> を

    ローカルスクリプト - キャラクターパスファインド

    local PathfindingService = game:GetService("PathfindingService")
    local Players = game:GetService("Players")
    local RunService = game:GetService("RunService")
    local path = PathfindingService:CreatePath({
    Costs = {
    Water = 20,
    UseBoat = 1
    }
    })
  6. Class.PathfindingLink.Label|Label モジュール名を変更すると、Humanoid:MoveTo() の代わりに、Class.PathfindingLink.Label|Label の名前を追加し、1>Class.Humanoid:MoveTo()1> の代わりに別のアクションを実行します。この場合、4>Class.Human

    ローカルスクリプト - キャラクターパスファインド

    local PathfindingService = game:GetService("PathfindingService")
    local Players = game:GetService("Players")
    local RunService = game:GetService("RunService")
    local path = PathfindingService:CreatePath({
    Costs = {
    Water = 20,
    UseBoat = 1
    }
    })
    local player = Players.LocalPlayer
    local character = player.Character
    local humanoid = character:WaitForChild("Humanoid")
    local TEST_DESTINATION = Vector3.new(228.9, 17.8, 292.5)
    local waypoints
    local nextWaypointIndex
    local reachedConnection
    local blockedConnection
    local function followPath(destination)
    -- パスを計算
    local success, errorMessage = pcall(function()
    path:ComputeAsync(character.PrimaryPart.Position, destination)
    end)
    if success and path.Status == Enum.PathStatus.Success then
    -- パスウェイポイントを取得する
    waypoints = path:GetWaypoints()
    -- パスがブロックされるかどうかを検出
    blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
    -- 障害物がパスをさらに下にあるかどうかチェック
    if blockedWaypointIndex >= nextWaypointIndex then
    -- パスが再計算されるまで、パスブロックを検出しないでください
    blockedConnection:Disconnect()
    -- 新しいパスを再計算するための関数を呼び出す
    followPath(destination)
    end
    end)
    -- 次の移動ポイントへの移動が完了したときに検出
    if not reachedConnection then
    reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
    if reached and nextWaypointIndex < #waypoints then
    -- ウェイポイントインデックスを増加し、次のウェイポイントに移動する
    nextWaypointIndex += 1
    -- ボートが使用されている場合は、「ボートを使用」ラベルです。そうでない場合は、次のボートに移動します
    if waypoints[nextWaypointIndex].Label == "UseBoat" then
    useBoat()
    else
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    else
    reachedConnection:Disconnect()
    blockedConnection:Disconnect()
    end
    end)
    end
    -- 最開始に 2番目のウェイポイントに移動します (最初のウェイポイントはパススタートです)
    nextWaypointIndex = 2
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    else
    warn("Path not computed!", errorMessage)
    end
    end
    function useBoat()
    local boat = workspace.BoatModel
    humanoid.Seated:Connect(function()
    -- エージェントが座っている場合は、ボートを開始します
    if humanoid.Sit then
    task.wait(1)
    boat.CylindricalConstraint.Velocity = 5
    end
    -- 島との関係で制限位置を検出する
    local boatPositionConnection
    boatPositionConnection = RunService.PostSimulation:Connect(function()
    -- 島の隣にボートを停止する
    if boat.CylindricalConstraint.CurrentPosition >= 94 then
    boatPositionConnection:Disconnect()
    boat.CylindricalConstraint.Velocity = 0
    task.wait(1)
    -- エージェントを降りると続行します
    humanoid.Sit = false
    humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
    end
    end)
    end)
    end
    followPath(TEST_DESTINATION)

ストリーミングの対応

In-experience インスタンスストリーミング は、プレイヤーのキャラクターが世界中で動くたびに 3D コンテンツを動的に読み込み、読み込み直します。スペースストリームをそのデバイスにストリームアウトするための新しいサブセットと、既存のサブセットの一部がストリームアウトする可能性があります。

ストリーミング有効のエクスペリエンスで PathfindingService を使用するための次のベストプラクティスを考慮してください:

  • ストリーミングは、キャラクターがそのパスを沿って移動すると、ブロックまたはアンブロックすることができるパスをブロックまたはアンブロックできます。たとえば、キャラクターが森林を走り抜くと、木が前方の場所にストリームされ、パスを邪魔します。ストリーミングをスムーズにパスファイン

  • パス検索の共通のアプローチは、計算、パスの目的地を現存の 宝箱 モデルの位置に設定、など、世界中のサーバーか

    この問題に対処するために、BasePart を持つ目的地を持つ persistent モデル内の PersistentLoaded の位置を設定することを検討してください。持続モデルは、プレイヤーが参加するとすぐに読み込まれ、イベントが終了すると永続モデルにアク