Tutorials für Fortgeschrittene

Treffererkennung mit Lasern

*Dieser Inhalt wurde mit KI (Beta) übersetzt und kann Fehler enthalten. Um diese Seite auf Englisch zu sehen, klicke hier.

In diesem Tutorial lernst du, wie man von einem Blaster einen Laser abfeuert in Spielerwerkzeuge erstellen und erkennt, ob er einen Spieler trifft oder nicht.

Raycasting zur Kollisionserkennung

Raycasting erzeugt einen unsichtbaren Strahl von einer Startposition in eine gegebene Richtung mit einer definierten Länge. Wenn der Strahl auf Objekte oder Terrain in seinem Weg trifft, gibt er Informationen über die Kollision zurück, wie z. B. die Position und das Objekt, mit dem er kollidiert hat.

Raycast von A nach B gegen eine Wand

Finde die Mausposition

Bevor ein Laser abgefeuert werden kann, muss man zuerst wissen, wo der Spieler zielt. Dies kann durch Raycasting von der 2D-Mausposition des Spielers auf dem Bildschirm direkt nach vorne von der Kamera in die 3D-Welt erfolgen. Der Strahl wird mit dem, auf das der Spieler mit der Maus zielt, kollidieren.

  1. Öffne das ToolController-Skript im Blaster-Werkzeug aus Spielerwerkzeuge erstellen. Wenn du dieses Tutorial noch nicht abgeschlossen hast, kannst du das Blaster-Modell herunterladen und es in StarterPack einfügen.

  2. Deklariere am Anfang des Skripts eine Konstante namens MAX_MOUSE_DISTANCE mit einem Wert von 1000.

  3. Erstelle eine Funktion namens getWorldMousePosition.


    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
    -- Verbinde Ereignisse mit den entsprechenden Funktionen
    tool.Equipped:Connect(toolEquipped)
    tool.Activated:Connect(toolActivated)
  4. Verwende die GetMouseLocation-Funktion von UserInputService, um die 2D-Mausposition des Spielers auf dem Bildschirm zu erhalten. Weise dies einer Variablen namens mouseLocation zu.


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

Nun ist die 2D-Mausposition bekannt, ihre X- und Y-Eigenschaften können als Parameter für die Funktion Camera:ViewportPointToRay() verwendet werden, die einen Ray von dem Bildschirm in die 3D-Welt erzeugt.

  1. Verwende die X- und Y-Eigenschaften von mouseLocation als Argumente für die ViewportPointToRay()-Funktion. Weisen dies einer Variablen namens screenToWorldRay zu.


    local function getWorldMousePosition()
    local mouseLocation = UserInputService:GetMouseLocation()
    -- Erzeuge einen Strahl von der 2D-Mausposition
    local 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. Dazu sind eine Startposition und ein Richtungsvektor erforderlich: In diesem Beispiel wirst du die Origin- und die Directions-Eigenschaften von screenToWorldRay verwenden.

Die Länge des Richtungsvektors bestimmt, wie weit der Strahl reisen wird. Der Strahl muss so lange wie MAX_MOUSE_DISTANCE sein, daher musst du den Richtungsvektor mit MAX_MOUSE_DISTANCE multiplizieren.

  1. Deklariere eine Variable namens directionVector und weise ihr den Wert von screenToWorldRay.Direction, multipliziert mit MAX_MOUSE_DISTANCE, zu.


    local function getWorldMousePosition()
    local mouseLocation = UserInputService:GetMouseLocation()
    -- Erzeuge einen Strahl von der 2D-Mausposition
    local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
    -- Der Einheitsrichtungsvektor des Strahls multipliziert mit einer maximalen Entfernung
    local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
  2. Rufe die Raycast-Funktion von workspace auf und übergebe die Origin-Eigenschaft von screenToWorldRay als erstes Argument und directionVector als zweites. Weisen dies einer Variablen namens raycastResult zu.


    local function getWorldMousePosition()
    local mouseLocation = UserInputService:GetMouseLocation()
    -- Erzeuge einen Strahl von der 2D-Mausposition
    local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
    -- Der Einheitsrichtungsvektor des Strahls multipliziert mit einer maximalen Entfernung
    local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
    -- Raycast von der Ursprung des Strahls in Richtung seiner Richtung
    local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)

Kollisioninformationen

Wenn die Raycast-Operation ein Objekt findet, das vom Strahl getroffen wurde, gibt sie ein RaycastResult zurück, welches Informationen über die Kollision zwischen dem Strahl und dem Objekt enthält.

RaycastResult-EigenschaftBeschreibung
InstanceDie BasePart oder die Terrain Zelle, die der Strahl durchschnitten hat.
PositionWo die Schnittstelle aufgetreten ist; normalerweise ein Punkt direkt auf der Oberfläche eines Parts oder Terrains.
MaterialDas Material an der Kollisionsstelle.
NormalDer Normalenvektor der durchquerten Fläche. Dies kann verwendet werden, um zu bestimmen, in welche Richtung die Fläche zeigt.

