Lazerlerle vurma tespiti

*Bu içerik, yapay zekâ (beta) kullanılarak çevrildi ve hatalar içerebilir. Sayfayı İngilizce görüntülemek için buraya tıkla.

Bu eğitimde, Oyuncu Araçları Oluştur bölümündeki blasterdan lazer nasıl atılacağını ve bunun bir oyuncuya çarpıp çarpmadığını nasıl tespit edeceğinizi öğreneceksiniz.

Çarpışmaları bulmak için Raycasting

Raycasting, bir başlangıç pozisyonundan belirli bir yön ve tanımlı bir uzunlukla görünmez bir ışın oluşturur. Eğer ışın, yolundaki nesneler veya arazi ile çarpışırsa, çarpışma hakkında konum ve çarpıştığı nesne gibi bilgiler döner.

A'dan B'ye doğru giden ve bir duvara çarpan raycast

Fare konumunu bulma

Bir lazer atılmadan önce, oyuncunun nereye nişan aldığını bilmeniz gerekir. Bu, oyuncunun ekran üzerindeki 2D fare konumundan, kameradan 3D dünyaya doğru raycasting yaparak bulunabilir. Işın, oyuncunun fare ile nişan aldığı her şeye çarpacaktır.

  1. Oyuncu Araçları Oluştur bölümündeki Blaster aracının içindeki ToolController scriptini açın. Eğer bu eğitimi henüz tamamlamadıysanız, Blaster modelini indirebilir ve StarterPack'e ekleyebilirsiniz.

  2. Scriptin en üstünde, değeri 1000 olan MAX_MOUSE_DISTANCE adında bir sabit tanımlayın.

  3. getWorldMousePosition adında bir fonksiyon oluşturun.

    local tool = script.Parent
    local MAX_MOUSE_DISTANCE = 1000
    local function getWorldMousePosition()
    end
    local function toolEquipped()
    tool.Handle.Equip:Play()
    end
    local function toolActivated()
    tool.Handle.Activate:Play()
    end
    -- Olayları uygun fonksiyonlara bağlayın
    tool.Equipped:Connect(toolEquipped)
    tool.Activated:Connect(toolActivated)
  4. UserInputService'in GetMouseLocation fonksiyonunu kullanarak oyuncunun ekran üzerindeki 2D fare konumunu alın. Bunu mouseLocation adında bir değişkene atayın.

    local UserInputService = game:GetService("UserInputService")
    local tool = script.Parent
    local MAX_MOUSE_DISTANCE = 1000
    local function getWorldMousePosition()
    local mouseLocation = UserInputService:GetMouseLocation()
    end

Artık 2D fare konumu biliniyor, X ve Y özellikleri Camera:ViewportPointToRay() fonksiyonu için parametre olarak kullanılabilir; bu fonksiyon ekranın 3D dünyaya bir Ray oluşturur.

  1. mouseLocation'ın X ve Y özelliklerini Camera:ViewportPointToRay() fonksiyonu için argüman olarak kullanın. Bunu screenToWorldRay adında bir değişkene 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

Artık WorldRoot:Raycast() fonksiyonunu kullanarak ışının bir nesneye çarpıp çarpmadığını kontrol etme zamanı. Bu, bir başlangıç pozisyonu ve yön vektörü gerektirir: bu örnekte, screenToWorldRay'in origin ve direction özelliklerini kullanacaksınız.

Yön vektörünün uzunluğu, ışının ne kadar yol alacağını belirler. Işının MAX_MOUSE_DISTANCE kadar uzun olması gerektiğinden, yön vektörünü MAX_MOUSE_DISTANCE ile çarpmanız gerekecek.

  1. directionVector adında bir değişken tanımlayın ve screenToWorldRay.Direction değerini MAX_MOUSE_DISTANCE ile çarparak 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)
    -- Işının birim yön vektörü, maksimum mesafe ile çarpılmış
    local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
  2. workspace'in WorldRoot:Raycast() fonksiyonunu çağırın, screenToWorldRay'in Origin özelliğini ilk argüman olarak ve directionVector'ı ikinci argüman olarak geçirin. Bunu raycastResult adında bir değişkene 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)
    -- Işının birim yön vektörü, maksimum mesafe ile çarpılmış
    local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
    -- Işının başlangıç noktasından yönüne doğru raycast yap
    local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)

Çarpışma bilgileri

Eğer raycast işlemi, ışın tarafından vurulan bir nesne bulursa, bu, ışın ile nesne arasındaki çarpışma hakkında bilgi içeren bir RaycastResult döner.

RaycastResult ÖzelliğiAçıklama
InstanceIşının kesiştiği BasePart veya Terrain hücresi.
PositionKesişmenin gerçekleştiği yer; genellikle bir parça veya arazi yüzeyinde doğrudan bir nokta.
MaterialÇarpışma noktasındaki malzeme.
NormalKesişen yüzeyin normal vektörü. Bu, yüzeyin hangi yöne baktığını belirlemek için kullanılabilir.

