การหาทาง

*เนื้อหานี้แปลโดยใช้ AI (เวอร์ชัน Beta) และอาจมีข้อผิดพลาด หากต้องการดูหน้านี้เป็นภาษาอังกฤษ ให้คลิกที่นี่

การหาทาง คือกระบวนการเคลื่อนที่ของตัวละครหรือวัตถุ (ตัวแทน) ตามเส้นทางที่มีเหตุผลรอบอุปสรรคเพื่อไปยังจุดหมาย โดยอาจหลีกเลี่ยงวัสดุอันตรายหรือพื้นที่ที่กำหนด

การแสดงผลการนำทาง

เพื่อช่วยในการจัดเรียงและการดีบักการหาทาง Studio สามารถเรนเดอร์เมชการนำทางและ ตัวปรับ ได้ เพื่อเปิดใช้งานให้เปิดสวิตช์ Navigation mesh และ Pathfinding modifiers จาก Visualization Options วิดเจ็ตที่มุมขวาบนของมุมมอง 3D

มุมมองใกล้ของมุมมอง 3D โดยมีปุ่ม Visualization Options ระบุในมุมขวาบน.

เมื่อเปิดใช้งาน Navigation mesh พื้นที่ที่มีสีจะแสดงว่าตัวละครอาจเดินหรือว่ายน้ำได้ ลูกศรเล็กๆ แสดงพื้นที่ที่ตัวละครจะพยายามไปถึงโดยการกระโดด

เมชการนำทางแสดงใน Studio

การนำไปใช้

แม้ว่าการหาทางสามารถนำไปใช้ในหลายวิธีผ่าน PathfindingService และวิธีที่เกี่ยวข้องเช่น CreatePath() ส่วนนี้จะใช้สคริปต์การหาทางต่อไปนี้สำหรับตัวละครของผู้เล่น