Die Position-Eigenschaft wird die Position des Objekts sein, über dem die Maus schwebt. Wenn die Maus nicht über einem Objekt innerhalb der Distanz von MAX_MOUSE_DISTANCE schwebt, wird raycastResult nil sein.

  1. Erstelle eine if-Anweisung, um zu überprüfen, ob raycastResult existiert.

  2. Wenn raycastResult einen Wert hat, gib die Position-Eigenschaft zurück.

  3. Wenn raycastResult nil ist, finde das Ende des Raycasts. Berechne die 3D-Position der Maus, indem du screenToWorldRay.Origin und directionVector zusammenaddierst.


local function getWorldMousePosition()
local mouseLocation = UserInputService:GetMouseLocation()
-- Erzeuge einen Strahl von der 2D-Mausposition
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- Der Einheitsrichtungsvektor des Strahls multipliziert mit einer maximalen Entfernung
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- Raycast von der Ursprung des Strahls in Richtung seiner Richtung
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- Gib den 3D-Schnittpunkt zurück
return raycastResult.Position
else
-- Kein Objekt wurde getroffen, also berechne die Position am Ende des Strahls
return screenToWorldRay.Origin + directionVector
end
end

Ziel feuern

Jetzt, da die 3D-Mausposition bekannt ist, kann sie als Zielposition verwendet werden, um einen Laser abzufeuern. Ein zweiter Strahl kann zwischen der Waffe des Spielers und der Zielposition unter Verwendung der Raycast-Funktion abgefeuert werden.

  1. Deklariere eine Konstante namens MAX_LASER_DISTANCE am Anfang des Skripts und weise ihr den Wert 500 oder den gewählten Bereich für den Laserblaster zu.


    local UserInputService = game:GetService("UserInputService")
    local tool = script.Parent
    local MAX_MOUSE_DISTANCE = 1000
    local MAX_LASER_DISTANCE = 500
  2. Erstelle eine Funktion namens fireWeapon unter der getWorldMousePosition-Funktion.

  3. Rufe getWorldMousePosition auf und weise das Ergebnis einer Variablen namens mousePosition zu. Dies wird die Zielposition für den Raycast sein.


    -- Kein Objekt wurde getroffen, also berechne die Position am Ende des Strahls
    return screenToWorldRay.Origin + directionVector
    end
    end
    local function fireWeapon()
    local mouseLocation = getWorldMousePosition()
    end
    local function toolEquipped()
    tool.Handle.Equip:Play()
    end

Dieses Mal wird der Richtungsvektor für die Raycast-Funktion die Richtung von der Position des Werkzeugs des Spielers zur Zielposition darstellen.

  1. Deklariere eine Variable namens targetDirection und berechne den Richtungsvektor, indem du die Werkzeugposition von mouseLocation subtrahierst.

  2. Normalisiere den Vektor, indem du seine Unit-Eigenschaft verwendest. Dies gibt ihm eine Größe von 1, was es später einfach macht, ihn mit einer Länge zu multiplizieren.


    local function fireWeapon()
    local mouseLocation = getWorldMousePosition()
    -- Berechne einen normalisierten Richtungsvektor und multipliziere mit der Laserentfernung
    local targetDirection = (mouseLocation - tool.Handle.Position).Unit
    end
  3. Deklariere eine Variable namens directionVector und weise ihr den targetDirection multipliziert mit der MAX_LASER_DISTANCE zu.


    local targetDirection = (mouseLocation - tool.Handle.Position).Unit
    -- Die Richtung, um die Waffe zu feuern, multipliziert mit einer maximalen Entfernung
    local directionVector = targetDirection * MAX_LASER_DISTANCE
    end

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 Raycast nicht versehentlich mit dem Spieler kollidiert, der die Waffe abfeuert. Alle Teile, die in der FilterDescendantsInstances-Eigenschaft eines RaycastParams-Objekts enthalten sind, werden im Raycast ignoriert.

  1. Setze die fireWeapon-Funktion fort und erkläre eine Variable namens weaponRaycastParams. Weisen ihr ein neues RaycastParams-Objekt zu.

  2. Erstelle eine Tabelle, die den lokalen character des Spielers enthält, und weise sie der weaponRaycastParams.FilterDescendantsInstances-Eigenschaft zu.

  3. Raycast von der Position des Werkzeuggriffs des Spielers in eine Richtung zur directionVector. Denke daran, diesmal weaponRaycastParams als Argument hinzuzufügen. Weisen dies einer Variablen namens 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()
-- Berechne einen normalisierten Richtungsvektor und multipliziere mit der Laserentfernung
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- Die Richtung, um die Waffe zu feuern, multipliziert mit einer maximalen Entfernung
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- Ignoriere den Charakter des Spielers, um zu verhindern, dass er sich selbst verletzt
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
end