Position özelliği, farenin üzerinde durduğu nesnenin konumu olacaktır. Eğer fare, MAX_MOUSE_DISTANCE mesafesi içinde herhangi bir nesne üzerinde durmuyorsa, raycastResult nil olacaktır.

  1. raycastResult'ın var olup olmadığını kontrol etmek için bir if ifadesi oluşturun.

  2. Eğer raycastResult bir değere sahipse, Position özelliğini döndürün.

  3. Eğer raycastResult nil ise, raycast'in sonunu bulun. Fare konumunun 3D pozisyonunu screenToWorldRay.Origin ile directionVector'ı toplayarak hesaplayın.

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 çarpılmış
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- Işının başlangıç noktasından yönüne doğru raycast yap
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- Kesişme 3D noktasını döndür
return raycastResult.Position
else
-- Hiçbir nesne vurulmadı, bu yüzden rayin sonundaki konumu hesapla
return screenToWorldRay.Origin + directionVector
end
end

Hedefe ateş etme

Artık 3D fare pozisyonu biliniyor, bu pozisyon lazerin ateşleneceği hedef pozisyonu olarak kullanılabilir. Oyuncunun silahı ile hedef pozisyonu arasında ikinci bir ışın atılabilir.

  1. Scriptin en üstünde MAX_LASER_DISTANCE adında bir sabit tanımlayın ve değerini 500 olarak atayın veya lazer blaster için seçtiğiniz bir menzil belirleyin.

    local UserInputService = game:GetService("UserInputService")
    local tool = script.Parent
    local MAX_MOUSE_DISTANCE = 1000
    local MAX_LASER_DISTANCE = 500
  2. getWorldMousePosition fonksiyonunun altında fireWeapon adında bir fonksiyon oluşturun.

  3. getWorldMousePosition'ı çağırın ve sonucu mousePosition adında bir değişkene atayın. Bu, raycast için hedef pozisyon olacaktır.

    -- Hiçbir nesne vurulmadı, bu yüzden rayin sonundaki konumu hesapla
    return screenToWorldRay.Origin + directionVector
    end
    end
    local function fireWeapon()
    local mouseLocation = getWorldMousePosition()
    end
    local function toolEquipped()
    tool.Handle.Equip:Play()
    end

Bu sefer, raycast fonksiyonu için yön vektörü, oyuncunun araç pozisyonundan hedef konumuna olan yönü temsil edecektir.

  1. targetDirection adında bir değişken tanımlayın ve mouseLocation'dan tool.Handle.Position'ı çıkararak yön vektörünü hesaplayın.

  2. Vektörü Unit özelliğini kullanarak normalize edin. Bu, ona 1'lik bir büyüklük verir, bu da daha sonra bir uzunluk ile çarpmayı kolaylaştırır.

    local function fireWeapon()
    local mouseLocation = getWorldMousePosition()
    -- Normalleştirilmiş bir yön vektörü hesaplayın ve lazer mesafesi ile çarpın
    local targetDirection = (mouseLocation - tool.Handle.Position).Unit
    end
  3. directionVector adında bir değişken tanımlayın ve targetDirection'ı MAX_LASER_DISTANCE ile çarparak atayın.

    local targetDirection = (mouseLocation - tool.Handle.Position).Unit
    -- Silahı ateşlemek için yön, maksimum mesafe ile çarpılmış
    local directionVector = targetDirection * MAX_LASER_DISTANCE
    end

RaycastParams nesnesi, raycast fonksiyonu için ek parametreler depolamak için kullanılabilir. Bu, lazer blaster'ınızda, raycast'in silahı ateşleyen oyuncuya çarpmasını önlemek için kullanılacaktır. FilterDescendantsInstances özelliğine dahil edilen herhangi bir parça, raycast'te göz ardı edilecektir.

  1. fireWeapon fonksiyonunu devam ettirin ve weaponRaycastParams adında bir değişken tanımlayın. Ona yeni bir RaycastParams nesnesi atayın.

  2. Oyuncunun yerel karakter'ini içeren bir tablo oluşturun ve bunu weaponRaycastParams.FilterDescendantsInstances özelliğine atayın.

  3. Oyuncunun araç tutma pozisyonundan, directionVector yönüne doğru raycast yapın. Bu sefer weaponRaycastParams'ı bir argüman olarak eklemeyi unutmayın. Bunu weaponRaycastResult adında bir değişkene 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()
-- Normalleştirilmiş bir yön vektörü hesaplayın ve lazer mesafesi ile çarpın
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- Silahı ateşlemek için yön, maksimum mesafe ile çarpılmış
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- Oyuncunun karakterini göz ardı edin, böylece kendilerine zarar vermelerini önleyin
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
end

