Bu eğitimde, bir lazerin blasterden nasıl atılacağını öğrenecek ve bir oyuncuya vurup vurmadığını tespit edeceksiniz Oyuncu araçları oluşturma ve bir oyuncuya vurup vurmadığını tespit edeceksiniz.
Çarpışma bulmak için Raycasting
Işın yayımı bir başlangıç pozisyonundan belirli bir uzunlukla verilen yöne doğru görünmez bir ışın yaratır.Işın yolundaki nesnelerle veya arazilerle çarpışırsa, konum ve çarpıştığı nesne gibi çarpışma bilgilerini geri verecektir.

Fare konumunu bul
Bir lazer vurulmadan önce, oyuncunun nereye hedeflediğini bilmeniz gerekir.Bu, doğrudan kameradan ekrana 2D fare konumundan oyun dünyasına göndererek oyuncunun ekrandaki yerinden bulunabilir.Işın, oyuncunun fareyle hedef aldığı her şeyle çarpışacaktır.
Blaster aracındaki Araç Kontrolörü skriptini Oyuncu araçları oluştur aracılığıyla açın.Bu eğitimi henüz bitirmediyseniz Patlayıcı modelini indirip StarterPack'e ekleyebilirsiniz.
Senaryonun üstünde, değeri 1000 olan bir sabit olan MAX_MOUSE_DISTANCE adlı sabiti ilan edin.
getWorldMousePosition adlı bir işlev oluşturun.
local tool = script.Parentlocal MAX_MOUSE_DISTANCE = 1000local function getWorldMousePosition()endlocal function toolEquipped()tool.Handle.Equip:Play()endlocal function toolActivated()tool.Handle.Activate:Play()end-- Etkinlikleri uygun işlevlere bağlatool.Equipped:Connect(toolEquipped)tool.Activated:Connect(toolActivated)Ekranda oyuncunun 2B fare konumunu almak için UserInputService GetMouseLocation işlevini kullanın.Bunu fareLocation adlı değişkenine atayın.
local UserInputService = game:GetService("UserInputService")local tool = script.Parentlocal MAX_MOUSE_DISTANCE = 1000local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()end
Şimdi 2D fare konumu biliniyor, X ve Y özellikleri ekrandan 3D oyun dünyasına bir şey yaratan fonksiyonun parametreleri olarak kullanılabiliyor, ki bu ekrandan 3D oyun dünyasına bir şey yaratıyor.
X ve Y özelliklerini > işlevinin argümanları olarak kullanın.Bunu ekranToWorldRay adlı değişkenine atayın.
local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()-- 2D fare konumundan bir ışın oluşturlocal screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)end
Işın bir nesneye vurup vurmadığını kontrol etmek için Raycast işlevini kullanma zamanı geldi.Bunun bir başlangıç pozisyonu ve yön vektörü gerektirir: bu örnekte, screenToWorldRay 'in kaynağı ve yön özelliklerini kullanacaksınız.
Yön vektörünün uzunluğu, ışının ne kadar seyahat edeceğini belirler.Işın, MAX_MOUSE_DISTANCE kadar uzun olmalıdır, bu yüzden yön vektörünü MAX_MOUSE_DISTANCE ile çarpmalısınız.
Bir değişken olan yönVector adlı değişkeni ilan edin ve ona çarpan değeri atayın.
local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()-- 2D mouseLocation'dan bir ışın oluşturlocal screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)-- Işının birim yön vektörü maksimum mesafe ile çarptırıldılocal directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCEÇalışma alanının Raycast fonksiyonunu çağırın, ilk argüman olarak Köken özelliğini screenToWorldRay ve ikinci olarak da directionVector özelliğini geçirin.Bunu raycastResult adlı değişkenine atayın.
local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()-- 2D mouseLocation'dan bir ışın oluşturlocal screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)-- Işının birim yön vektörü maksimum mesafe ile çarptırıldılocal directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE-- Işının kaynağından yönüne doğru ışın yayını Raycast from the ray's origin towards its directionlocal raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
Çarpışma bilgisi
Işın atma işlemi, ışın tarafından vurulan bir nesne bulursa, ışın ve nesne arasındaki çarpışma hakkında bilgiler içeren bir RaycastResult döndürecektir.
RaycastResult Özelliği | Açıklama |
---|---|
İstisna | Işının kesiştiği BasePart veya Terrain hücre. |
Pozisyon | Kesişme gerçekleştiği yer; genellikle bir parçanın veya arazinin yüzeyinde doğrudan bir nokta. |
Malzeme | Çarpışma noktasındaki malzeme. |
Normallik | Kesişen yüzün normal vektörü. Bu, yüzün hangi yöne işaret ettiğini belirlemeye kullanılabilir. |
Pozisyon özelliği, fare üzerinde gezinilen nesnenin pozisyonu olacaktır.Fare, MAX_MOUSE_DISTANCE mesafede herhangi bir nesneye uçmuyorsa, raycastResult olacaktır nil .
raycastResult var olup olmadığını kontrol etmek için bir if ifadesi oluşturun.
Eğer raycastResult bir değere sahipse, onun Konumu özelliğini geri döndürün.
Eğer ise, ışın atışının sonunu bulun.Fare konumunu 3B olarak hesaplamak için screenToWorldRay.Origin ve directionVector birlikte ekleyin.
local function getWorldMousePosition()
local mouseLocation = UserInputService:GetMouseLocation()
-- 2D mouseLocation'dan bir ışın oluştur
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- Işının birim yön vektörü maksimum mesafe ile çarptırıldı
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- Işının kaynağından yönüne doğru ışın yayını Raycast from the ray's origin towards its direction
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- 3B kesişme noktasını geri dönün
return raycastResult.Position
else
-- Hiçbir nesne vurulmadı, bu yüzden ışının sonundaki konumu hesaplayın
return screenToWorldRay.Origin + directionVector
end
end
Hedefe ateş edin
Artık 3B fare konumu biliniyor, bir lazeri hedef almak için bir hedef konumu olarak kullanılabilir.İkinci bir ışın, oyuncunun silahı ve hedef konumu arasında Işın Fırlatma işlevi kullanarak yapılabilir.
Senaryonun başında sabit bir değer olan MAX_LASER_DISTANCE ilan edin ve lazer tabancası için seçilen menzile atayın, ya da 500 .
local UserInputService = game:GetService("UserInputService")local tool = script.Parentlocal MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 500fireWeapon adlı bir işlev oluşturun getWorldMousePosition işlevinin altında.
getWorldMousePosition 'yi arayın ve sonucu farePosition adlı bir değişkene atayın. Bu, ışın atışı için hedef konum olacaktır.
-- Hiçbir nesne vurulmadı, bu yüzden ışının sonundaki konumu hesaplayınreturn screenToWorldRay.Origin + directionVectorendendlocal function fireWeapon()local mouseLocation = getWorldMousePosition()endlocal function toolEquipped()tool.Handle.Equip:Play()end
Bu kez, ışın atma işlevinin yön vektörü, oyuncunun alet pozisyonundan hedef konumuna yönü temsil edecektir.
Hedef yönü adında bir değişken ilan edin ve hedef yönü aracı konumundan çıkararak yön vektörünü hesaplayın mouseLocation .
Vektörün Birimi özelliğini kullanarak normalleştirin. Bu, daha sonra bir uzunluk ile çarpmayı kolaylaştıran bir büyüklük verir.
local function fireWeapon()local mouseLocation = getWorldMousePosition()-- Normalize edilmiş bir yön vektörü hesaplayın ve lazer mesafesi ile çarptırınlocal targetDirection = (mouseLocation - tool.Handle.Position).UnitendBir değişken olan yönVector adlı değişkeni ilan edin ve ona targetDirection çarpan ile atayın MAX_LASER_DISTANCE.
local targetDirection = (mouseLocation - tool.Handle.Position).Unit-- Silahı ateş etmek için yön, maksimum mesafe ile çarptırılırlocal directionVector = targetDirection * MAX_LASER_DISTANCEend
Bir RaycastParams nesnesi, ışın atma işlevi için ek parametler depolamak için kullanılabilir.Lazer bombardmanınızda, silahı ateş eden oyuncuyla kazara çarpışmayacağından emin olmak için kullanılacaktır.Bir RaycastParams nesnesinin FilterDescendantsInstances dahil edilen herhangi bir parça, raycastta göz ardı edilecektir.
fireWeapon fonksiyonunu devam ettirin ve silahRaycastParams adlı bir değişken ilan edin. Ona yeni bir RaycastParams nesnesi atayın.
oyuncuyerel karakterini içeren bir tablo oluştur ve onu weaponRaycastParams.FilterDescendantsInstances özelliğine atayın.
Oyuncunun alet kolu konumundan directionVector yönünde bir yayın yap, oyuncunun alet kolu konumundan yayın yap, oyuncunun alet kolu konumundan yayın yapBu sefer bir argüman olarak weaponRaycastParams eklemek unutmayın.Bunu silahRaycastResult adlı değişkenine atayın.
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local tool = script.Parent
local MAX_MOUSE_DISTANCE = 1000
local MAX_LASER_DISTANCE = 500
local function getWorldMousePosition()
local function fireWeapon()
local mouseLocation = getWorldMousePosition()
-- Normalize edilmiş bir yön vektörü hesaplayın ve lazer mesafesi ile çarptırın
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- Silahı ateşleme yönü maksimum mesafe ile çarptırılmış
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- oyuncukarakterini görmezden gelerek kendilerine zarar vermelerini engelle
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
end
Son olarak, ışın atma işleminin bir değer döndürdüğünü kontrol etmeniz gerekecek.Bir değer döndürülürse, bir nesne silah ve vuruş konumu arasında bir lazer oluşturulabilir ve bir değer döndürülürse, bir nesne silah ve vuruş konumu arasında bir lazer oluşturulabilir.Hiçbir şey dönmediyse, lazer oluşturmak için son konum hesaplanmalıdır.
Boş bir değişken olan hitPosition adlı değişkeni ilan edin.
Bir değere sahip olup olmadığını kontrol etmek için bir if ifadesi kullanın. Eğer bir nesneye vurulduysa, weaponRaycastResult 'e weaponRaycastResult.Position atayın hitPosition .
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)-- Başlangıç ve bitiş konumları arasında herhangi bir nesneye vuruldu mu kontrol edinlocal hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.PositionendEğer weaponRaycastResult değeri yoksa, ışın atışının son konumunu hesaplamak için alet tutucunun pozisyonunu ile directionVector 'i birleştirerek ekleyin.Bunu vuruş konumuna atayın.
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)-- Başlangıç ve bitiş konumları arasında herhangi bir nesneye vuruldu mu kontrol edinlocal hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.Positionelse-- Maksimum lazer mesafesi üzerine dayanarak son konumu hesaplahitPosition = tool.Handle.Position + directionVectorendendNavigate to the toolActivated function and call the fireWeapon function so that the lazer her defasında alet etkinleştirildiğinde ateş eder.
local function toolActivated()tool.Handle.Activate:Play()fireWeapon()end
Nesneye vuruş kontrol et
Lazer tarafından vurulan nesnenin bir oyuncunun karakterinin bir parçası olup olmadığını bulmak veya sadece bir manzara parçası olup olmadığını bulmak için, her karakterin bir tane olduğundan bir Humanoid aramalısınız.
Öncelikle, karakter modelini bulmanız gerekecek.Karakterin bir kısmı vurulduysa, vurulan nesnenin ebeveyninin karakter olacağını varsayamazsınız.Lazer bir vücut parçasına, bir aksesuara veya bir aleta vurabilir, hepsi de karakterin hiyerarşisinin farklı kısımlarında bulunur.
Lazer tarafından vurulan nesneye ait bir karakter modeli atası bulmak için FindFirstAncestorOfClass kullanabilirsiniz, eğer bir tane varsa.Bir model bulursanız ve bir insansız içeriyorsa, çoğu durumda bunun bir karakter olduğunu varsayabilirsiniz.
Bir karaktere vurulduğunu kontrol etmek için weaponRaycastResult if ifadesine vurgulanan kodu ekleyin.
-- Başlangıç ve bitiş konumları arasında herhangi bir nesneye vuruldu mu kontrol edinlocal hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.Position-- Vuruş örneği bir karakter modelinin yavrusu olacak-- Bir insansız modelde bulunursa, muhtemelen oyuncunun karakteridirlocal characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid thenprint("Player hit")endendelse-- Maksimum lazer mesafesi üzerine dayanarak son konumu hesaplahitPosition = tool.Handle.Position + directionVectorend
Şimdi lazer patlayıcısı, ışın atma işlemi başka bir oyuncuya vurduğunda her seferinde çıktı penceresine Player hit basmalıdır.
Çok oyuncu ile test et
Silah ışınlarının diğer oyuncuları bulduğunu test etmek için iki oyuncu gereklidir, bu yüzden yerel bir sunucu başlatmanız gerekir.
Studio'da Test sekmesini seçin.
Oyuncuların bırakılması '2 Oyuncu' olarak ayarlanmış olduğundan emin olun ve başlat düğmesine tıklayarak yerel bir sunucuyu 2 istemci ile başlatın .Üç pencere görünecek.İlk pencere yerel sunucu olacak, diğer pencereler Player1 ve Player2 için müşteriler olacak.
Bir kliende, diğer oyuncuyu silahla vurarak testere ateş etmeyi test edin.Oyuncu vuruşu her oyuncuya vurulduğunda çıktıda görüntülenmelidir. "Player hit" should be displayed in the output each time a player is shot.
Test sekmesi hakkında daha fazla bilgi edinebilirsiniz burada.
Lazer konumunu bul
Lazer, hedefine kırmızı bir ışın atmalıdır.Bunun için işlevi bir ModuleScript içinde olacak, böylece daha sonra diğer kodlarda tekrar kullanılabilecek.Öncelikle, senaryonun lazer ışınının görüntülenmesi gereken konumu bulması gerekecek.
Create a ModülScript named LaserRenderer , StarterPlayerScripts altında StarterPlayer'a bağlı olarak
Senaryoyu aç ve modül tablosunu senaryonun adına yeniden adlandır LazerRenderörü .
Bir değere sahip SHOT_DURATION adlı bir değişkeni ilan edin, değeri 0.15 .Bu, lazerin görülebildiği süre (saniyeler) olacaktır.
LazerRenderör'ün adı createLaser olan bir işlev oluşturun ve iki parametre ile çağrılan toolHandle ve endPosition .
local LaserRenderer = {}local SHOT_DURATION = 0.15 -- Lazerin görülebildiği süre-- Bir başlangıç pozisyonundan son bir pozisyona doğru bir lazer ışını oluşturfunction LaserRenderer.createLaser(toolHandle, endPosition)endreturn LaserRendererBir değişken olan başlangıçPozisyonu adlı değişkeni ilan edin ve Pozisyon özelliğini toolHandle değer olarak ayarlayın.Bu, oyuncunun lazer bombardmanının konumu olacaktır.
Bir değişken olan lazer mesafe adlı değişkeni ilan edin ve iki vektör arasındaki farkı bulmak için endPosition 'den çıkarın startPosition çıkarın.Lazer ışınının uzunluğunu almak için bu Büyüklük özelliğini kullanın.
function LaserRenderer.createLaser(toolHandle, endPosition)local startPosition = toolHandle.Positionlocal laserDistance = (startPosition - endPosition).MagnitudeendLazer ışınının konumunu ve yönünü depolamak için bir laserCFrame değişken ilan edinPozisyon, ışının başlangıcından ve bitiminden orta nokta olmalıdır.Yeni bir CFrame.lookAt oluşturmak için 'a yerleştirilen ve 'e doğru yönelen yeni bir oluşturmak için kullanın ].Bunu negatif laserDistance yarısı bir Z eksen değeri ile yeni bir CFrame ile çarparak orta noktayı alın
function LaserRenderer.createLaser(toolHandle, endPosition)local startPosition = toolHandle.Positionlocal laserDistance = (startPosition - endPosition).Magnitudelocal laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)end
Lazer parçasını oluştur
Artık bir lazer ışını nerede oluşturacağınızı bildiğinize göre, ışının kendisini eklemelisiniz. Bu, Neon parçası ile kolayca yapılabilir.
Bir değişkeni lazerPart ilan edin ve ona yeni bir Part durum.
Aşağıdaki özellikleri laserPart ayarlayın:
- Boyut : Vector3.new(0.2, 0.2, lazer mesafesi)
- CFrame : lazerCFrame
- Sabitlenmiş : true
- CanCollide : false: Yapışabilir
- Renk : Color3.fromRGB(225, 0, 0) (güçlü kırmızı renk)
- Malzeme : Enum.Material.Neon
Ebeveyn laserPart Çalışma Alanına .
Parçayı Debris servisine ekleyin, böylece SHOT_DURATION değişkenin saniye sayısından sonra kaldırılır.
function LaserRenderer.createLaser(toolHandle, endPosition)local startPosition = toolHandle.Positionlocal laserDistance = (startPosition - endPosition).Magnitudelocal laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)local laserPart = Instance.new("Part")laserPart.Size = Vector3.new(0.2, 0.2, laserDistance)laserPart.CFrame = laserCFramelaserPart.Anchored = truelaserPart.CanCollide = falselaserPart.Color = Color3.fromRGB(225, 0, 0)laserPart.Material = Enum.Material.NeonlaserPart.Parent = workspace-- Kaldırılması ve temizlenmesi gereken Debris hizmetine lazer işını ekleyinDebris:AddItem(laserPart, SHOT_DURATION)end
Şimdi lazer ışınını görüntüleme işlevi tamamlandı, Araç Denetleyicisi tarafından çağrılabilir.
Araç Denetleyicisi skriptinin üstünde, LaserRenderer adlı bir değişken ilan edin ve OyuncuScriptlerde bulunan LaserRenderer ModülScript'ini gerektirin.
local UserInputService = game:GetService("UserInputService")local Players = game:GetService("Players")local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)local tool = script.ParentfireWeapon işlevinin dibinde, araç kolu ve createLaser ve hitPosition argümanları kullanarak LaserRenderer işlevini çağırın.
-- Maksimum lazer mesafesi üzerine dayanarak son konumu hesaplahitPosition = tool.Handle.Position + directionVectorendLaserRenderer.createLaser(tool.Handle, hitPosition)endOyun düğmesine tıklayarak silahı test edin. Araç etkinleştirildiğinde silah ve fare arasında bir lazer ışını görünmelidir.
Silah ateş değerlendirkontrol et
Silahların her atış arasında bir gecikmeye ihtiyacı vardır, böylece oyuncular kısa bir sürede çok fazla hasar veremez.Bir oyuncunun son kez ateş edildiğinden beri yeterli süre geçip geçmediğini kontrol ederek bunun kontrol edilebilir.
Bir değişkeni Araç Denetleyicisi üstünde ATEŞ_HIZI olarak ilan edin.Bu, her atış arasındaki minimum süre olacaktır.Seçtiğiniz bir değere verin; bu örnek 0.3 saniye kullanır.
Altında başka bir değişken ilan edin timeOfPreviousShot ile bir değeri 0 .Bu, oyuncunun son kez ateş ettiğini ve her atışla güncelleneceğini saklar.
local MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 300local FIRE_RATE = 0.3local timeOfPreviousShot = 0Hiçbir parametre ile canShootWeapon adlı bir işlev oluşturun.Bu işlev, önceki atıştan beri ne kadar süre geçtiğine bakacak ve gerçek veya yanlış döndürecek.
local FIRE_RATE = 0.3local timeOfPreviousShot = 0-- Önceki atışın ateş edildiğinden beri yeterli süre geçtiğini kontrol etlocal function canShootWeapon()endlocal function getWorldMousePosition()İşlevin içinde, currentTime adlı bir değişken ilan edin; tick() işlevini çağırmak sonucunu ona atayın.Bu, 1 Ocak 1970'ten (zamanı hesaplamak için yaygın olarak kullanılan rastgele bir tarihten) beri kaç saniye geçtiğini döndürür (zaman hesaplamak için geniş çapta kullanılan rastgele bir tarih).
Sonucun daha küçük olduğu durumda 'den çıkar ve yanlış geri döner eğer sonuç daha küçükse; aksi takdirde doğru geri döner.
-- Önceki atışın ateş edildiğinden beri yeterli süre geçtiğini kontrol etlocal function canShootWeapon()local currentTime = tick()if currentTime - timeOfPreviousShot < FIRE_RATE thenreturn falseendreturn trueendfireWeapon işlevinin sonunda, silah timeOfPreviousShot kullanılarak her seferinde güncellenir tick.
hitPosition = tool.Handle.Position + directionVectorendtimeOfPreviousShot = tick()LaserRenderer.createLaser(tool.Handle, hitPosition)endtoolActivated işlevinin içinde, bir if ifadesi oluşturun ve silahın ateş edilebilir olup olmadığını kontrol etmek için canShootWeapon çağırın.
local function toolActivated()if canShootWeapon() thentool.Handle.Activate:Play()fireWeapon()endend
Patlamayı test ettiğinizde, ne kadar hızlı tıklarsanız tıklayın, her atış arasında daima kısa bir 0.3 saniye gecikme olacağını bulmalısınız.
oyuncuzarar ver
Müşteriler doğrudan diğer müşterilere hasar veremez; bir oyuncuya hasar verildiğinde sunucunun hasar verme sorumluluğu üstlenmesi gerekir.
Müşteriler, bir karakterin vurulduğunu sunucuya söylemek için bir RemoteEvent kullanabilir.Bunların her ikisine de açık olduğu Yeniden Yazılabilir Depolama 'da saklanması gerekir.
ReplicatedStorage'a adı Etkinlikler olan bir Klasör oluştur .
Uzaktan Etkinliği Etkinlikler klasörüne ekleyin ve adlandırın HasarKarakteri .
In Araç Denetleyicisi , ReplicatedStorage ve Etkinlikler klasörünün başında değişkenler oluşturun.
local UserInputService = game:GetService("UserInputService")local Players = game:GetService("Players")local ReplicatedStorage = game:GetService("ReplicatedStorage")local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)local tool = script.Parentlocal eventsFolder = ReplicatedStorage.Eventslocal MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 500"Player hit" baskı ifadesini fireWeapon Luau ile bir satırla değiştirin, böylece HasarKarakteri uzaktaki olayı ile characterModel değişken bir argman olarak ateşleyin.
local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid theneventsFolder.DamageCharacter:FireServer(characterModel)endendelse-- Maksimum lazer mesafesi üzerine dayanarak son konumu hesaplahitPosition = tool.Handle.Position + directionVectorend
Sunucu, olay ateşlendiğinde vurulan oyuncuya hasar vermelidir.
ServerScriptService'e bir Kript Yazma ekleyin ve adlandırın Sunucu Lazer Yöneticisi .
LASER_DAMAGE adlı bir değişken ilan edin ve onu 10 veya seçtiğiniz bir değere ayarlayın.
Oluştur damageCharacter iki parametre ile adlandırılan bir işlev playerFired ve characterToDamage ile isimlendirin.
İşlevin içinde, karakterin Humanoid'ini bul ve sağlığından LASER_DAMAGE çıkar.
damageCharacter fonksiyonunu HasarKarakteri uzaktan etkinliğine Etkinlik klasöründe bağlayın.
local ReplicatedStorage = game:GetService("ReplicatedStorage")local eventsFolder = ReplicatedStorage.Eventslocal LASER_DAMAGE = 10function damageCharacter(playerFired, characterToDamage)local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")if humanoid then-- Karakterden sağlığı kaldırhumanoid.Health -= LASER_DAMAGEendend-- Etkinlikleri uygun işlevlere bağlaeventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)Yerel bir sunucu başlatarak patlayıcıyı 2 oyuncu ile test edin.Diğer oyuncuyu vurduğunuzda, sağlıkları LASER_DAMAGE 'a atanan sayı ile azalacaktır.
Diğer oyuncunun lazer ışınlarını görüntüle
Şu anda, lazer ışını silahı ateşleyen müşteri tarafından oluşturulduğundan, sadece onlar lazer ışını görebileceklerdir.
Lazer ışını sunucuda oluşturulduysa, herkes onu görebilirdi.Bununla birlikte, müşterinin silahı ateşlemesi ve sunucunun atışla ilgili bilgileri alması arasında küçük bir gecikme olurdu.Bu, müşterinin silahı ateş etmesinin, silahı aktifleştirdikleri ve lazer ışını gördükleri arasında bir gecikme görmesi demektir; sonuç olarak silah gecikmeli hissedecektir.
Bu sorunu çözmek için, her bir müşteri kendi lazer ışınlarını oluşturacaktır.Bu, müşterinin silahı ateşlemesiyle lazer ışını anında göreceği anlamına gelir.Diğer kullanıcılar, başka bir oyuncu ateş ettiğinde ve bir ışın göründüğünde küçük bir gecikme yaşayacaktır.En iyi durum senaryosu budur: başka müşterilerin lazerini bir müşteriden daha hızlı iletmenin bir yolu yoktur.
Ateş edenin müşterisi
Öncelikle, müşterinin, bir lazer ateşlediğini ve son konumu sağladığını sunucuya söylemesi gerekir.
ReplicatedStorage'daki Etkinlikler klasörüne bir Uzaktan Etkinlik ekleyin ve adlandırın LazerAteşli .
fireWeapon fonksiyonunu Araç Denetleyicisi skriptinde bulun.İşlevin sonunda, LaserFired uzaktan etkinliğini bir argüman olarak hitPosition ateşleyin.
hitPosition = tool.Handle.Position + directionVectorendtimeOfPreviousShot = tick()eventsFolder.LaserFired:FireServer(hitPosition)LaserRenderer.createLaser(tool.Handle, hitPosition)end
Sunucu
Artık sunucu, müşterinin ateşlediği olayı almalı ve tüm müşterilere lazer ışınının başlangıç ve bitiş konumunu söylemelidir, böylece onu da gösterebilirler.
Sunucu Lazer Yöneticisi skriptinde, oyuncuAteşlenenLazer adlı bir işlev oluşturun ve damageCharacter ve playerFired olarak adlandırılan iki parametre ile endPosition .
İşlevi LaserFired uzaktan etkinliğine bağlayın.
-- Tüm müşterilere bir lazerın ateş edildiğini bildirin, böylece lazeri görebilirlerlocal function playerFiredLaser(playerFired, endPosition)end-- Etkinlikleri uygun işlevlere bağlaeventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)
Sunucu lazerin başlangıç konumuna ihtiyaç duyar.Bunlar istemci tarafından gönderilebilir, ancak mümkün olduğunda istemciye güvenmekten kaçınılmalıdır.Karakterin silah tutma konumu başlangıç pozisyonu olacak, böylece sunucu oradan bulabilir.
Bir işlev oluştur getPlayerToolHandle playerFiredLaser işlevinin üzerinde bir parametre ile çalıştırın player .
Silah için oyuncunun karakterini aramak için aşağıdaki kodu kullanın ve kullanıcı arayüzü nesnesini geri gönderin.
local LASER_DAMAGE = 10-- Oyuncunun tuttuğu aletin kolu bulunlocal function getPlayerToolHandle(player)local weapon = player.Character:FindFirstChildOfClass("Tool")if weapon thenreturn weapon:FindFirstChild("Handle")endend-- Tüm müşterilere bir lazerın ateş edildiğini bildirin, böylece lazeri görebilirlerlocal function playerFiredLaser(playerFired, endPosition)
Sunucu artık FireAllClients ı LaserFired uzaktaki olaya çağırarak lazerin müşterilere gönderilmesi gereken bilgileri gönderebilir.Buna, lazeri ateşleyen oyuncu dahil edilir (yani bu oyuncu için müşteri, lazer için başlangıç pozisyonu olarak hareket eden blaster ve lazerin son pozisyonu), lazerin son pozisyonu ve lazerin son pozisyonu.
işlevinde, işlevini bir argman olarak çağırın ve değeri toolHandle adlı değişkene atayın.
Eğer toolHandle varsa, playerFired , toolHandle ve endPosition gibi tüm kullanıcılar için LaserFired etkinliğini ateşleyin, argüman olarak.
-- Tüm müşterilere bir lazerın ateş edildiğini bildirin, böylece lazeri görebilirlerlocal function playerFiredLaser(playerFired, endPosition)local toolHandle = getPlayerToolHandle(playerFired)if toolHandle theneventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)endend
Müşterilerde görüntüleme
Şimdi FireAllClients çağrıldı ve her bir kullanıcı, lazer ışını görüntülemek için sunucudan bir olay alacak.Her bir müşteri, lazer ışınını sunucunun tarafından gönderilen aletin tutma konumu ve son konum değeri kullanarak renderlemek için daha önce LazerRenderörü modülünü yeniden kullanabilir.Lazer ışını ilk sırada ateşleyen oyuncu bu olayı görmezse, 2 lazer görecekler.
BaşlatıcıOyunScriptleri adlı YerelScript oluşturun, ClientLaserManager adında.
Senaryo içinde, LazerRenderleyici modülünü gerektirin.
CreatePlayerLaser adlı işlevi createPlayerLaser ile parametreler playerWhoShot , toolHandle ve endPosition ile oluşturun.
İşlevi LaserFired uzaktan etkinliğine Etkinlikler klasöründe bağlayın.
Fonksiyonda, if ifadesini kullanarak, ifadesinin Yerel Oynatıcı ile eşit olmadığını kontrol edin.
if ifadesinin içinde, createLaser fonksiyonunu toolHandle ve endPosition argümanları kullanarak LaserRenderer modülünden çağırın.
local Players = game:GetService("Players")local ReplicatedStorage = game:GetService("ReplicatedStorage")local LaserRenderer = require(script.Parent:WaitForChild("LaserRenderer"))local eventsFolder = ReplicatedStorage.Events-- Diğer bir oyuncunun lazerini gösterlocal function createPlayerLaser(playerWhoShot, toolHandle, endPosition)if playerWhoShot ~= Players.LocalPlayer thenLaserRenderer.createLaser(toolHandle, endPosition)endendeventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)Yerel bir sunucu başlatarak patlayıcıyı 2 oyuncu ile test edin.Her bir müşteriyi monitörün farklı taraflarına yerleştirin, böylece her iki pencereyi aynı anda görebilirsiniz.Bir müşteride vurduğunuzda, diğer müşteride lazeri görmelisiniz.
Ses etkileri
Ateş eden ses efekti şu anda sadece mermiyi ateş eden istemci üzerinde çalıyor.Kodu oynatmak için ses çıkarmak için diğer oyuncuların da duyacağı şekilde taşımanız gerekecek.
Araç Denetleyicisi skriptinde, araç aktifleştirildi işlevine geç ve aktifleştirme sesini çalan satırı kaldır.
local function toolActivated()if canShootWeapon() thenfireWeapon()endendLazerRenderör içindeki fonksiyonun dibinde, atış sesi adlı bir değişken ilan edin ve aktifleştirme sesi kontrol etmek için yöntemini kullanın.
if ifadesini kullanarak var olup olmadığını kontrol edin shootingSound ; eğer varsa, onun Oynatma işlevini çağırın.
laserPart.Parent = workspace-- Kaldırılması ve temizlenmesi gereken Debris hizmetine lazer işını ekleyinDebris:AddItem(laserPart, SHOT_DURATION)-- Silahın atış sesini çallocal shootingSound = toolHandle:FindFirstChild("Activate")if shootingSound thenshootingSound:Play()endend
Doğrulama kullanarak uzaktan güvenli hale getirme
Sunucu gelen isteklerden veri kontrol etmiyorsa, bir bilgisayar korsanı uzaktaki işlevleri ve olayları kötüye kullanabilir ve sunucuya sahte değerler göndermek için kullanabilir.Bunu önlemek için sunucu tarafı doğrulama kullanmak önemlidir.
Mevcut formunda, HasarKarakteri uzaktan olayı saldırıya çok açıktır.Hackerlar bu olayı kullanarak oyunda istedikleri herhangi bir oyuncuya ateş etmeden hasar verebilirler.
Doğrulama, sunucuya gönderilen değerlerin gerçekçi olup olmadığını kontrol etme sürecidir. Bu durumda, sunucunun şunlara ihtiyacı olacaktır:
- Oyuncu ve lazer tarafından vurulan konum arasındaki mesafenin belirli bir sınır içinde olup olmadığını kontrol edin.
- Lazer ateşleyen silah ve vuruş pozisyonu arasında ışın atışının mümkün olduğundan ve herhangi bir duvardan geçmediğinden emin olmak için Raycast.
Müşteri
Client, ışınlama tarafından vurulan konumu sunucuya göndermelidir, böylece mesafenin gerçekçi olup olmadığını kontrol edebilir.
In Araç Denetleyicisi , DamageCharacter uzaktan etkinliğinin fireWeapon fonksiyonunda ateşlendiği satıra yönlendirin.
Bir argüman olarak hitPosition ekleyin.
if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid theneventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)endend
Sunucu
Müşteri şimdi HasarKarakter uzaktan etkinliği aracılığıyla ek bir parametre gönderiyor, bu yüzden kabul etmek için SunucuLazerYöneticisi ayarlandı gerekiyor.
Sunucu Lazer Yöneticisi skriptinde, hitPosition fonksiyonuna bir damageCharacter değeri ekleyin.
function damageCharacter(playerFired, characterToDamage, hitPosition)local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")if humanoid then-- Karakterden sağlığı kaldırhumanoid.Health -= LASER_DAMAGEendend] işlevinin altında, üç parametre ile adlandırılan bir işlev oluşturun: isHitValid , ve .
endlocal function isHitValid(playerFired, characterToDamage, hitPosition)end
İlk kontrol, vuruş pozisyonu ve karakter vuruşu arasındaki mesafe olacaktır.
Senaryonun başında bir değişken olan MAX_HIT_PROXIMITY adlı değişkeni ilan edin ve ona bir değer atayın 10 .Bu, isabet ve karakter arasında izin verilen maksimum mesafe olacaktır.Karakter, müşteri etkinliği ateşlediğinden beri hafifçe hareket etmiş olabilir, bu yüzden bir tolerans gereklidir.
local ReplicatedStorage = game:GetService("ReplicatedStorage")local eventsFolder = ReplicatedStorage.Eventslocal LASER_DAMAGE = 10local MAX_HIT_PROXIMITY = 10isHitValid fonksiyonunda, karakter ve vuruş pozisyonu arasındaki mesafeyi hesaplayın.Mesafe MAX_HIT_PROXIMITY daha büyükse, geri dön yalan .
local function isHitValid(playerFired, characterToDamage, hitPosition)-- Karakter vuruşu ve vuruş pozisyonu arasındaki mesafeyi doğrulalocal characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitudeif characterHitProximity > MAX_HIT_PROXIMITY thenreturn falseendend
İkinci kontrol, ateş edilen silah ve vuruş pozisyonu arasında bir ışın atışı içerecektir.Işın atışı karakter olmayan bir nesneyi döndürürse, atışın geçersiz olduğunu varsayabilirsiniz, çünkü bir şey atışı engelliyordu.
Bu kontrol etyürütmek için aşağıdaki kodu kopyalayın. İşlevin sonunda doğru döndürün: eğer bitirulaşırsa, tüm kontroller geçmiştir.
local function isHitValid(playerFired, characterToDamage, hitPosition)-- Karakter vuruşu ve vuruş pozisyonu arasındaki mesafeyi doğrulalocal characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitudeif characterHitProximity > 10 thenreturn falseend-- Duvarlardan atış yapıp yapmadığınızı kontrol edinlocal toolHandle = getPlayerToolHandle(playerFired)if toolHandle thenlocal rayLength = (hitPosition - toolHandle.Position).Magnitudelocal rayDirection = (hitPosition - toolHandle.Position).Unitlocal raycastParams = RaycastParams.new()raycastParams.FilterDescendantsInstances = {playerFired.Character}local rayResult = workspace:Raycast(toolHandle.Position, rayDirection * rayLength, raycastParams)-- Karakter olmayan bir örnek vurulduysa, atışı görmezden gelinif rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) thenreturn falseendendreturn trueendGeçerli atış olarak adlandırılan damageCharacter işlevinde bir değişken ilan edin validShot .Üç argümanla bir isHitValid fonksiyonuna yapılan çağrının sonucunu atayın: playerFired , characterToDamage ve hitPosition.
Aşağıdaki if ifadesinde, 'in doğru olup olmadığını kontrol etmek için bir ve operatörü ekleyin.
function damageCharacter(playerFired, characterToDamage, hitPosition)local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")local validShot = isHitValid(playerFired, characterToDamage, hitPosition)if humanoid and validShot then-- Karakterden sağlığı kaldırhumanoid.Health -= LASER_DAMAGEendend
Artık hasarKarakter uzaktan etkinliği daha güvenli ve çoğu oyuncunun bunu kötüye kullanmasını engelleyecek.Bazı kötü niyetli oyuncuların sıklıkla doğrulama etrafında yollar bulacağını unutmayın; uzaktaki olayları güvende tutmak sürekli bir çaba.
Lazer bombardman silahınız artık temel bir vuruş algılama sistemi kullanarak raycasting ile tamamlandı.Lazer silahınıza yeniden yükleme eylemi ekleyebilmenizi veya eğlenceli bir oyun haritası oluşturabilmenizi ve diğer oyuncularla lazer silahınızı deneyebilmenizi bulmak için Kullanıcı Girişi Tespiti eğitimini deneyin!
Final kodu
Araç Kontrolörü
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)
local tool = script.Parent
local eventsFolder = ReplicatedStorage.Events
local MAX_MOUSE_DISTANCE = 1000
local MAX_LASER_DISTANCE = 500
local FIRE_RATE = 0.3
local timeOfPreviousShot = 0
-- Önceki atışın ateş edildiğinden beri yeterli süre geçtiğini kontrol et
local function canShootWeapon()
local currentTime = tick()
if currentTime - timeOfPreviousShot < FIRE_RATE then
return false
end
return true
end
local function getWorldMousePosition()
local mouseLocation = UserInputService:GetMouseLocation()
-- 2D fare konumundan bir ışın oluştur
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- Işının birim yön vektörü maksimum mesafe ile çarptırıldı
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- Kraliyetin kaynağından kendi yönüne doğru ışınlanma
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- 3B kesişme noktasını geri dönün
return raycastResult.Position
else
-- Hiçbir nesne vurulmadı, bu yüzden ışının sonundaki konumu hesaplayın
return screenToWorldRay.Origin + directionVector
end
end
local function fireWeapon()
local mouseLocation = getWorldMousePosition()
-- Normalize edilmiş bir yön vektörü hesaplayın ve lazer mesafesi ile çarptırın
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- Silahı ateş etmek için yön, maksimum mesafe ile çarptırılır
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- oyuncukarakterini görmezden gelerek kendilerine zarar vermelerini engelle
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
-- Başlangıç ve bitiş konumları arasında herhangi bir nesneye vuruldu mu kontrol edin
local hitPosition
if weaponRaycastResult then
hitPosition = weaponRaycastResult.Position
-- Vuruş örneği bir karakter modelinin yavrusu olacak
-- Bir insansız modelde bulunursa, muhtemelen oyuncunun karakteridir
local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")
if characterModel then
local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
if humanoid then
eventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)
end
end
else
-- Maksimum lazer mesafesi üzerine dayanarak son konumu hesapla
hitPosition = tool.Handle.Position + directionVector
end
timeOfPreviousShot = tick()
eventsFolder.LaserFired:FireServer(hitPosition)
LaserRenderer.createLaser(tool.Handle, hitPosition)
end
local function toolEquipped()
tool.Handle.Equip:Play()
end
local function toolActivated()
if canShootWeapon() then
fireWeapon()
end
end
tool.Equipped:Connect(toolEquipped)
tool.Activated:Connect(toolActivated)
Lazer Renderlayıcı
local LaserRenderer = {}
local Debris = game:GetService("Debris")
local SHOT_DURATION = 0.15 -- Lazerin görülebildiği süre
-- Bir başlangıç pozisyonundan son bir pozisyona doğru bir lazer ışını oluştur
function LaserRenderer.createLaser(toolHandle, endPosition)
local startPosition = toolHandle.Position
local laserDistance = (startPosition - endPosition).Magnitude
local laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)
local laserPart = Instance.new("Part")
laserPart.Size = Vector3.new(0.2, 0.2, laserDistance)
laserPart.CFrame = laserCFrame
laserPart.Anchored = true
laserPart.CanCollide = false
laserPart.Color = Color3.fromRGB(255, 0, 0)
laserPart.Material = Enum.Material.Neon
laserPart.Parent = workspace
-- Kaldırılması ve temizlenmesi gereken Debris hizmetine lazer işını ekleyin
Debris:AddItem(laserPart, SHOT_DURATION)
-- Silahın atış sesini çal
local shootingSound = toolHandle:FindFirstChild("Activate")
if shootingSound then
shootingSound:Play()
end
end
return LaserRenderer
SunucuLazerYöneticisi
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local eventsFolder = ReplicatedStorage.Events
local LASER_DAMAGE = 10
local MAX_HIT_PROXIMITY = 10
-- Oyuncunun tuttuğu aletin kolu bulun
local function getPlayerToolHandle(player)
local weapon = player.Character:FindFirstChildOfClass("Tool")
if weapon then
return weapon:FindFirstChild("Handle")
end
end
local function isHitValid(playerFired, characterToDamage, hitPosition)
-- Karakter vuruşu ve vuruş pozisyonu arasındaki mesafeyi doğrula
local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
if characterHitProximity > MAX_HIT_PROXIMITY then
return false
end
-- Duvarlardan atış yapıp yapmadığınızı kontrol edin
local toolHandle = getPlayerToolHandle(playerFired)
if toolHandle then
local rayLength = (hitPosition - toolHandle.Position).Magnitude
local rayDirection = (hitPosition - toolHandle.Position).Unit
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {playerFired.Character}
local rayResult = workspace:Raycast(toolHandle.Position, rayDirection * rayLength, raycastParams)
-- Karakter olmayan bir örnek vurulduysa, atışı görmezden gelin
if rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) then
return false
end
end
return true
end
-- Tüm müşterilere bir lazerın ateş edildiğini bildirin, böylece lazeri görebilirler
local function playerFiredLaser(playerFired, endPosition)
local toolHandle = getPlayerToolHandle(playerFired)
if toolHandle then
eventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)
end
end
function damageCharacter(playerFired, characterToDamage, hitPosition)
local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
local validShot = isHitValid(playerFired, characterToDamage, hitPosition)
if humanoid and validShot then
-- Karakterden sağlığı kaldır
humanoid.Health -= LASER_DAMAGE
end
end
-- Etkinlikleri uygun işlevlere bağla
eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)
MüşteriLazerYöneticisi
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LaserRenderer = require(Players.LocalPlayer.PlayerScripts:WaitForChild("LaserRenderer"))
local eventsFolder = ReplicatedStorage.Events
-- Diğer bir oyuncunun lazerini göster
local function createPlayerLaser(playerWhoShot, toolHandle, endPosition)
if playerWhoShot ~= Players.LocalPlayer then
LaserRenderer.createLaser(toolHandle, endPosition)
end
end
eventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)