Yolda Bulma

*Bu içerik, yapay zekâ (beta) kullanılarak çevrildi ve hatalar içerebilir. Sayfayı İngilizce görüntülemek için buraya tıkla.

Yolda Bulma, bir karakterin veya nesnenin (ajanın), hedefe ulaşmak için engellerin etrafında mantıksal bir yol boyunca hareket etme sürecidir; istenildiğinde tehlikeli maddelerden veya tanımlanmış bölgelerden kaçınır.

Yolda bulma yerleşimini ve hata ayıklama süreçlerini desteklemek için, Studio bir navigasyon ağı ve modifikatör etiketleri oluşturabilir. Bunları etkinleştirmek için, 3D görünümün sağ üst köşesindeki Görselleştirme Seçenekleri aracından Navigasyon ağı ve Yolda bulma modifikatörleri seçeneklerini açın.

3D görünümün sağ üst köşesinde Görselleştirme Seçenekleri düğmesinin işaretlendiği yakın çekim görüntü.

Navigasyon ağı etkinleştirildiğinde, renklendirilmiş alanlar bir karakterin yürüyebileceği veya yüzebileceği yerleri gösterir. Küçük oklar, bir karakterin zıplayarak ulaşmaya çalışacağı alanları gösterir.

Studio'da görülen navigasyon ağı

Uygulama

Yolda bulma, PathfindingService ve bununla ilişkili CreatePath() metodları üzerinden çeşitli şekillerde uygulanabilir. Bu bölüm, oyuncunun karakteri için aşağıdaki yolda bulma betiğini kullanmaktadır.

Okurken denemek için:

  1. ÖNEMLİ
    Explorer içinde StarterPlayer konteynerini seçin. Ardından, Properties penceresinde DevComputerMovementMode ve DevTouchMovementMode'yu Scriptable olarak ayarlayın.

  2. Aşağıdaki kodu LocalScript içine, StarterCharacterScripts içinde kopyalayın veya bu paketi edinin ve StarterCharacterScripts'e bırakın.

    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
    -- Compute the distance from humanoid to destination plane
    local dist = currentWaypointPlaneNormal:Dot(humanoid.RootPart.Position) - currentWaypointPlaneDistance
    -- Compute the component of the humanoid velocity that is towards the plane
    local velocity = -currentWaypointPlaneNormal:Dot(humanoid.RootPart.Velocity)
    -- Compute the threshold from the destination plane based on humanoid velocity
    local threshold = math.max(1.0, VELOCITY_MULTIPLIER * velocity)
    -- Consider waypoint reached if less then threshold in front of the plane
    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]
    -- Build destination plane from next waypoint towards current one
    currentWaypointPlaneNormal = currentWaypoint.Position - nextWaypoint.Position
    -- Set normal perpendicular to Y plane when not climbing up
    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
    -- Call your own customized function to make agent use the boat
    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()
    -- Compute the path
    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("Path not computed!", errorMessage)
    return
    end
    -- Get the path waypoints
    waypoints = path:GetWaypoints()
    -- Detect if path becomes blocked
    blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
    -- Check if the obstacle is further down the path
    if blockedWaypointIndex >= nextWaypointIndex then
    -- Stop detecting path blockage until path is re-computed
    blockedConnection:Disconnect()
    resetWaypointData()
    -- Call function to re-compute new path
    followPath()
    end
    end)
    findStartingPoint(waypoints)
    moveToNextWaypoint()
    end
    followPath()
  3. DESTINATION değişkenini (

    SATIR 5
    ) 3D dünyada oyuncu karakterinin ulaşabileceği bir Vector3 hedefi ile değiştirin.

  4. Yolda hesaplama ve karakter hareketi hakkında daha fazla bilgi edinmek için aşağıdaki bölümleri inceleyin.

Yol Oluşturma

Yolda bulma, PathfindingService ve onun CreatePath() metodu üzerinden başlatılır (

SATIRLAR 9–14
). Bu metot, karakterin (ajanın) yol boyunca nasıl hareket edeceğini ince ayar yapacak isteğe bağlı bir parametreler tablosu alır.

