Bu öğretici, lazeri Oyuncu Aletlerini Oluşturma blasterinden nasıl kullanacağınızı öğretecek ve bir oyuncuya vurup vurmadığını tespit edecek.
Çarpışma Bulmak için Raycasting
Raycasting başlangıç pozisyonundan itibaren belirli bir yöne doğru görünmez bir ray oluşturur. Eğer ışın kaynağının yolunun üstünde nesneler veya arazi ile çarpışırsa, çarpışma konusunda ara bilgisi döndürür. Bu, konum ve çarpıştığı nesne gibi yolunuzun üzerindeki nesneleri içerir.
Farenin Konumunu Bulma
Lazer atışlanmadan önce, oyuncunun nereye nişan alacağını ilk olarak bilmelisiniz. Bu, oyuncunun 2D mouse'ının ekranda doğrudan kamera tarafından ileriye gönderilmiş yerinde raycasting yaparak bulunabilir. Oyun dünyasındaki fareçarpışacaktır.
Oyuncu Araçları Oluşturucu içindeki AraçKontrolörü scriptini açın. Eğer oyunu tamamlamadıysanız, Blaster modelini indirebilir ve StarterPack'e kaydederken kullanabilirsiniz.
Skriptinizin başında, 1000 ile bir konum belirleyin.
getWorldMousePosition adında bir işlev oluştur.
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-- Olayları uygun işlevlere bağlayıntool.Equipped:Connect(toolEquipped)tool.Activated:Connect(toolActivated)Ekranda oyuncunun 2D mouse konumunu almak için UserInputService 의 GetMouseLocation işlevini kullanın. Bu, mouseLocation adlı değişkeni 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, onun X ve Y özellikleri Class.Camera:ViewportPointToRay() fonksiyonu için parametre olarak kullanılabilir, bu da ekrandanı 3D oyun dünyasına oluşturan bir 1> Datatype.Ray1> oluşturur.
- X ve Y özelliklerini kullanırken mouseLocation ile bir 1> Class.Camera:ViewportPointToRay()|ViewportPointToRay()1> işlevi için bir argüman olarak kullanın. Bu, 4> screenToWorldRay4> adlı bir değişkeni kullanarak atayın.
local function getWorldMousePosition()
local mouseLocation = UserInputService:GetMouseLocation()
-- 2D fare konumundan bir ışın oluştur
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
end
Raycast'ı kullanarak objeye ışınlanıp ışınlanmadığını kontrol etme zamanı geldi. Bu, bir başlangıç pozisyonu ve yön vektörü gerektirir: Bu ö例mde, Raycast 'in orijinal ve yön özelliklerini kullanacaksınız.
Yön vektörünün uzunluğu, ışının seyahat etmesi için ne kadar uzun olacağını belirler. Işın MAX_MOUSE_DISTANCE uzunluğundan olmalıdır, bu yüzden yön vektörünü MAX_MOUSE_DISTANCE ile çarpmalısınız.
directionVector adında bir değişkeni ilan et ve screenToWorldRay.Direction ile çarpan MAX_MOUSE_DISTANCE değerine sahip.
local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()-- 2D fareLocation'inden bir ray oluşturlocal screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)-- Işının maksimum mesafeyle çarpan birimi direktörülocal directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCEÇalışma alanındaki Raycast işlevini çağırın, screenToWorldRaynın ilk argümanı olarak screenToWorldRay özelliğini kullanarak ortak olarak verin ve 2>raycastResult2> olarak ikinci olarak. Bu, 5>raycastResult5> adlı değişkeni
local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()-- 2D fareLocation'inden bir ray oluşturlocal screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)-- Işının maksimum mesafeyle çarpan birimi direktörülocal directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE-- Ray'in yönüne doğru uzay kayışılocal raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
Çarpışma Bilgisi
Raycast operasyonu bir raya vurulan bir nesneyi bulursa, bir RaycastResult döndürür, bu, ray ve nesne arasındaki çarpışma hakkında bilgi içerir.
RaycastResult Özelliği | Açıklama |
---|---|
Oyuncu Instancesı | Işının kesiştiği BasePart veya Terrain hücre. |
Pozisyon | Çarpışma nerede gerçekleşir; genellikle bir noktanın yüzeyinde doğrudan bir noktadır. |
Malzeme | Çarpışma noktasındaki malzeme. |
Normal | Kesişmiş yüzün normal vektörü. Bu, yüzün hangi yönde olduğunu belirlemek için kullanılabilir. |
Pozisyon özelliği, farenin üzerinde durduğu nesnenin pozisyonu olacaktır. Eğer fare MAX_MOUSE_DISTANCE içinde herhangi bir nesneye değilse, raycastResult nil olacaktır.
raycastResult ile ilgili olup olmadığını kontrol etmek için bir if oluşturun.
Eğer raycastResult bir değeri varsa, onun Position özelliğini döndür.
Eğer raycastResult boşsa, ışınlanmanın sonunu bulun. screenToWorldRay.Origin ile ışınlanmanın 3D konumunu hesaplayın, directionVector ile birlikte.
local function getWorldMousePosition()
local mouseLocation = UserInputService:GetMouseLocation()
-- 2D fareLocation'inden bir ray oluştur
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- Işının maksimum mesafeyle çarpan birimi direktörü
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- Ray'in yönüne doğru uzay kayışı
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- 3D kesişim noktasını iade edin
return raycastResult.Position
else
-- Hiçbir nesneye vurulmadığı için, ışının sonundaki pozisyonu hesaplayın
return screenToWorldRay.Origin + directionVector
end
end
Hedefe Doğru Ateşleniyor
Artık 3D mouse pozisyonu biliniyor, bir lazerın doğru yönünü vurmak için kullanılabilir bir hedef pozisyonu . Bir ikinci ışın oyuncunun silahından hedef pozisyonuna kullanılabilir Raycast işlevi kullanılır.
Scriptinizin üstündeki MAX_LASER_DISTANCE değerini ilan et ve onu 500 veya lazer makinesi için seçtiğin menziliye atla.
local UserInputService = game:GetService("UserInputService")local tool = script.Parentlocal MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 500fireWeapon adında bir işlev oluşturun getWorldMousePosition işlevi altında.
getWorldMousePosition çağırın ve sonucu mousePosition değişkenine atayın. Bu, raycast için hedef pozisyonu olacaktır.
-- Hiçbir nesneye vurulmadığı için, ışının sonundaki pozisyonu hesaplayınreturn screenToWorldRay.Origin + directionVectorendendlocal function fireWeapon()local mouseLocation = getWorldMousePosition()endlocal function toolEquipped()tool.Handle.Equip:Play()end
Bu sefer, raycast işlevinin yön vektörü, oyuncunun alet pozisyonundan hedef konumuna yönü temsil edecektir.
Hedef Yönü adındaki bir değişkeni ilan edin ve araç pozisyonunu mouseLocation 'den çıkararak yön vektörünü hesaplayın.
Vektörü normalize etmek için onun Unit özelliğini kullanın. Bu, onu daha sonra uzunluğa çarpanmak için kolaylıkla 1 büyüklüğünde yapar.
local function fireWeapon()local mouseLocation = getWorldMousePosition()-- Normal bir yön vektörü hesaplayın ve lazer mesafesi ile çarpanlocal targetDirection = (mouseLocation - tool.Handle.Position).UnitendBir çeşyayı DirectionVector adında ilan et ve targetDirection ile çarpan MAX_LASER_DISTANCE değerine sahip ol.
local targetDirection = (mouseLocation - tool.Handle.Position).Unit-- Silahı ateş etmenin yönü, maksimum mesafe ile çarpanlocal directionVector = targetDirection * MAX_LASER_DISTANCEend
Bir RaycastParams nesnesi, raycast için ek göstergeleri depolamak için kullanılabilir. It will be used in your laser blaster to make sure the raycast doesn't accidentally collide with the player firing the weapon. Any parts included in the FilterDescendantsInstances property
fireWeapon işlevini devam ettirin ve bir değişken olan SilahRaycastParams 'yi ilan edin. Yeni bir RaycastParams nesline atın.
oyuncuyerel karakterini içeren bir tab oluştur ve weaponRaycastParams.FilterDescendantsInstances özelliğine atla.
oyuncualet kolu pozisyonundan, bir yönde directionVector 'e doğru şekilde weaponRaycastParams ekleyin. Bu sefer weaponRaycastParams olarak bir argüman ekleyin. Bu değişkeni 2> silahRaycastResult2> olarak 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()
-- Normal bir yön vektörü hesaplayın ve lazer mesafesi ile çarpan
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- Silahı ateş etmenin yönü maksimum mesafe ile çarpan bir mesafe arttırılır
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- oyuncukarakterini görmezden gelin, onların kendilerine zarar vermesini önleyin
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
end
Son olarak, raycast operasyonunun bir değer döndürdüğünden emin olmalısınız. Eğer bir değer döndürülürse, bir obje silahın yanında oluşturulur ve bir lazer oluşturulur. Hiçbir şey döndürülmediyse, lazer oluşturmak için son pozisyon hesaplanmalıdır.
Boş bir değer oluşturarak hitPosition adında bir boş değer ilan edin.
Bir if ifadesini kullanarak weaponRaycastResult ın bir değeri olup olmadığını kontrol edin. Eğer bir nesne vurulursa, weaponRaycastResult.Position ın 1> hitPosition1> ına atın.
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)-- Başlangıç ve son pozisyonları arasında herhangi bir nesneye vurulup vurulmadığını kontrol edinlocal hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.PositionendEğer weaponRaycastResult hiç değer yoksa, pozyon ı alet başlığı ile birleştirerek directionVector hesaplayın. Bu değeri 1>hataPosition1> ile atayın.
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)-- Başlangıç ve son pozisyonları arasında herhangi bir nesneye vurulup vurulmadığını kontrol edinlocal hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.Positionelse-- Maksimum lazer mesafasına dayanarak son pozisyonu hesap ethitPosition = tool.Handle.Position + directionVectorendendNavigate to the toolActivated function and call the fireWeapon function so that the laser fires each time the tool is activated.
local function toolActivated()tool.Handle.Activate:Play()fireWeapon()end
Nesne Hit'ini Kontrol Etme
Lazer tarafından vurulan nesnenin bir oyuncunun karakteri parçası olduğunu veya sadece bir manzara parçası olduğunu bulmak için bir Humanoid arayın, her karaktere bir tane var.
İlk olarak, karakter modelini bulmanız gerekir. Eğer karakterin bir kısmı vurulursa, vurulan karakterin ebeveyni olarak karakteri varsayamazsınız. Laser bir vücut bölgesine, bir aksesuara veya bir alete vurabilir, tüm bu bölgeler karakterin hierarjisinde bulunur.
Lazer tarafından vurulan bir nesnenin karakter modeli atalarını bulmak için FindFirstAncestorOfClass kullanabilirsiniz, varsa. Eğer bir model varsa ve bir insanoid içeriyorsa, çoğu durumda bunu bir karakter olarak varsayabilirsiniz.
Bir karakterin vurulup vurulmadığını kontrol etmek için weaponRaycastResultif if statement'ına bir kod ekleyin.
-- Başlangıç ve son pozisyonları arasında herhangi bir nesneye vurulup vurulmadığını kontrol edinlocal hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.Position-- İstek edilen instans bir karakter modelinin bir çocuğu olacaktır-- Bir humanoid modelinde bulunursa, muhtemelen bir oyuncu karakteridirlocal characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid thenprint("Player hit")endendelse-- Maksimum lazer mesafasına dayanarak son pozisyonu hesap ethitPosition = tool.Handle.Position + directionVectorend
Şimdi lazer blaster herhangi bir oyuncu tarafından vurulduğunda Player hit çıkış penceresine yazdırmalıdır.
Çok Oyunculu Test
Silah ışınlanma aracının başka oyuncuları bulup bulmadığını test etmek için iki oyuncu gerekli, bu yüzden yerel bir sunucuya başlatmanız gerekir.
Stüdyo'daki Test seklini seçin.
Oyuncuların menüsünü '2 Oyuncu' olarak ayarladığından emin olun ve Başlat düğmesine tıklayarak başlat bir yerel sunucuyu 2 istemcisiyle başlatın. Üç pencere görüntülenir. İlk pencere yerel sunucu olacak, diğer pencereler Player1 ve Player2 için istemciler olacak.
Bir klijüste, diğer oyuncuya silahla tıklayarak test atışını test edin. "Player hit" her oyuncu vurulduğunda çıktıda görüntülenmelidir.
Test buradan sayfasında daha fazlasını öğrenebilirsiniz.
Lazer Konumunu Bulma
Blaster hedefine kırmızı bir ışın atmalıdır. Bunun için kullanılan işlev ModuleScript içine olacaktır, böylece daha sonra başka kodlarda kullanılabilir. İlk olarak, kodun laser ışınının renderlenmesi gereken yerini bulması gerekir.
Bir ModuleScript oluştur, LaserRender adında, StarterPlayerScripts altındaki ebeveyni.
Scripti aç ve modül tablosunu LaserRender isimine yeniden adlandır.
Lazerin görünür olduğu süreyi belirtmek için SHOT_DURATION adlı bir değişkeni kullanın. Bu, lazerin görünür olduğu süreyi (saniye olarak) belirtir.
LaserRender'ın bir işlevini oluştur createLaser ile iki parametreli toolHandle ve endPosition .
local LaserRenderer = {}local SHOT_DURATION = 0.15 -- Lazerin görünür olması için-- Bir lazer kaynağından bir başlangıç pozisyonuna kadar bir son pozisyon oluşturfunction LaserRenderer.createLaser(toolHandle, endPosition)endreturn LaserRendererBir çeşyayı başlangıç pozisyonu olarak adlandır ve pozyon özelliğini toolHandle olarak değer olarak ayarla. Bu, oyuncunun lazer silahının pozisyonunu olacak.
Lazer mesafesini lazerDistance olarak deklare ve endPosition 'i startPosition 'den çıkararak iki vektör arasındaki farkı bulmak için kullanın. Bu öğünkü 1> Büyüklüğü1> özelliğini kullanarak lazer ışını uzunluğunu elde edebilirsiniz.
function LaserRenderer.createLaser(toolHandle, endPosition)local startPosition = toolHandle.Positionlocal laserDistance = (startPosition - endPosition).MagnitudeendBir laserCFrame değişkenini depolamak için lazer ışınının konumunu ve yönünü. Konum, başlangıç ve sonu iletkenin orta noktası olmalıdır. Kullanmak i
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ı Oluşturulması
Lazer gücünü oluşturacak yeri biliyorsunuz, şimdi güç için kendi başına eklemelisiniz. Bu, bir Neon parçasıyla kolayca yapılabilir.
Bir değişken laserPart ilan et ve ona yeni bir Part durumatla.
laserPart 'in aşağıdaki özelliklerini ayarlar:
- Boyut : Vector3.new(0.2, 0.2, laserDistance)
- CFrame : laserCFrame
- Sabitlenmiş : doğru
- Çarpışabilir miyim : false
- Rengi : Color3.fromRGB(225, 0, 0) (güçlü bir kırmızı renk)
- Malzeme : Enum.Material.Neon
Ana laserPart Çalışma Alanı .
Parçayı Debris hizmetine ekleyin, böylece SHOT_DURATION değişkeninin miktarı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-- Kayıp parçalar hizmetine lazer gecesi ekleyin ve temizleDebris:AddItem(laserPart, SHOT_DURATION)end
Lazer ışınını oluşturan işlev artık tamamlandı, Araç Kontrolörü olarak adlandırılabilir.
AraçKontrolörü scriptinin yukarı kısmında, LaserRender adında bir değişken ilan et ve PlayerScripts'de bulunan LaserRender Modülü Kısmını gerektir.
local UserInputService = game:GetService("UserInputService")local Players = game:GetService("Players")local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)local tool = script.ParentfireWeapon işlevinin altında, araç kolu ile LaserRender createLaser işlevini çağırın ve hitPosition ile argeler olarak kullanın.
-- Maksimum lazer mesafasına dayanarak son pozisyonu hesap ethitPosition = tool.Handle.Position + directionVectorendLaserRenderer.createLaser(tool.Handle, hitPosition)endSilahı test etmek için Oyna düğmesine tıklayın. Bir lazer gücü, alet etkinleştirildiğinde silah ve fare arasında görünmelidir.
Silah Ateş Hızını Kontrol Etme
Silahlar, oyuncuların çok fazla hasar vermesini önlemek için her atış arasında bir gecikmeye ihtiyaç duyar. Bu, bir oyuncu son kez ateş ettiğinden beri yeterli süre geçmişかどうか kontrol ederek kontrol edilebilir.
Araç Kontrolcüsü'nün üstünde bir değişken ilan et Ateş Hızı . Bu, her atış arasındaki minimum zaman olacaktır. Ona seçtiğin değer ver; bu örnek 0.3 saniye kullanıyor.
Aşağıdaki timeOfPreviousShot adındaki başka bir değişkeni 0 değerinde aşağıda ilan etmek. Bu, oyuncunun ateş ettiği son kez güncellenir ve her atışla güncellenecek.
local MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 300local FIRE_RATE = 0.3local timeOfPreviousShot = 0Bir parametre olmadan canShootWeapon adında bir işlev oluşturun. Bu işlev, önceki atıştan bu yana kaç saniye olduğunu gözden geçirecek ve geri dönüşümüzü doğru veya yanlış yapacaktır.
local FIRE_RATE = 0.3local timeOfPreviousShot = 0-- Önceki atıştan sonra yeterli süre geçmiş olup olmadığını kontrol edinlocal function canShootWeapon()endlocal function getWorldMousePosition()İşlevin içinde currentTime adında bir değişken ilan edin; bu, tick() işlevinin sonucunu atar. Bu, 1. Ocak 1970'den beri (genel olarak kullanılan herhangi bir tarih) itibariyle kaç saniye olduğunu gösterir.
timeOfPreviousShot ‘i currentTime ‘den çıkar ve sonuç FIRE_LETE ‘den daha küçükse 1> false1> ‘i döndür; aksi takdirde 4> true4> döndür.
-- Önceki atıştan sonra yeterli süre geçmiş olup olmadığını kontrol edin
local function canShootWeapon()
local currentTime = tick()
if currentTime - timeOfPreviousShot < FIRE_RATE then
return false
end
return true
end
fireWeapon işlevinin sonunda, silahın ateşlenmesi her seferinde timeOfPreviousShot güncellemeyi gösterir.
hitPosition = tool.Handle.Position + directionVectorendtimeOfPreviousShot = tick()LaserRenderer.createLaser(tool.Handle, hitPosition)endtoolActivated işlevinin içinde, bir if ifadesini oluşturun ve silahı ateş etmeyi kontrol etmek için canShootWeapon ı arayın.
local function toolActivated()if canShootWeapon() thentool.Handle.Activate:Play()fireWeapon()endend
Blaster'ı test ettiğinizde, ne kadar hızlı tıkladığınıza bağlı olarak, her atış arasında daima kısa bir 0.3 saniye gecikme olacağını bulmalısınız.
Oyuncuya Hasar Verme
İstemciler diğer istemcilere doğrudan hasar veremez; sunucunun bir oyuncuya vurduğunda hasar vermeyi sorumlu olması gerekir.
Müşteriler, bir karakterin vurulduğunu söylemek için bir RemoteEvent kullanabilir. Bunlar ReplicatedStorage , bunların herhangi bir müşteri ve sunucu tarafından görüntülenebileceği yer olmalıdır.
Etkinlikler adında ReplicatedStorage içinde bir Dizin Oluştur.
Etkinlikler klasına bir uzaktan etkinliği ekleyin ve ona şu adı verin DamageCharacter .
In ToolController , script'in başlangıcındaki değişkenleri ReplicatedStorage ve Etkinlikler klasörleri için 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 = 500DamageCharacter uzaktan etkinliğiyle ilgili fireWeapon iletişimini bir Lua satırıyla değiştirerek 1>Player hit1> iletişimini değiştirin.
local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid theneventsFolder.DamageCharacter:FireServer(characterModel)endendelse-- Maksimum lazer mesafasına dayanarak son pozisyonu hesap ethitPosition = tool.Handle.Position + directionVectorend
Olay başlatıldığında oyuncuya hasar vermesi gerekir.
ServerScriptService'e bir Script kaydeder ve ismini ServerLaserManager olarak değiştirir.
LASER_DAMAGE adında bir değişkeni ilan et ve 10 değerini veya seçimin değerini ayarla.
İki damageCharacter ve karakterToDamage ile adlandırılmış iki parametreli bir işlev oluşturun.
İşlevin içinde, karakterin Humanoid'ini bulun ve sağlığından LASER_DAMAGE azaltın.
Etkinleştirici damageCharacter işlevini Etkinleştirici Karakteri sayfasına 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-- Olayları uygun işlevlere bağlayıneventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)Blaster'ı 2 oyuncu ile birlikte test etmek için bir yerel sunucuyu başlatın. Diğer oyuncuya ateş ettiğinizde, onların sağlığı LASER_DAMAGE ile azalacaktır.
Diğer Oyuncunun Laser Işınlarını Görüntüleme
Mürettebatın silahı ateş ettiği anda silahın görüntüsü laser olarak oluşturulur, böylece sadece mürettebatın silahını görebilir.
Lazer ışını servis器de oluşturulduysa, herkes bunu görebilirdi. Ancak, silahı vuran klien ve sunucu arasında küçük bir gecikme olurdu. Bu, silahı vuran klienin silahı görmesinin arttırıcı olacağını ifade eder. Klien silahı etkisiz hale getirir.
Bu sorunu çözmek için, her klien kendi lazer ışınlarını oluşturacak. Bu, silahı vuran klienin lazer ışınını anında göreceği anlamına gelir. Diğer klienler, bir oyuncunun silahı vurduğunda ve bir ışın göründüğünde arasında bir küçük gecikmeyi deneyecek. Bu en iyi senaryo durumudur: bir klienin
Tüfek Klient
İlk olarak, istemci bir lazeri ateşlediğini söylemelidir ve son pozisyonu sağlamalıdır.
ReplicatedStorage'daki Etkinlikler'e bir Uzaktan Etkinlik Etkinleştirici ekleyin ve ismini LaserFired olarak değiştirin.
Arayın fireWeapon işlevini ArayıcıKontrolör yazılımında bulun. Fonksiyonun sonunda, LaserFired uzaktaki etkinliği 1> hitPosition1> olarak bir argüman olarak ateş edin.
hitPosition = tool.Handle.Position + directionVectorendtimeOfPreviousShot = tick()eventsFolder.LaserFired:FireServer(hitPosition)LaserRenderer.createLaser(tool.Handle, hitPosition)end
Sunucu
Sunucu artık etkinliği almalı ve tüm müşterileri laser ışınının başlangıcını ve sonunu bilmelidir, böylece onu da rendeleyebilirler.
In the ServerLaserManager script, create a function named playerFiredLaser above damageCharacter with two parameters called 1> playerFired1> and 4> endPosition4> .
İşlevi LaserFired uzaktaki etkinliğine bağlayın.
-- Lazerın ateşlendiğini tüm müşterilerin görebilmesi için bildirlocal function playerFiredLaser(playerFired, endPosition)end-- Olayları uygun işlevlere bağlayıneventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)
Sunucunun lazerin başlangıç pozisyonuna ihtiyacı vardır. Bu, mümkün olduğunca klije gönderilebilir, ancak mümkün olduğunca çok klijeye güvenmekten kaçınmanız gerekir. Karakterin silah tutuş pozisyonu, sunucunun onu bulmasından önce klije olabilir.
Aşağıdaki oyuncu ile ilgili işlevi oluştur playerFiredLaser şunu yap:
Silah için oyuncunun karakterini aramak için aşağıdaki kodu kullanın ve bağlantı nesnesini iade edin.
local LASER_DAMAGE = 10-- Oyuncunun tutduğu aracın etiketini bulunlocal function getPlayerToolHandle(player)local weapon = player.Character:FindFirstChildOfClass("Tool")if weapon thenreturn weapon:FindFirstChild("Handle")endend-- Lazerın ateşlendiğini tüm müşterilerin görebilmesi için bildirlocal function playerFiredLaser(playerFired, endPosition)
Sunucu artık LaserFired uzaktaki etkinliğine FireAllClients çağrabilir ve gerekli bilgileri göndermek için laserı müşterilere göndermek için gereken bilgileri gönderir. Bunun içinde laserı ateşleyen oyuncu (böylece müşterinin laseri iki kat görmediğ
In the playerFiredLaser function, call the getPlayerToolHandle function with playerFired as an argument andassign the value to a variable named 1> toolHandle1> .
Eğer toolHandle 存在sa, playerFired etkinliğini kullanarak tüm müşterileri toolHandle, 1> toolHandle1> ve 4> endPosition4> olarak argüman olarak yanlatın.
-- Lazerın ateşlendiğini tüm müşterilerin görebilmesi için bildirlocal function playerFiredLaser(playerFired, endPosition)local toolHandle = getPlayerToolHandle(playerFired)if toolHandle theneventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)endend
Clients'ta Rendering
Şimdi FireAllClients çağrıldı, her klienin laser ışınını göndermek için sunucudan bir etkinliği alacak. Her klienin aletinin el ve bir son pozisyon değerini kullanarak lazer ışınını göndermesini gerektiren birazcığı vardır. Laser ışınını ilk yerden
StarterPlayerScripts'in ClientLaserManager adlı oyununun bir Yerel Kod oluştur.
Script içinde, LaserRender modülünü gerektirir.
Aşağıdaki parametrelerle PlayerLaser adında bir işlev oluşturun: playerWhoShot, toolHandle ve 1> endPosition1> .
İşlevi LaserFired olayına uzaktaki etkinliğine bağlayın.
İşlevde, if ifadesini kullanarak LocalPlayer ile eşit olup olmadığını kontrol edin.
if ifadesinin içinde, LaserRender modülünden LaserRender modülüne createLaser işlevini toolHandle ve endPosition olarak argüman olarak çağırın.
local Players = game:GetService("Players")local ReplicatedStorage = game:GetService("ReplicatedStorage")local LaserRenderer = require(script.Parent:WaitForChild("LaserRenderer"))local eventsFolder = ReplicatedStorage.Events-- Başka bir oyuncunun lazerini gösterlocal function createPlayerLaser(playerWhoShot, toolHandle, endPosition)if playerWhoShot ~= Players.LocalPlayer thenLaserRenderer.createLaser(toolHandle, endPosition)endendeventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)Blaster'ı 2 oyuncu ile test etmek için bir yerel sunucuyu başlatarak. Her bir klienin monitörünüzün farklı taraflarında yerini görebilmeniz için. 1 oyuncu üzerinde çektiğinizde lazeri diğer kliende görmelisiniz.
Ses efektleri
Projeleri vuran kliğin sesi etkisi sadece vuran kliğin sesi etkisi olarak kodu hareket ettirmeniz gerekir. Aksi takdirde, diğer oyuncular da duyacaktır.
AraçKontrolörü scriptinde, AçıldığınızAraçlar işlevine gidin ve etkinleştirme sesini çalan satırı kaldırın.
local function toolActivated()if canShootWeapon() thenfireWeapon()endendLaserRender İçindeki createLaser işlevinin altında, shootingSound adında bir değişken ilan et ve Class.Instance:FindFirstChild()|FindFirstChild() yöntemini kullanarak 4>Aktivate4> sesini kontrol etmek için kullan.
Eğer mevcutsa shootingSound değerini kontrol etmek için bir shootingSound ifadesini kullanın; eğer mevcutsa, Oyna işlevini çağırın.
laserPart.Parent = workspace-- Kayıp parçalar hizmetine lazer gecesi ekleyin ve temizleDebris:AddItem(laserPart, SHOT_DURATION)-- Silahın atış sesini oynatlocal shootingSound = toolHandle:FindFirstChild("Activate")if shootingSound thenshootingSound:Play()endend
Kurallara Uygunluk Kullanılarak Uzaktan Güvenli Erişim
Eğer sunucu gelen isteklerden gelen verileri kontrol etmiyorsa, bir hacker uzaktan işlevleri ve etkinlikleri kötüye kullanabilir ve bunları kullanarak sahte değerleri sunucuya gönderebilir. Bunu önlemek için sunucu-taraflı doğrulama kullanılmalıdır.
Mevcut formunda, HasarKarakteri uzaktaki etkinliği çok kolay saldırıya maruz kalır. Hacker bu etkinliği kullanarak oyunu oynadığı herhangi bir oyuncuya hasar verebilir.
Geçerlileştirme, sunulan değerlerin gerçek olduğunu doğrulama sürecidir. Bu durumda, sunucunun:
- Oyuncu ve lazerin vurduğu pozisyon arasındaki mesafeyi belirli bir sınır içinde kontrol edin.
- Lazerı ateşleyen silah ve vurma pozisyonu arasında raycast yaparak merminin olup olmadığından emin olunur ve hiç duvar geçmez.
Müşteri
Müşteri, uzaktaki bir parçayı ışınlayarak vuran konumu sunmak zorunda, böylece uzaktaki mesafeyi gerçekçi olarak kontrol edebilir.
In ToolController , DamageCharacter uzaktaki etkinliğinin fireWeapon işlevinde başladığı satıra gidin.
Bir hitPosition ile argüman olarak eklenir.
if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid theneventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)endend
Sunucu
ServerLaserManager artı bir parametre gönderiyor, bu yüzden DamageCharacter uzaktaki etkinliği kabul etmek için ServerLaserManager ayarlandı.
In the ServerLaserManager script, add a hitPosition parameter to the damageCharacter function.
function damageCharacter(playerFired, characterToDamage, hitPosition)local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")if humanoid then-- Karakterden sağlığı kaldırhumanoid.Health -= LASER_DAMAGEendendgetPlayerToolHandle işlevinin altında, üç parametre ile isHitValid adında bir işlev oluşturun: playerFired, 1>characterToDamage1> ve 4>hitPosition4> .
end
local function isHitValid(playerFired, characterToDamage, hitPosition)
end
İlk kontrol, vuruş pozisyonundan karaktere vurulma mesafesi olacaktır.
Kaynağın üst kısmında MAX_HIT_PROXIMITY adında bir değişken ilan edin ve ona bir değer 10 atayın. Bu, etkileşim ve karakter arasındaki maksimum mesafeyi temsil edecektir. Bir tolerans gereklidir, çünkü karakter, etkinliği başlatan müşteriden kaynaklanan biraz yer hareketi olabilir.
local ReplicatedStorage = game:GetService("ReplicatedStorage")local eventsFolder = ReplicatedStorage.Eventslocal LASER_DAMAGE = 10local MAX_HIT_PROXIMITY = 10In the isHitValid function, hesap etme mesajının karakter ile hit pozisyonu arasındaki mesafeyi hesaplayın. Eğer mesafe MAX_HIT_PROXIMITY ile daha büyükse, false ı döndürün.
local function isHitValid(playerFired, characterToDamage, hitPosition)-- Karakterin vurulduğu ve vurulma pozisyonu arasındaki mesafeyi doğrulalocal characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitudeif characterHitProximity > MAX_HIT_PROXIMITY thenreturn falseendend
İkinci kontrol, silahı ateşleyen ve vurma pozisyonu arasında bir raycast gerektirecektir. Eğer raycast, karakter olmayan bir nesneyi iade ederse, vurma geçersiz olduğundan şüphelenebilirsiniz, çünkü şüpheli bir şey vurma işlemini engelliyordu.
Bu kontrol etyerine getirmek için aşağıdaki kodu kopyalayın. Fonksiyonun sonunda doğru döndürün: eğer sona ulaşırsa, tüm kontroller geçerli olur.
local function isHitValid(playerFired, characterToDamage, hitPosition)-- Karakterin vurulduğu ve vurulma pozisyonu arasındaki mesafeyi doğrulalocal characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitudeif characterHitProximity > 10 thenreturn falseend-- Duvarlar aracılığıyla atış yapmak için 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)-- Bir karakter değilse bir nesneye vurulursa atışı görmezden gelif rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) thenreturn falseendendreturn trueendDeğişkeni damageCharacter fonksiyonuna ilan edin, validShot . üç argümanlı isHitValid ile ilgili sonucunu atın: 2> playerFired2>, 5> characterToDamage5> ve 8> hitPosition8> .
Aşağıdaki ifade içinde, ve operatörlerini ekleyin ki validShotdoğru olup olmadığını kontrol edebilsiniz.
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
Şimdi hasar karakteri uzaktaki etkinlik daha güvenli ve çoğu oyuncunun bunu kötüye kullanmasını önleyecek. Not olası bazı kötü niyetli oyuncuların etkinliği etrafında yollar bulması çok yaygındır; uzaktaki etkinlikleri güvenli tutmak sürekli bir çaba.
Lazer kılıcınız şimdi tamamlandı, raycasting kullanan temel bir çarpışma algılama sistemiyle. Kullanıcı Etkileşimi öğretimini deneyin, nasıl lazer kılıcınıza bir yeniden yükleme eylemi ekleyebileceğinizi veya eğlenceli bir oyun haritası oluşturabileceğinizi öğrenin!
Nihai Kod
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ıştan sonra yeterli süre geçmiş olup olmadığını kontrol edin
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 maksimum mesafeyle çarpan birimi direktörü
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- Roy'un yönüne doğru uzay ışını
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- 3D kesişim noktasını iade edin
return raycastResult.Position
else
-- Hiçbir nesneye vurulmadığı için, ışının sonundaki pozisyonu hesaplayın
return screenToWorldRay.Origin + directionVector
end
end
local function fireWeapon()
local mouseLocation = getWorldMousePosition()
-- Normal bir yön vektörü hesaplayın ve lazer mesafesi ile çarpan
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- Silahı ateş etmenin yönü, maksimum mesafe ile çarpan
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- oyuncukarakterini görmezden gelin, onların kendilerine zarar vermesini önleyin
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
-- Başlangıç ve son pozisyonları arasında herhangi bir nesneye vurulup vurulmadığını kontrol edin
local hitPosition
if weaponRaycastResult then
hitPosition = weaponRaycastResult.Position
-- İstek edilen instans bir karakter modelinin bir çocuğu olacaktır
-- Bir humanoid modelinde bulunursa, muhtemelen bir oyuncu 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 mesafasına dayanarak son pozisyonu hesap et
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)
LazerRender
local LaserRenderer = {}
local Debris = game:GetService("Debris")
local SHOT_DURATION = 0.15 -- Lazerin görünür olması için
-- Bir lazer kaynağından bir başlangıç pozisyonuna kadar bir son pozisyon 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
-- Kayıp parçalar hizmetine lazer gecesi ekleyin ve temizle
Debris:AddItem(laserPart, SHOT_DURATION)
-- Silahın atış sesini oynat
local shootingSound = toolHandle:FindFirstChild("Activate")
if shootingSound then
shootingSound:Play()
end
end
return LaserRenderer
Sunucu Laser Yöneticisi
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local eventsFolder = ReplicatedStorage.Events
local LASER_DAMAGE = 10
local MAX_HIT_PROXIMITY = 10
-- Oyuncunun tutduğu aracın etiketini 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)
-- Karakterin vurulduğu ve vurulma pozisyonu arasındaki mesafeyi doğrula
local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
if characterHitProximity > MAX_HIT_PROXIMITY then
return false
end
-- Duvarlar aracılığıyla atış yapmak için 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)
-- Bir karakter değilse bir nesneye vurulursa atışı görmezden gel
if rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) then
return false
end
end
return true
end
-- Lazerın ateşlendiğini tüm müşterilerin görebilmesi için bildir
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
-- Olayları uygun işlevlere bağlayın
eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)
Müşteri Laser Yöneticisi
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LaserRenderer = require(Players.LocalPlayer.PlayerScripts:WaitForChild("LaserRenderer"))
local eventsFolder = ReplicatedStorage.Events
-- Başka 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)