Zuletzt musst du prüfen, ob die Raycast-Operation einen Wert zurückgegeben hat. Wenn ein Wert zurückgegeben wird, wurde ein Objekt vom Strahl getroffen und ein Laser kann zwischen der Waffe und der Trefferposition erstellt werden. Wenn nichts zurückgegeben wird, muss die endgültige Position berechnet werden, um den Laser zu erstellen.

  1. Deklariere eine leere Variable namens hitPosition.

  2. Verwende eine if-Anweisung, um zu prüfen, ob weaponRaycastResult einen Wert hat. Wenn ein Objekt getroffen wurde, weise weaponRaycastResult.Position hitPosition zu.


    local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
    -- Überprüfen, ob zwischen Start- und Endposition Objekte getroffen wurden
    local hitPosition
    if weaponRaycastResult then
    hitPosition = weaponRaycastResult.Position
    end
  3. Wenn weaponRaycastResult keinen Wert hat, berechne die Endposition des Raycasts, indem du die Position des Werkzeuggriffs mit dem directionVector addierst. Weisen dies hitPosition zu.


    local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
    -- Überprüfen, ob zwischen Start- und Endposition Objekte getroffen wurden
    local hitPosition
    if weaponRaycastResult then
    hitPosition = weaponRaycastResult.Position
    else
    -- Berechne die Endposition basierend auf der maximalen Laserentfernung
    hitPosition = tool.Handle.Position + directionVector
    end
    end
  4. Gehe zur toolActivated-Funktion und rufe die fireWeapon-Funktion auf, damit der Laser jedes Mal abgefeuert wird, wenn das Werkzeug aktiviert wird.


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

Überprüfe das getroffene Objekt

Um herauszufinden, ob das Objekt, das vom Laser getroffen wurde, Teil des Charakters eines Spielers oder nur ein Stück Landschaft ist, musst du nach einem Humanoid suchen, da jeder Charakter einen hat.

Zuerst musst du das Charaktermodell finden. Wenn ein Teil des Charakters getroffen wurde, kannst du nicht davon ausgehen, dass der Elternteil des getroffenen Objekts der Charakter ist. Der Laser könnte ein Körperteil, ein Zubehör oder ein Werkzeug getroffen haben, die sich alle in verschiedenen Teilen der Hierarchie des Charakters befinden.

Du kannst FindFirstAncestorOfClass verwenden, um ein Charaktermodell-Ahne von dem Objekt zu finden, das vom Laser getroffen wurde, falls vorhanden. Wenn du ein Modell findest und es einen Humanoiden enthält, kannst du in den meisten Fällen davon ausgehen, dass es sich um einen Charakter handelt.

  1. Füge den hervorgehobenen Code unten zur if-Anweisung von weaponRaycastResult hinzu, um zu überprüfen, ob ein Charakter getroffen wurde.


    -- Überprüfen, ob zwischen Start- und Endposition Objekte getroffen wurden
    local hitPosition
    if weaponRaycastResult then
    hitPosition = weaponRaycastResult.Position
    -- Die getroffene Instanz wird ein Kind eines Charaktermodells sein
    -- Wenn ein Humanoid im Modell gefunden wird, ist es wahrscheinlich der Charakter eines Spielers
    local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")
    if characterModel then
    local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    print("Spieler getroffen")
    end
    end
    else
    -- Berechne die Endposition basierend auf der maximalen Laserentfernung
    hitPosition = tool.Handle.Position + directionVector
    end

Jetzt sollte der Laserblaster Spieler getroffen im Ausgabe-Fenster ausgeben, jedes Mal, wenn die Raycast-Operation einen anderen Spieler trifft.

Teste mit mehreren Spielern

Es sind zwei Spieler erforderlich, um zu testen, ob der Waffensystems Raycast andere Spieler findet, also musst du einen lokalen Server starten. Siehe multi‑client simulation für Anleitungen.

Teste auf einem Client, den anderen Spieler mit der Waffe zu beschießen, indem du auf ihn klickst. "Spieler getroffen" sollte jedes Mal in der Ausgabe angezeigt werden, wenn ein Spieler getroffen wird.

Finde die Laserposition

