Implémenter le comportement du blaster

*Ce contenu est traduit en utilisant l'IA (Beta) et peut contenir des erreurs. Pour consulter cette page en anglais, clique ici.

Implémenter le comportement du blaster est le processus de programmation d'un mécanisme de tir dans les jeux de tir à la première personne. Bien que les joueurs puissent tirer avec un simple clic ou une pression sur un bouton, créer un comportement de tir satisfaisant et précis est important car cela améliore le plaisir des joueurs dans l'ensemble du gameplay.

En utilisant le jeu de laser tag d'exemple comme référence, cette section du tutoriel vous apprend les scripts derrière l'implémentation du comportement du blaster pour deux types différents de blasters, y compris des conseils sur :

  • Détecter quand les joueurs appuient sur le bouton de tir.
  • Vérifier si le joueur peut utiliser son blaster s'il a récemment appuyé sur le bouton de tir.
  • Générer des données de tir qui indiquent au serveur qui a initié le tir, d'où il vient et quelle était la destination finale de chaque faisceau laser.
  • Notifier le serveur des données de tir afin qu'il puisse effectuer les actions appropriées si le tir a heurté un autre joueur.
  • Réinitialiser le blaster entre chaque tir pour donner au blaster suffisamment de temps pour refroidir avant de pouvoir tirer à nouveau.

Après avoir terminé cette section, vous apprendrez les scripts qui permettent au blaster de détecter quand ses tirs heurtent d'autres joueurs, puis de déduire le montant correspondant de santé selon chaque type de blaster.

Détecter l'entrée du joueur

La première étape pour implémenter le comportement du blaster est d'écouter quand un joueur appuie sur le bouton de tir. Le type d'entrée que les joueurs utilisent pour appuyer sur le bouton de tir dépend de l'appareil qu'ils utilisent pour accéder au jeu. Par exemple, le jeu de laser tag d'exemple prend en charge les contrôles de souris et de clavier, les manettes de jeu et les contrôles tactiles. Vous pouvez voir chacun de ces types d'entrée dans ReplicatedStorageUserInputHandler.

Ce script client utilise ContextActionService pour lier MouseButton1 et ButtonR2 à l'action de tir. Cela signifie qu'à chaque fois qu'un joueur appuie sur le bouton gauche de la souris ou sur le bouton R2 d'une manette, cela déclenche un faisceau laser qui sort du blaster. Notez que le HUDGui contient un bouton pour tirer sur les appareils mobiles, qui est connecté plus tard dans le script.

UserInputHandler
ContextActionService:BindAction("_", onBlasterActivated, false,
Enum.UserInputType.MouseButton1,
Enum.KeyCode.ButtonR2
)

Une autre note importante est l'utilisation de Enum.UserInputState.Begin dans la définition de onBlasterActivated(). De nombreuses interactions de l'interface utilisateur, comme le choix d'un blaster dans cet exemple, ne se produisent pas avant que le bouton de la souris ne se relâche (Enum.UserInputState.End), ce qui donne aux utilisateurs une dernière chance d'éviter l'interaction. Cependant, un mécanisme de tir ne semble pas réactif à moins qu'il ne se produise instantanément lorsque le bouton est enfoncé.

Pour démontrer, vous pouvez changer Enum.UserInputState.Begin en Enum.UserInputState.End, puis tester le jeu pour voir comment la réactivité du tir impacte le gameplay. Par exemple, si les joueurs peuvent maintenir le bouton enfoncé sans déclencher le tir, comment cela pourrait-il changer leur expérience en taguant d'autres joueurs ?

UserInputHandler
local function onBlasterActivated(_actionName: string,
inputState: Enum.UserInputState, _inputObject: InputObject)
if inputState == Enum.UserInputState.End then -- ligne mise à jour, assurez-vous de revenir en arrière
attemptBlastClient()
end
end

Vérifier si le joueur peut tirer