Son olarak, raycast işleminin bir değer döndürüp döndürmediğini kontrol etmeniz gerekecek. Eğer bir değer dönerse, ışın bir nesneye çarpmıştır ve silah ile çarpma konumu arasında bir lazer oluşturulabilir. Eğer hiçbir şey döndürülmezse, lazeri oluşturmak için son pozisyon hesaplanmalıdır.

  1. hitPosition adında boş bir değişken tanımlayın.

  2. weaponRaycastResult'ın bir değeri olup olmadığını kontrol etmek için bir if ifadesi kullanın. Eğer bir nesne vurulduysa, weaponRaycastResult.Position'ı hitPosition'a atayın.

    local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
    -- Başlangıç ve bitiş pozisyonu arasında herhangi bir nesne vurulup vurulmadığını kontrol et
    local hitPosition
    if weaponRaycastResult then
    hitPosition = weaponRaycastResult.Position
    end
  3. Eğer weaponRaycastResult değeri yoksa, raycast'in son pozisyonunu, araç tutma pozisyonunun pozisyonu ile directionVector'ı toplayarak hesaplayın. Bunu hitPosition'a atayın.

    local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
    -- Başlangıç ve bitiş pozisyonu arasında herhangi bir nesne vurulup vurulmadığını kontrol et
    local hitPosition
    if weaponRaycastResult then
    hitPosition = weaponRaycastResult.Position
    else
    -- Maksimum lazer mesafesine göre son pozisyonu hesapla
    hitPosition = tool.Handle.Position + directionVector
    end
    end
  4. toolActivated fonksiyonuna gidin ve lazerin her seferinde ateşlenmesi için fireWeapon fonksiyonunu çağırın.

    local function toolActivated()
    tool.Handle.Activate:Play()
    fireWeapon()
    end

Vurulan nesneyi kontrol etme

Lazerin vurduğu nesnenin bir oyuncunun karakterinin parçası mı yoksa sadece bir manzara parçası mı olduğunu bulmak için, her karakterin bir Humanoid içerdiğini kontrol etmeniz gerekecek.

Öncelikle karakter modelini bulmanız gerekecek. Eğer karakterin bir parçası vurulduysa, vurulan nesnenin ebeveyninin karakter olduğunu varsayamazsınız. Lazer, bir vücut parçasına, bir aksesuara veya bir araca çarpmış olabilir; bunların hepsi karakterin hiyerarşisinde farklı yerlerde bulunur.

Işının vurduğu nesnenin bir karakter modeli üst nesnesi olup olmadığını bulmak için FindFirstAncestorOfClass kullanabilirsiniz. Eğer bir model bulursanız ve bu model bir humanoid içeriyorsa, çoğu durumda bunun bir karakter olduğunu varsayabilirsiniz.

  1. weaponRaycastResult if ifadesine aşağıdaki vurgulanan kodu ekleyin, böylece bir karakterin vurulup vurulmadığını kontrol edin.

    -- Başlangıç ve bitiş pozisyonu arasında herhangi bir nesne vurulup vurulmadığını kontrol et
    local hitPosition
    if weaponRaycastResult then
    hitPosition = weaponRaycastResult.Position
    -- Vurulan nesne bir karakter modelinin çocuğu olacaktır
    -- Eğer modelde bir humanoid bulunursa, muhtemelen bir oyuncunun karakteridir
    local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")
    if characterModel then
    local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    print("Oyuncu vuruldu")
    end
    end
    else
    -- Maksimum lazer mesafesine göre son pozisyonu hesapla
    hitPosition = tool.Handle.Position + directionVector
    end

Artık lazer blaster, raycast işlemi her başka bir oyuncuyu vurduğunda Çıktı penceresine Oyuncu vuruldu yazdırmalıdır.

Birden fazla oyuncu ile test etme

Silah raycast'inin diğer oyuncuları bulup bulmadığını test etmek için iki oyuncuya ihtiyacınız var, bu yüzden yerel bir sunucu başlatmanız gerekiyor. Talimatlar için çoklu istemci simülasyonu bölümüne bakın.

Bir istemcide, diğer oyuncuya nişan alarak silahı ateş etmeyi test edin. Her seferinde "Oyuncu vuruldu" çıktısı görünmelidir.

Lazer pozisyonunu bulma

Blaster, hedefe kırmızı bir ışın ateşlemelidir. Bunun için fonksiyon, daha sonra diğer scriptlerde yeniden kullanılabilmesi için bir ModuleScript içinde olacaktır. Öncelikle, lazer ışınının nerede render edileceğini bulmanız gerekecek.

  1. LaserRenderer adında bir ModuleScript oluşturun ve bunu StarterPlayer altında StarterPlayerScripts'e yerleştirin.

  2. Scripti açın ve modül tablosunun adını scriptin adı olan LaserRenderer olarak değiştirin.

  3. SHOT_DURATION adında bir değişken tanımlayın ve değerini 0.15 olarak atayın. Bu, lazerin görünür olacağı süre (saniye cinsinden) olacaktır.

  4. toolHandle ve endPosition adında iki parametreye sahip createLaser adında bir LaserRenderer fonksiyonu oluşturun.

    local LaserRenderer = {}
    local SHOT_DURATION = 0.15 -- Lazerin görünür olduğu süre
    -- Başlangıç pozisyonundan bir bitiş pozisyonuna lazer ışını oluştur
    function LaserRenderer.createLaser(toolHandle, endPosition)
    end
    return LaserRenderer
  5. startPosition adında bir değişken tanımlayın ve toolHandle'ın Position özelliğini değer olarak atayın. Bu, oyuncunun lazer blaster'ının pozisyonu olacaktır.

  6. laserDistance adında bir değişken tanımlayın ve endPosition'dan startPosition'ı çıkararak iki vektör arasındaki farkı bulun. Bunun Magnitude özelliğini kullanarak lazer ışınının uzunluğunu elde edin.

    function LaserRenderer.createLaser(toolHandle, endPosition)
    local startPosition = toolHandle.Position
    local laserDistance = (startPosition - endPosition).Magnitude
    end
  7. Lazer ışınının pozisyonunu ve yönünü depolamak için bir laserCFrame değişkeni tanımlayın. Pozisyon, ışının başlangıç ve bitiş noktalarının ortası olmalıdır. CFrame.lookAt kullanarak startPosition'da bulunan ve endPosition'a bakan yeni bir CFrame oluşturun. Bunu, negatif laserDistance'in yarısı olan yeni bir CFrame ile çarparak ortayı elde edin.

    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)
    end