Der Blaster sollte einen roten Lichtstrahl auf sein Ziel abfeuern. Die Funktion dafür wird in einem ModuleScript sein, damit sie später in anderen Skripten wiederverwendet werden kann. Zuerst muss das Skript die Position finden, an der der Laserstrahl gerendert werden soll.

  1. Erstelle ein ModuleScript mit dem Namen LaserRenderer, das in StarterPlayerScripts unter StarterPlayer eingefügt wird.

  2. Öffne das Skript und benenne die Modultabelle in den Namen des Skripts LaserRenderer um.

  3. Deklariere eine Variable namens SHOT_DURATION mit einem Wert von 0.15. Dies wird die Zeit (in Sekunden) sein, für die der Laser sichtbar ist.

  4. Erstelle eine Funktion von LaserRenderer namens createLaser mit zwei Parametern namens toolHandle und endPosition.


    local LaserRenderer = {}
    local SHOT_DURATION = 0.15 -- Zeit, die der Laser sichtbar ist
    -- Erzeuge einen Laserstrahl von einer Startposition zu einer Endposition
    function LaserRenderer.createLaser(toolHandle, endPosition)
    end
    return LaserRenderer
  5. Deklariere eine Variable namens startPosition und setze die Position-Eigenschaft von toolHandle als ihren Wert. Dies wird die Position des Laserblasters des Spielers sein.

  6. Deklariere eine Variable namens laserDistance und subtrahiere endPosition von startPosition, um den Unterschied zwischen den beiden Vektoren zu finden. Verwende die Magnitude-Eigenschaft davon, um die Länge des Laserstrahls zu erhalten.


    function LaserRenderer.createLaser(toolHandle, endPosition)
    local startPosition = toolHandle.Position
    local laserDistance = (startPosition - endPosition).Magnitude
    end
  7. Deklariere eine laserCFrame-Variable, um die Position und Orientierung des Laserstrahls zu speichern. Die Position muss der Mittelpunkt des Starts und des Endes des Strahls sein. Verwende CFrame.lookAt, um einen neuen CFrame zu erzeugen, der sich an startPosition befindet und in Richtung endPosition zeigt. Multipliziere dies mit einem neuen CFrame mit einem Z-Achs-Wert, der der Hälfte des negativen laserDistance entspricht, um den Mittelpunkt zu erhalten.


    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

Erstelle das Laserteil

Jetzt, da du weißt, wo du einen Laserstrahl erzeugen sollst, musst du den Strahl selbst hinzufügen. Dies kann einfach mit einem Neon-Teil gemacht werden.

  1. Deklariere eine Variable laserPart und weise ihr eine neue Part-Instanz zu.

  2. Setze die folgenden Eigenschaften von laserPart:

    1. Size: Vector3.new(0.2, 0.2, laserDistance)
    2. CFrame: laserCFrame
    3. Anchored: true
    4. CanCollide: false
    5. Color: Color3.fromRGB(225, 0, 0) (eine kräftige rote Farbe)
    6. Material: Enum.Material.Neon
  3. Füge laserPart zu Workspace hinzu.

  4. Füge das Teil dem Debris-Dienst hinzu, sodass es nach der Anzahl von Sekunden in der SHOT_DURATION-Variablen entfernt wird.


    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
    -- Füge den Laserstrahl dem Debris-Dienst hinzu, um entfernt und bereinigt zu werden
    Debris:AddItem(laserPart, SHOT_DURATION)
    end

Jetzt ist die Funktion zum Rendern des Laserstrahls abgeschlossen, sie kann vom ToolController aufgerufen werden.

  1. Deklariere am Anfang des ToolController-Skripts eine Variable namens LaserRenderer und erfordere das LaserRenderer ModuleScript, das in PlayerScripts zu finden ist.


    local UserInputService = game:GetService("UserInputService")
    local Players = game:GetService("Players")
    local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)
    local tool = script.Parent
  2. Am Ende der fireWeapon-Funktion rufe die Funktion LaserRenderer createLaser auf, indem du den Werkzeuggriff und hitPosition als Argumente verwendest.


    -- Berechne die Endposition basierend auf der maximalen Laserentfernung
    hitPosition = tool.Handle.Position + directionVector
    end
    LaserRenderer.createLaser(tool.Handle, hitPosition)
    end
  3. Teste die Waffe, indem du die Play-Taste drückst. Ein Laserstrahl sollte sichtbar sein zwischen der Waffe und der Maus, wenn das Werkzeug aktiviert wird.

Steuerung der Feuerate der Waffe