AnahtarAçıklamaTürVarsayılan
AgentRadiusAjanın yarıçapı, stud cinsinden. Engellerden minimum ayrımı belirlemek için yararlıdır.integer2
AgentHeightAjanın yüksekliği, stud cinsinden. Bu değerden küçük olan boş alanlar, merdiven altındaki alan gibi, geçilemez olarak işaretlenecektir.integer5
AgentCanJumpYolda bulma sırasında zıplamanın izin verilip verilmediğini belirler.booleantrue
AgentCanClimbYolda bulma sırasında TrussParts tırmanmanın izin verilen olup olmadığını belirler. Tırmanılabilir bir yol, Label adında Climb etiketine sahiptir ve maliyet olarak varsayılan değer 1'dir.booleanfalse
WaypointSpacingYolda, ara noktalar arasındaki mesafe. math.huge olarak ayarlanırsa, ara noktalar olmayacaktır.number4
CostsMalzemelerin veya tanımlı PathfindingModifiers tabloları ve geçiş maliyetleri. Ajanın belirli malzemeleri/bölgeleri diğerlerinden daha tercih etmesi için yararlıdır. Daha fazla bilgi için modifikatörlere bakın.tablenil

Yol Hesaplama

CreatePath() ile geçerli bir yol oluşturduktan sonra, bu yolun hesaplanması gerekir; bunun için Path:ComputeAsync() metodunu çağırarak hem başlangıç noktası hem de hedef olarak bir Vector3 belirtilir (

SATIRLAR 133–139
).

İki köprü arasındaki yol başlangıcı/bitişi işaretlenmiş

Path hesaplandığında, başlangıçtan sona doğru yolda iz süren bir dizi nokta içerecektir. Bu noktalar Path:GetWaypoints() metodu ile toplanabilir (

SATIR 142
). Döndürülen dizi, yol başlangıcından yol sonuna kadar olan noktalar sırasıyla dizilmiştir.

Hesaplanan yol boyunca yer alan noktalar
Hesaplanan yol boyunca yer alan noktalar

Yol Hareketi

Her PathWaypoint, bir Position (Vector3) ve Action (PathWaypointAction) içerir. Tipik bir Roblox karakteri gibi bir Humanoid içeren bir karakteri hareket ettirmek için en iyi yol, noktadan noktaya geçmek için Humanoid:Move() metodunu çağırmak ve her nokta için karakterin ulaşıp ulaşmadığını tespit etmek için betiğin isCurrentWaypointReached() geri çağırmasını kullanmaktır (

SATIRLAR 32–56
).

Engellenen Yollar

Birçok Roblox dünyası dinamik olduğundan, parçalar hareket edebilir veya düşebilir ve zeminler çökebilir. Bu, hesaplanan bir yolu engelleyebilir ve karakterin hedefe ulaşmasını engelleyebilir. Bununla başa çıkmak için, Path.Blocked olayına bağlanabilir ve engel oluşturan nesnenin etrafında yolu yeniden hesaplayabilirsiniz (

SATIRLAR 145–154
).

Yolda Bulma Modifikatörleri

Varsayılan olarak, Path:ComputeAsync() başlangıç noktasından hedefe giden en kısa yolu döndürür; ancak zıplamalardan kaçınmaya çalışır. Bu bazı durumlarda doğal görünmeyebilir; örneğin, bir yolun bataklık suyu üzerinden geçmesi, su yolunun geometrik olarak daha kısa olduğu için, etrafından dolanmaktansa geçilmesini tercih eder.

İki yol, daha kısa olan yol mantıklı olmayabilir

Yolda bulmayı daha da optimize etmek için, belirli malzemeler üzerinden, tanımlı bölgelerin etrafında veya engelleri görmezden gelmek için daha akıllı yollar hesaplamak için yolda bulma modifikatörleri uygulayabilirsiniz.

