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.
Navigasyon Görselleştirmesi
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.

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.

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:
- ÖNEMLİExplorer içinde StarterPlayer konteynerini seçin. Ardından, Properties penceresinde DevComputerMovementMode ve DevTouchMovementMode'yu Scriptable olarak ayarlayın.


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.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-- Compute the distance from humanoid to destination planelocal dist = currentWaypointPlaneNormal:Dot(humanoid.RootPart.Position) - currentWaypointPlaneDistance-- Compute the component of the humanoid velocity that is towards the planelocal velocity = -currentWaypointPlaneNormal:Dot(humanoid.RootPart.Velocity)-- Compute the threshold from the destination plane based on humanoid velocitylocal threshold = math.max(1.0, VELOCITY_MULTIPLIER * velocity)-- Consider waypoint reached if less then threshold in front of the planereached = 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]-- Build destination plane from next waypoint towards current onecurrentWaypointPlaneNormal = currentWaypoint.Position - nextWaypoint.Position-- Set normal perpendicular to Y plane when not climbing upif 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-- Call your own customized function to make agent use the boatelseif 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()-- Compute the pathpathfinderWorking = truewaitForGround()local success, errorMessage = pcall(function()path:ComputeAsync(character.PrimaryPart.Position, DESTINATION)end)if not success or path.Status ~= Enum.PathStatus.Success thenwarn("Path not computed!", errorMessage)returnend-- Get the path waypointswaypoints = path:GetWaypoints()-- Detect if path becomes blockedblockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)-- Check if the obstacle is further down the pathif blockedWaypointIndex >= nextWaypointIndex then-- Stop detecting path blockage until path is re-computedblockedConnection:Disconnect()resetWaypointData()-- Call function to re-compute new pathfollowPath()endend)findStartingPoint(waypoints)moveToNextWaypoint()endfollowPath()DESTINATION değişkenini (
SATIR 5) 3D dünyada oyuncu karakterinin ulaşabileceği bir Vector3 hedefi ile değiştirin.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 (
| Anahtar | Açıklama | Tür | Varsayılan |
|---|---|---|---|
| AgentRadius | Ajanın yarıçapı, stud cinsinden. Engellerden minimum ayrımı belirlemek için yararlıdır. | integer | 2 |
| AgentHeight | Ajanın yüksekliği, stud cinsinden. Bu değerden küçük olan boş alanlar, merdiven altındaki alan gibi, geçilemez olarak işaretlenecektir. | integer | 5 |
| AgentCanJump | Yolda bulma sırasında zıplamanın izin verilip verilmediğini belirler. | boolean | true |
| AgentCanClimb | Yolda 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. | boolean | false |
| WaypointSpacing | Yolda, ara noktalar arasındaki mesafe. math.huge olarak ayarlanırsa, ara noktalar olmayacaktır. | number | 4 |
| Costs | Malzemelerin 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. | table | nil |
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 (

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 (

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 (
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 (
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.

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.01local VELOCITY_MULTIPLIER = 0.0625local 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.
Etkini olduğunuz bölge etrafında Anchored tipinde bir parça oluşturun ve CanCollide özelliğini false olarak ayarlayın.

Parçaya bir PathfindingModifier nesnesi ekleyin, Label özelliğini bulun ve DangerZone gibi anlamlı bir isim verin.

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.01local VELOCITY_MULTIPLIER = 0.0625local 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.
Bir nesnenin etrafında Anchored tipinde bir parça oluşturun ve CanCollide özelliğini false olarak ayarlayın.

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

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.

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.

Bu örneği kullanarak bir PathfindingLink oluşturmak için:
- İSTEĞE BAĞLI3D 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.
Bir kayık koltuğuna bir tane ve kayığın iniş noktasına bir tane olmak üzere iki Attachments oluşturun.

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


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.

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.01local VELOCITY_MULTIPLIER = 0.0625local path = PathfindingService:CreatePath({AgentCanClimb = true,Costs = {UseBoat = 2, Water = 20}})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.