Après que UserInputHandler détecte une pression sur un bouton ou un tapotement sur l'écran, il appelle ReplicatedStorageBlasterattemptBlastClient pour vérifier si le joueur peut tirer ou non. Comme la plupart des vérifications dans le jeu de laser tag d'exemple, cela se produit deux fois : d'abord sur le client, puis plus tard sur le serveur. attemptBlastClient appelle ensuite ReplicatedStorageBlastercanLocalPlayerBlast pour effectuer une vérification simple de l'attribut joueur blasterStateClient :

canLocalPlayerBlast
local function canLocalPlayerBlast(): boolean
return localPlayer:GetAttribute(PlayerAttribute.blasterStateClient) == BlasterState.Ready
end

Si vous examinez ReplicatedStorageBlasterBlasterState, vous pouvez voir que le jeu a trois états de blaster : Ready, Blasting, et Disabled. Pour voir l'effet de chacun de ces états, vous pouvez tester le jeu, sélectionner votre joueur sous le service Players, puis observer l'attribut blasterStateClient dans la fenêtre Properties. Remarquez comment il affiche Disabled pendant que vous choisissez votre blaster, Ready la plupart du temps, et Blasting pendant moins d'une seconde après que vous ayez appuyé sur le bouton.

Cette légère pause vous empêche de tirer aussi rapidement que vous pouvez cliquer. Par exemple, si vous changez la fonction pour toujours retourner vrai, vous pouvez tirer rapidement avec votre blaster sans aucun délai, ce qui est irréaliste pour le gameplay de laser tag.

canLocalPlayerBlast
local function canLocalPlayerBlast(): boolean
return true -- ligne mise à jour, assurez-vous de revenir en arrière
end

Générer des données de tir

Après avoir vérifié que le blaster du joueur est dans l'état Ready, attemptBlastClient appelle ReplicatedStorageattemptBlastClientblastClient. La première étape que blastClient effectue est de définir l'attribut joueur blasterStateClient sur Blasting, ce qui évite le même cas de tir rapide mentionné précédemment.

L'étape suivante consiste à générer les données de tir. Si vous consultez ReplicatedStorageBlasterBlastData, vous pouvez voir que chaque tir se compose de trois informations :

  • Le joueur qui initie le tir.
  • Un DataType.CFrame qui représente le point d'origine du tir.
  • Un tableau RayResult qui contient la destination finale de chaque faisceau laser et le joueur touché, s'il a touché un autre joueur.

Pour générer ces données, blastClient appelle ReplicatedStorageattemptBlastClientblastClientgenerateBlastData, que vous pouvez consulter ci-dessous.

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

Cette fonction commence par utiliser getBlasterConfig pour récupérer le type de blaster du joueur. L'exemple fournit deux types de blasters : un qui produit plusieurs faisceaux avec une large dispersion horizontale, et un autre qui produit un seul faisceau. Vous pouvez trouver leurs configurations dans ReplicatedStorageInstancesLaserBlastersFolder.

La fonction utilise ensuite currentCamera.CFrame comme point d'origine pour le tir, le passant à getDirectionsForBlast. À ce stade, le code ne concerne plus le blaster, mais le faisceau laser, dont vous apprendrez davantage dans la section détecter les coups du tutoriel. Enfin, après avoir créé le tableau rayResults, generateBlastData a toutes les informations nécessaires pour retourner les données de tir à blastClient.

Notifier le serveur

Une fois que blastClient a des données complètes pour le tir, il déclenche deux événements :

blastClient
local laserBlastedBindableEvent = ReplicatedStorage.Instances.LaserBlastedBindableEvent
local laserBlastedEvent = ReplicatedStorage.Instances.LaserBlastedEvent
laserBlastedBindableEvent:Fire(blastData)
laserBlastedEvent:FireServer(blastData)