Lazer parçasını oluşturma

Artık bir lazer ışını oluşturmak için nereye gideceğinizi biliyorsunuz, şimdi ışını kendisini eklemeniz gerekiyor. Bu, Neon bir parça ile kolayca yapılabilir.

  1. laserPart adında bir değişken tanımlayın ve ona yeni bir Part örneği atayın.

  2. laserPart'ın aşağıdaki özelliklerini ayarlayın:

    1. Boyut: Vector3.new(0.2, 0.2, laserDistance)
    2. CFrame: laserCFrame
    3. Sabit: true
    4. Çarpışma: false
    5. Renk: Color3.fromRGB(225, 0, 0) (güçlü bir kırmızı renk)
    6. Malzeme: Enum.Material.Neon
  3. laserPart'ı Workspace'e ekleyin.

  4. Parçayı Debris servisine ekleyin, böylece SHOT_DURATION değişkenindeki saniye sayısı kadar sonra kaldırılır.

    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(225, 0, 0)
    laserPart.Material = Enum.Material.Neon
    laserPart.Parent = workspace
    -- Lazer ışınını Debris servisine ekleyin, böylece kaldırılır ve temizlenir
    Debris:AddItem(laserPart, SHOT_DURATION)
    end

Artık lazer ışınını render etmek için fonksiyon tamamlandı, bu fonksiyon ToolController tarafından çağrılabilir.

  1. ToolController scriptinin en üstünde, LaserRenderer adında bir değişken tanımlayın ve PlayerScripts'teki LaserRenderer ModuleScript'ini gereksin.

    local UserInputService = game:GetService("UserInputService")
    local Players = game:GetService("Players")
    local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)
    local tool = script.Parent
  2. fireWeapon fonksiyonunun sonunda, lazeri oluşturmak için LaserRenderer createLaser fonksiyonunu çağırın, argüman olarak araç tutma ve hitPosition'ı kullanın.

    -- Maksimum lazer mesafesine göre son pozisyonu hesapla
    hitPosition = tool.Handle.Position + directionVector
    end
    LaserRenderer.createLaser(tool.Handle, hitPosition)
    end
  3. Oyuncunun silahı ateşleyerek lazerin görünür olup olmadığını test edin. Araç etkinleştirildiğinde, silah ile fare arasında bir lazer ışını görünmelidir.

Silah ateşleme hızını kontrol etme

Silahların, oyuncuların kısa bir süre içinde çok fazla hasar vermesini önlemek için her atış arasında bir gecikmeye ihtiyacı vardır. Bu, bir oyuncunun en son ne zaman ateş ettiğini kontrol ederek kontrol edilebilir.

  1. ToolController'ın en üstünde FIRE_RATE adında bir değişken tanımlayın. Bu, her atış arasındaki minimum süre olacaktır. Seçtiğiniz bir değeri verin; bu örnek 0.3 saniye kullanmaktadır.

  2. Altında timeOfPreviousShot adında başka bir değişken tanımlayın ve değerini 0 olarak atayın. Bu, oyuncunun en son ateş ettiği zamanı saklayacak ve her atışta güncellenecektir.

    local MAX_MOUSE_DISTANCE = 1000
    local MAX_LASER_DISTANCE = 300
    local FIRE_RATE = 0.3
    local timeOfPreviousShot = 0
  3. Parametre almayan canShootWeapon adında bir fonksiyon oluşturun. Bu fonksiyon, önceki atıştan bu yana ne kadar zaman geçtiğini kontrol edecek ve true veya false döndürecektir.

    local FIRE_RATE = 0.3
    local timeOfPreviousShot = 0
    -- Önceki atıştan bu yana yeterince zaman geçip geçmediğini kontrol et
    local function canShootWeapon()
    end
    local function getWorldMousePosition()
  4. Fonksiyonun içinde currentTime adında bir değişken tanımlayın; ona tick() fonksiyonunu çağırarak atayın. Bu, 1 Ocak 1970'ten (zamanı hesaplamak için yaygın olarak kullanılan bir tarih) bu yana geçen süreyi saniye cinsinden döndürür.

  5. timeOfPreviousShot'ı currentTime'dan çıkarın ve sonuç FIRE_RATE'den küçükse false döndürün; aksi takdirde true döndürün.

    -- Önceki atıştan bu yana yeterince zaman geçip geçmediğini kontrol et
    local function canShootWeapon()
    local currentTime = tick()
    if currentTime - timeOfPreviousShot < FIRE_RATE then
    return false
    end
    return true
    end
  6. fireWeapon fonksiyonunun sonunda, silah her ateşlendiğinde timeOfPreviousShot'ı tick ile güncelleyin.

    hitPosition = tool.Handle.Position + directionVector
    end
    timeOfPreviousShot = tick()
    LaserRenderer.createLaser(tool.Handle, hitPosition)
    end
  7. toolActivated fonksiyonunun içinde, silahın ateşlenip ateşlenemeyeceğini kontrol etmek için bir if ifadesi oluşturun ve canShootWeapon'ı çağırın.

    local function toolActivated()
    if canShootWeapon() then
    tool.Handle.Activate:Play()
    fireWeapon()
    end
    end