เพื่อทดสอบในขณะที่อ่าน:

  1. สำคัญ
    ใน Explorer ให้เลือกคอนเทนเนอร์ StarterPlayer จากนั้นในหน้าต่าง Properties ให้ตั้งค่า DevComputerMovementMode และ DevTouchMovementMode เป็น Scriptable

  2. คัดลอกโค้ดต่อไปนี้ไปยัง LocalScript ภายใน StarterCharacterScripts หรือ รับแพ็คเกจนี้ และวางลงใน StarterCharacterScripts

    PlayerPathFollow (LocalScript in StarterCharacterScripts)
    local PathfindingService = game:GetService("PathfindingService")
    local Players = game:GetService("Players")
    local RunService = game:GetService("RunService")
    local DESTINATION = Vector3.new(20, 0.5, 20)
    local GROUND_WAIT = 0.01
    local VELOCITY_MULTIPLIER = 0.0625
    local path = PathfindingService:CreatePath({
    AgentCanClimb = true,
    Costs = {
    Water = 20
    }
    })
    local character = script.Parent
    local humanoid = character:WaitForChild("Humanoid")
    local waypoints
    local nextWaypointIndex
    local blockedConnection
    local currentWaypointReachedConnection
    local currentWaypointPlaneNormal = Vector3.zero
    local currentWaypointPlaneDistance = 0
    local pathfinderWorking = false
    local function disconnectCurrentWaypointReachedConnection()
    if not currentWaypointReachedConnection then return end
    currentWaypointReachedConnection:Disconnect()
    currentWaypointReachedConnection = nil
    end
    local function isCurrentWaypointReached()
    if humanoid.FloorMaterial == Enum.Material.Air then
    return false
    end
    local reached = false
    if currentWaypointPlaneNormal ~= Vector3.zero then
    -- คำนวณระยะห่างจากฮิวมานอยด์ไปยังพื้นผิวจุดหมาย
    local dist = currentWaypointPlaneNormal:Dot(humanoid.RootPart.Position) - currentWaypointPlaneDistance
    -- คำนวณส่วนประกอบของความเร็วฮิวมานอยด์ที่อยู่ในทิศทางของพื้นผิว
    local velocity = -currentWaypointPlaneNormal:Dot(humanoid.RootPart.Velocity)
    -- คำนวณเกณฑ์จากพื้นผิวจุดหมายตามความเร็วฮิวมานอยด์
    local threshold = math.max(1.0, VELOCITY_MULTIPLIER * velocity)
    -- พิจารณาว่าจุดหมายถึงแล้วหากน้อยกว่าเกณฑ์ที่อยู่ข้างหน้าพื้นผิว
    reached = dist < threshold
    else
    reached = true
    end
    if reached then
    currentWaypointPlaneNormal = Vector3.zero
    currentWaypointPlaneDistance = 0
    moveToNextWaypoint()
    end
    end
    local function calculateNextWaypointApproach()
    nextWaypointIndex += 1
    if nextWaypointIndex > #waypoints then
    return false
    end
    local currentWaypoint = waypoints[nextWaypointIndex - 1]
    local nextWaypoint = waypoints[nextWaypointIndex]
    -- สร้างพื้นผิวจุดหมายจากจุดหมายถัดไปไปยังจุดหมายปัจจุบัน
    currentWaypointPlaneNormal = currentWaypoint.Position - nextWaypoint.Position
    -- ตั้งค่าปกติให้ตั้งฉากกับพื้น Y เมื่อไม่ปีนขึ้น
    if nextWaypoint.Label ~= "Climb" then
    currentWaypointPlaneNormal = Vector3.new(currentWaypointPlaneNormal.X, 0, currentWaypointPlaneNormal.Z)
    end
    if currentWaypointPlaneNormal.Magnitude > 0.000001 then
    currentWaypointPlaneNormal = currentWaypointPlaneNormal.Unit
    currentWaypointPlaneDistance = currentWaypointPlaneNormal:Dot(nextWaypoint.Position)
    end
    return true
    end
    local function resetWaypointData()
    humanoid:Move(Vector3.zero)
    currentWaypointPlaneNormal = Vector3.zero
    currentWaypointPlaneDistance = 0
    disconnectCurrentWaypointReachedConnection()
    pathfinderWorking = false
    end
    local function waitForGround()
    while humanoid.FloorMaterial == Enum.Material.Air do
    task.wait(GROUND_WAIT)
    end
    end
    function moveToNextWaypoint()
    if calculateNextWaypointApproach() then
    disconnectCurrentWaypointReachedConnection()
    currentWaypointReachedConnection = RunService.Heartbeat:Connect(isCurrentWaypointReached)
    local nextWaypointPosition = waypoints[nextWaypointIndex].Position
    local nextWaypointAction = waypoints[nextWaypointIndex].Action
    humanoid:Move(nextWaypointPosition - humanoid.RootPart.Position)
    if waypoints[nextWaypointIndex + 1] and waypoints[nextWaypointIndex + 1].Label == "UseBoat" then
    nextWaypointIndex += 1
    -- เรียกฟังก์ชันที่กำหนดเองเพื่อให้ตัวแทนใช้เรือ
    elseif nextWaypointAction == Enum.PathWaypointAction.Jump then
    humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
    while humanoid.FloorMaterial ~= Enum.Material.Air do
    task.wait(GROUND_WAIT)
    end
    humanoid:Move(nextWaypointPosition - humanoid.RootPart.Position)
    end
    else
    resetWaypointData()
    end
    end
    local function findStartingPoint(waypoints)
    nextWaypointIndex = 1
    while nextWaypointIndex + 1 <= #waypoints do
    local dist = waypoints[nextWaypointIndex + 1].Position - humanoid.RootPart.Position
    dist = Vector3.new(dist.X, 0, dist.Z)
    if dist.magnitude >= 2 then
    return
    end
    nextWaypointIndex += 1
    end
    end
    local function followPath()
    -- คำนวณเส้นทาง
    pathfinderWorking = true
    waitForGround()
    local success, errorMessage = pcall(function()
    path:ComputeAsync(character.PrimaryPart.Position, DESTINATION)
    end)
    if not success or path.Status ~= Enum.PathStatus.Success then
    warn("ไม่สามารถคำนวณเส้นทาง!", errorMessage)
    return
    end
    -- รับจุดหมายของเส้นทาง
    waypoints = path:GetWaypoints()
    -- ตรวจสอบว่าทางถูกบล็อกหรือไม่
    blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
    -- ตรวจสอบว่ามีอุปสรรคอยู่ไกลออกไปในเส้นทางหรือไม่
    if blockedWaypointIndex >= nextWaypointIndex then
    -- หยุดการตรวจจับการบล็อกเส้นทางจนกว่าเส้นทางจะถูกคำนวณใหม่
    blockedConnection:Disconnect()
    resetWaypointData()
    -- เรียกฟังก์ชันเพื่อคำนวณเส้นทางใหม่
    followPath()
    end
    end)
    findStartingPoint(waypoints)
    moveToNextWaypoint()
    end
    followPath()
  3. แก้ไขตัวแปร DESTINATION (

    บรรทัด 5
    ) เป็นจุดหมาย Vector3 ภายในโลก 3D ที่ตัวละครผู้เล่นสามารถเข้าถึงได้

  4. ดำเนินการผ่านส่วนถัดไปเพื่อเรียนรู้เกี่ยวกับการคำนวณเส้นทางและการเคลื่อนที่ของตัวละคร