Le BindableEvent notifie d'autres scripts clients du tir. Par exemple, ReplicatedStorageFirstPersonBlasterVisuals utilise cet événement pour savoir quand afficher des effets visuels, tels que l'animation de tir et la barre de recharge. De même, le RemoteEvent notifie les scripts serveur du tir, ce qui commence à traiter le tir dans ServerScriptServiceLaserBlastHandler.

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

Pour aider à prévenir la tricherie, le serveur doit vérifier toutes les données que chaque client envoie. Ces vérifications incluent :

  1. Est-ce que BlastData est un tableau ? Contient-il un Class.CFrame et un autre tableau nommé rayResults ?
  2. Le joueur a-t-il un blaster équipé ?
  3. Le joueur a-t-il un personnage et une position dans le monde ?
  4. Après avoir envoyé les données de tir, le joueur s'est-il déplacé d'une distance excessive par rapport à l'endroit où il a tiré le faisceau laser ?

Cette dernière vérification implique un jugement, et selon la latence du serveur et la vitesse de mouvement du joueur, vous pourriez décider que différentes valeurs sont excessives pour votre propre jeu. Pour démontrer comment faire ce jugement, vous pouvez avoir une idée de l'ampleur typique du changement de position en ajoutant une instruction d'impression dans getValidatedBlastData et en testant le jeu.

getValidatedBlastData
local distanceFromCharacterToOrigin = blastData.originCFrame.Position - rootPartCFrame.Position
print(distanceFromCharacterToOrigin.Magnitude) -- ligne mise à jour, assurez-vous de retirer
if distanceFromCharacterToOrigin.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS then
warn(`Le joueur {player.Name} a échoué à un contrôle de validité d'origine lors du tir`)
return
end

En vous déplaçant et en tirant, notez la sortie. Cela pourrait ressembler à ceci :

1.9019629955291748
3.1549558639526367
2.5742883682250977
4.8044586181640625
2.6434271335601807

Si vous augmentez la vitesse de mouvement des joueurs dans ReplicatedStoragePlayerStateHandlertogglePlayerMovement, puis testez à nouveau, vous rencontrerez probablement de nombreux échecs de vérification en raison d'un mouvement excessif entre les tirs.

togglePlayerMovement
local ENABLED_WALK_SPEED = 60 -- ligne mise à jour, assurez-vous de revenir en arrière

Le serveur effectue ensuite les actions suivantes :

  • Valide rayResults.
  • Vérifie si le joueur peut tirer.
  • Réinitialise l'état du blaster.
  • Réduit la santé de tous les joueurs tagués.
  • Réplique le tir à tous les autres joueurs afin qu'ils puissent voir les visuels en troisième personne.

Pour plus d'informations sur ces opérations serveur, consultez la section détecter les coups du tutoriel.

Réinitialiser le blaster

Dans le jeu de laser tag d'exemple, les blasters utilisent un mécanisme de chaleur. Plutôt que de recharger après un nombre défini de tirs, ils ont besoin de temps pour "refroidir" entre chaque tir. Ce même délai de refroidissement se produit à la fois sur le client (blastClient) et sur le serveur (blastServer), le serveur agissant comme la source de vérité.

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

L'attribut secondsBetweenBlasts fait partie de la configuration du blaster dans ReplicatedStorageInstancesLaserBlastersFolder. Après que le délai secondsBetweenBlasts soit écoulé, le joueur peut tirer à nouveau, et tout le processus se répète. Pour aider le joueur à comprendre quand il peut tirer à nouveau, le jeu inclut une barre de recharge.

À ce stade, les joueurs peuvent apparaître et réapparaître, viser et tirer, mais le jeu doit encore déterminer les résultats de chaque tir. Dans la prochaine section du tutoriel, vous apprendrez à programmer la capacité du blaster à détecter quand le tir touche un autre joueur, puis à réduire le montant approprié de santé du joueur selon les paramètres du blaster.

©2026 Société Roblox. Roblox, le logo Roblox et Powering Imagination font partie de nos marques déposées aux États-Unis et dans d'autres pays.