Blasterverhalten implementieren ist der Prozess, eine Blast-Mechanik in Ego-Shooter-Spielen zu programmieren. Während Spieler mit einem einzigen Klick oder Druck auf eine Taste blasten können, ist es wichtig, ein zufriedenstellendes und genaues Blast-Verhalten zu schaffen, da es das Spielerlebnis insgesamt verbessert.
Anhand des Beispiel-Lasertag-Spiels wird in diesem Abschnitt des Tutorials erklärt, wie die Skripte zur Implementierung des Blasterverhaltens für zwei verschiedene Arten von Blastern funktionieren, einschließlich Anleitungen zu:
- Erkennen, wann Spieler die Blast-Taste drücken.
- Überprüfen, ob der Spieler seinen Blaster verwenden kann, wenn er kürzlich die Blast-Taste gedrückt hat.
- Generieren von Blast-Daten, die dem Server mitteilen, wer den Blast initiiert hat, wo er herkam und was das endgültige Ziel jedes Laserstrahls war.
- Benachrichtigen des Servers über die Blast-Daten, damit er die entsprechenden Aktionen ausführen kann, wenn der Blast mit einem anderen Spieler kollidiert.
- Zurücksetzen des Blasters zwischen jedem Blast, um dem Blaster genügend Zeit zum Abkühlen zu geben, bevor er erneut blasten kann.
Nachdem Sie diesen Abschnitt abgeschlossen haben, lernen Sie die Skripte kennen, die es dem Blaster ermöglichen, zu erkennen, wann seine Blasts mit anderen Spielern kollidieren, und dann die entsprechende Menge an Gesundheit gemäß jedem Blastertyp abzuziehen.
Spielerinput überprüfen
Der erste Schritt zur Implementierung des Blasterverhaltens besteht darin, darauf zu hören, wann ein Spieler die Blast-Taste drückt. Der Eingabetyp, den die Spieler verwenden, um die Blast-Taste zu drücken, hängt davon ab, welches Gerät sie verwenden, um auf das Spiel zuzugreifen. Zum Beispiel unterstützt das Beispiel-Lasertag-Spiel Maus- und Tastatursteuerung, Gamepads und Touch-Steuerung. Sie können jeden dieser Eingabetypen in ReplicatedStorage ⟩ UserInputHandler sehen.
Dieses Client-Skript verwendet ContextActionService, um MouseButton1 und ButtonR2 mit der Blast-Aktion zu verknüpfen. Das bedeutet, dass jedes Mal, wenn ein Spieler entweder die linke Maustaste oder die R2-Taste eines Gamepads drückt, ein Laserstrahl aus dem Blaster herausgeschossen wird. Beachten Sie, dass die HUDGui eine Schaltfläche zum Blasten auf mobilen Geräten enthält, die später im Skript damit verbunden wird.
ContextActionService:BindAction("_", onBlasterActivated, false,
Enum.UserInputType.MouseButton1,
Enum.KeyCode.ButtonR2
)Ein weiterer wichtiger Hinweis ist die Verwendung von Enum.UserInputState.Begin in der Definition von onBlasterActivated(). Viele Benutzeroberflächeninteraktionen, wie das Auswählen eines Blasters in diesem Beispiel, treten nicht auf, bis die Maustaste losgelassen wird (Enum.UserInputState.End), was den Benutzern eine letzte Chance gibt, die Interaktion zu vermeiden. Ein Blast-Mechanismus fühlt sich jedoch nicht reaktionsschnell an, es sei denn, er tritt sofort ein, wenn die Taste gedrückt wird.
Um dies zu demonstrieren, können Sie Enum.UserInputState.Begin in Enum.UserInputState.End ändern und dann das Spiel testen, um zu sehen, wie die Reaktionsfähigkeit des Blasts das Gameplay beeinflusst. Wenn Spieler beispielsweise die Taste gedrückt halten können, ohne den Blast auszulösen, wie könnte sich das auf ihr Erlebnis beim Taggen anderer Spieler auswirken?
local function onBlasterActivated(_actionName: string,
inputState: Enum.UserInputState, _inputObject: InputObject)
if inputState == Enum.UserInputState.End then -- aktualisierte Zeile, unbedingt zurückändern
attemptBlastClient()
end
endÜberprüfen, ob der Spieler blasten kann
Nachdem UserInputHandler einen Tastendruck oder Bildschirmtippen erkannt hat, ruft es ReplicatedStorage ⟩ Blaster ⟩ attemptBlastClient auf, um zu überprüfen, ob der Spieler blasten kann oder nicht. Wie die meisten Überprüfungen im Beispiel-Lasertag-Spiel erfolgt dies zweimal: zuerst auf dem Client und später auf dem Server. attemptBlastClient ruft dann ReplicatedStorage ⟩ Blaster ⟩ canLocalPlayerBlast auf, um eine einfache Überprüfung des Spielerattributs blasterStateClient durchzuführen:
local function canLocalPlayerBlast(): boolean
return localPlayer:GetAttribute(PlayerAttribute.blasterStateClient) == BlasterState.Ready
endWenn Sie ReplicatedStorage ⟩ Blaster ⟩ BlasterState untersuchen, können Sie sehen, dass das Spiel drei Blaster-Zustände hat: Ready, Blasting und Disabled. Um die Auswirkungen jedes dieser Zustände zu sehen, können Sie das Spiel testen, Ihren Spieler unter dem Players-Dienst auswählen und dann das Attribut blasterStateClient im Properties-Fenster beobachten. Beachten Sie, wie es Disabled anzeigt, während Sie Ihren Blaster auswählen, Ready die meiste Zeit und Blasting für weniger als eine Sekunde, nachdem Sie die Taste gedrückt haben.
Diese kurze Pause verhindert, dass Sie so schnell blasten können, wie Sie klicken können. Wenn Sie beispielsweise die Funktion ändern, um immer true zurückzugeben, können Sie Ihren Blaster ohne Verzögerung schnell blasten, was für das Lasertag-Gameplay unrealistisch ist.
local function canLocalPlayerBlast(): boolean
return true -- aktualisierte Zeile, unbedingt zurückändern
endBlast-Daten generieren
Nachdem überprüft wurde, dass der Blaster des Spielers im Zustand Ready ist, ruft attemptBlastClient ReplicatedStorage ⟩ attemptBlastClient ⟩ blastClient auf. Der erste Schritt, den blastClient unternimmt, besteht darin, das Spielerattribut blasterStateClient auf Blasting zu setzen, um den gleichen schnellen Feuervorfall von zuvor zu vermeiden.
Der nächste Schritt besteht darin, die Blast-Daten zu generieren. Wenn Sie ReplicatedStorage ⟩ Blaster ⟩ BlastData überprüfen, können Sie sehen, dass jeder Blast aus drei Informationsstücken besteht:
- Der Spieler, der den Blast initiiert.
- Ein DataType.CFrame, das den Ursprungspunkt des Blasts darstellt.
- Eine RayResult-Tabelle, die das endgültige Ziel jedes Laserstrahls und den getroffenen Spieler enthält, falls ein anderer Spieler getroffen wurde.
Um diese Daten zu generieren, ruft blastClient ReplicatedStorage ⟩ attemptBlastClient ⟩ blastClient ⟩ generateBlastData auf, das Sie unten überprüfen können.
local function generateBlastData(): BlastData.Type
local blasterConfig = getBlasterConfig()
local rayDirections = getDirectionsForBlast(
currentCamera.CFrame, blasterConfig)
local rayResults = castLaserRay(
localPlayer, currentCamera.CFrame.Position, rayDirections)
local blastData: BlastData.Type = {
player = localPlayer,
originCFrame = currentCamera.CFrame,
rayResults = rayResults,
}
return blastData
endDiese Funktion beginnt damit, getBlasterConfig zu verwenden, um den Blastertyp des Spielers abzurufen. Das Beispiel bietet zwei Arten von Blastern: einen, der mehrere Strahlen mit einer breiten, horizontalen Streuung erzeugt, und einen anderen, der einen einzelnen Strahl erzeugt. Sie können deren Konfigurationen in ReplicatedStorage ⟩ Instances ⟩ LaserBlastersFolder finden.
Die Funktion verwendet dann currentCamera.CFrame als Ursprungspunkt für den Blast und übergibt ihn an getDirectionsForBlast. An diesem Punkt geht es im Code nicht mehr um den Blaster, sondern um den Laserstrahl, über den Sie im Abschnitt Treffer erkennen des Tutorials mehr erfahren werden. Schließlich hat generateBlastData nach dem Erstellen der rayResults-Tabelle alle Informationen, die es benötigt, um die Blast-Daten an blastClient zurückzugeben.
Den Server benachrichtigen
Sobald blastClient vollständige Daten für den Blast hat, feuert es zwei Ereignisse ab:
local laserBlastedBindableEvent = ReplicatedStorage.Instances.LaserBlastedBindableEvent
local laserBlastedEvent = ReplicatedStorage.Instances.LaserBlastedEvent
laserBlastedBindableEvent:Fire(blastData)
laserBlastedEvent:FireServer(blastData)Das BindableEvent benachrichtigt andere Client-Skripte über den Blast. Zum Beispiel verwendet ReplicatedStorage ⟩ FirstPersonBlasterVisuals dieses Ereignis, um zu wissen, wann visuelle Effekte angezeigt werden sollen, wie die Blast-Animation und die Abkühlleiste. Ebenso benachrichtigt das RemoteEvent die Server-Skripte über den Blast, die mit der Verarbeitung des Blasts in ServerScriptService ⟩ LaserBlastHandler beginnen.
local function onLaserBlastedEvent(playerBlasted: Player, blastData: BlastData.Type)
local validatedBlastData = getValidatedBlastData(playerBlasted, blastData)
if not validatedBlastData then
return
end
if not canPlayerBlast(playerBlasted) then
return
end
blastServer(playerBlasted)
processTaggedPlayers(playerBlasted, blastData)
for _, replicateToPlayer in Players:GetPlayers() do
if playerBlasted == replicateToPlayer then
continue
end
replicateBlastEvent:FireClient(replicateToPlayer, playerBlasted, blastData)
end
endUm Betrug zu verhindern, muss der Server alle Daten, die jeder Client sendet, überprüfen. Diese Überprüfungen umfassen:
- Ist BlastData eine Tabelle? Enthält sie ein Class.CFrame und eine andere Tabelle namens rayResults?
- Hat der Spieler einen Blaster ausgerüstet?
- Hat der Spieler einen Charakter und einen Standort innerhalb der Welt?
- Hat sich der Spieler nach dem Senden der Blast-Daten über eine übermäßige Distanz von dem Ort entfernt, an dem er den Laserstrahl abgefeuert hat?
Diese letzte Überprüfung erfordert eine Beurteilung, und je nach Serverlatenz und Bewegungsgeschwindigkeit des Spielers könnten Sie entscheiden, dass unterschiedliche Werte für Ihr eigenes Spiel übermäßig sind. Um zu demonstrieren, wie man diese Beurteilung trifft, können Sie eine Druckanweisung in getValidatedBlastData hinzufügen und das Spiel testen.
local distanceFromCharacterToOrigin = blastData.originCFrame.Position - rootPartCFrame.Position
print(distanceFromCharacterToOrigin.Magnitude) -- aktualisierte Zeile, unbedingt entfernen
if distanceFromCharacterToOrigin.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS then
warn(`Spieler {player.Name} hat eine Ursprungsüberprüfung beim Blasten nicht bestanden`)
return
endWährend Sie sich bewegen und blasten, beachten Sie die Ausgabe. Sie könnte etwa so aussehen:
1.9019629955291748
3.1549558639526367
2.5742883682250977
4.8044586181640625
2.6434271335601807Wenn Sie die Bewegungsgeschwindigkeit für Spieler in ReplicatedStorage ⟩ PlayerStateHandler ⟩ togglePlayerMovement erhöhen, dann testen Sie das Spiel erneut, werden Sie wahrscheinlich viele fehlgeschlagene Überprüfungen aufgrund übermäßiger Bewegung zwischen den Blasts feststellen.
local ENABLED_WALK_SPEED = 60 -- aktualisierte Zeile, unbedingt zurückändernDer Server führt dann Folgendes aus:
- Validiert rayResults.
- Überprüft, ob der Spieler blasten kann.
- Setzt den Blaster-Zustand zurück.
- Reduziert die Gesundheit für alle getaggten Spieler.
- Repliziert den Blast an alle anderen Spieler, damit sie die Third-Person-Visuals sehen können.
Für weitere Informationen zu diesen Serveroperationen siehe den Abschnitt Treffer erkennen des Tutorials.
Den Blaster zurücksetzen
Im Beispiel-Lasertag-Spiel verwenden Blaster einen Wärme-Mechanismus. Anstatt nach einer festgelegten Anzahl von Blasts nachzuladen, benötigen sie Zeit, um zwischen jedem Blast "abzukühlen". Diese gleiche Abkühlverzögerung tritt sowohl auf dem Client (blastClient) als auch auf dem Server (blastServer) auf, wobei der Server als Quelle der Wahrheit fungiert.
local blasterConfig = getBlasterConfig(player)
local secondsBetweenBlasts = blasterConfig:GetAttribute("secondsBetweenBlasts")
task.delay(secondsBetweenBlasts, function()
local currentState = player:GetAttribute(PlayerAttribute.blasterStateServer)
if currentState == BlasterState.Blasting then
player:SetAttribute(PlayerAttribute.blasterStateServer, BlasterState.Ready)
end
end)Das Attribut secondsBetweenBlasts ist Teil der Blaster-Konfiguration in ReplicatedStorage ⟩ Instances ⟩ LaserBlastersFolder. Nachdem die Verzögerung von secondsBetweenBlasts vergangen ist, kann der Spieler erneut blasten, und der gesamte Prozess wiederholt sich. Um dem Spieler zu helfen zu verstehen, wann er wieder blasten kann, enthält das Spiel eine Abkühlleiste.
An diesem Punkt können Spieler erscheinen und respawnen, zielen und blasten, aber das Spiel muss immer noch die Ergebnisse jedes Blasts bestimmen. Im nächsten Abschnitt des Tutorials lernen Sie, wie Sie die Fähigkeit programmieren, dass der Blaster erkennt, wann der Blast einen anderen Spieler trifft, und dann die entsprechende Menge an Spieler-Gesundheit gemäß den Blaster-Einstellungen reduziert.