In diesem Tutorial lernst du, wie du einen Laser vom Blaster in Spielerwerkzeuge erstellen ausstrahlst und ob er einen Spieler:intrifft oder nicht.
Raycasting, um Kollisionen zu finden
Raycasting erstellt einen unsichtbaren Strahl von einer Startposition in eine bestimmte Richtung mit einer definierten Länge.Wenn der Strahl mit Objekten oder Terrain auf seinem Weg zusammenstößt, gibt er Informationen über die Kollision zurück, wie die Position und das Objekt, mit dem er zusammenstieß.

Finde die Mausposition
Bevor ein Laser abgefeuert werden kann, musst du zuerst wissen, wo der Spieler zielt.Dies kann durch Raycasting von der 2D-Mausposition des Spieler:inauf dem Bildschirm direkt von der Kamera in die Weltübertragen werden.Der Strahl wird mit allem zusammenstoßen, auf das der Spieler mit der Maus abzielt.
Öffne das ToolController -Skript innerhalb des Blaster-Tools von Spielerwerkzeugen erstellen.Wenn du das Tutorial noch nicht abgeschlossen hast, kannst du das Blaster-Modell herunterladen und es in das StarterPack einfügen.
Am Anfang des Skript, das. PL: die Skriptserklären Sie eine Konstante namens MAX_MOUSE_DISTANCE mit einem Wert von 1000 .
Erstelle eine Funktion mit dem Namen getWorldMousePosition.
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-- Verbinden von Ereignissen mit geeigneten Funktionentool.Equipped:Connect(toolEquipped)tool.Activated:Connect(toolActivated)Verwende die Funktion GetMouseLocation von UserInputService, um die 2D-Mausposition des Spieler:inauf dem Bildschirm zu erhalten.Weisen Sie dies einer Variable mit dem Namen MouseLocation zu.
local UserInputService = game:GetService("UserInputService")local tool = script.Parentlocal MAX_MOUSE_DISTANCE = 1000local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()end
Jetzt ist die 2D-Mausposition bekannt, ihre X und Y Eigenschaften können als Parameter für die Camera:ViewportPointToRay() verwendet werden, die eine Ray vom Bildschirm in die Welterstellt.
Verwende die X - und Y -Eigenschaften von mouseLocation als Argumente für die ViewportPointToRay().Weisen Sie dies einer Variable mit dem Namen screenToWorldRay zu.
local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()-- Erstelle einen Strahl aus der 2D-Mauspositionlocal screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)end
Es ist Zeit, die Raycast-Funktion zu verwenden, um zu überprüfen, ob der Strahl ein Objekt trifft.Dafür benötigen Sie eine Startposition und Vektorkraft: In diesem Beispiel verwenden Sie die Herkunfts- und Richtungs属性 von screenToWorldRay .
Die Länge des Richtungsvektors bestimmt, wie weit der Strahl reisen wird.Der Strahl muss so lang sein wie der MAX_MOUSE_DISTANCE, also musst du den Richtungsvektor mit MAX_MOUSE_DISTANCE multiplizieren.
Erkläre eine Variable mit dem Namen directionVector und weise ihr den Wert von screenToWorldRay.Direction multipliziert mit MAX_MOUSE_DISTANCE zu.
local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()-- Erstelle einen Strahl aus der 2D-Mauspositionlocal screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)-- Der Einheitenrichtungsvektor des Strahls multipliziert mit einer maximalen Entfernunglocal directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCERufen Sie die Raycast Funktion des Arbeitsbereichs auf, indem Sie die Eigenschaft Herkunft von screenToWorldRay als erstes Argument und directionVector als zweites Argument übergeben.Weisen Sie dies einer Variable mit dem Namen raycastResult zu.
local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()-- Erstelle einen Strahl aus der 2D-Mauspositionlocal screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)-- Der Einheitenrichtungsvektor des Strahls multipliziert mit einer maximalen Entfernunglocal directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE-- Raycast von der Herkunft des Strahls in Richtung seiner Richtunglocal raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
Kollisionsinformationen
Wenn die Raycast-Operation ein von dem Strahl getroffenes Objekt findet, gibt es eine RaycastResult zurück, die Informationen über die Kollision zwischen dem Strahl und dem Objekt enthält.
RaycastResult-Eigenschaft | Beschreibung |
---|---|
Instanz | Die BasePart oder Terrain Zelle, die der Strahl gekreuzt hat. |
Stelle | Wo die Intersektion auftrat; gewöhnlich ein Punkt direkt auf der Oberfläche eines Teils oder Gelände. |
Materiel | Das Material am Kollisionspunkt. |
Normativ | Der normale Vektor des überschnittenen Gesichts. Dies kann verwendet werden, um zu bestimmen, in welche Richtung das Gesicht zeigt. |
Die Position -Eigenschaft wird die Position des Objekts sein, auf dem sich die Maus befindet.Wenn die Maus nicht über einem Objekt in einer Entfernung von MAX_MOUSE_DISTANCE schwebt, wird raycastResult sein nil.
Erstelle ein if-Statement, um zu überprüfen, ob raycastResult existiert.
Wenn raycastResult einen Wert hat, geben Sie seine Eigenschaftenzurück.
Wenn raycastResult ist nil dann finden Sie das Ende des Raycasts.Berechne die 3D-Position der Maus, indem du screenToWorldRay.Origin und directionVector zusammen fügst.
local function getWorldMousePosition()
local mouseLocation = UserInputService:GetMouseLocation()
-- Erstelle einen Strahl aus der 2D-Mausposition
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- Der Einheitenrichtungsvektor des Strahls multipliziert mit einer maximalen Entfernung
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- Raycast von der Herkunft des Strahls in Richtung seiner Richtung
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- Gibt den 3D-Punkt der Intersektion zurück
return raycastResult.Position
else
-- Kein Objekt wurde getroffen, also berechne die Position am Ende des Strahls
return screenToWorldRay.Origin + directionVector
end
end
Feuere auf das Ziel
Jetzt, da die 3D-Mausposition bekannt ist, kann sie als Zielposition verwendet werden, um einen Laser darauf abzufeuern.Ein zweiter Strahl kann zwischen der Waffe des Spieler:inund der Zielposition mit der Funktion Raycast geworfen werden.
Erkläre eine Konstante namens MAX_LASER_DISTANCE an der Spitze des Skripts und weise sie auf 500 oder deine gewählte Reichweite für den Laserblaster zu.
local UserInputService = game:GetService("UserInputService")local tool = script.Parentlocal MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 500Erstelle eine Funktion namens fireWeapon unter der getWorldMousePosition Funktion.
Rufen Sie getWorldMousePosition auf und weisen Sie das Ergebnis einer Variable mit dem Namen mousePosition zu. Dies wird die Zielposition für den Raycast sein.
-- Kein Objekt wurde getroffen, also berechne die Position am Ende des Strahlsreturn screenToWorldRay.Origin + directionVectorendendlocal function fireWeapon()local mouseLocation = getWorldMousePosition()endlocal function toolEquipped()tool.Handle.Equip:Play()end
Dieses Mal wird der Richtungsvektor für die Raycast-Funktion die Richtung von der Werkzeugposition des Spieler:inzum Zielort darstellen.
Erkläre eine Variable mit dem Namen targetDirection und berechne den Richtungsvektor, indem du die Toolposition von mouseLocation subtrahierst.
Normalisiere den Vektor durch die Verwendung seiner Eigenschaften. Dies gibt ihm eine Größe von 1, was es einfach macht, später mit einer Länge zu multiplizieren.
local function fireWeapon()local mouseLocation = getWorldMousePosition()-- Berechnen Sie einen normalisierten Richtungsvektor und multiplizieren Sie ihn mit der Laserdistanzlocal targetDirection = (mouseLocation - tool.Handle.Position).UnitendErkläre eine Variable mit dem Namen directionVector und weise ihr die multipliziert durch die zu.
local targetDirection = (mouseLocation - tool.Handle.Position).Unit-- Die Richtung, in der die Waffe abgefeuert wird, multipliziert mit einer maximalen Entfernunglocal directionVector = targetDirection * MAX_LASER_DISTANCEend
Ein RaycastParams-Objekt kann verwendet werden, um zusätzliche Parameter für die Raycast-Funktion zu speichern.Es wird in deinem Laserblaster verwendet, um sicherzustellen, dass der Strahl nicht versehentlich mit dem Spieler zusammenstößt, der die Waffe abfeuert.Alle Teile, die in der FilterDescendantsInstances Eigenschaft eines RaycastParams-Objekts enthalten sind, werden im Raycast ignoriert **** .
Fortführe die fireWeapon-Funktion und erkläre eine Variable namens weaponRaycastParams . Weise ihr ein neues RaycastParams-Objekt zu.
Erstelle eine Tabelle mit dem lokalen Charakter des Spieler:inund weise sie der Eigenschaftenzu.
Raycast von der Werkzeuggriffposition des Spieler:inin eine Richtung auf die directionVector.Denken Sie daran, weaponRaycastParams als Argument diesmal hinzuzufügen.Weisen Sie dies einer Variable mit dem Namen weaponRaycastResult zu.
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()
-- Berechnen Sie einen normalisierten Richtungsvektor und multiplizieren Sie ihn mit der Laserdistanz
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- Die Richtung, um die Waffe mit einer maximalen Entfernung zu feuern
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- Ignoriere den Charakter des Spieler:in, um ihn daran zu hindern, sich selbst zu schaden
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
end
Schließlich musst du überprüfen, dass die Raycast-Operation einen Wert zurückgegeben hat.Wenn ein Wert zurückgegeben wird, wurde ein Objekt vom Strahl getroffen und zwischen der Waffe und dem Trefferort kann ein Laser erstellt werden.Wenn nichts zurückgegeben wurde, muss die endgültige Position berechnet werden, um den Laser zu erstellen.
Erkläre eine leere Variable mit dem Namen hitPosition .
Verwende ein if Statement, um zu überprüfen, ob weaponRaycastResult einen Wert hat. Wenn ein Objekt getroffen wurde, weise weaponRaycastResult.Position an hitPosition zu.
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)-- Überprüfe, ob irgendwelche Objekte zwischen der Start- und Endposition getroffen wurdenlocal hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.PositionendWenn weaponRaycastResult keinen Wert hat, berechne die Endposition des Raycasts, indem du die Position des Werkzeuggriffs mit der directionVector addierst.Zuordnen Sie dies zu hitPosition .
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)-- Überprüfe, ob irgendwelche Objekte zwischen der Start- und Endposition getroffen wurdenlocal hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.Positionelse-- Berechnen Sie die Endposition basierend auf der maximalen LaserdistanzhitPosition = tool.Handle.Position + directionVectorendendNavigiere zur toolActivated-Funktion und rufe die fireWeapon-Funktion auf, damit der Laser jedes Mal feuert, wenn das Werkzeug aktiviert wird.
local function toolActivated()tool.Handle.Activate:Play()fireWeapon()end
Überprüfen Sie den Objekt-Hit
Um zu finden, ob das von dem Laser getroffene Objekt Teil des Charakters eines Spieler:inist oder nur ein Stück Landschaft, musst du nach einem Humanoid suchen, da jeder Charakter eines hat.
Zuerst musst du das Zeichenmodell finden .Wenn ein Teil des Charakters getroffen wurde, kannst du nicht davon ausgehen, dass der Elternteil des getroffenen Objekts der Charakter sein würde.Der Laser hätte ein Körperteil, ein Zubehör oder ein Tooltreffen können, alle befinden sich in verschiedenen Teilen der Hierarchie des Charakters.
Du kannst FindFirstAncestorOfClass verwenden, um einen Vorfahren eines Zeichenmodells des Objekts zu finden, das vom Laser getroffen wurde, wenn es existiert.Wenn du ein Modell findest und es einen Humanoiden enthält, kannst du in den meisten Fällen davon ausgehen, dass es ein Charakter ist.
Füge den hervorgehobenen Code unten zum weaponRaycastResult wenn Statement hinzu, um zu überprüfen, ob ein Zeichen getroffen wurde.
-- Überprüfe, ob irgendwelche Objekte zwischen der Start- und Endposition getroffen wurdenlocal hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.Position-- Die Instanztreffer werden ein Kind eines Modellsein-- Wenn ein Humanoid im Modell gefunden wird, ist es wahrscheinlich der Charakter eines Spieler:inlocal characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid thenprint("Player hit")endendelse-- Berechnen Sie die Endposition basierend auf der maximalen LaserdistanzhitPosition = tool.Handle.Position + directionVectorend
Jetzt sollte der Laserblaster jedes Mal, wenn die Raycast-Operation einen anderen Spieler:intrifft, Player hit in das Ausgabe-Fenster drucken.
Teste mit mehreren Spielern
Zwei Spieler sind erforderlich, um zu testen, ob der Waffenstrahl andere Spieler findet, also musst du einen lokalen Server starten.
Wählen Sie die Test -Registerkarte in Studio.
Stellen Sie sicher, dass die Dropdown-Liste der Spieler auf "2 Spieler" eingestellt ist, und klicken Sie auf die Start-Schaltfläche, um einen lokalen Server mit 2 Clients zu starten .Drei Fenster erscheinen.Das erste Fenster wird der lokale Server sein, die anderen Fenster werden die Clients für Player1 und Player2 sein.
Auf einem Client teste den anderen Spieler mit der Waffe, indem du auf sie klickst.Der "Spielerangriff" sollte in der Ausgabe jedes Mal angezeigt werden, wenn ein Spieler geschossen wird.
Weitere Informationen zu der Test -Registerkarte findest du hier.
Finde die Laserposition
Der Blaster sollte einen roten Lichtstrahl auf sein Ziel abfeuern.Die Funktion dafür wird in einem ModuleScript sein, so dass sie später in anderen Skripten wiederverwendet werden kann.Zuerst muss das Skript die Position finden, an der der Laserstrahl gerendert werden soll.
Erstellen Sie ein Modulskript mit dem Namen LaserRenderer , das unter StarterPlayer zu den StarterPlayer-Skripts gehört.
Öffne das Skript und benenne den Modultisch zum Namen des Skripts um LaserRenderer .
Erkläre eine Variable mit dem Namen SCHUSS_DAUER mit einem Wert von 0.15 .Dies wird die Zeit sein (in Sekunden), für die der Laser sichtbar ist.
Erstellen Sie eine Funktion von LaserRenderer namens createLaser mit zwei Parametern namens toolHandle und endPosition .
local LaserRenderer = {}local SHOT_DURATION = 0.15 -- Zeit, für die der Laser sichtbar ist-- Erstelle einen Laserstrahl von einer Startposition in Richtung einer Endpositionfunction LaserRenderer.createLaser(toolHandle, endPosition)endreturn LaserRendererErkläre eine Variable mit dem Namen startPosition und lege die Position -Eigenschaft von toolHandle als ihren Wert fest.Dies wird die Position des Laserblasters des Spieler:insein.
Erkläre eine Variable namens laserDistance und subtrahiere endPosition von startPosition um den Unterschied zwischen den beiden Vektoren zu finden.Verwende die Größe -Eigenschaft dieser, um die Länge des Laserstrahls zu erhalten.
function LaserRenderer.createLaser(toolHandle, endPosition)local startPosition = toolHandle.Positionlocal laserDistance = (startPosition - endPosition).MagnitudeendErkläre eine lasercFrame -Variable, um die Position und Ausrichtung des Laserstrahls zu speichern.Die Position muss der mittlere Punkt des Starts und des Endes des Beams sein.Verwende CFrame.lookAt , um einen neuen CFrame zu erstellen, der sich an startPosition befindet und in Richtung endPosition ausgerichtet ist.Multiplizieren Sie dies mit einem neuen CFrame mit einem Z-Achsenwert von der Hälfte von negativ laserDistance , um den Mittelpunkt zu erhalten.
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
Erstelle das Laserteil
Jetzt, wo du weißt, wo du einen Laserstrahl erstellen kannst, musst du den Strahl selbst hinzufügen. Dies kann einfach mit einem Neon-Teil erledigt werden.
Erkläre eine Variable laserPart und weise ihr eine neue Part zu.
Setze die folgenden Eigenschaften von laserPart :
- Größe : Vector3.new(0.2, 0.2, laserDistance)
- CFrame : laserCFrame
- Verankert : true
- Kann kollidieren : false
- Farbe : Color3.fromRGB(225, 0, 0) (eine starke rote Farbe)
- Material : Enum.Material.Neon
Eltern laserPart an Arbeitsplatz .
Füge das Teil zum Debris-Service hinzu, damit es nach der Anzahl der Sekunden in der SHOT_DURATION-Variable entfernt wird.
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-- Füge einen Laserstrahl zum Debris-Service hinzu, der entfernt und gereinigt werden sollDebris:AddItem(laserPart, SHOT_DURATION)end
Jetzt ist die Funktion zum Rendern des Laserstrahls vollständig, sie kann vom ToolController aufgerufen werden.
Am Anfang des ToolController -Skripts erklären Sie eine Variable mit dem Namen LaserRenderer und benötigen das LaserRenderer-Modulskript, das sich in den PlayerScripts befindet.
local UserInputService = game:GetService("UserInputService")local Players = game:GetService("Players")local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)local tool = script.ParentAm unteren Rand der fireWeapon Funktion ruft man die LaserRenderer-Funktion createLaser mit dem Werkzeuggriff und hitPosition als Argumenten auf.
-- Berechnen Sie die Endposition basierend auf der maximalen LaserdistanzhitPosition = tool.Handle.Position + directionVectorendLaserRenderer.createLaser(tool.Handle, hitPosition)endTeste die Waffe, indem du auf die Schaltfläche "Spielen" klickst. Ein Laserstrahl sollte zwischen der Waffe und der Maus sichtbar sein, wenn das Werkzeug aktiviert wird.
Kontrolliere die bewertender Waffe
Waffen brauchen eine Verzögerung zwischen jedem Schuss, um Spieler daran zu hindern, in kurzer Zeit zu viel Schaden zu verursachen.Dies kann durch die Überprüfung gesteuert werden, ob seit dem letzten Feuern eines Spielers genügend Zeit verstrichen ist.
Erkläre eine Variable an der Spitze des ToolControllers , die aufgerufen wird FIRE_RATE .Das wird die minimale Zeit zwischen jedem Schuss sein.Gib ihm einen Wert deiner Wahl; dieses Beispiel verwendet 0,3 Sekunden.
Erkläre eine andere Variable darunter mit dem Namen timeOfPreviousShot mit einem Wert von 0 .Dies speichert das letzte Mal, dass der Spieler geschossen hat, und wird mit jedem Schuss aktualisiert.
local MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 300local FIRE_RATE = 0.3local timeOfPreviousShot = 0Erstelle eine Funktion namens kannShootWeapon ohne Parameter.Diese Funktion wird betrachten, wie viel Zeit seit dem vorherigen Schuss vergangen ist, und true oder false zurückgeben.
local FIRE_RATE = 0.3local timeOfPreviousShot = 0-- Überprüfe, ob genug Zeit vergangen ist, seit der letzte Schuss abgefeuert wurdelocal function canShootWeapon()endlocal function getWorldMousePosition()Innerhalb der Funktion erkläre eine Variable namens aktuelle Zeit ; zuweisen Sie ihr das Ergebnis des Aufrufs der tick() Funktion zu.Dies gibt zurück, wie viel Zeit verstrichen ist, in Sekunden, seit dem 1. Januar 1970 (ein zufälliges Datum, das weit verbreitet verwendet wird, um die Zeit zu berechnen).
Subtrahiere das timeOfPreviousShot von currentTime und gib falsch zurück, wenn das Ergebnis kleiner als FIRE_RATE ist; ansonsten gib wahr zurück.
-- Überprüfe, ob genug Zeit vergangen ist, seit der letzte Schuss abgefeuert wurdelocal function canShootWeapon()local currentTime = tick()if currentTime - timeOfPreviousShot < FIRE_RATE thenreturn falseendreturn trueendAm Ende der fireWeapon Funktion aktualisieren Sie timeOfPreviousShot jedes Mal, wenn die Waffe mit tick abgefeuert wird.
hitPosition = tool.Handle.Position + directionVectorendtimeOfPreviousShot = tick()LaserRenderer.createLaser(tool.Handle, hitPosition)endInnerhalb der toolActivated-Funktion erstellt eine wenn -Anweisung und ruft canShootWeapon auf, um zu überprüfen, ob die Waffe abgefeuert werden kann.
local function toolActivated()if canShootWeapon() thentool.Handle.Activate:Play()fireWeapon()endend
Wenn du den Blaster testest, solltest du feststellen, dass es egal, wie schnell du klicken, immer eine kurze Verzögerung von 0,3 Sekunden zwischen jedem Schuss gibt.
Schädige den Spieler:in
Clients können anderen Clients nicht direkt Schaden zufügen; der Server muss verantwortlich sein, Schaden zu verursachen, wenn ein Spieler getroffen wird.
Clients können eine RemoteEvent verwenden, um dem Server mitzuteilen, dass ein Zeichen getroffen wurde.Diese sollten in ReplicatedStorage gespeichert werden, wo sie sowohl für den Client als auch für den Server sichtbar sind.
Erstellen Sie einen Ordner in ReplicatedStorage mit dem Namen Veranstaltungen .
Füge ein Remote-Ereignis in den Ordner Ereignisse ein und benenne es Schadenscharakter .
In ToolController erstellen Sie Variablen zu Beginn des Skripts für ReplicatedStorage und den Ordner Ereignisse.
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 = 500Ersetze die "Player hit" Druck statement in fireWeapon durch eine Zeile von Luau, um das Schadenszeichen Remote-Ereignis mit der characterModel Variable als Argument zu feuern.
local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid theneventsFolder.DamageCharacter:FireServer(characterModel)endendelse-- Berechnen Sie die Endposition basierend auf der maximalen LaserdistanzhitPosition = tool.Handle.Position + directionVectorend
Der Server muss dem Spieler Schaden zufügen, der getroffen wurde, wenn das Ereignis ausgelöst wird.
Füge ein Skript in den ServerScriptService ein und benenne es ServerLaserManager .
Erkläre eine Variable mit dem Namen LASER_DAMAGE und stelle sie auf 10 oder einen Wert deiner Wahl ein.
Erstelle eine Funktion namens damageCharacter mit zwei Parametern namens playerFired und characterToDamage .
Innerhalb der Funktion finden Sie den Humanoiden des Charakters und subtrahieren LASER_DAMAGE von seiner Gesundheit.
Verbinden Sie die damageCharacter-Funktion mit dem Schadenscharakter-Remote-Ereignis im Ordner Ereignisse.
local ReplicatedStorage = game:GetService("ReplicatedStorage")local eventsFolder = ReplicatedStorage.Eventslocal LASER_DAMAGE = 10function damageCharacter(playerFired, characterToDamage)local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")if humanoid then-- Leben vom Charakter entfernenhumanoid.Health -= LASER_DAMAGEendend-- Verbinden von Ereignissen mit geeigneten FunktioneneventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)Teste den Blaster mit 2 Spielern, indem du einen lokalen Server startest.Wenn du den anderen Spieler:inschießt, wird seine Gesundheit durch die Zahl, die auf LASER_DAMAGE zugewiesen ist, verringert.
Laserstrahlen anderer Spieler:inrendern
Derzeit wird der Laserstrahl vom Client erzeugt, der die Waffe abfeuert, sodass nur sie den Laserstrahl sehen können.
Wenn der Laserstrahl auf dem Server erstellt wurde, dann könnte jeder ihn sehen.Es würde jedoch eine kleine Verzögerung zwischen dem Client, der die Waffe schießt, und dem Server geben, der die Informationen über den Schuss erhält.Das würde bedeuten, dass der Client, der die Waffe schießt, eine Verzögerung sieht, zwischen dem Zeitpunkt, an dem er die Waffe aktiviert, und dem Zeitpunkt, an dem er den Laserstrahl sieht; die Waffe würde sich verzögert fühlen.
Um dieses Problem zu lösen, wird jeder Client eigene Laserstrahlen erstellen.Das bedeutet, dass der Client, der die Waffe schießt, den Laserstrahl sofort sieht.Andere Clients erleben eine kleine Verzögerung zwischen dem Zeitpunkt, an dem ein anderer Spieler schießt, und dem Auftauchen eines Strahls.Das ist der beste Fall: Es gibt keine Möglichkeit, den Laser eines Clients schneller an andere Clients zu kommunizieren.
Client des Schützen
Zuerst muss der Client dem Server mitteilen, dass er einen Laser abgefeuert hat und die Endposition bereitstellt.
Füge ein Remote-Ereignis in den Ordner Ereignisse in ReplicatedStorage ein und benenne es LaserFired .
Lokalisieren Sie die fireWeapon-Funktion im ToolController Skript, das. PL: die Skripts.Am Ende der Funktion feuere das LaserFired Remote-Ereignis mit als Argument ab.
hitPosition = tool.Handle.Position + directionVectorendtimeOfPreviousShot = tick()eventsFolder.LaserFired:FireServer(hitPosition)LaserRenderer.createLaser(tool.Handle, hitPosition)end
Der Server
Der Server muss jetzt das Ereignis empfangen, das der Client abgefeuert hat, und allen Clients die Start- und Endposition des Laserstrahls mitteilen, damit sie ihn auch rendern können.
Im Skript, das. PL: die Skriptserstellen Sie eine Funktion mit dem Namen playerFiredLaser über damageCharacter mit zwei Parametern namens playerFired und endPosition.
Verbinde die Funktion mit dem LaserFired Remote-Ereignis.
-- Benachrichtige alle Clients, dass ein Laser abgefeuert wurde, damit sie den Laser anzeigen könnenlocal function playerFiredLaser(playerFired, endPosition)end-- Verbinden von Ereignissen mit geeigneten FunktioneneventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)
Der Server benötigt die Startposition des Lasers.Dies könnte vom Client gesendet werden, aber es ist am besten, den Client dort zu vermeiden, wo es möglich ist.Die Waffengriffposition des Charakters wird die Startposition sein, so dass der Server sie von dort aus finden kann.
Erstellen Sie eine Funktion getPlayerToolHandle über der playerFiredLaser Funktion mit einem Parameter namens player.
Verwende den folgenden Code, um den Charakter des Spieler:innach der Waffe zu suchen und das Objektzurückzugeben.
local LASER_DAMAGE = 10-- Finde den Griff des Werkzeugs, das der Spieler hältlocal function getPlayerToolHandle(player)local weapon = player.Character:FindFirstChildOfClass("Tool")if weapon thenreturn weapon:FindFirstChild("Handle")endend-- Benachrichtige alle Clients, dass ein Laser abgefeuert wurde, damit sie den Laser anzeigen könnenlocal function playerFiredLaser(playerFired, endPosition)
Der Server kann jetzt FireAllClients auf das LaserFired Remote-Ereignis aufrufen, um die Informationen zu senden, die zum Anzeigen des Lasers an die Clients erforderlich sind.Dazu gehören der Spieler , der den Laser abgefeuert hat (so dass der Client für diesen Spieler den Laser nicht zweimal rendert), der Griff des Blasters (der als Startposition für den Laser dient) und die Endposition des Lasers.
In der playerFiredLaser-Funktion rufen Sie die getPlayerToolHandle-Funktion mit playerFired als Argument auf und weisen den Wert einer Variable mit dem Namen toolHandle zu.
Wenn Werkzeuggriff existiert, feuere das LaserFired-Ereignis für alle Clients ab, die playerFired, toolHandle und endPosition als Argumente verwenden.
-- Benachrichtige alle Clients, dass ein Laser abgefeuert wurde, damit sie den Laser anzeigen könnenlocal function playerFiredLaser(playerFired, endPosition)local toolHandle = getPlayerToolHandle(playerFired)if toolHandle theneventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)endend
Auf den Clients rendern
Jetzt wurde FireAllClients aufgerufen, jeder Client wird ein Ereignis vom Server erhalten, um einen Laserstrahl zu rendern.Jeder Client kann das Laserrenderer -Modul von früheren wiederverwenden, um den Laserstrahl mit der Griffposition und dem Endpositionwert des Tools des Servers zu rendern.Der Spieler, der den Laserstrahl zuerst abgefeuert hat, sollte dieses Ereignis ignorieren, sonst werden sie 2 Laser sehen.
Erstellen Sie ein Lokales Skript in StarterPlayerScripts mit dem Namen ClientLaserManager .
Im Inneren des Skript, das. PL: die Skriptserfordert das Modul LaserRenderer .
Erstelle eine Funktion namens createPlayerLaser mit den Parametern playerWhoShot , toolHandle und endPosition .
Verbinde die Funktion mit dem LaserFired Remote-Ereignis im Ordner Ereignisse.
Verwende in der Funktion eine if Aussage, um zu überprüfen, ob nicht gleich dem LocalPlayer ist.
Innerhalb der if-Anweisung rufen Sie die createLaser-Funktion aus dem LaserRenderer-Modul mit toolHandle und endPosition als Argumenten auf.
local Players = game:GetService("Players")local ReplicatedStorage = game:GetService("ReplicatedStorage")local LaserRenderer = require(script.Parent:WaitForChild("LaserRenderer"))local eventsFolder = ReplicatedStorage.Events-- Laser eines anderen Spieler:inanzeigenlocal function createPlayerLaser(playerWhoShot, toolHandle, endPosition)if playerWhoShot ~= Players.LocalPlayer thenLaserRenderer.createLaser(toolHandle, endPosition)endendeventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)Teste den Blaster mit 2 Spielern, indem du einen lokalen Server startest.Stelle jeden Client auf unterschiedliche Seiten deines Monitors, damit du beide Fenster gleichzeitig sehen kannst.Wenn du auf einem Client schießt, solltest du den Laser auf dem anderen Client sehen.
Soundeffekte
Der Schuss-Soundeffekt spielt derzeit nur auf dem Client, der das Projektil schießt.Du musst den Code verschieben, um den Ton abzuspielen, damit andere Spieler es auch hören.
Im ToolController Skript, das. PL: die Skriptsnavigieren Sie zur Funktion toolActivated und entfernen Sie die Zeile, die den Aktivierungsklang wiedergibt.
local function toolActivated()if canShootWeapon() thenfireWeapon()endendAm Boden der createLaser-Funktion in LaserRenderer , erkläre eine Variable namens shootingSound und verwende die FindFirstChild()-Methode von toolHandle, um den Aktivieren- -Sound zu überprüfen.
Verwende ein if Statement, um zu überprüfen, ob shootingSound existiert; wenn es existiert, rufe seine Spiel Funktion auf.
laserPart.Parent = workspace-- Füge einen Laserstrahl zum Debris-Service hinzu, der entfernt und gereinigt werden sollDebris:AddItem(laserPart, SHOT_DURATION)-- Spiele den Schuss音 der Waffe ablocal shootingSound = toolHandle:FindFirstChild("Activate")if shootingSound thenshootingSound:Play()endend
Sichere Fernbedienungen mit Validierung
Wenn der Server keine Daten von eingehenden Anfragen überprüft, kann ein Hacker remote-Funktionen und -Ereignisse missbrauchen und sie verwenden, um dem Server falsche Werte zu senden.Es ist wichtig, Server-seitige Validierung zu verwenden, um dies zu verhindern.
In seiner derzeitigen Form ist das Schadenscharakter Remote-Ereignis sehr anfällig für Angriffe.Hacker könnten dieses Ereignis nutzen, um jeden Spieler zu beschädigen, den sie im Spiel wollen, ohne ihn zu schießen.
Die Validierung ist der Prozess, bei dem überprüft wird, dass die Werte, die an den Server gesendet werden, realistisch sind. In diesem Fall muss der Server:
- Überprüfe, ob die Entfernung zwischen dem Spieler und der Position, die vom Laser getroffen wird, innerhalb einer bestimmten Grenze liegt.
- Schießen zwischen der Waffe, die den Laser abfeuert, und der Zielposition, um sicherzustellen, dass der Schuss möglich war und keine Wände durchschlug.
Client
Der Client muss dem Server die von dem Strahl getroffene Position senden, damit er überprüfen kann, ob die Entfernung realistisch ist.
In ToolController , navigiere zur Zeile, in der das Schadenszeichen-Remote-Ereignis in der fireWeapon abgefeuert wird.
Füge hitPosition als Argument hinzu.
if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid theneventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)endend
Server
Der Client sendet jetzt einen zusätzlichen Parameter durch das Remote-Ereignis Schadencharakter, so dass der Serverlasermanager angepasst werden muss, um es zu akzeptieren.
Im ServerLaserManager Skript, das. PL: die Skriptsfüge einen hitPosition -Parameter zur damageCharacter -Funktion hinzu.
function damageCharacter(playerFired, characterToDamage, hitPosition)local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")if humanoid then-- Leben vom Charakter entfernenhumanoid.Health -= LASER_DAMAGEendendUnter der getPlayerToolHandle-Funktion erstellt eine Funktion namens isHitValid mit drei Parametern: playerFired, characterToDamage und hitPosition.
endlocal function isHitValid(playerFired, characterToDamage, hitPosition)end
Die erste Prüfung wird die Entfernung zwischen der Trefferposition und dem getroffenen Zeichen sein.
Erkläre eine Variable mit dem Namen MAX_HIT_PROXIMITY an der Spitze des Skripts und weise ihr einen Wert von 10 zu.Dies wird die maximale erlaubte Distanz zwischen dem Treffer und dem Charakter sein.Eine Toleranz ist erforderlich, da der Charakter sich möglicherweise leicht bewegt hat, seit der Client das Ereignis abgefeuert hat.
local ReplicatedStorage = game:GetService("ReplicatedStorage")local eventsFolder = ReplicatedStorage.Eventslocal LASER_DAMAGE = 10local MAX_HIT_PROXIMITY = 10In der isHitValid-Funktion berechnen Sie die Entfernung zwischen dem Zeichen und der Trefferposition.Wenn die Entfernung größer als MAX_HIT_PROXIMITY ist, dann gib false zurück.
local function isHitValid(playerFired, characterToDamage, hitPosition)-- Bestätigen Sie die Entfernung zwischen dem Charaktertreffer und der Trefferpositionlocal characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitudeif characterHitProximity > MAX_HIT_PROXIMITY thenreturn falseendend
Die zweite Überprüfung wird einen Raycast zwischen der abgefeuerten Waffe und der Zielposition beinhalten.Wenn der Raycast ein Objekt zurückgibt, das nicht der Charakter ist, kannst du davon ausgehen, dass der Schuss ungültig war, da etwas den Schuss blockierte.
Kopiere den Code unten, um diese überprüfendurchzuführen. Gibt true am Ende der Funktion zurück: Wenn es das beendenerreicht, sind alle Überprüfungen bestanden.
local function isHitValid(playerFired, characterToDamage, hitPosition)-- Bestätigen Sie die Entfernung zwischen dem Charaktertreffer und der Trefferpositionlocal characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitudeif characterHitProximity > 10 thenreturn falseend-- Überprüfe, ob du durch Wände schießtlocal 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)-- Wenn eine Instanz getroffen wurde, die nicht der Charakter war, ignoriere den Schussif rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) thenreturn falseendendreturn trueendErkläre eine Variable in der damageCharacter Funktion namens validShot , die aufgerufen wird.Weise ihm das Ergebnis eines Anrufs bei der isHitValid -Funktion mit drei Argumenten zu: playerFired , characterToDamage und hitPosition .
Fügen Sie in der folgenden if-Anweisung einen und Operator hinzu, um zu überprüfen, ob validShot wahr ist.
function damageCharacter(playerFired, characterToDamage, hitPosition)local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")local validShot = isHitValid(playerFired, characterToDamage, hitPosition)if humanoid and validShot then-- Leben vom Charakter entfernenhumanoid.Health -= LASER_DAMAGEendend
Jetzt ist das Schadencharakter-Remote-Ereignis sicherer und wird die meisten Spieler davon abhalten, es zu missbrauchen.Beachten Sie, dass einige böswillige Spieler oft Wege finden werden, um die Validierung zu umgehen; die Sicherung von Fernereignissen ist ein kontinuierlicher Bemühen.
Ihr Laserblaster ist jetzt abgeschlossen, mit einem grundlegenden Treffererkennungssystem, das Raycasting verwendet.Probieren Sie das Benutereingabeerkennung Tutorial aus, um herauszufinden, wie Sie eine Nachladeaktion zu Ihrem Laserblaster hinzufügen können, oder erstellen Sie eine lustige Spielkarte und probieren Sie Ihren Laserblaster mit anderen Spielern aus!
Letzter Codes
Werkzeugsteuerung
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
-- Überprüfe, ob genug Zeit vergangen ist, seit der letzte Schuss abgefeuert wurde
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()
-- Erstelle einen Strahl aus der 2D-Mausposition
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- Der Einheitenrichtungsvektor des Strahls multipliziert mit einer maximalen Entfernung
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- Strahlcast von der Herkunft des roy in Richtung seiner Richtung
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- Gibt den 3D-Punkt der Intersektion zurück
return raycastResult.Position
else
-- Kein Objekt wurde getroffen, also berechne die Position am Ende des Strahls
return screenToWorldRay.Origin + directionVector
end
end
local function fireWeapon()
local mouseLocation = getWorldMousePosition()
-- Berechnen Sie einen normalisierten Richtungsvektor und multiplizieren Sie ihn mit der Laserdistanz
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- Die Richtung, in der die Waffe abgefeuert wird, multipliziert mit einer maximalen Entfernung
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- Ignoriere den Charakter des Spieler:in, um ihn daran zu hindern, sich selbst zu schaden
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
-- Überprüfe, ob irgendwelche Objekte zwischen der Start- und Endposition getroffen wurden
local hitPosition
if weaponRaycastResult then
hitPosition = weaponRaycastResult.Position
-- Die Instanztreffer werden ein Kind eines Modellsein
-- Wenn ein Humanoid im Modell gefunden wird, ist es wahrscheinlich der Charakter eines Spieler:in
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
-- Berechnen Sie die Endposition basierend auf der maximalen Laserdistanz
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 -- Zeit, für die der Laser sichtbar ist
-- Erstelle einen Laserstrahl von einer Startposition in Richtung einer Endposition
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
-- Füge einen Laserstrahl zum Debris-Service hinzu, der entfernt und gereinigt werden soll
Debris:AddItem(laserPart, SHOT_DURATION)
-- Spiele den Schuss音 der Waffe ab
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
-- Finde den Griff des Werkzeugs, das der Spieler hält
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)
-- Bestätigen Sie die Entfernung zwischen dem Charaktertreffer und der Trefferposition
local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
if characterHitProximity > MAX_HIT_PROXIMITY then
return false
end
-- Überprüfe, ob du durch Wände schießt
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)
-- Wenn eine Instanz getroffen wurde, die nicht der Charakter war, ignoriere den Schuss
if rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) then
return false
end
end
return true
end
-- Benachrichtige alle Clients, dass ein Laser abgefeuert wurde, damit sie den Laser anzeigen können
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
-- Leben vom Charakter entfernen
humanoid.Health -= LASER_DAMAGE
end
end
-- Verbinden von Ereignissen mit geeigneten Funktionen
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
-- Laser eines anderen Spieler:inanzeigen
local function createPlayerLaser(playerWhoShot, toolHandle, endPosition)
if playerWhoShot ~= Players.LocalPlayer then
LaserRenderer.createLaser(toolHandle, endPosition)
end
end
eventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)