การสร้างเส้นทาง

การหาทางเริ่มต้นผ่าน PathfindingService และวิธี CreatePath() (

บรรทัด 9–14
) วิธีนี้รับตารางพารามิเตอร์ที่เลือกได้ซึ่งปรับแต่งวิธีที่ตัวละคร (ตัวแทน) เคลื่อนที่ตามเส้นทาง

คีย์คำอธิบายประเภทค่าเริ่มต้น
AgentRadiusรัศมีของตัวแทนในหน่วยสตัด ใช้สำหรับกำหนดการแยกขั้นต่ำจากอุปสรรคจำนวนเต็ม2
AgentHeightความสูงของตัวแทนในหน่วยสตัด พื้นที่ว่างที่มีขนาดเล็กกว่าค่านี้ เช่น พื้นที่ใต้บันได จะถูกทำเครื่องหมายว่าไม่สามารถข้ามได้จำนวนเต็ม5
AgentCanJumpกำหนดว่าการกระโดดระหว่างการหาทางอนุญาตหรือไม่บูลีนtrue
AgentCanClimbกำหนดว่าการปีน TrussParts ระหว่างการหาทางอนุญาตหรือไม่ เส้นทางที่สามารถปีนได้มี Label ชื่อว่า Climb และ ค่าใช้จ่าย สำหรับเส้นทางที่สามารถปีนได้คือ 1 โดยค่าเริ่มต้นบูลีนfalse
WaypointSpacingระยะห่างระหว่างจุดหมายกลางในเส้นทาง หากตั้งค่าเป็น math.huge จะไม่มีจุดหมายกลางจำนวน4
Costsตารางของวัสดุหรือ PathfindingModifiers ที่กำหนดและค่าใช้จ่ายสำหรับการข้าม ใช้สำหรับทำให้ตัวแทนชอบวัสดุ/พื้นที่บางอย่างมากกว่าที่อื่น ดู modifiers สำหรับรายละเอียดตารางnil

การคำนวณเส้นทาง

หลังจากที่คุณสร้างเส้นทางที่ถูกต้องด้วย CreatePath() มันต้องถูก คำนวณ โดยการเรียก Path:ComputeAsync() โดยใช้ Vector3 สำหรับทั้งจุดเริ่มต้นและจุดหมาย (

บรรทัด 133–139
)

จุดเริ่มต้น/จุดสิ้นสุดของเส้นทางที่ทำเครื่องหมายข้ามสะพานสองแห่ง

เมื่อ Path ถูกคำนวณ มันจะมีชุดของ จุดหมาย ที่ติดตามเส้นทางจากจุดเริ่มต้นไปยังจุดสิ้นสุด จุดเหล่านี้สามารถรวบรวมได้ด้วยวิธี Path:GetWaypoints() (

บรรทัด 142
) อาร์เรย์ที่ส่งกลับจะถูกจัดเรียงตามลำดับของจุดหมายจากจุดเริ่มต้นของเส้นทางไปยังจุดสิ้นสุดของเส้นทาง

จุดหมายที่ระบุข้ามเส้นทางที่คำนวณ
จุดหมายที่ระบุข้ามเส้นทางที่คำนวณ

การเคลื่อนที่ตามเส้นทาง

แต่ละ PathWaypoint ประกอบด้วยทั้ง Position (Vector3) และ Action (PathWaypointAction) เพื่อเคลื่อนที่ตัวละครที่มี Humanoid เช่น ตัวละคร Roblox ทั่วไป วิธีที่ดีที่สุดคือการเรียก Humanoid:Move() จากจุดหมายไปยังจุดหมายและใช้การเรียกกลับ isCurrentWaypointReached() ของสคริปต์ (

บรรทัด 32–56
) เพื่อตรวจจับเมื่อใดที่ตัวละครถึงแต่ละจุดหมาย

เส้นทางที่ถูกบล็อก

