Treffer erkennen

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

Schläge zu erkennen ist der Prozess, bei dem Blasten mit Spielern kollidieren, und dann ihre Gesundheit entsprechend reduzieren. Auf einer hohen Ebene können Sie diesen Work als Folgendes betrachten:

  1. Ein physisch simulierter Check, ob ein Projektil das Ziel traf.
  2. Eine sofortige Prüfung, ob der Blaster auf das Ziel zielte.

Die Art der Treffererkennung, die Sie verwenden, hängt von den Spielanforderungen Ihres Erlebnisses ab. Zum Beispiel ist ein physisch simulierter Check für ein Dodgeball-Erlebnis geeignet, bei dem Bälle eine bestimmte Geschwindigkeit verlassen müssen, fallen, wenn sie durch die Luft fliegen, oder sich von Umgebungsfaktoren wie Gravitation und Windgeschwindigkeit ändern. Allerdings ist ein sofortiges Check ein besseres Match für ein Lasertag

Dieser Abschnitt des Tutorials leitet Sie in die Skripte ein, die hinter der Treffererkennung im Platzliegen, einschließlich Anleitung:

  • Erhalte die Richtung der Explosion aus den aktuellen Kamerawerten und dem eingebendes Spieler:in.
  • Wirft Strahlen in einem geraden Weg vom Blaster, während er schießt.
  • Validiere die Explosion, um die Exploitation von Blaster-Daten zu verhindern.
  • Reduzieren Sie die Gesundheit des Spielers gemäß dem Explosionsschaden von jedem Typ von Blaster und wie vielen Strahlen den Spieler:intreffen.

Nachdem Sie diesen Abschnitt abgeschlossen haben, können Sie weitere Entwicklungsforen erkunden, um Ihr Gameplay zu verbessern, z. B. Audiodateien, Beleuchtung und Spezialeffekte.

Blast Richtung erhalten

Nachdem ein Spieler seinen Blaster gesprengt hat, ReplicatedStorage > Blaster > attemptBlastClient > 1> blastClient 1> > 4> generateBlastData4> nennt zwei Funktionen, um den Treffer-Entdeckungsprozess zu starten: 7> rayDirections()7> und 0> rayResults()

erzeugenBlastData

local rayDirections = getDirectionsForBlast(currentCamera.CFrame, blasterConfig)
local rayResults = castLaserRay(localPlayer, currentCamera.CFrame.Position, rayDirections)

Die Eingaben für rayDirections sind einfach: die aktuelle Kameraposition und Rotationswerte und der eingebendes Spieler:in. Wenn die Beispiel-Laser-Tag-Erfahrung nur Spieler mit Blastern, die einen einzigen Laserstrahl erzeugen, versorgt, würde ReplicatedStorage > Laser

Da der Probe jedoch ein zusätzlichen Blaster-Typ bereitstellt, der mehrere Laserstrahlen mit einer breit horizontalen Streuung erzeugt, muss getDirectionsForBlast die Richtung für jeden Laserstrahl der Streuung nach ihren Winkeln innerhalb der Blaster-Konfiguration berechnen:

erhalte Richtungen für Blast

if numLasers == 1 then
-- Für einzelne Laser zielen sie gerade
table.insert(directions, originCFrame.LookVector)
elseif numLasers > 1 then
-- Für mehrere Laser, verteilen Sie sie in horizontale Ausbreitung
-- über ein Intervall laserSpreadDegrees um die Mitte
local leftAngleBound = laserSpreadDegrees / 2
local rightAngleBound = -leftAngleBound
local degreeInterval = laserSpreadDegrees / (numLasers - 1)
for angle = rightAngleBound, leftAngleBound, degreeInterval do
local direction = (originCFrame * CFrame.Angles(0, math.rad(angle), 0)).LookVector
table.insert(directions, direction)
end
end

Um dieses Konzept weiter zu demonstrieren, wenn Sie einen dritten eingebenmit einer breit angelegten, vertikalen Streuung enthalten, könnten Sie ein neues Blaster-Attribut erstellen, z. B. spreadDirection , dann die Berechnung des CFrame anpassen, um eine andere Achse zu verwenden. Zum Beispiel beachten


if numLasers == 1 then
table.insert(directions, originCFrame.LookVector)
elseif numLasers > 1 then
local leftAngleBound = laserSpreadDegrees / 2
local rightAngleBound = -leftAngleBound
local degreeInterval = laserSpreadDegrees / (numLasers - 1)
for angle = rightAngleBound, leftAngleBound, degreeInterval do
local direction
if spreadDirection == "vertical" then
direction = (originCFrame * CFrame.Angles(math.rad(angle), 0, 0)).LookVector
else
direction = (originCFrame * CFrame.Angles(0, math.rad(angle), 0)).LookVector
end
table.insert(directions, direction)
end
end
return directions

