Yol Bulma, bir karakterin veya nesnenin (ajan) bir hedefe ulaşmak için engeller etrafında mantıksal bir yol boyunca hareket etme sürecidir; isteğe bağlı olarak tehlikeli maddelerden veya tanımlı bölgelerden kaçınabilir.
Navigasyon görselleştirmesi
Yol bulma düzeni ve hata ayıklama konusunda yardımcı olmak için, Studio bir navigasyon ağı ve modifikatör etiketleri oluşturabilir. Bunları etkinleştirmek için, 3D görünüm alanının sağ üst köşesindeki Görselleştirme Seçenekleri aracından Navigasyon ağı ve Yol Bulma modifikatörleri seçeneklerini açın.

Navigasyon ağı etkinleştirildiğinde, renkli 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.

Uygulama
Yol bulma, PathfindingService ve CreatePath() gibi ilişkili yöntemler aracılığıyla çeşitli şekillerde uygulanabilir; bu bölüm, oyuncunun karakteri için aşağıdaki yol bulma betiğini kullanır.
Okurken test etmek için:
- ÖNEMLİExplorer içinde StarterPlayer konteynerini seçin. Ardından, Özellikler penceresinde DevComputerMovementMode ve DevTouchMovementMode değerlerini Scriptable olarak ayarlayın.