โลก Roblox หลายแห่งมีพลศาสตร์; ส่วนต่างๆ อาจเคลื่อนที่หรือล้มและพื้นอาจพังทลาย สิ่งนี้สามารถบล็อกเส้นทางที่คำนวณและป้องกันไม่ให้ตัวละครไปถึงจุดหมายของมัน เพื่อจัดการกับสิ่งนี้ คุณสามารถเชื่อมต่อเหตุการณ์ Path.Blocked และคำนวณเส้นทางใหม่รอบๆ สิ่งที่บล็อกมัน (

บรรทัด 145–154
)

ตัวปรับการหาทาง

โดยค่าเริ่มต้น Path:ComputeAsync() จะส่งคืนเส้นทางที่ สั้นที่สุด ระหว่างจุดเริ่มต้นและจุดหมาย โดยมีข้อยกเว้นว่ามันพยายามหลีกเลี่ยงการกระโดด สิ่งนี้ดูไม่เป็นธรรมชาติในบางสถานการณ์; ตัวอย่างเช่น เส้นทางอาจผ่านน้ำในบึงแทนที่จะรอบๆ มันเพียงเพราะเส้นทางผ่านน้ำมีความยาวทางเรขาคณิตสั้นกว่า

เส้นทางสองเส้นที่ระบุโดยเส้นทางที่สั้นกว่าไม่จำเป็นต้องมีเหตุผลมากกว่า

เพื่อเพิ่มประสิทธิภาพการหาทางให้ดียิ่งขึ้น คุณสามารถใช้ ตัวปรับการหาทาง เพื่อคำนวณเส้นทางที่ชาญฉลาดข้ามวัสดุที่หลากหลาย วัสดุ รอบๆ พื้นที่ที่กำหนด หรือ ละเว้นอุปสรรค

ค่าใช้จ่ายของวัสดุ

เมื่อทำงานกับวัสดุ Terrain และ BasePart คุณสามารถรวมตาราง Costs ภายใน CreatePath() เพื่อทำให้วัสดุบางอย่างข้ามได้ง่ายกว่าวัสดุอื่นๆ วัสดุทั้งหมดมีค่าใช้จ่ายเริ่มต้นที่ 1 และวัสดุใดๆ สามารถกำหนดให้ไม่สามารถข้ามได้โดยการตั้งค่าค่าเป็น math.huge

คีย์ในตาราง Costs ควรเป็นชื่อ สตริง ที่แสดงถึงชื่อ Enum.Material เช่น Water สำหรับ Enum.Material.Water หรือ CrackedLava สำหรับ Enum.Material.CrackedLava

PlayerPathFollow (LocalScript)
local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local DESTINATION = Vector3.new(20, 0.5, 20)
local GROUND_WAIT = 0.01
local VELOCITY_MULTIPLIER = 0.0625
local path = PathfindingService:CreatePath({
AgentCanClimb = true,
Costs = {
Water = 20, CrackedLava = 100, Slate = 20
}
})

กำหนดพื้นที่

ในบางกรณี ความชอบวัสดุ ไม่เพียงพอ ตัวอย่างเช่น คุณอาจต้องการให้ตัวละครหลีกเลี่ยง พื้นที่ที่กำหนด โดยไม่คำนึงถึงวัสดุที่อยู่ใต้เท้า สิ่งนี้สามารถทำได้โดยการเพิ่มวัตถุ PathfindingModifier ลงในส่วน

  1. สร้างส่วน Anchored รอบๆ พื้นที่และตั้งค่าคุณสมบัติ CanCollide เป็น false

    ส่วนที่ถูกยึดซึ่งกำหนดพื้นที่เพื่อใช้ตัวปรับการหาทาง.
  2. แทรกอินสแตนซ์ PathfindingModifier ลงในส่วน ค้นหาคุณสมบัติ Label และกำหนดชื่อที่มีความหมายเช่น DangerZone

    อินสแตนซ์ PathfindingModifier ที่มีคุณสมบัติ Label ตั้งค่าเป็น DangerZone.
  3. รวมคีย์ DangerZone ที่ตรงกันและค่าตัวเลขที่เกี่ยวข้องภายในตาราง Costs ของ CreatePath() ตัวปรับสามารถกำหนดให้ไม่สามารถข้ามได้โดยการตั้งค่าค่าเป็น math.huge

    PlayerPathFollow (LocalScript)
    local PathfindingService = game:GetService("PathfindingService")
    local Players = game:GetService("Players")
    local RunService = game:GetService("RunService")
    local DESTINATION = Vector3.new(20, 0.5, 20)
    local GROUND_WAIT = 0.01
    local VELOCITY_MULTIPLIER = 0.0625
    local path = PathfindingService:CreatePath({
    AgentCanClimb = true,
    Costs = {
    DangerZone = math.huge, Water = 20, CrackedLava = 20, Slate = 20
    }
    })