Letztlich gibt die Funktion rayDirections() eine Tabelle von Vectors zurück, die die Richtung jedes Laserstrahls repräsentiert. Wenn es hilfreich ist, können Sie einige Logs hinzufügen, um ein Gefühl zu bekommen, wie diese Daten aussehen.

erzeugenBlastData

local rayDirections = getDirectionsForBlast(currentCamera.CFrame, blasterConfig)
for _, direction in rayDirections do -- neue zeile
print(direction) -- neue zeile
end -- neue zeile
local rayResults = castLaserRay(localPlayer, currentCamera.CFrame.Position, rayDirections)

Cast Rays

castLaserRay() , die zweite Funktion in ReplicatedStorage > Blaster > 0> attemptBlastClient</

Diese Information ist besonders nützlich für First-Person-Shooter-Erlebnisse, da sie es ermöglicht, zu sehen, wann und wo Blast mit Spielern oder der Umgebung intersect. Zum Beispiel zeigt das folgende Bild zwei Strahlen, die parallel zueinander casten. Laut ihrem Herkunftspunkt und Richtung fehlt Ray A die Wand und fährt fort, bis sie ihre maximale Distanz erreicht, während Ray B mit der Wand kollidiert

A diagram where Ray A continues through the wall, and Ray B collides with the wall.

Die castLaserRay() -Parameter bestimmen, dass Raycast() -Anrufe jeden Teil in der Arbeitsbereich except den Charakter, der gesprengt hat, berücksichtigen müssen. Das Skript castet dann einen Strahl für jede Richtung in der 2>directions2> -Tabelle. Wenn ein Strahl etwas trifft, erzeugt es ein 5>Datatype

Der Instance-Wert ist der wichtigste dieser Eigenschaften für das Spiel des Laser-Tags auf der Probe-Laser-Tag-Erlebnistafel, da er kommuniziert, wenn Strahlen mit anderen Spieler:inkoll

castLaserRay() dann verwendet Position und Normal, um einen neuen 0> Datatype.CFrame

castLaserRay

if result then
-- Die Explosion hat etwas getroffen, überprüfen Sie, ob es ein Spieler:inwar.
destination = CFrame.lookAt(result.Position, result.Position + result.Normal)
taggedPlayer = getPlayerFromDescendant(result.Instance)
else
-- Die Explosion hat nichts getroffen, also ist sein Ziel
-- den punkt in seiner maximalen reichweite.
local distantPosition = origin + rayDirection * MAX_DISTANCE
destination = CFrame.lookAt(distantPosition, distantPosition - rayDirection)
taggedPlayer = nil
end

Überprüfen Sie die Explosion

Um Cheating zu verhindern, erklärt der vorherige Kapitel Blaster- Skript, das. PL: die Skripts, wie blastClient den Server des Blastes mit einem Class.RemoteEvent benachrichtigt, damit

  1. Zuerst, getValidatedRayResults nennt validateRayResult, um zu überprüfen, dass jedes Eintrag in der rayResults Tabelle des Clients ein 1> Datatype.CFrame1> und ein 4> Player4> (oder null) ist.

  2. Nächste, es ruft isRayAngleFromOriginValid auf, um die erwarteten Winkel des Laser-Spreads mit denjenigen des Clients zu vergleichen. Dieser Code in particular zeigt den Vorteil der Verwendung von ReplicatedStorage, weil der Server aufrufen kann, getDirectionsForBlast selbst, speichern die Rückgabe als erwartete Daten und dann vergleichen Sie sie gegen die Daten des Clients

    So wie die Blaster-Validierung aus dem vorherigen Kapitel, isRayAngleFromOriginValid basiert auf einem Toleranzwert, um festzustellen, was ein "übertriebener" Unterschied in Angewinkeln darstellt:

    istRayAngleFromOriginGültig

    local claimedDirection = (rayResult.destination.Position - originCFrame.Position).Unit
    local directionErrorDegrees = getAngleBetweenDirections(claimedDirection, expectedDirection)
    return directionErrorDegrees <= ToleranceValues.BLAST_ANGLE_SANITY_CHECK_TOLERANCE_DEGREES

    Roblox-Abstraktionen entfernen die meisten beteiligten Mathe-Bit, sodass das Ergebnis eine kurze, wiederverwendbare Hilfsfunktion mit Anwendbarkeit auf eine Reihe von Erlebnissen ist:

    erhaltenAngleBetweenDirections

    local function getAngleBetweenDirections(directionA: Vector3, directionB: Vector3)
    local dotProduct = directionA:Dot(directionB)
    local cosAngle = math.clamp(dotProduct, -1, 1)
    local angle = math.acos(cosAngle)
    return math.deg(angle)
    end
  3. Der nächste Check ist der intuitivste. Während getValidatedBlastData``DISTANCE_SANITY_CHECK_TOLERANCE_STUDS verwendet, um zu überprüfen, dass der Spieler, der gesprengt wurde, in der Nähe des Strahlen-Punkts verwendet, isPlayerNearPosition verwendet identische Logik, um zu überprüfen, ob der mark

    istPlayerNearPosition

    local distanceFromCharacterToPosition = position - character:GetPivot().Position
    if distanceFromCharacterToPosition.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS then
    return false
    end
  4. Die finale Prüfung isRayPathObstructed verwendet eine Variation der Ray-Cast-Operation, um zu überprüfen, ob die Zielperson des Rays hinter einer Wand oder einer anderen Störung von der Position des Clients steht. Zum Beispiel, wenn ein böser Spieler alle Wände aus der Erfahrung entfernt, um andere Spieler zu markieren, würde der Server überprüfen und bestätigen, dass die Rays ungültig sind, da er jede Objektposition innerhalb der Umgebung

    istRayPathObstruiert

    local scaledDirection = (rayResult.destination.Position - blastData.originCFrame.Position)
    scaledDirection *= (scaledDirection.Magnitude - 1) / scaledDirection.Magnitude