Aşağıdaki kodu LocalScript içine StarterCharacterScripts içinde kopyalayın veya bu paketi alın ve StarterCharacterScripts içine bırakın.
PlayerPathFollow (StarterCharacterScripts içindeki 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.01local VELOCITY_MULTIPLIER = 0.0625local path = PathfindingService:CreatePath({AgentCanClimb = true,Costs = {Water = 20}})local character = script.Parentlocal humanoid = character:WaitForChild("Humanoid")local waypointslocal nextWaypointIndexlocal blockedConnectionlocal currentWaypointReachedConnectionlocal currentWaypointPlaneNormal = Vector3.zerolocal currentWaypointPlaneDistance = 0local pathfinderWorking = falselocal function disconnectCurrentWaypointReachedConnection()if not currentWaypointReachedConnection then return endcurrentWaypointReachedConnection:Disconnect()currentWaypointReachedConnection = nilendlocal function isCurrentWaypointReached()if humanoid.FloorMaterial == Enum.Material.Air thenreturn falseendlocal reached = falseif currentWaypointPlaneNormal ~= Vector3.zero then-- Humanoid ile hedef düzlem arasındaki mesafeyi hesaplalocal dist = currentWaypointPlaneNormal:Dot(humanoid.RootPart.Position) - currentWaypointPlaneDistance-- Humanoid hızının düzleme doğru olan bileşenini hesaplalocal velocity = -currentWaypointPlaneNormal:Dot(humanoid.RootPart.Velocity)-- Humanoid hızına dayalı olarak hedef düzlemden hesaplanan eşiklocal threshold = math.max(1.0, VELOCITY_MULTIPLIER * velocity)-- Düzlemin önünde eşik değerinden daha azsa waypoint'in ulaşıldığını kabul etreached = dist < thresholdelsereached = trueendif reached thencurrentWaypointPlaneNormal = Vector3.zerocurrentWaypointPlaneDistance = 0moveToNextWaypoint()endendlocal function calculateNextWaypointApproach()nextWaypointIndex += 1if nextWaypointIndex > #waypoints thenreturn falseendlocal currentWaypoint = waypoints[nextWaypointIndex - 1]local nextWaypoint = waypoints[nextWaypointIndex]-- Mevcut olanın yanına gelecek şekilde bir düzlem oluşturcurrentWaypointPlaneNormal = currentWaypoint.Position - nextWaypoint.Position-- Yukarı tırmanmıyorsanız Y düzlemine dik normal ayarlayınif nextWaypoint.Label ~= "Climb" thencurrentWaypointPlaneNormal = Vector3.new(currentWaypointPlaneNormal.X, 0, currentWaypointPlaneNormal.Z)endif currentWaypointPlaneNormal.Magnitude > 0.000001 thencurrentWaypointPlaneNormal = currentWaypointPlaneNormal.UnitcurrentWaypointPlaneDistance = currentWaypointPlaneNormal:Dot(nextWaypoint.Position)endreturn trueendlocal function resetWaypointData()humanoid:Move(Vector3.zero)currentWaypointPlaneNormal = Vector3.zerocurrentWaypointPlaneDistance = 0disconnectCurrentWaypointReachedConnection()pathfinderWorking = falseendlocal function waitForGround()while humanoid.FloorMaterial == Enum.Material.Air dotask.wait(GROUND_WAIT)endendfunction moveToNextWaypoint()if calculateNextWaypointApproach() thendisconnectCurrentWaypointReachedConnection()currentWaypointReachedConnection = RunService.Heartbeat:Connect(isCurrentWaypointReached)local nextWaypointPosition = waypoints[nextWaypointIndex].Positionlocal nextWaypointAction = waypoints[nextWaypointIndex].Actionhumanoid:Move(nextWaypointPosition - humanoid.RootPart.Position)if waypoints[nextWaypointIndex + 1] and waypoints[nextWaypointIndex + 1].Label == "UseBoat" thennextWaypointIndex += 1-- Ajanın botu kullanmasını sağlamak için kendi özelleştirilmiş fonksiyonunuzu çağırınelseif nextWaypointAction == Enum.PathWaypointAction.Jump thenhumanoid:ChangeState(Enum.HumanoidStateType.Jumping)while humanoid.FloorMaterial ~= Enum.Material.Air dotask.wait(GROUND_WAIT)endhumanoid:Move(nextWaypointPosition - humanoid.RootPart.Position)endelseresetWaypointData()endendlocal function findStartingPoint(waypoints)nextWaypointIndex = 1while nextWaypointIndex + 1 <= #waypoints dolocal dist = waypoints[nextWaypointIndex + 1].Position - humanoid.RootPart.Positiondist = Vector3.new(dist.X, 0, dist.Z)if dist.magnitude >= 2 thenreturnendnextWaypointIndex += 1endendlocal function followPath()-- Yolu hesaplapathfinderWorking = truewaitForGround()local success, errorMessage = pcall(function()path:ComputeAsync(character.PrimaryPart.Position, DESTINATION)end)if not success or path.Status ~= Enum.PathStatus.Success thenwarn("Yol hesaplanamadı!", errorMessage)returnend-- Yol noktalarını alwaypoints = path:GetWaypoints()-- Yolun engellendiğini tespit etblockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)-- Engel yolun daha ilerinde mi kontrol etif blockedWaypointIndex >= nextWaypointIndex then-- Yol yeniden hesaplanana kadar yol engelini tespit etmeyi durdurblockedConnection:Disconnect()resetWaypointData()-- Yeni yolu yeniden hesaplamak için fonksiyonu çağırfollowPath()endend)findStartingPoint(waypoints)moveToNextWaypoint()endfollowPath()DESTINATION değişkenini (
SATIR 5) oyuncu karakterinin ulaşabileceği bir Vector3 hedefi ile düzenleyin.Yol hesaplama ve karakter hareketi hakkında bilgi edinmek için aşağıdaki bölümlerden devam edin.
Yol oluşturma
Yol bulma, PathfindingService ve CreatePath() yöntemi aracılığıyla başlatılır (
| Anahtar | Açıklama | Tür | Varsayılan |
|---|---|---|---|
| AgentRadius | Ajan yarıçapı, stud cinsinden. Engellerden minimum ayrımı belirlemek için kullanışlıdır. | tam sayı | 2 |
| AgentHeight | Ajan yüksekliği, stud cinsinden. Bu değerden daha küçük boşluklar, merdivenlerin altındaki alan gibi, geçilemez olarak işaretlenecektir. | tam sayı | 5 |
| AgentCanJump | Yol bulma sırasında zıplamanın izin verilip verilmediğini belirler. | boolean | true |
| AgentCanClimb | Yol bulma sırasında TrussParts tırmanmanın izin verilip verilmediğini belirler. Tırmanılabilir bir yolun Label adı Climb olmalıdır ve tırmanılabilir bir yolun maliyeti varsayılan olarak 1'dir. | boolean | false |
| WaypointSpacing | Yol boyunca ara waypoint'ler arasındaki mesafe. math.huge olarak ayarlanırsa, ara waypoint'ler olmayacaktır. | number | 4 |
| Costs | Geçiş için malzemelerin veya tanımlı PathfindingModifiers tablosu ve maliyetleri. Ajanın belirli malzemeleri/bölgeleri diğerlerine tercih etmesi için kullanışlıdır. Ayrıntılar için modifikatörlere bakın. | table | nil |
Yol hesaplama
Geçerli bir yolu CreatePath() ile oluşturduktan sonra, bu yol hesaplanmalıdır; bu, başlangıç noktası ve hedef için Vector3 ile Path:ComputeAsync() çağrılarak yapılır (

Path hesaplandıktan sonra, başlangıçtan sona kadar olan yolu izleyen bir dizi waypoint içerecektir. Bu noktalar, Path:GetWaypoints() yöntemi ile toplanabilir (

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, waypoint'ten waypoint'e Humanoid:Move() çağrısı yapmak ve karakterin her waypoint'e ulaşıp ulaşmadığını tespit etmek için betiğin isCurrentWaypointReached() geri çağrısını kullanmaktır (
Engellenmiş yollar
Birçok Roblox dünyası dinamik olup; parçalar hareket edebilir veya düşebilir ve zeminler çökebilir. Bu, hesaplanan bir yolu engelleyebilir ve karakterin hedefine ulaşmasını engelleyebilir. Bunu ele almak için, Path.Blocked olayına bağlanabilir ve engelleyen nesnenin etrafında yolu yeniden hesaplayabilirsiniz (
Yol Bulma Modifikatörleri
Varsayılan olarak, Path:ComputeAsync() başlangıç noktası ile hedef arasındaki en kısa yolu döndürür; zıplamalardan kaçınmaya çalışır. Bu bazı durumlarda doğal görünmez; örneğin, bir yol, suyun etrafında değil, suyun içinden geçebilir çünkü su içindeki yol geometrik olarak daha kısadır.

Yol bulmayı daha da optimize etmek için, çeşitli malzemeler üzerinden, tanımlı bölgelerin etrafında veya engelleri yok saymak için yol bulma modifikatörleri uygulayabilirsiniz.
Malzeme maliyetleri
Terrain ve BasePart malzemeleri ile çalışırken, belirli malzemelerin diğerlerinden daha geçilebilir olmasını sağlamak için CreatePath() içinde bir Costs tablosu ekleyebilirsiniz. Tüm malzemelerin varsayılan maliyeti 1'dir ve herhangi bir malzeme, değerini math.huge olarak ayarlayarak geçilemez olarak tanımlanabilir.
Costs tablosundaki anahtarlar, Enum.Material adlarını temsil eden string isimler olmalıdır; örneğin, Enum.Material.Water için Water veya Enum.Material.CrackedLava için CrackedLava.
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 tercihi yeterli olmayabilir. Örneğin, karakterlerin altındaki malzemelerden bağımsız olarak tanımlı bir bölgeden kaçınmasını isteyebilirsiniz. Bu, bir parçaya bir PathfindingModifier nesnesi ekleyerek gerçekleştirilebilir.
Bölgeyi tanımlamak için etrafında Anchored bir parça oluşturun ve CanCollide özelliğini false olarak ayarlayın.

Parçaya bir PathfindingModifier örneği ekleyin, Label özelliğini bulun ve DangerZone gibi anlamlı bir isim atayın.

CreatePath() içindeki Costs tablosuna eşleşen bir DangerZone anahtarı ve ilişkili sayısal değer ekleyin. Bir modifikatör, değerini math.huge olarak ayarlayarak geçilemez olarak tanımlanabilir.
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.01local VELOCITY_MULTIPLIER = 0.0625local path = PathfindingService:CreatePath({AgentCanClimb = true,Costs = {DangerZone = math.huge, Water = 20, CrackedLava = 20, Slate = 20}})
Engelleri yok sayma
Bazı durumlarda, katı engellerin içinden yol bulmak yararlı olabilir. Bu, belirli fiziksel engellerden geçerek bir yol hesaplamanızı sağlar; bu, hesaplamanın tamamen başarısız olmasını önler.
Engelin etrafında Anchored bir parça oluşturun ve CanCollide özelliğini false olarak ayarlayın.

Parçaya bir PathfindingModifier örneği ekleyin ve PassThrough özelliğini etkinleştirin.

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

Yol Bulma Bağlantıları
Bazen, normalde geçilemeyen bir alan üzerinden bir yol bulmak ve bir sonraki waypoint'e ulaşmak için özel bir eylem gerçekleştirmek gerekebilir. Bu, PathfindingLink nesnesi aracılığıyla gerçekleştirilebilir.
Yukarıdaki örneği kullanarak, ajanı bir bot kullanmaya yönlendirebilirsiniz.

Bu örneği kullanarak bir PathfindingLink oluşturmak için:
- İSTEĞE BAĞLI3D görünüm alanının sağ üst köşesindeki Görselleştirme Seçenekleri aracından Yol Bulma bağlantılarını etkinleştirin. Bu, yol bulma bağlantılarını uygularken görselleştirme ve hata ayıklama konusunda yardımcı olur.
Botun koltuğuna ve botun iniş noktasına yakın iki Attachments oluşturun.

Çalışma alanında bir PathfindingLink nesnesi oluşturun, ardından Attachment0 ve Attachment1 özelliklerini sırasıyla başlangıç ve bitiş bağlantılarına atayın.


Label özelliğine UseBoat gibi anlamlı bir isim atayın. Bu isim, ajanın başlangıç bağlantı noktasına ulaştığında özel bir eylemi tetiklemek için yol bulma betiğinde bir bayrak olarak kullanılır.

CreatePath() içinde hem bir Water anahtarı hem de Label özellik adı ile eşleşen özel bir anahtar içeren bir Costs tablosu ekleyin. Özel anahtara, Water'ın değerinden 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.01local VELOCITY_MULTIPLIER = 0.0625local path = PathfindingService:CreatePath({AgentCanClimb = true,Costs = {UseBoat = 2, Water = 20}})moveToNextWaypoint() fonksiyonunda (
SATIR 93–114), Label modifikatör adı için özel bir kontrol kullanarak Humanoid:Move()'dan farklı bir eylem gerçekleştirebilirsiniz; bu durumda, ajanın botun içinde oturmasını sağlamak, botu suyun üzerinden hareket ettirmek, ajanın botun iniş noktasında inmesini sağlamak ve ardından ajanın yoluna devam etmesini sağlamak için bir fonksiyon çağırabilirsiniz.
Akış uyumluluğu
Oyun içi örnek akışı, bir oyuncunun karakteri dünyada hareket ettikçe 3D içeriği dinamik olarak yükleyen ve boşaltan güçlü bir özelliktir. 3D alanı keşfettikçe, alanın yeni alt kümeleri cihazlarına akarken, mevcut alt kümelerden bazıları akıştan çıkabilir.
PathfindingService'i akış destekli oyunlarda kullanırken aşağıdaki en iyi uygulamaları göz önünde bulundurun:
Akış, bir karakter bir yol boyunca hareket ederken belirli bir yolu engelleyebilir veya engeli kaldırabilir. Örneğin, bir karakter bir ormandan geçerken, bir ağaç önlerinde bir yere akabilir ve yolu engelleyebilir. Yol bulmanın akışla sorunsuz çalışmasını sağlamak için, engellenmiş yolları ele alma tekniğini kullanmanız ve gerektiğinde yolu yeniden hesaplamanız şiddetle önerilir.
Yol bulmada yaygın bir yaklaşım, mevcut nesnelerin koordinatlarını hesaplama için kullanmaktır; örneğin, bir yol hedefini dünyadaki mevcut bir TreasureChest modelinin konumuna ayarlamak. Bu yaklaşım, sunucunun her zaman dünyanın tam görünümüne sahip olduğu için sunucu tarafı Scripts ile tamamen uyumludur, ancak istemcide çalışan LocalScripts ve ModuleScripts, akışta olmayan bir nesneye yol hesaplamaya çalışırlarsa başarısız olabilir.
Bu sorunu ele almak için, hedefi kalıcı bir model içindeki bir BasePart konumuna ayarlamayı düşünün. Kalıcı modeller, oyuncu katıldıktan kısa bir süre sonra yüklenir ve asla akıştan çıkmaz, bu nedenle istemci tarafı bir betik, PersistentLoaded olayına bağlanabilir ve olay tetiklendiğinde modelin erişimini güvenli bir şekilde sağlayabilir.
Sınırlamalar ve başarısızlık faktörleri
Yol bulma motoru, verimli işleme ve optimal performans sağlamak için belirli sınırlamalara sahiptir. Ayrıca, yol bulma hesaplamaları çeşitli nedenlerle başarısız olabilir; aşağıda belirtilmiştir.