ละเว้นอุปสรรค

ในบางกรณี การหาทางผ่านอุปสรรคที่เป็นของแข็งเป็นสิ่งที่มีประโยชน์เหมือนกับว่ามันไม่มีอยู่ สิ่งนี้ช่วยให้คุณคำนวณเส้นทางผ่านตัวบล็อกทางกายภาพเฉพาะ แทนที่จะทำให้การคำนวณล้มเหลวโดยตรง

  1. สร้างส่วน Anchored รอบๆ วัตถุและตั้งค่าคุณสมบัติ CanCollide เป็น false

    ส่วนที่ถูกยึดซึ่งกำหนดพื้นที่เพื่อใช้ตัวปรับการหาทาง.
  2. แทรกอินสแตนซ์ PathfindingModifier ลงในส่วนและเปิดใช้งานคุณสมบัติ PassThrough

    อินสแตนซ์ PathfindingModifier ที่มีคุณสมบัติ PassThrough เปิดใช้งาน.

    ตอนนี้เมื่อมีการคำนวณเส้นทางจาก NPC ซอมบี้ไปยังตัวละครผู้เล่น เส้นทางจะขยายออกไปนอกประตูและคุณสามารถกระตุ้นให้ซอมบี้ข้ามมันได้ แม้ว่าซอมบี้จะไม่สามารถเปิดประตูได้ แต่ก็จะตอบสนองเหมือนกับที่ "ได้ยิน" ตัวละครอยู่หลังประตู

    เส้นทางของ NPC ซอมบี้ที่ผ่านประตูที่เคยบล็อกอยู่.

ลิงก์การหาทาง

บางครั้งจำเป็นต้องหาทางข้ามพื้นที่ที่ไม่สามารถข้ามได้ตามปกติ เช่น ข้ามช่องว่าง และทำการกระทำที่กำหนดเองเพื่อไปยังจุดหมายถัดไป สิ่งนี้สามารถทำได้ผ่านวัตถุ PathfindingLink

โดยใช้ตัวอย่างจากข้างต้น คุณสามารถทำให้ตัวแทนใช้เรือ

PathfindingLink แสดงให้เห็นว่าตัวแทนสามารถใช้เรือได้อย่างไร.

ในการสร้าง PathfindingLink โดยใช้ตัวอย่างนี้:

  1. ตัวเลือก
    เปิดใช้งาน Pathfinding links จาก Visualization Options วิดเจ็ตที่มุมขวาบนของมุมมอง 3D สิ่งนี้ช่วยในการแสดงผลและการดีบักเมื่อใช้ลิงก์การหาทาง

  2. สร้าง Attachments สองตัว หนึ่งตัวบนที่นั่งของเรือและอีกหนึ่งตัวใกล้จุดลงจอดของเรือ

    การแนบที่สร้างขึ้นสำหรับจุดเริ่มต้นและจุดสิ้นสุดของลิงก์การหาทาง.
  3. สร้างวัตถุ PathfindingLink ในพื้นที่ทำงาน จากนั้นกำหนดคุณสมบัติ Attachment0 และ Attachment1 ให้กับการแนบจุดเริ่มต้นและจุดสิ้นสุดตามลำดับ

    คุณสมบัติ Attachment0/Attachment1 ของ PathfindingLink. PathfindingLink แสดงในโลก 3D.
  4. กำหนดชื่อที่มีความหมายเช่น UseBoat ให้กับคุณสมบัติ Label ของมัน ชื่อนี้ใช้เป็นธงในสคริปต์การหาทางเพื่อกระตุ้นการกระทำที่กำหนดเองเมื่อเอเจนต์ไปถึงจุดเริ่มต้นของลิงก์

    คุณสมบัติ Label ที่ระบุสำหรับ PathfindingLink.
  5. รวมตาราง Costs ภายใน CreatePath() ที่มีทั้งคีย์ Water และคีย์ที่กำหนดเองที่ตรงกับชื่อคุณสมบัติ Label กำหนดให้คีย์ที่กำหนดเองมีค่าต่ำกว่า Water

    PlayerPathFollow (LocalScript)
    local PathfindingService = game:GetService("PathfindingService")
    local Players = game:GetService("Players")
    local RunService = game:GetService("RunService")
    local DESTINATION = Vector3.new(20, 0.5, 20)
    local GROUND_WAIT = 0.01
    local VELOCITY_MULTIPLIER = 0.0625
    local path = PathfindingService:CreatePath({
    AgentCanClimb = true,
    Costs = {
    UseBoat = 2, Water = 20
    }
    })
  6. ในฟังก์ชัน moveToNextWaypoint() (

    บรรทัด 93–114
    ) สามารถใช้การตรวจสอบที่กำหนดเองสำหรับชื่อโมดิฟายเออร์ Label เพื่อทำการกระทำที่แตกต่างจาก Humanoid:Move() ในกรณีนี้ คุณอาจเรียกฟังก์ชันเพื่อให้ตัวแทนได้นั่งในเรือ เคลื่อนที่เรือข้ามน้ำ ปลดที่นั่งตัวแทนที่จุดลงจอดของเรือ และจากนั้นดำเนินการเส้นทางของตัวแทนไปยังจุดหมายสุดท้ายของมัน