Malzeme Maliyetleri

Terrain ve BasePart malzemeleri ile çalışırken, CreatePath() içerisine bir Costs tablosu dahil ederek belirli malzemelerin diğerlerine göre daha geçilebilir olmasını sağlayabilirsiniz. Tüm malzemelerin varsayılan maliyeti 1'dir ve herhangi bir malzeme değeri math.huge olarak ayarlandığında geçilemez hale gelebilir.

Costs tablosundaki anahtarlar, Enum.Material adlarının temsil eden string isimler olmalıdır; örneğin Enum.Material.Water için Water veya Enum.Material.CrackedLava için 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
}
})

Bölgeleri Yapılandırma

Bazı durumlarda, malzeme tercihleri yeterli olmayabilir. Örneğin, karakterlerin belirli bir bölgeden kaçınmasını isteyebilirsiniz; bu, altındaki malzemelerden bağımsızdır. Bunu, bir parçaya bir PathfindingModifier nesnesi ekleyerek gerçekleştirebilirsiniz.

  1. Etkini olduğunuz bölge etrafında Anchored tipinde bir parça oluşturun ve CanCollide özelliğini false olarak ayarlayın.

    Yol bulma modifikatörlerinin uygulanacağı bir bölgeyi tanımlayan sabit parça.
  2. Parçaya bir PathfindingModifier nesnesi ekleyin, Label özelliğini bulun ve DangerZone gibi anlamlı bir isim verin.

    Label özelliği DangerZone olarak ayarlanmış PathfindingModifier örneği.
  3. CreatePath() içindeki Costs tablosuna eşleşen bir DangerZone anahtarını ve ilişkili bir sayısal değer ekleyin. Bir modifikatörü geçilemez olarak tanımlamak için değerini math.huge olarak ayarlayın.

    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
    }
    })

Engelleri Görmezden Gelme

Bazı durumlarda, katı engellerden geçmiş gibi yolda bulmak yararlı olabilir. Bu, belirli fiziksel engellerin üzerinden bir yol hesaplamanızı sağlar; aksi takdirde hesaplama tamamen başarısız olur.

  1. Bir nesnenin etrafında Anchored tipinde bir parça oluşturun ve CanCollide özelliğini false olarak ayarlayın.

    Yol bulma modifikatörünün uygulanacağı bir bölgeyi tanımlayan sabit parça.
  2. Parçaya bir PathfindingModifier nesnesi ekleyin ve PassThrough özelliğini etkinleştirin.

    PassThrough özelliği etkinleştirilmiş PathfindingModifier örneği.

    Artık, zombi NPC'den oyuncu karakterine bir yol hesaplandığında, yol kapının ötesine uzanır ve zombiyi geçmesini sağlayabilirsiniz. Zombi kapıyı açamazsa bile, kapının arkasındaki karakteri "duyuyor" gibi tepki gösterir.

    Zombie NPC'nin daha önce engelleyici olan kapının üzerine geçişi.

Yolda Bulma Bağlantıları

Bazen, normal olarak geçilemeyen bir alan üzerinden bir yol bulmak gerekebilir; örneğin bir uçurumun üzerinden geçmek ve bir sonraki noktaya ulaşmak için özel bir eylem gerçekleştirmek. Bu, PathfindingLink nesnesi aracılığıyla gerçekleştirilebilir.

Yukarıdaki örneği kullanarak, ajanın bir kayık kullanmasını sağlayabilirsiniz.

PathfindingLink, bir ajanın kayığı nasıl kullanabileceğini göstermektedir.