Waffen benötigen eine Verzögerung zwischen den einzelnen Schüssen, um zu verhindern, dass Spieler in kurzer Zeit zu viel Schaden verursachen. Dies kann kontrolliert werden, indem überprüft wird, ob genügend Zeit seit dem letzten Schuss vergangen ist.

  1. Deklariere eine Variable am Anfang des ToolController mit dem Namen FIRE_RATE. Dies wird die minimale Zeit zwischen jedem Schuss sein. Gib ihr einen Wert deiner Wahl; dieses Beispiel verwendet 0.3 Sekunden.

  2. Deklariere darunter eine weitere Variable mit dem Namen timeOfPreviousShot mit einem Wert von 0. Diese speichert die letzte Zeit, zu der der Spieler abgefeuert hat, und wird mit jedem Schuss aktualisiert.


    local MAX_MOUSE_DISTANCE = 1000
    local MAX_LASER_DISTANCE = 300
    local FIRE_RATE = 0.3
    local timeOfPreviousShot = 0
  3. Erstelle eine Funktion namens canShootWeapon ohne Parameter. Diese Funktion wird überprüfen, wie viel Zeit seit dem vorherigen Schuss vergangen ist und true oder false zurückgeben.


    local FIRE_RATE = 0.3
    local timeOfPreviousShot = 0
    -- Überprüfen, ob genügend Zeit seit dem letzten Schuss vergangen ist
    local function canShootWeapon()
    end
    local function getWorldMousePosition()
  4. Innerhalb der Funktion deklariere eine Variable namens currentTime; weise ihr das Ergebnis des Aufrufs der tick()-Funktion zu. Dies gibt zurück, wie viel Zeit in Sekunden seit dem 1. Januar 1970 (einem willkürlichen Datum, das häufig zur Berechnung der Zeit verwendet wird) vergangen ist.

  5. Subtrahiere timeOfPreviousShot von currentTime und gib false zurück, wenn das Ergebnis kleiner als FIRE_RATE ist; andernfalls gib true zurück.


    -- Überprüfen, ob genügend Zeit seit dem letzten Schuss vergangen ist
    local function canShootWeapon()
    local currentTime = tick()
    if currentTime - timeOfPreviousShot < FIRE_RATE then
    return false
    end
    return true
    end
  6. Am Ende der Funktion fireWeapon aktualisiere timeOfPreviousShot jedes Mal, wenn die Waffe abgefeuert wird, unter Verwendung von tick.


    hitPosition = tool.Handle.Position + directionVector
    end
    timeOfPreviousShot = tick()
    LaserRenderer.createLaser(tool.Handle, hitPosition)
    end
  7. Innerhalb der toolActivated-Funktion erstelle eine if-Anweisung und rufe canShootWeapon auf, um zu überprüfen, ob die Waffe abgefeuert werden kann.


    local function toolActivated()
    if canShootWeapon() then
    fireWeapon()
    end
    end

Wenn du den Blaster testest, solltest du feststellen, dass es unabhängig von der Klickgeschwindigkeit immer eine kurze Verzögerung von 0,3 Sekunden zwischen jedem Schuss gibt.

Spieler beschädigen

Clients können andere Clients nicht direkt schädigen; der Server muss verantwortlich sein für das Ausgeben von Schaden, wenn ein Spieler getroffen wird.

Clients können ein RemoteEvent verwenden, um dem Server mitzuteilen, dass ein Charakter getroffen wurde. Diese sollten in ReplicatedStorage gespeichert werden, wo sie sowohl für den Client als auch für den Server sichtbar sind.

  1. Erstelle einen Ordner in ReplicatedStorage mit dem Namen Events.

  2. Füge ein RemoteEvent in den Events-Ordner ein und nenne es DamageCharacter.

  3. Erstelle im ToolController Variablen zu Beginn des Skripts für ReplicatedStorage und den Events-Ordner.


    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. Ersetze die "Spieler getroffen"-Ausgabemeldung in fireWeapon durch eine Zeile von Luau, um das DamageCharacter-Remote-Event mit der Variable characterModel als Argument auszulösen.


    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
    -- Berechne die Endposition basierend auf der maximalen Laserentfernung
    hitPosition = tool.Handle.Position + directionVector
    end

Der Server muss Schaden am Spieler austeilen, der getroffen wurde, wenn das Ereignis ausgelöst wird.

  1. Füge ein Skript in ServerScriptService ein und nenne es ServerLaserManager.

  2. Deklariere eine Variable namens LASER_DAMAGE und setze sie auf 10 oder einen Wert deiner Wahl.

  3. Erstelle eine Funktion namens damageCharacter mit zwei Parametern, die playerFired und characterToDamage heißen.

  4. Innerhalb der Funktion finde den Humanoid des Charakters und ziehe LASER_DAMAGE von seiner Gesundheit ab.

  5. Verbinde die Funktion damageCharacter mit dem DamageCharacter-Remote-Event im Events-Ordner.


    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
    -- Gesundheit des Charakters reduzieren
    humanoid.Health -= LASER_DAMAGE
    end
    end
    -- Verbinde Ereignisse mit den entsprechenden Funktionen
    eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
  6. Teste den Blaster mit 2 Spielern, indem du einen lokalen Server startest. Wenn du den anderen Spieler abschießt, verringert sich seine Gesundheit um den Wert, der LASER_DAMAGE zugewiesen ist.

Rendern der Laserstrahlen anderer Spieler

Derzeit wird der Laserstrahl nur vom Client erstellt, der die Waffe abfeuert, sodass nur dieser ihn sehen kann.