ความเข้ากันได้กับการสตรีม

การสตรีม อินสแตนซ์ในเกม เป็นฟีเจอร์ที่ทรงพลังซึ่งโหลดและปลดโหลดเนื้อหา 3D อย่างไดนามิกเมื่อผู้เล่นเคลื่อนที่ไปรอบๆ โลก ขณะที่พวกเขาสำรวจพื้นที่ 3D ชุดย่อยใหม่ของพื้นที่จะสตรีมไปยังอุปกรณ์ของพวกเขาและบางส่วนของชุดย่อยที่มีอยู่บางส่วนอาจสตรีมออก

พิจารณาข้อปฏิบัติที่ดีที่สุดต่อไปนี้สำหรับการใช้ PathfindingService ในเกมที่เปิดใช้งานการสตรีม:

  • การสตรีมสามารถบล็อกหรือปลดบล็อกเส้นทางที่กำหนดเมื่อมีตัวละครเคลื่อนที่ไปตามเส้นทางนั้น ตัวอย่างเช่น ขณะที่ตัวละครวิ่งผ่านป่า ต้นไม้หนึ่งอาจสตรีมเข้ามาที่ไหนสักแห่งข้างหน้าและขัดขวางเส้นทาง เพื่อให้การหาทางทำงานได้อย่างราบรื่นกับการสตรีม แนะนำอย่างยิ่งให้คุณใช้เทคนิค การจัดการเส้นทางที่ถูกบล็อก และคำนวณเส้นทางใหม่เมื่อจำเป็น

  • วิธีการทั่วไปในการหาทางคือการใช้พิกัดของวัตถุที่มีอยู่สำหรับ การคำนวณ เช่น การตั้งค่าจุดหมายเส้นทางไปยังตำแหน่งของโมเดล TreasureChest ที่มีอยู่ในโลก วิธีนี้เข้ากันได้อย่างสมบูรณ์กับ Scripts ฝั่งเซิร์ฟเวอร์ เนื่องจากเซิร์ฟเวอร์มีมุมมองเต็มรูปแบบของโลกตลอดเวลา แต่ LocalScripts และ ModuleScripts ที่ทำงานบนไคลเอนต์อาจล้มเหลวหากพวกเขาพยายามคำนวณเส้นทางไปยังวัตถุที่ยังไม่ได้สตรีม

    เพื่อแก้ไขปัญหานี้ ให้พิจารณาตั้งค่าจุดหมายไปยังตำแหน่งของ BasePart ภายในโมเดล ถาวร โมเดลถาวรจะโหลดทันทีหลังจากผู้เล่นเข้าร่วมและจะไม่ถูกสตรีมออก ดังนั้นสคริปต์ฝั่งไคลเอนต์สามารถเชื่อมต่อกับเหตุการณ์ PersistentLoaded และเข้าถึงโมเดลเพื่อสร้างจุดหมายหลังจากเหตุการณ์เกิดขึ้น

ข้อจำกัดและปัจจัยที่ทำให้ล้มเหลว

เอนจินการหาทางมีข้อจำกัดเฉพาะเพื่อให้แน่ใจว่ามีการประมวลผลที่มีประสิทธิภาพและประสิทธิภาพที่ดีที่สุด นอกจากนี้การคำนวณการหาทาง การคำนวณ อาจล้มเหลวด้วยเหตุผลหลายประการตามที่ระบุไว้ด้านล่าง

©2026 Roblox Corporation. Roblox, โลโก้ Roblox และ Powering Imagination เป็นส่วนหนึ่งของเครื่องหมายการค้าที่จดทะเบียน และไม่ได้จดทะเบียนของเราในสหรัฐฯ และประเทศอื่นๆ