Blaster'ı test ettiğinizde, ne kadar hızlı tıklarsanız tıklayın, her atış arasında her zaman kısa bir 0.3 saniyelik gecikme olacağını bulmalısınız.

Oyuncuyu hasar verme

İstemciler, diğer istemcileri doğrudan hasar veremez; sunucu, bir oyuncu vurulduğunda hasar vermekten sorumlu olmalıdır.

İstemciler, bir karakterin vurulduğunu sunucuya bildirmek için bir RemoteEvent kullanabilir. Bunlar, hem istemci hem de sunucu tarafından görülebilir olan ReplicatedStorage içinde saklanmalıdır.

  1. ReplicatedStorage içinde Events adında bir Klasör oluşturun.

  2. Events klasörüne bir RemoteEvent ekleyin ve adını DamageCharacter olarak belirleyin.

  3. ToolController içinde, scriptin başında ReplicatedStorage ve Events klasörü için 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.Parent
    local eventsFolder = ReplicatedStorage.Events
    local MAX_MOUSE_DISTANCE = 1000
    local MAX_LASER_DISTANCE = 500
  4. fireWeapon içindeki "Oyuncu vuruldu" yazdırma ifadesini, characterModel değişkenini argüman olarak kullanarak DamageCharacter uzaktan olayını ateşleyecek bir Luau satırı ile değiştirin.

    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 mesafesine göre son pozisyonu hesapla
    hitPosition = tool.Handle.Position + directionVector
    end

Sunucu, olay ateşlendiğinde vurulan oyuncuya hasar vermelidir.

  1. ServerScriptService içine bir Script ekleyin ve adını ServerLaserManager olarak belirleyin.

  2. LASER_DAMAGE adında bir değişken tanımlayın ve değerini 10 olarak ayarlayın veya seçtiğiniz bir değeri verin.

  3. playerFired ve characterToDamage adında iki parametreye sahip damageCharacter adında bir fonksiyon oluşturun.

  4. Fonksiyonun içinde, karakterin Humanoid'ini bulun ve sağlığından LASER_DAMAGE'ı çıkarın.

  5. damageCharacter fonksiyonunu Events klasöründeki DamageCharacter uzaktan olayına bağlayın.

    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local eventsFolder = ReplicatedStorage.Events
    local LASER_DAMAGE = 10
    function damageCharacter(playerFired, characterToDamage)
    local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    -- Karakterin sağlığını azalt
    humanoid.Health -= LASER_DAMAGE
    end
    end
    -- Olayları uygun fonksiyonlara bağlayın
    eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
  6. İki oyuncu ile blasterı test edin, yerel bir sunucu başlatarak. Diğer oyuncuya ateş ettiğinizde, sağlıkları LASER_DAMAGE'a atanan değere göre azalacaktır.

Diğer oyuncuların lazer ışınlarını render etme

Şu anda, lazer ışını, silahı ateşleyen istemci tarafından oluşturuluyor, bu yüzden sadece o istemci lazer ışınını görebiliyor.

Eğer lazer ışını sunucuda oluşturulursa, herkes bunu görebilir. Ancak, istemcinin silahı ateşlemesi ile sunucunun ateş hakkında bilgi alması arasında küçük bir gecikme olacaktır. Bu, silahı ateşleyen istemcinin, silahı etkinleştirdiklerinde lazer ışınını görmeleri ile lazer ışınını görmeleri arasında bir gecikme olacağı anlamına gelir; bu da silahın gecikmeli hissettirmesine neden olur.

Bu sorunu çözmek için, her istemci kendi lazer ışınlarını oluşturacaktır. Bu, silahı ateşleyen istemcinin lazer ışınını anında görmesini sağlar. Diğer istemciler, başka bir oyuncu ateş ettiğinde lazerin görünmesi arasında küçük bir gecikme yaşayacaklardır. Bu en iyi senaryodur: bir istemcinin lazerini diğer istemcilere iletmenin daha hızlı bir yolu yoktur.

Ateş eden istemci