Bu örneği kullanarak bir PathfindingLink oluşturmak için:

  1. İSTEĞE BAĞLI
    3D görünümün sağ üst köşesindeki Görselleştirme Seçenekleri aracından Yolda Bulma bağlantılarını açın. Bu, yol bulma bağlantılarını uygularken görselleştirme ve hata ayıklama amaçları için yardımcı olur.

  2. Bir kayık koltuğuna bir tane ve kayığın iniş noktasına bir tane olmak üzere iki Attachments oluşturun.

    Pathfinding bağlantısının başlangıç ve bitişi için oluşturulan ekler.
  3. Workspace içinde bir PathfindingLink nesnesi oluşturun; ardından Attachment0 ve Attachment1 özelliklerini sırasıyla başlangıç ve bitiş eklerine atayın.

    PathfindingLink'in Attachment0/Attachment1 özellikleri. 3D dünyada görselleştirilen PathfindingLink.
  4. Label özelliğine UseBoat gibi anlamlı bir isim verin. Bu isim, ajan başlangıç bağlantı noktasına ulaştığında özel bir eylemi tetiklemek için yol bulma scriptinde bir bayrak olarak kullanılır.

    PathfindingLink için belirtilen Label özelliği.
  5. CreatePath() içinde, bir Water anahtarı ve Label özellik ipucuna uyan özel bir anahtar içeren bir Costs tablosu ekleyin. Özel anahtara, Water anahtarından daha düşük bir değer atayın.

    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() fonksiyonunda (

    SATIRLAR 93–114
    ) Label modifikatör adı için özel bir kontrol kullanarak, Humanoid:Move() işleminden farklı bir eylemi gerçekleştirebilirsiniz; bu durumda, ajanı kayığa oturtma işlevini çağırabilir, kayığı suyun üzerinden taşıyabilir, oyuncunun kayığın iniş noktasında oturmadan kalkmasını sağlayabilir ve sonra ajanın yoluna devam edebilirsiniz.

Akış Uyumluluğu

Oyun içi örnek akışı, bir oyuncunun dünyada hareket ettikçe 3D içerikleri dinamik olarak yükleyip boşaltan güçlü bir özelliktir. 3D alanda keşfederken, alanın yeni alt katmanları cihazlarına akarken mevcut katmanlardan bazıları da akmadan çıkabilir.

PathfindingService kullanımı için akış destekli oyunlarda dikkate almanız gereken en iyi uygulamalar şunlardır:

  • Akış, karakterin bir yol boyunca hareket ederken belirli bir yolu engelleyebilir veya engeli kaldırabilir. Örneğin, bir karakter bir ormandan koşarken, bir ağaç ileride bir yere akabilir ve yolu engelleyebilir. Yolda bulmanın akış ile sorunsuz çalışabilmesi için, engellenen yolları ele almak tekniğini kullanmanız ve gerekli olduğunda yolu yeniden hesaplamanız şiddetle önerilir.

  • Yolda bulmada yaygın bir yaklaşım, mevcut nesnelerin koordinatlarını hesaplama için kullanmaktır; örneğin, bir yol hedefini dünyadaki bir TreasureChest modelinin konumuna ayarlamak. Bu yaklaşım, sunucunun her zaman dünyanın tamamını görebildiğinden sunucu tarafı Scripts ile tamamen uyumludur; ancak istemcide çalışan LocalScripts ve ModuleScripts nesneleri, akıtılmamış bir nesneye doğru bir yol hesaplamaya kalkarlarsa başarısız olabilir.

    Bu sorunu gidermek için, hedefi sürekli kalıcı bir model içinde BasePart konumuna ayarlamayı düşünebilirsiniz. Kalıcı modeller, oyuncu katıldıktan sonra hemen yüklenir ve asla akmadan çıkmaz; bu nedenle, istemci tarafı bir script PersistentLoaded olayına bağlanabilir ve olay ateşlendiğinde modelde yollar oluşturarak güvenli bir şekilde erişebilir.

Sınırlamalar ve Hata Faktörleri

Yolda bulma motoru, verimli işlemeyi ve optimal performansı sağlamak için belirli sınırlamalar içerir. Ayrıca, hesaplamalar çeşitli nedenlerle başarısız olabilir; bu nedenler aşağıda açıklanmıştır.

©2026 Roblox Corporation. Roblox, the Roblox logo and Powering Imagination are among our registered and unregistered trademarks in the U.S. and other countries.