Wenn der Laserstrahl auf dem Server erstellt würde, könnten ihn alle sehen. Es gäbe jedoch eine kleine Verzögerung zwischen dem Abfeuern der Waffe durch den Client und dem Server, der die Informationen über den Schuss erhält. Dies würde bedeuten, dass der Client, der die Waffe abfeuert, eine Verzögerung zwischen der Aktivierung der Waffe und der Sichtbarkeit des Laserstrahls sehen würde; die Waffe würde sich dadurch langsam anfühlen.

Um dieses Problem zu lösen, wird jeder Client seine eigenen Laserstrahlen erstellen. Das bedeutet, dass der Client, der die Waffe abfeuert, den Laserstrahl sofort sieht. Andere Clients werden eine kleine Verzögerung zwischen dem Schuss eines anderen Spielers und dem Erscheinen eines Strahls erleben. Dies ist das beste Szenario: Es gibt keine Möglichkeit, einen 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 bereitstellen.

  1. Füge ein RemoteEvent in den Events-Ordner in ReplicatedStorage ein und nenne es LaserFired.

  2. Suche die fireWeapon-Funktion im ToolController-Skript. Am Ende der Funktion löse das LaserFired-Remote-Event unter Verwendung von hitPosition als Argument aus.


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

Der Server

Der Server muss jetzt das Ereignis empfangen, dass der Client einen Laser abgefeuert hat, und allen Clients die Start- und Endposition des Laserstrahls mitteilen, damit sie ihn ebenfalls rendern können.

  1. Erstelle in dem ServerLaserManager-Skript eine Funktion mit dem Namen playerFiredLaser über der Funktion damageCharacter mit zwei Parametern, die playerFired und endPosition heißen.

  2. Verbinde die Funktion mit dem LaserFired-Remote-Event.


    -- Benachrichtige alle Clients, dass ein Laser abgefeuert wurde, damit sie den Laser anzeigen können
    local function playerFiredLaser(playerFired, endPosition)
    end

    -- Verbinde Ereignisse mit den entsprechenden Funktionen
    eventsFolder.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 besser, dem Client so wenig Vertrauen wie möglich entgegenzubringen. Die Position des Werkzeuggriffs des Charakters wird die Startposition sein, sodass der Server sie von dort aus finden kann.

  1. Erstelle eine Funktion getPlayerToolHandle über der Funktion playerFiredLaser mit einem Parameter, der den Namen player hat.

  2. Verwende den folgenden Code, um den Charakter des Spielers nach dem Werkzeug zu durchsuchen und das Griffobjekt zurückzugeben.


    local LASER_DAMAGE = 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
    -- Benachrichtige alle Clients, dass ein Laser abgefeuert wurde, damit sie den Laser anzeigen können
    local function playerFiredLaser(playerFired, endPosition)

Der Server kann nun das FireAllClients auf dem LaserFired-Remote-Event aufrufen, um die Informationen bereitzustellen, die erforderlich sind, um den Laser an die Clients zu rendern. Dazu gehört der Spieler, der den Laser abgefeuert hat (damit 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.

  1. Rufe in der Funktion playerFiredLaser die getPlayerToolHandle-Funktion mit playerFired als Argument auf und weise den Wert einer Variablen namens toolHandle zu.

  2. Wenn toolHandle existiert, löse das LaserFired-Event für alle Clients aus, indem du playerFired, toolHandle und endPosition als Argumente verwendest.


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

Rendering auf den Clients

Jetzt, da FireAllClients aufgerufen wurde, wird jeder Client ein Ereignis vom Server erhalten, um einen Laserstrahl zu rendern. Jeder Client kann das im vorherigen Schritt verwendete LaserRenderer-Modul wiederverwenden, um den Laserstrahl unter Verwendung der Griffposition des Werkzeugs und des Endpositionswerts, der vom Server gesendet wurde, zu rendern. Der Spieler, der den Laserstrahl ursprünglich abgefeuert hat, sollte dieses Ereignis ignorieren, andernfalls sieht er zwei Laser.

  1. Erstelle ein LocalScript in StarterPlayerScripts mit dem Namen ClientLaserManager.

  2. Innerhalb des Skripts fordere das LaserRenderer-Modul an.

  3. Erstelle eine Funktion mit dem Namen createPlayerLaser mit den Parametern playerWhoShot, toolHandle und endPosition.

  4. Verbinde die Funktion mit dem LaserFired-Remote-Event im Events-Ordner.

  5. In der Funktion verwende eine if-Anweisung, um zu überprüfen, ob playerWhoShot ungleich dem LocalPlayer ist.

  6. Innerhalb der if-Anweisung rufe die Funktion createLaser aus dem LaserRenderer-Modul mit toolHandle und endPosition als Argumente auf.


    local Players = game:GetService("Players")
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local LaserRenderer = require(script.Parent:WaitForChild("LaserRenderer"))
    local eventsFolder = ReplicatedStorage.Events
    -- Zeige den Laser eines anderen Spielers an
    local function createPlayerLaser(playerWhoShot, toolHandle, endPosition)
    if playerWhoShot ~= Players.LocalPlayer then
    LaserRenderer.createLaser(toolHandle, endPosition)
    end
    end
    eventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)
  7. Teste den Blaster mit 2 Spielern, indem du einen lokalen Server startest. Positioniere jeden Client an verschiedenen Seiten deines Monitors, damit du beide Fenster gleichzeitig sehen kannst. Wenn du dort auf einem Client schießt, solltest du den Laser auf dem anderen Client sehen.