Öncelikle, istemcinin sunucuya bir lazer ateşlediğini bildirmesi ve bitiş pozisyonunu sağlaması gerekir.

  1. ReplicatedStorage'deki Events klasörüne bir RemoteEvent ekleyin ve adını LaserFired olarak belirleyin.

  2. ToolController scriptindeki fireWeapon fonksiyonunu bulun. Fonksiyonun sonunda, LaserFired uzaktan olayını hitPosition'ı argüman olarak kullanarak ateşleyin.

    hitPosition = tool.Handle.Position + directionVector
    end
    timeOfPreviousShot = tick()
    eventsFolder.LaserFired:FireServer(hitPosition)
    LaserRenderer.createLaser(tool.Handle, hitPosition)
    end

Sunucu

Sunucu şimdi, istemcinin ateş ettiğini bildiren olayı almalı ve tüm istemcilere lazer ışınının başlangıç ve bitiş pozisyonunu bildirmelidir, böylece onlar da lazer ışınını render edebilirler.

  1. ServerLaserManager scriptinde, iki parametreye sahip playerFiredLaser adında bir fonksiyon oluşturun: playerFired ve endPosition.

  2. Fonksiyonu LaserFired uzaktan olayına bağlayın.

    -- Tüm istemcilere bir lazer ateşlendiğini bildirin, böylece lazeri görüntüleyebilirler
    local function playerFiredLaser(playerFired, endPosition)
    end
    -- Olayları uygun fonksiyonlara bağlayın
    eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
    eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)

Sunucunun lazerin başlangıç pozisyonunu alması gerekir. Bu istemciden gönderilebilir, ancak mümkün olduğunca istemciye güvenmemek en iyisidir. Karakterin silah tutma pozisyonu başlangıç pozisyonu olacaktır, bu yüzden sunucu bunu oradan bulabilir.

  1. playerFiredLaser fonksiyonunun üstünde, player adında bir parametre ile getPlayerToolHandle adında bir fonksiyon oluşturun.

  2. Aşağıdaki kodu kullanarak oyuncunun karakterinde silahı arayın ve tutma nesnesini döndürün.

    local LASER_DAMAGE = 10
    -- Oyuncunun tuttuğu aracın tutma nesnesini bul
    local function getPlayerToolHandle(player)
    local weapon = player.Character:FindFirstChildOfClass("Tool")
    if weapon then
    return weapon:FindFirstChild("Handle")
    end
    end
    -- Tüm istemcilere bir lazer ateşlendiğini bildirin, böylece lazeri görüntüleyebilirler
    local function playerFiredLaser(playerFired, endPosition)

Artık sunucu, LaserFired uzaktan olayında FireAllClients çağrısı yaparak, istemcilere render etmek için gereken bilgileri gönderebilir. Bu, lazeri ateşleyen oyuncu (böylece o oyuncunun istemcisi lazeri iki kez render etmez), lazerin başlangıç pozisyonu olan tutma ve lazerin bitiş pozisyonunu içerir.

  1. playerFiredLaser fonksiyonunda, getPlayerToolHandle fonksiyonunu playerFired ile çağırın ve sonucu toolHandle adında bir değişkene atayın.

  2. Eğer toolHandle varsa, playerFired, toolHandle ve endPosition argümanları ile LaserFired olayını tüm istemcilere ateşleyin.

    -- Tüm istemcilere bir lazer ateşlendiğini bildirin, böylece lazeri görüntüleyebilirler
    local function playerFiredLaser(playerFired, endPosition)
    local toolHandle = getPlayerToolHandle(playerFired)
    if toolHandle then
    eventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)
    end
    end

İstemcilerde render etme

Artık FireAllClients çağrıldığında, her istemci sunucudan lazer ışınını render etmek için bir olay alacaktır. Her istemci, sunucudan gönderilen silahın tutma pozisyonunu ve bitiş pozisyonu değerini kullanarak lazer ışınını render etmek için daha önceki LaserRenderer modülünü yeniden kullanabilir. Lazer ışınını ilk ateşleyen oyuncu, bu olayı göz ardı etmelidir, aksi takdirde iki lazer görecektir.

  1. StarterPlayerScripts içinde ClientLaserManager adında bir LocalScript oluşturun.

  2. Scriptin içinde LaserRenderer modülünü gereksin.

  3. playerWhoShot, toolHandle ve endPosition parametrelerine sahip createPlayerLaser adında bir fonksiyon oluşturun.

  4. Fonksiyonu Events klasöründeki LaserFired uzaktan olayına bağlayın.

  5. Fonksiyonda, playerWhoShot'ın LocalPlayer ile eşit olmadığını kontrol etmek için bir if ifadesi kullanın.

  6. If ifadesinin içinde, toolHandle ve endPosition argümanlarını kullanarak LaserRenderer modülünden createLaser fonksiyonunu ç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örüntüle
    local function createPlayerLaser(playerWhoShot, toolHandle, endPosition)
    if playerWhoShot ~= Players.LocalPlayer then
    LaserRenderer.createLaser(toolHandle, endPosition)
    end
    end
    eventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)
  7. İki oyuncu ile blasterı test edin, yerel bir sunucu başlatarak. Her iki istemciyi de monitörünüzün farklı taraflarına yerleştirin, böylece her iki pencereyi de görebilirsiniz. Bir istemcide ateş ettiğinizde, diğer istemcide lazer görünmelidir.

