# Basit Yol Bulma

- **İngilizce aslı:** https://wiki.facepunch.com/gmod/Simple_Pathfinding
- **Çeviri tarihi:** 2025-09-08

## NextBot'lar için otomatik yol bulma

[NextBot](https://gmod.tr/wiki/NextBot)'lar, mevcut konumlarından hedeflerine nasıl gideceklerini hesaplamak için [navmesh](https://gmod.tr/wiki/navmesh)'i kullanır.

Bu işlem, [PathFollower](https://gmod.tr/wiki/PathFollower) gibi yardımcı sınıflar kullanılarak yapılır ve yol oluşturma işleminin çoğu dahili olarak gerçekleştirilir.

Ancak, [PathFollower:Compute](https://gmod.tr/wiki/PathFollower:Compute) fonksiyonunun 3. argümanını kullanarak, [NextBot](https://gmod.tr/wiki/NextBot)'ların yolu hesaplarken nerelere gidip gidemeyeceğini etkileyebilirsiniz.

<!-- Belki daha sonra buraya örnekler eklenebilir -->

Aşağıda, yol oluşturma üzerinde tam kontrole sahip olmanızı sağlayan ve böylece bunun sadece [NextBot](https://gmod.tr/wiki/NextBot)'larla sınırlı kalmamasını sağlayan örnekler bulacaksınız.

## Terminoloji

- navmesh - [Navigasyon ağı](https://developer.valvesoftware.com/wiki/Navigation_Meshes).
- agent (ajan/aktör) - Ajan, oluşturulan yolu kullanacak olan varlıktır, örneğin bir oyuncu botu veya bir NPC.
- path (yol) - Oluşturulan yol, ajanın hedefe ulaşmak için geçmesi gereken bir dizi düğüm.
- node (düğüm) - Ulaşılabilecek pozisyonları belirten, birbirine bağlı noktalar.

## A* ve navmesh kütüphanesi kullanarak manuel yol bulma

[CNavArea](https://gmod.tr/wiki/CNavArea), oyuncu botları için yol bulma gibi kendi amaçlarınız için tamamen özel bir A* yol bulma algoritmasını hızlıca kurmanıza olanak tanıyan metotlar sağlar.

Bu metotlar şunlardır:

- [CNavArea:SetCostSoFar](https://gmod.tr/wiki/CNavArea:SetCostSoFar)
- [CNavArea:GetCostSoFar](https://gmod.tr/wiki/CNavArea:GetCostSoFar)
- [CNavArea:SetTotalCost](https://gmod.tr/wiki/CNavArea:SetTotalCost)
- [CNavArea:GetTotalCost](https://gmod.tr/wiki/CNavArea:GetTotalCost)
- [CNavArea:AddToOpenList](https://gmod.tr/wiki/CNavArea:AddToOpenList)
- [CNavArea:AddToClosedList](https://gmod.tr/wiki/CNavArea:AddToClosedList)
- [CNavArea:ClearSearchLists](https://gmod.tr/wiki/CNavArea:ClearSearchLists)
- [CNavArea:IsOpenListEmpty](https://gmod.tr/wiki/CNavArea:IsOpenListEmpty)
- [CNavArea:PopOpenList](https://gmod.tr/wiki/CNavArea:PopOpenList)
- [CNavArea:RemoveFromClosedList](https://gmod.tr/wiki/CNavArea:RemoveFromClosedList)
- [CNavArea:UpdateOnOpenList](https://gmod.tr/wiki/CNavArea:UpdateOnOpenList)
- [CNavArea:IsOpen](https://gmod.tr/wiki/CNavArea:IsOpen)
- [CNavArea:IsClosed](https://gmod.tr/wiki/CNavArea:IsClosed)

Bunların hepsi A* yol bulma algoritmasında kullanılan temel fonksiyonlardır.

İşte bu metotları kullanarak [Wikipedia'daki temel bir A* algoritmasını](https://en.wikipedia.org/wiki/A*_search_algorithm) nasıl uygulayacağınıza dair bir örnek:

```lua
function Astar( start, goal )
	if ( !IsValid( start ) || !IsValid( goal ) ) then return false end
	if ( start == goal ) then return true end

	start:ClearSearchLists()

	start:AddToOpenList()

	local cameFrom = {}

	start:SetCostSoFar( 0 )

	start:SetTotalCost( heuristic_cost_estimate( start, goal ) )
	start:UpdateOnOpenList()

	while ( !start:IsOpenListEmpty() ) do
		local current = start:PopOpenList() // Açık listedeki en düşük maliyetli alanı kaldır ve geri döndür
		if ( current == goal ) then
			return reconstruct_path( cameFrom, current )
		end

		current:AddToClosedList()

		for k, neighbor in pairs( current:GetAdjacentAreas() ) do
			local newCostSoFar = current:GetCostSoFar() + heuristic_cost_estimate( current, neighbor )

			if ( neighbor:IsUnderwater() ) then // Buraya kendi alan filtrelerinizi veya başka şeyleri ekleyin
				continue
			end

			if ( ( neighbor:IsOpen() || neighbor:IsClosed() ) && neighbor:GetCostSoFar() <= newCostSoFar ) then
				continue
			else
				neighbor:SetCostSoFar( newCostSoFar );
				neighbor:SetTotalCost( newCostSoFar + heuristic_cost_estimate( neighbor, goal ) )

				if ( neighbor:IsClosed() ) then

					neighbor:RemoveFromClosedList()
				end

				if ( neighbor:IsOpen() ) then
					// Bu alan zaten açık listede, maliyetleri sıralı tutmak için listedeki konumunu güncelle
					neighbor:UpdateOnOpenList()
				else
					neighbor:AddToOpenList()
				end

				cameFrom[ neighbor:GetID() ] = current:GetID()
			end
		end
	end

	return false
end

function heuristic_cost_estimate( start, goal )
	// Belki hangi köşenin en yakın/en uzak olduğu veya başka bir şey üzerine bazı hesaplamalarla oynayın
	return start:GetCenter():Distance( goal:GetCenter() )
end

// CNavArea'ları tablo anahtarı olarak kullanmak çalışmaz, bu yüzden ID'leri kullanıyoruz
function reconstruct_path( cameFrom, current )
	local total_path = { current }

	current = current:GetID()
	while ( cameFrom[ current ] ) do
		current = cameFrom[ current ]
		table.insert( total_path, navmesh.GetNavAreaByID( current ) )
	end
	return total_path
end
```

Bu örnekte, Astar() fonksiyonu 2 argüman alır: Başlangıç [CNavArea](https://gmod.tr/wiki/CNavArea)'sı, örneğin oyuncu botunun veya NPC'nin o an bulunduğu yer, ve hedef [CNavArea](https://gmod.tr/wiki/CNavArea)'sı, yani botun veya NPC'nin gitmek istediği yer.

Astar() fonksiyonu 3 değerden birini döndürür:

- Hedef [CNavArea](https://gmod.tr/wiki/CNavArea)'sına fiziksel olarak ulaşmak imkansızsa, false döndürür
- Başlangıç [CNavArea](https://gmod.tr/wiki/CNavArea)'sı hedef [CNavArea](https://gmod.tr/wiki/CNavArea) ile aynıysa, true döndürür
- Aksi takdirde, botun/NPC'nin hedefe ulaşmak için içinden geçmesi gereken bir [CNavArea](https://gmod.tr/wiki/CNavArea) dizisi döndürür (birbiri ardına, hedef [CNavArea](https://gmod.tr/wiki/CNavArea) dizideki ilk girdi olacak şekilde, gerekirse dizi sırasını tersine çevirmek için [table.Reverse](https://gmod.tr/wiki/table.Reverse) kullanın).

Aşağıda, bu örnek fonksiyonu kullanarak oyuncu botlarını yol bulma ile belirli bir hedefe nasıl hareket ettireceğinize dair birkaç örnek bulacaksınız.

### Başlangıç ve hedef pozisyonları olarak vektörleri kullanma

İstediğiniz [Vector](https://gmod.tr/wiki/Vector) pozisyonuna en yakın [CNavArea](https://gmod.tr/wiki/CNavArea)'yı bulmak için [navmesh.GetNearestNavArea](https://gmod.tr/wiki/navmesh.GetNearestNavArea) fonksiyonunu kullanabilirsiniz.

İşte Astar() fonksiyonu için girdi olarak 2 vektör alan bir örnek fonksiyon:

```lua
function AstarVector( start, goal )
	local startArea = navmesh.GetNearestNavArea( start )
	local goalArea = navmesh.GetNearestNavArea( goal )
	return Astar( startArea, goalArea )
end
```

### A*, alanlarla değil, nokta düğümleriyle en iyi şekilde çalışır

Garry's Mod'da, navigasyon ağı [Vector](https://gmod.tr/wiki/Vector) pozisyonlarından değil, [CNavArea](https://gmod.tr/wiki/CNavArea)'lardan oluşur. Sonuç olarak, buradaki örneklerin ajanı çoğunlukla bir [CNavArea](https://gmod.tr/wiki/CNavArea)'nın merkezinden diğerinin merkezine taşıdığını fark edeceksiniz. Bu, oluşturulan yolların doğal görünmemesine neden olur.

Daha doğal yollar elde etmek için, ajanın içinden geçmesi gereken pozisyonları oluştururken, [CNavArea](https://gmod.tr/wiki/CNavArea)'ların köşelerini kullanmak, köşeleri kesmek veya belirli pozisyonları atmak için Görüş Hattı (Line of Sight) kontrollerini kullanmak gibi daha gelişmiş teknikler gerekecektir.

### Yol bulma kolay değildir

Lütfen tüm bu örneklerin eğitim amaçlı olarak olabildiğince basit tutulduğunu unutmayın. Mutlak en verimli yolları oluşturmayabilir. Yolların doğal hissettirmesi veya verimli olması için ajanın hareket koduna daha fazla çalışma yapılması gerekecektir.

### Oluşturulan yolu test etmek ve görselleştirmek için örnek konsol komutu

Bu örnek kod, oluşturulan yolu [debugoverlay](https://gmod.tr/wiki/debugoverlay) kullanarak doğrudan Astar() fonksiyonundan çizecek bir fonksiyon içerir.

```lua
function drawThePath( path, time )
	local prevArea
	for _, area in pairs( path ) do
		debugoverlay.Sphere( area:GetCenter(), 8, time or 9, color_white, true  )
		if ( prevArea ) then
			debugoverlay.Line( area:GetCenter(), prevArea:GetCenter(), time or 9, color_white, true )
		end

		area:Draw()
		prevArea = area
	end
end
```

Lütfen [debugoverlay](https://gmod.tr/wiki/debugoverlay)'in yalnızca çok oyunculu modda ve yalnızca **developer** konsol komutu sıfırdan farklı bir değere ayarlandığında çalıştığını unutmayın.

Bu örnek, yol oluşturma işleminizi test etmek ve hatalarını ayıklamak için Astar() ve drawThePath() fonksiyonlarını birlikte nasıl kullanabileceğinizi gösterir.

```lua
concommand.Add( "test_astar", function( ply )

	// Konsol komutunu çalıştıran oyuncunun başlangıç pozisyonunu kullan
	local start = navmesh.GetNearestNavArea( ply:GetPos() )

	// Hedef pozisyon, bu örnek için oyuncunun nişan aldığı pozisyonu kullan
	local goal = navmesh.GetNearestNavArea( ply:GetEyeTrace().HitPos )

	local path = Astar( start, goal )
	if ( !istable( path ) ) then // Hedefe fiziksel olarak ulaşamıyoruz veya zaten hedefin içindeyiz.
		return
	end

	PrintTable( path ) // Hata ayıklama için oluşturulan yolu konsola yazdır
	drawThePath( path ) // Oluşturulan yolu 9 saniye boyunca çiz

end)
```

### Oyuncu botları ile örnek kullanım

Bu örnek, bir oyuncu botunu (bir ajan) oluşturulan yol boyunca hareket ettirmenin en temel yolunu gösterir:

```lua
local rePathDelay = 1 // Yolu güncel tutmak için yeniden oluşturmadan önce kaç saniye geçmesi gerektiği
hook.Add( "StartCommand", "astar_example", function( ply, cmd )

	// Bu kodu sadece botlar üzerinde ve sadece bot_mimic 0'a ayarlıysa çalıştır
	if ( !ply:IsBot() || GetConVarNumber( "bot_mimic" ) != 0 ) then return end

	cmd:ClearButtons()
	cmd:ClearMovement()

	local currentArea = navmesh.GetNearestNavArea( ply:GetPos() )

	// hedef oyuncuyla aynı hızda kalmak için yolu her X saniyede bir yeniden oluşturmak için dahili değişken
	ply.lastRePath = ply.lastRePath or 0

	// yolun ne sıklıkta (yeniden) oluşturulabileceğini sınırlamak için dahili değişken
	ply.lastRePath2 = ply.lastRePath2 or 0

	if ( ply.path && ply.lastRePath + rePathDelay < CurTime() && currentArea != ply.targetArea ) then
		ply.path = nil
		ply.lastRePath = CurTime()
	end

	if ( !ply.path && ply.lastRePath2 + rePathDelay < CurTime() ) then

		local targetPos = Entity( 1 ):GetPos() // gidilecek hedef pozisyon, sunucudaki ilk oyuncu
		local targetArea = navmesh.GetNearestNavArea( targetPos )

		ply.targetArea = nil
		ply.path = Astar( currentArea, targetArea )
		if ( !istable( ply.path ) ) then // Hedefle aynı alandayız veya hedefe gidemiyoruz
			ply.path = nil // Yolu temizle, vazgeç ve bir dahaki sefere tekrar dene
			ply.lastRePath2 = CurTime()
			return
		end
		//PrintTable( ply.path )

		// TODO: Alan kesişimlerine ara noktalar ekle
		// TODO: Son alanda, son alanın merkezine değil, hedef pozisyona doğru hareket et
		table.remove( ply.path ) // Sadece bu örnek için, başlangıç alanını kaldır, zaten içindeyiz!
	end

	// Yolumuz yok veya boş (hedefe vardık), yeni bir yol bulmaya çalış.
	if ( !ply.path || #ply.path < 1 ) then
		ply.path = nil
		ply.targetArea = nil
		return
	end

	// Hedefimize giden bir yolumuz var!
	drawThePath( ply.path, .1 ) // Hata ayıklama için yolu çiz

	// Gitmek istediğimiz bir sonraki alanı seç
	if ( !IsValid( ply.targetArea ) ) then
		ply.targetArea = ply.path[ #ply.path ]
	end

	// Seçtiğimiz alan geçersiz veya zaten oradayız, kaldır, vazgeç ve bir sonraki döngüyü bekle
	if ( !IsValid( ply.targetArea ) || ( ply.targetArea == currentArea && ply.targetArea:GetCenter():Distance( ply:GetPos() ) < 64 ) ) then
		table.remove( ply.path ) // Son elemanı kaldırır
		ply.targetArea = nil
		return
	end

	// Gidilecek hedefi bulduk, oraya nişan al ve HAREKET ET
	local targetang = ( ply.targetArea:GetCenter() - ply:GetPos() ):GetNormalized():Angle()
	cmd:SetViewAngles( targetang )
	cmd:SetForwardMove( 1000 )

end )
```

Bu örnek, sunucudaki tüm botların sunucudaki ilk oyuncuya doğru hareket etmesini sağlayacaktır. Oluşturulan yol güzel değil, ancak bu örneğin amacı, bir ajanı oluşturulmuş bir yol boyunca hareket ettirmek için yolun nasıl kullanılacağını göstermektir.

- [GMod Wiki ana sayfası](https://gmod.tr/wiki)

---

[Tüm sunucular](https://gmod.tr/) · [GmodTR Launcher](https://gmod.tr/launcher) · [Rehber](https://gmod.tr/rehber) · [GMod Wiki](https://gmod.tr/wiki) · [GmodTR nedir?](https://gmod.tr/hakkinda) · [Sunucu ekle](https://gmod.tr/sunucu-ekle) · [Discord](https://discord.gg/gmodtr)

Kaynak: https://gmod.tr/wiki/Simple_Pathfinding
