FiveM sunucu geliştirmede sıkça karşılaşılan en büyük mantık hatalarından biri, etkileşim sistemlerinde yalnızca oyuncu ile hedef arasındaki mesafeyi (#(coordsA - coordsB) < 2.0) kontrol etmektir. Bir duvarın arkasındaki oyuncuyu kelepçelemek, kapalı bir garaj kapısının gerisindeki aracı kilitlemek veya binaların içinden ATM'ye erişebilmek gibi sayısız açık, 'Line of Sight' (Görüş Hattı) doğrulaması yapılmamasından kaynaklanır.
2026 geliştirici ekosisteminde hedefleme ve etkileşim sistemlerinin omurgasını ShapeTest (Raycast) mimarisi oluşturur. Bu rehberde; istemci performansını düşürmeden (0.00ms resmon hedefiyle) ışın izleme yöntemlerini, bayrak (flags) matrisini ve kameradan nesne yakalama sistemlerini sıfırdan adım adım inceleyeceğiz.
Raycast (ShapeTest) Nedir ve Neden Hayatidir?
Raycast, 3 boyutlu oyun dünyasında belirlenen bir başlangıç noktasından hedef noktaya doğru sanal ve görünmez bir ışın fırlatılması işlemidir. Bu ışın yol boyunca bir varlığa (araba, ped, dünya modeli, kapı veya prop) çarptığında, çarpışma noktasının koordinatlarını, yüzey normalini ve çarpılan varlığın benzersiz Entity ID değerini geri döndürür.
- Görüş Hattı Kontrolü: Oyuncu ile nesne arasında duvar, cam veya kolon olup olmadığını milimetrik olarak denetler.
- Hassas Hedefleme: Oyuncunun baktığı veya kameranın ortaladığı belirli bir parçayı (örn: aracın motor kaputu, sağ arka lastik) tespit eder.
- Zemin ve Eğim Analizi: Karakterin bastığı zeminin materyalini ve eğimini hesaplayarak dinamik animasyonlar veya efektler tetikler.
1. ShapeTest Türleri ve Performans Tuzakları
GTA V native kütüphanesinde birden fazla ShapeTest fonksiyonu yer alır. Acemi geliştiricilerin düştüğü en kritik hata, adında *Expensive* geçen senkron fonksiyonları bir döngü içerisine yerleştirmektir.
StartExpensiveSynchronousShapeTestLos native'i ana iş parçacığını (main thread) kilitler ve anlık FPS düşüşlerine (micro-stutter) neden olur. Her zaman standart StartShapeTestRay veya asenkron ShapeTest çağrılarını tercih edin.ShapeTest Bayrakları (Flags)
Işının hangi nesnelerle çarpışacağını belirlemek için bitmask mantığı kullanılır:
- 1: Statik Dünya Modelleri (Binalar, yollar, kaldırımlar)
- 2: Araçlar (Arabalar, motorlar, tekneler, helikopterler)
- 4: Pedler (Oyuncular ve yapay zeka NPC'ler)
- 8: Ragdoll (Yere düşmüş pedler)
- 16: Nesneler ve Proplar (ATM'ler, çöpler, kutular)
- 256: Bitki örtüsü (Ağaçlar, çalılar)
- -1: Her Şey (Tüm çarpışma modelleri)
Birden fazla nesne türünü taramak için değerleri toplamanız yeterlidir. Örneğin; hem araçları hem nesneleri taramak istiyorsanız: 2 + 16 = 18 bayrağını kullanabilirsiniz.
2. Kameradan İleriye Doğru Raycast Atma (Adım Adım)
Oyuncunun ekranının tam ortasından baktığı yöne doğru 10 metrelik bir ışın gönderen modern bir yardımcı fonksiyon kuralım.
Klasör yapınızı şu şekilde organize edin:
resources/[scripts]/core_interaction/client/raycast.lua
-- client/raycast.lua
local function RotationToDirection(rotation)
local adjustedRotation = vector3(
(math.pi / 180) * rotation.x,
(math.pi / 180) * rotation.y,
(math.pi / 180) * rotation.z
)
return vector3(
-math.sin(adjustedRotation.z) * math.abs(math.cos(adjustedRotation.x)),
math.cos(adjustedRotation.z) * math.abs(math.cos(adjustedRotation.x)),
math.sin(adjustedRotation.x)
)
end
function CastRayFromCamera(distance, flag)
local cameraRotation = GetGameplayCamRot()
local cameraCoord = GetGameplayCamCoord()
local direction = RotationToDirection(cameraRotation)
local destination = cameraCoord + (direction * distance)
-- Işını başlat: 1 = Dünya, 2 = Araç, 16 = Prop
local rayHandle = StartShapeTestRay(
cameraCoord.x, cameraCoord.y, cameraCoord.z,
destination.x, destination.y, destination.z,
flag or (1 + 2 + 16),
PlayerPedId(),
0
)
local retval, hit, endCoords, surfaceNormal, entityHit = GetShapeTestResult(rayHandle)
return hit == 1, entityHit, endCoords, surfaceNormal
end3. Pratik Uygulama: Duvar Arkası Hilesini Engelleyen Akıllı Etkileşim
Şimdi oluşturduğumuz bu modülü pratik bir örnekte kullanalım. Oyuncu E tuşuna bastığında, doğrudan önündeki aracı tespit edip bagajını açmak istesin; ancak araba ile kendi arasında duvar varsa etkileşim engellensin.
-- client/interaction.lua
local function ToggleTrunk()
local playerPed = PlayerPedId()
local hit, entity, hitCoords = CastRayFromCamera(5.0, 1 + 2) -- Dünya ve Araçlar
if not hit or entity == 0 then
return
end
-- Çarptığımız varlık bir araç mı?
if IsEntityAVehicle(entity) then
local playerCoords = GetEntityCoords(playerPed)
-- Oyuncu ile araç arasında net bir görüş hattı var mı? (Ekstra güvenlik raycasti)
local hasClearLineOfSight = HasEntityClearLosToEntity(playerPed, entity, 17)
if hasClearLineOfSight then
local isTrunkOpen = GetVehicleDoorAngleRatio(entity, 5) > 0.0
if isTrunkOpen then
SetVehicleDoorShut(entity, 5, false)
else
SetVehicleDoorOpen(entity, 5, false, false)
end
else
print("^1[GÜVENLİK]: Görüş hattı kapalı, duvar arkasından işlem engellendi.")
end
end
end
RegisterCommand('bagaj_test', function()
ToggleTrunk()
end, false)HasEntityClearLosToEntity native'i, iki varlık arasındaki görünmezliği denetleyen optimize edilmiş dahili bir motor fonksiyonudur. Karmaşık döngüler kurmadan raycast güvenliğini pekiştirmek için birebirdir.4. Özel Sistemleri Sıfırdan Kodlamak Zor mu Geliyor?
Karmaşık mimarileri, target sistemlerini, raycast doğrulamalarını ve resmon optimizasyonlarını kendi başınıza inşa etmek ciddi bir zaman ve matematiksel altyapı gerektirir. Eğer sunucunuzun altyapısını profesyonel, sıfır hatalı ve optimize bir temele oturtmak isterseniz ekibimizin sunduğu Developerlik Hizmeti seçeneklerini değerlendirebilir ya da tüm bu sistemlerin önceden entegre edildiği anahtar teslim DxAV1 - Roleplay Paketi ile sunucunuzu hemen yayına alabilirsiniz.
Sıkça Sorulan Sorular (SSS)
1. Raycast çağrıları her karede (Tick) çalışırsa FPS düşürür mü?
Eğer StartShapeTestRay fonksiyonunu doğru bayraklarla (yalnızca ihtiyaç duyulan modelleri tarayarak) kullanırsanız ve ışın mesafesini makul (3 ila 10 metre) tutarsanız resmon değeri 0.01ms'yi aşmaz. Ancak menzili 100+ metre yapmak veya her karede 5 farklı raycast atmak istemciyi yoracaktır.
2. Raycast neden bazen şeffaf camların arkasını görmezden geliyor?
Cam objeleri materyal flag ayarlarında çarpışma (collision) içerir. Işının camı delip geçmesini istiyorsanız ShapeTest başlatırken 7 bayrağını (ignore transparent/glass) veya StartShapeTestLosProbe varyasyonunu kullanmanız gerekir.
3. Raycast ile zemin materyali (asfalt, çimen, su) nasıl öğrenilir?
Işının çarptığı noktada zemin materyal kodunu almak için GetShapeTestResultEx native'ini kullanabilirsiniz. Bu native, standart fonksiyondan farklı olarak materialHash çıktısı da verir; böylece oyuncunun bastığı zemine göre ses veya parçacık efekti oluşturabilirsiniz.