Ses efektleri

Ateş etme ses efekti şu anda sadece projeyi ateşleyen istemcide çalıyor. Diğer oyuncuların da bunu duyması için sesi çalma kodunu taşımak gerekecek.

  1. ToolController scriptinde, toolActivated fonksiyonuna gidin ve Activate sesini çalan satırı kaldırın.

    local function toolActivated()
    if canShootWeapon() then
    fireWeapon()
    end
    end
  2. LaserRenderer içindeki createLaser fonksiyonunun sonunda, shootingSound adında bir değişken tanımlayın ve toolHandle'ın Activate sesini kontrol etmek için FindFirstChild() yöntemini kullanın.

  3. shootingSound varsa, Play() fonksiyonunu çağırın.

    laserPart.Parent = workspace
    -- Lazer ışınını Debris servisine ekleyin, böylece kaldırılır ve temizlenir
    Debris:AddItem(laserPart, SHOT_DURATION)
    -- Silahın ateş etme sesini çal
    local shootingSound = toolHandle:FindFirstChild("Activate")
    if shootingSound then
    shootingSound:Play()
    end
    end

Uzaktan olayları doğrulama ile güvence altına alma

Eğer sunucu, gelen isteklerden gelen verileri kontrol etmiyorsa, bir hacker uzaktan fonksiyonları ve olayları kötüye kullanabilir ve sunucuya sahte değerler gönderebilir. Bunu önlemek için sunucu tarafı doğrulaması kullanmak önemlidir.

Mevcut haliyle, DamageCharacter uzaktan olayı saldırıya çok açıktır. Hackerlar, bu olayı kullanarak istedikleri herhangi bir oyuncuya hasar verebilirler.

Doğrulama, sunucuya gönderilen değerlerin gerçekçi olup olmadığını kontrol etme sürecidir. Bu durumda, sunucu:

  • Oyuncu ile lazerin vurduğu pozisyon arasındaki mesafenin belirli bir sınır içinde olup olmadığını kontrol etmelidir.
  • Lazerin ateşlendiği silah ile vurulan pozisyon arasında raycast yaparak, atışın mümkün olup olmadığını ve herhangi bir duvardan geçip geçmediğini kontrol etmelidir.

İstemci

İstemci, sunucuya raycast ile vurulan pozisyonu göndermelidir, böylece mesafenin gerçekçi olup olmadığını kontrol edebilir.

  1. ToolController'da, fireWeapon fonksiyonundaki DamageCharacter uzaktan olayının ateşlendiği satıra gidin.

  2. hitPosition'ı bir argüman olarak ekleyin.

    if characterModel then
    local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    eventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)
    end
    end

Sunucu

İstemci artık DamageCharacter uzaktan olayında ek bir parametre gönderiyor, bu yüzden ServerLaserManager'ı buna göre ayarlamak gerekecek.

  1. ServerLaserManager scriptinde, damageCharacter fonksiyonuna hitPosition parametresini ekleyin.

    function damageCharacter(playerFired, characterToDamage, hitPosition)
    local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    -- Karakterin sağlığını azalt
    humanoid.Health -= LASER_DAMAGE
    end
    end
  2. getPlayerToolHandle fonksiyonunun altına, isHitValid adında üç parametreye sahip bir fonksiyon oluşturun: playerFired, characterToDamage ve hitPosition.

    end
    local function isHitValid(playerFired, characterToDamage, hitPosition)
    end

İlk kontrol, vurulan pozisyon ile karakter arasındaki mesafeyi kontrol etmek olacaktır.

  1. Scriptin en üstünde MAX_HIT_PROXIMITY adında bir değişken tanımlayın ve değerini 10 olarak atayın. Bu, vurulan pozisyon ile karakter arasındaki maksimum mesafe olacaktır. Bir tolerans gereklidir çünkü karakter, istemci olayı ateşlediğinden beri biraz hareket etmiş olabilir.

    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local eventsFolder = ReplicatedStorage.Events
    local LASER_DAMAGE = 10
    local MAX_HIT_PROXIMITY = 10
  2. isHitValid fonksiyonunda, karakter ile vurulan pozisyon arasındaki mesafeyi hesaplayın. Eğer mesafe MAX_HIT_PROXIMITY'den büyükse, false döndürün.

    local function isHitValid(playerFired, characterToDamage, hitPosition)
    -- Vurulan pozisyon ile karakter arasındaki mesafeyi doğrula
    local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
    if characterHitProximity > MAX_HIT_PROXIMITY then
    return false
    end
    end