Keine Anti-Exploit-Strategie ist umfassend, aber es ist wichtig zu berücksichtigen, wie böswillige Spieler Ihr Erlebnis ansprechen können, damit Sie Checks einrichten können, die der Server ausführen kann, um verdächtiges Verhalten zu erkennen.

Reduzieren Sie die Gesundheit des Spielers

Nachdem ein Spieler einen anderen Spieler:ingetaggt hat, sind die letzten Schritte in der Erstellung des Hauptspiel循ops in der Beispiel-Laser-Tag-Erlebniss die Reduzierung der Gesundheit des getaggeden Spieler:in, das Erhöhen des Bestenlisten und das Respawnen des Spielers in die Runde.

Starting with reducing the tagged Spieler:in's health, Spawning and Respawning covers the distinction between Player and Player.Character, specifically that a

Die Erfahrung speichert Schadenswerte im damagePerHit-Attribut jedes Blasters. Zum Beisp

Health nimmt keine negativen Werte an, so dass onPlayerTagged etwas Logik hat, um die Spielergesundheit bei oder über der 0 zu halten. Nach dem Überprüfen, dass die Spielergesundheit über der 0 ist, vergleicht sie Gesundheit mit damagePerHit

Dieser Ansatz des Problems scheint etwas verwirrend zu sein. Zum Beispiel, warum nicht einfach die Gesundheit des Spielers auf Null setzen, wenn es negativ ist? Der Grund ist, weil das Setzen von Gesundheitswerten das Kraftfeld umgeht. Mit der Methode Humanoid:TakeDamage() garantiert die Verwendung der Methode Class.Humanoid:TakeDamage, dass Spieler keine Schaden erleiden, während ihre Kraftfelder aktiv sind.

aufPlayerTagged

local function onPlayerTagged(playerBlasted: Player, playerTagged: Player, damageAmount: number)
local character = playerTagged.Character
local isFriendly = playerBlasted.Team == playerTagged.Team
-- Unerlaubtes freundliches initiieren
if isFriendly then
return
end
local humanoid = character and character:FindFirstChild("Humanoid")
if humanoid and humanoid.Health > 0 then
-- Vermeiden Sie negative Gesundheit
local damage = math.min(damageAmount, humanoid.Health)
-- TakeDamage gewährleistet, dass die Gesundheit nicht gesenkt wird, wenn ForceField aktiv ist
humanoid:TakeDamage(damage)
if humanoid.Health <= 0 then
-- Erweist den Spieler mit einer Explosion einen Punkt für das Markieren von PlayerTagged
Scoring.incrementScore(playerBlasted, 1)
end
end
end

Der nächste Schritt ist es, die Bestenlistezu erhöhen. Es mag unnötig gewesen sein, dass LaserBlastHandler den Spieler einschließen, der neben den Blast-Daten gesprengt wurde, aber ohne diese Information kann die Erfahrung nicht den Spieler mit dem Taggen anzeigen. Schließlich respawns der getagged-aus Player in der Runde, die Sie in Spawnen und Respawnen überprüfen können.

Die fünf Kapitel in diesem Curriculum umfassen die Kern-Spielweise des Erlebnisses, aber es gibt immer noch viele Bereiche zu erkunden, wie z. B.:

  • Blaster- visuellen : Siehe ReplicatedStorage > FirstPersonBlasterVisuals und 0> ServerScriptService 0> > 3> ThirdPersonBlasterVisuals 3> .
  • Audio : Siehe ReplicatedStorage > SoundHandler .
  • Benutzerdefinierte Modi : Wie könnten Sie dieses Erlebnis modifizieren, um neue Arten von Zielen einzuführen, wie z. B. das Erzielen der meisten Punkte vor Ablauf der Zeit?

Für erweiterte Spiellogik für das Lasertag-Erlebnis sowie für wiederverwendbare, hochwertige Umwelt-Assets, überprüfen Sie die Lasertag-Vorlage.