Soundeffekte

Der Schuss-Soundeffekt wird derzeit nur auf dem Client abgespielt, der das Projektil abfeuert. Du musst den Code zum Abspielen des Sounds so verschieben, dass auch andere Spieler ihn hören können.

  1. Navigiere im ToolController-Skript zur toolActivated-Funktion und entferne die Zeile, die den Aktivierungs-Sound abspielt.


    local function toolActivated()
    if canShootWeapon() then
    fireWeapon()
    end
    end
  2. Am Ende der createLaser-Funktion in LaserRenderer deklarierst du eine Variable namens shootingSound und verwendest die Methode FindFirstChild() von toolHandle, um nach dem Aktivierungs-Sound zu suchen.

  3. Verwende eine if-Anweisung, um zu überprüfen, ob shootingSound existiert; wenn ja, rufe die Funktion Play() auf.


    laserPart.Parent = workspace
    -- Füge den Laserstrahl dem Debris-Dienst hinzu, um entfernt und bereinigt zu werden
    Debris:AddItem(laserPart, SHOT_DURATION)
    -- Spiele den Schuss-Sound der Waffe ab
    local shootingSound = toolHandle:FindFirstChild("Activate")
    if shootingSound then
    shootingSound:Play()
    end
    end

Sichere Remotes mit Validierung

Wenn der Server keine Daten von eingehenden Anfragen überprüft, kann ein Hacker Remote-Funktionen und -Ereignisse missbrauchen und damit gefälschte Werte an den Server senden. Es ist wichtig, serverseitige Validierung zu verwenden, um dies zu verhindern.

In ihrer aktuellen Form ist das DamageCharacter-Remote-Event sehr anfällig für Angriffe. Hacker könnten dieses Ereignis nutzen, um jeden Spieler zu verletzen, den sie wollen, ohne ihn zu beschießen.

Validierung ist der Prozess, der überprüft, ob die an den Server gesendeten Werte realistisch sind. In diesem Fall muss der Server:

  • Überprüfen, ob die Distanz zwischen dem Spieler und der vom Laser getroffenen Position innerhalb einer bestimmten Grenze liegt.
  • Raycast zwischen der Waffe, die den Laser abgefeuert hat, und der getroffenen Position, um sicherzustellen, dass der Schuss möglich war und nicht durch Wände gegangen ist.

Client

Der Client muss dem Server die Position senden, die durch den Raycast getroffen wurde, sodass er überprüfen kann, ob die Entfernung realistisch ist.

  1. Navigiere im ToolController zur Zeile, in der das DamageCharacter-Remote-Event in der fireWeapon-Funktion ausgelöst wird.

  2. Füge hitPosition als Argument hinzu.


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

Server

Der Client sendet jetzt einen zusätzlichen Parameter über das DamageCharacter-Remote-Event, sodass der ServerLaserManager angepasst werden muss, um ihn zu akzeptieren.

  1. Füge im ServerLaserManager-Skript der damageCharacter-Funktion einen hitPosition-Parameter hinzu.


    function damageCharacter(playerFired, characterToDamage, hitPosition)
    local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    -- Gesundheit des Charakters reduzieren
    humanoid.Health -= LASER_DAMAGE
    end
    end
  2. Unter der getPlayerToolHandle-Funktion erstelle eine Funktion mit dem Namen isHitValid mit drei Parametern: playerFired, characterToDamage und hitPosition.


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

Die erste Überprüfung wird die Distanz zwischen der getroffenen Position und dem Charakter sein.

  1. Deklariere eine Variable namens MAX_HIT_PROXIMITY am Anfang des Skripts und weise ihr einen Wert von 10 zu. Dies wird die maximale Distanz sein, die zwischen dem Treffer und dem Charakter erlaubt ist. Eine Toleranz ist notwendig, da der Charakter sich möglicherweise leicht bewegt hat, seit der Client das Ereignis abgefeuert hat.


    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local eventsFolder = ReplicatedStorage.Events
    local LASER_DAMAGE = 10
    local MAX_HIT_PROXIMITY = 10
  2. In der Funktion isHitValid berechne die Distanz zwischen dem Charakter und der getroffenen Position. Wenn die Distanz größer als MAX_HIT_PROXIMITY ist, gib false zurück.


    local function isHitValid(playerFired, characterToDamage, hitPosition)
    -- Überprüfe die Distanz zwischen dem getroffenen Charakter und der getroffenen Position
    local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
    if characterHitProximity > MAX_HIT_PROXIMITY then
    return false
    end
    end