İkinci kontrol, ateş edilen silah ile vurulan pozisyon arasında bir raycast yapmayı içerecektir. Eğer raycast, karakter olmayan bir nesneyi döndürürse, atışın geçerli olmadığını varsayabilirsiniz çünkü bir şey atışı engellemiştir.

  1. Aşağıdaki kodu bu kontrolü gerçekleştirmek için kopyalayın. Fonksiyonun sonunda true döndürün: eğer sona ulaşırsa, tüm kontroller geçmiştir.

    local function isHitValid(playerFired, characterToDamage, hitPosition)
    -- Vurulan pozisyon ile karakter arasındaki mesafeyi doğrula
    local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
    if characterHitProximity > 10 then
    return false
    end
    -- Duvarlardan geçip geçmediğini kontrol et
    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)
    -- Eğer vurulan nesne karakter değilse, atışı göz ardı et
    if rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) then
    return false
    end
    end
    return true
    end
  2. damageCharacter fonksiyonunda validShot adında bir değişken tanımlayın. Bunu isHitValid fonksiyonunu playerFired, characterToDamage ve hitPosition argümanları ile çağırarak atayın.

  3. Aşağıdaki if ifadesine, validShot'ın true olup olmadığını kontrol etmek için bir and operatörü ekleyin.

    function damageCharacter(playerFired, characterToDamage, hitPosition)
    local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
    local validShot = isHitValid(playerFired, characterToDamage, hitPosition)
    if humanoid and validShot then
    -- Karakterin sağlığını azalt
    humanoid.Health -= LASER_DAMAGE
    end
    end

Artık damageCharacter uzaktan olayı daha güvenli hale geldi ve çoğu oyuncunun bunu kötüye kullanmasını önleyecektir. Ancak bazı kötü niyetli oyuncular, doğrulamayı aşmanın yollarını bulabilir; uzaktan olayları güvenli tutmak sürekli bir çabadır.

Lazer blaster'ınız artık tamamlandı ve raycasting kullanarak temel bir vurma tespit sistemi ile donatıldı. Kullanıcı Girişini Tespit Etme eğitimine göz atarak lazer blaster'ınıza bir yeniden yükleme eylemi eklemeyi veya eğlenceli bir harita oluşturarak lazer blaster'ınızı diğer oyuncularla denemeyi deneyin!

Nihai kod

ToolController

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 bu yana yeterince zaman geçip geçmediğ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 çarpılmış
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- Işının başlangıç noktasından yönüne doğru raycast yap
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- Kesişme 3D noktasını döndür
return raycastResult.Position
else
-- Hiçbir nesne vurulmadı, bu yüzden rayin sonundaki konumu hesapla
return screenToWorldRay.Origin + directionVector
end
end
local function fireWeapon()
local mouseLocation = getWorldMousePosition()
-- Normalleştirilmiş bir yön vektörü hesaplayın ve lazer mesafesi ile çarpın
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- Silahı ateşlemek için yön, maksimum mesafe ile çarpılmış
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- Oyuncunun karakterini göz ardı edin, böylece kendilerine zarar vermelerini önleyin
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
-- Başlangıç ve bitiş pozisyonu arasında herhangi bir nesne vurulup vurulmadığını kontrol et
local hitPosition
if weaponRaycastResult then
hitPosition = weaponRaycastResult.Position
-- Vurulan nesne bir karakter modelinin çocuğu olacaktır
-- Eğer modelde bir humanoid bulunursa, muhtemelen bir 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 mesafesine göre son pozisyonu 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)

LaserRenderer

local LaserRenderer = {}
local Debris = game:GetService("Debris")
local SHOT_DURATION = 0.15 -- Lazerin görünür olduğu süre
-- Başlangıç pozisyonundan bir bitiş pozisyonuna 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
-- Lazer ışınını Debris servisine ekleyin, böylece kaldırılır ve temizlenir
Debris:AddItem(laserPart, SHOT_DURATION)
-- Silahın ateş etme sesini çal
local shootingSound = toolHandle:FindFirstChild("Activate")
if shootingSound then
shootingSound:Play()
end
end
return LaserRenderer

ServerLaserManager

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local eventsFolder = ReplicatedStorage.Events
local LASER_DAMAGE = 10
local MAX_HIT_PROXIMITY = 10
-- Oyuncunun tuttuğu aracın tutma nesnesini bul
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)
-- Vurulan pozisyon ile karakter arasındaki mesafeyi doğrula
local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
if characterHitProximity > MAX_HIT_PROXIMITY then
return false
end
-- Duvarlardan geçip geçmediğini kontrol et
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)
-- Eğer vurulan nesne karakter değilse, atışı göz ardı et
if rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) then
return false
end
end
return true
end
-- Tüm istemcilere bir lazer ateşlendiğini bildirin, böylece lazeri görüntüleyebilirler
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
-- Karakterin sağlığını azalt
humanoid.Health -= LASER_DAMAGE
end
end
-- Olayları uygun fonksiyonlara bağlayın
eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)

ClientLaserManager

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örüntüle
local function createPlayerLaser(playerWhoShot, toolHandle, endPosition)
if playerWhoShot ~= Players.LocalPlayer then
LaserRenderer.createLaser(toolHandle, endPosition)
end
end
eventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)
©2026 Roblox Corporation. Roblox, the Roblox logo and Powering Imagination are among our registered and unregistered trademarks in the U.S. and other countries.