Die zweite Überprüfung beinhaltet einen Raycast zwischen der abgefeuerten Waffe und der getroffenen Position. Wenn der Raycast ein Objekt zurückgibt, das nicht der Charakter ist, kannst du annehmen, dass der Schuss nicht gültig war, da etwas den Schuss blockierte.

  1. Kopiere den folgenden Code, um diese Überprüfung durchzuführen. Gib am Ende der Funktion true zurück: Wenn sie das Ende erreicht, haben alle Überprüfungen bestanden.


    local function isHitValid(playerFired, characterToDamage, hitPosition)
    -- Überprüfe die Distanz zwischen dem getroffenen Charakter und der getroffenen Position
    local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
    if characterHitProximity > 10 then
    return false
    end
    -- Überprüfen, ob durch Wände geschossen wurde
    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 den Charakter ist, ignoriere den Schuss
    if rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) then
    return false
    end
    end
    return true
    end
  2. Deklariere eine Variable in der damageCharacter-Funktion namens validShot. Weisen ihr das Ergebnis eines Aufrufs der isHitValid-Funktion mit drei Argumenten: playerFired, characterToDamage und hitPosition zu.

  3. Füge in die folgende if-Anweisung einen and-Operator hinzu, um zu überprüfen, ob validShot true ist.


    function damageCharacter(playerFired, characterToDamage, hitPosition)
    local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
    local validShot = isHitValid(playerFired, characterToDamage, hitPosition)
    if humanoid and validShot then
    -- Gesundheit des Charakters reduzieren
    humanoid.Health -= LASER_DAMAGE
    end
    end

Jetzt ist das DamageCharacter-Remote-Event sicherer und wird die meisten Spieler daran hindern, es zu missbrauchen. Beachte, dass einige böswillige Spieler oft Wege finden, um durch die Validierung zu gelangen; die Sicherstellung der Remote-Events ist eine kontinuierliche Aufgabe.

Dein Laserblaster ist jetzt fertig, mit einem grundlegenden Treffererkennungssystem, das Raycasting verwendet. Probiere das Benutzereingabe erkennen Tutorial aus, um herauszufinden, wie du eine Nachladeaktion hinzufügen kannst zu deinem Laserblaster oder erstelle eine unterhaltsame Karte und teste deinen Laserblaster mit anderen Spielern!

Endgültiger Code

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
-- Überprüfen, ob genügend Zeit seit dem vorherigen Schuss vergangen ist
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()
-- Erzeuge einen Strahl von der 2D-Mausposition
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- Der Einheitsrichtungsvektor des Strahls multipliziert mit einer maximalen Entfernung
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- Raycast von der Ursprung des Strahls in Richtung seiner Richtung
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- Gib den 3D-Schnittpunkt zurück
return raycastResult.Position
else
-- Kein Objekt wurde getroffen, also berechne die Position am Ende des Straßens
return screenToWorldRay.Origin + directionVector
end
end
local function fireWeapon()
local mouseLocation = getWorldMousePosition()
-- Berechne einen normalisierten Richtungsvektor und multipliziere mit der Laserentfernung
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- Die Richtung, um die Waffe zu feuern, multipliziert mit einer maximalen Entfernung
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- Ignoriere den Charakter des Spielers, um zu verhindern, dass er sich selbst verletzt
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
-- Überprüfen, ob zwischen der Start- und Endposition Objekte getroffen wurden
local hitPosition
if weaponRaycastResult then
hitPosition = weaponRaycastResult.Position
-- Die getroffene Instanz wird ein Kind eines Charaktermodells sein
-- Wenn ein Humanoid im Modell gefunden wird, ist es wahrscheinlich der Charakter eines Spielers
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
-- Berechne die Endposition basierend auf der maximalen Laserentfernung
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, die der Laser sichtbar ist
-- Erzeuge einen Laserstrahl von einer Startposition zu 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 den Laserstrahl dem Debris-Dienst hinzu, um entfernt und bereinigt zu werden
Debris:AddItem(laserPart, SHOT_DURATION)
-- Spiele den Schuss-Sound 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)
-- Überprüfe die Distanz zwischen dem getroffenen Charakter und der getroffenen Position
local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
if characterHitProximity > MAX_HIT_PROXIMITY then
return false
end
-- Überprüfen, ob durch Wände geschossen wurde
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 ist, 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
-- Gesundheit des Charakters reduzieren
humanoid.Health -= LASER_DAMAGE
end
end
-- Verbinde Ereignisse mit den entsprechenden 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
-- Zeige den Laser eines anderen Spielers an
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, das Roblox-Logo und "Powering Imagination" gehören zu unseren eingetragenen und nicht eingetragenen Markenzeichen in den USA und anderen Ländern.