Scripts IA
Préparation
Créez le répertoire de vos scripts .u2s scripts comme expliqué dans ce tutorial. Nous utiliserons le nom "u2stutorial". Téléchargez la map de test utilisée pour notre exemple. Il s'agit d'une simple pièce contenant 4 PathNodes, un PlayerStart, une Light et un marine. Le MapName du niveau est "u2stutorial", ce qui correspond à notre répertoire de scripts. La map contient également un Trigger qui sera utilisé pour des tests plus tard.
Si le niveau est testé, le marine se déplace au hasard dans la pièce. N'ayant pas de script attribué, il est dans un état dit autonome et erre sans but. Le comportement IA de base du Pawn le fait réagir aux événements extérieurs (comme voir ou entendre un ennemi).
Créez un fichier texte vide que vous nommerez "marine01.u2s" et placez-le dans votre dossier /Scripts/u2stutorial. Il s'agit du script IA qui sera utilisé pour contrôler le marine. Assurez-vous que votre éditeur de texte n'y ajoute pas une extension .txt.
Dans les propriétés du marine, dans l'onglet AI, ajoutez "marine01" (sans aucune extension) au champ CommandFileName, afin que le jeu sache quel script utiliser pour contrôler le Pawn. Sauvegardez la map
Patrouille
Ajoutez les lignes suivantes au fichier "marine01.u2s" et sauvegardez-le :
sleep 2
gotoactor PathNode0
gotoactor PathNode1
sleep 2
gotoactor PathNode2
agentcall Event_U_Wave 1
gotoactor PathNode3
sleep
Quand le niveau est lancé, le marine reste en place 2 secondes, court jusqu'au PathNode0 puis jusqu'au PathNode1, attend 2 secondes puis se rend au PathNode2, où il joue l'animation "Event_U_Wave". Enfin, il court jusqu'au PathNode3 et s'y arrête définitivement.
Voici le détail des commands utilisées dans ces exemple. Les paramètres entre parenthèses, "()", sont obligatoires. Ceux entre crochets, "[]", sont facultatifs :
- sleep [temps] : Le PNJ attend pendant le temps indiqué (en secondes). Si aucun délai n'est donné, le PNJ attend sans fin, jusqu'à ce qu'un événement externe vienne le réveiller.
- gotoactor (actor) : Le PNJ se rend jusqu'à l'actor demandé. Le paramètre doit recevoir le nom d'objet de l'actor (qui se trouve dans ses propriétés, Object → Name) et non son Tag. Notez que "gotoactor" est une commande latente, ce qui signifie que le script s'interrompt jusqu'à ce que l'action soit terminée (dans le cas présent, le script n'exécute pas d'autre commande avant que le marine n'ait atteint sa destination).
- agentcall (action) (0/1) : Exécute une action d'agent, qui est généralement une animation (plus de détails sur ce système d'agents sur la Golem University). 1 signifie que la commande agentcall est latente (le PNJ n'exécute aucune commande supplémentaire tant que son animation n'est pas terminée), 0 rend la commande non latente, permettant au PNJ d'exécuter les commandes suivantes immédiatement. En changeant le script en "agentcall Event_U_Wave 0", on peut constater la différence : le marine commence son animation et recommence immédiatement à courir vers le PathNode suivant (car il exécute la commande suivante immédiatement après la commande "agentcall").
Toutes les commandes du script doivent être écrites en minuscules, mais les autres éléments (par exemple le nom des actors, comme PathNode0) ignorent les changements de casse.
Labels
Un label est une section de script portant un nom arbitraire. Celui-ci est précédé du caractère ":" et doit être composé uniquement de lettres, de chiffres et du caractère "_". La commande "gotolabel" permet au script de sauter jusqu'à la section dont le nom est cité. Il est ainsi possible de réaliser, par exemple, des boucles d'actions.
Ajoutez deux nouvelles lignes au début et à la fin de votre script et retirez la commande "sleep" pour qu'il ressemble à ceci :
:MarinePatrol
sleep 2
gotoactor PathNode0
gotoactor PathNode1
sleep 2
gotoactor PathNode2
agentcall Event_U_Wave 1
gotoactor PathNode3
gotolabel MarinePatrol
Testez le niveau et voyez le comportement du PNJ.
La commande "call" permet d'appeler, ou "d'insérer", les commandes du label au milieu d'un autre script. Quand un tel appel est exécuté, le script en cours se met en pause, exécute les commandes du label et reprend son cours normal quand il rencontre la commande "return" :
:WaitABit
sleep 5
call PatrolThisArea
sleep 3
gotolabel WaitABit:PatrolThisArea
gotoactor PathNode0
gotoactor PathNode1
return
Dans cet exemple, le PNJ attend 5 secondes, puis (suite à "call PatrolThisArea"), se rend aux PathNode0 puis PathNode1. La commande suivante étant "return", il reprend le cours de la section WaitABit : le Pawn attend 3 seconds puis recommence la séquence.
Messages et Débuggage
Pour voir en temps réel si le script suit bien son cours, il est possible d'envoyer des messages dans la console une fois que celle-ci a été réactivée.
Modifiez à nouveau le script de cette façon :
:MarinePatrol
message "sleeping 2 seconds"
sleep 2
message "going to pathnode 0, then PathNode1"
gotoactor PathNode0
gotoactor PathNode1
message "sleeping 2 seconds"
sleep 2
message "going to pathnode 2"
gotoactor PathNode2
message "waving!"
agentcall Event_U_Wave 1
gotoactor PathNode3
message "starting over"
gotolabel MarinePatrol
En jeu, le script envoie des messages annonçant les actions que le marine s'apprête à entreprendre.
Le système de débuggage du jeu est cependant une meilleure façon d'étudier le déroulement du script sans s'appuyer sur des messages ajoutés à la main. En insérant "debugmode 11" au tout début du script, avant le label :MarinePatrol, le jeu écrit dans la console tout ce que le script exécute, à l'exception des Events.
Commandes principales
Voici les commandes principales, autres que celles déjà rencontrées :
- turntoactor (actor): Le PNJ se tourne vers l'actor donné (indiqué par son nom d'objet, pas son Tag).
- fire (duration): Le PNJ utilise le mode de tir principal de son arme pendant X secondes.
- firealt (duration): Le PNJ utilise le mode de tir secondaire de son arme pendant X secondes.
- setmovespeed: Change la vitesse de déplacement du PNJ.
Voici un exemple d'utilisation :
:MarinePatrol
sleep 2
gotoactor PathNode0
turntoactor Light0 // Le marine se tourne vers la Light
fire 2 // Il tire dessus pendant 2 secondes
firealt 2 // Idem, avec son tir secondaire
gotoactor PathNode1
sleep 2
setmovespeed 0.5 // Le marine se déplace maintenant à la moitié de sa vitesse normale
gotoactor PathNode2
setmovespeed 1 // Il reprend sa vitesse habituelle
agentcall Event_U_Wave 1
gotoactor PathNode3
gotolabel MarinePatrol
Events
Les Events sont extrêmement utiles pour faire réagir les scripts aux événements externes. Le niveau de test contient un Trigger qui émet l'Event "ChangeMarinePatrol". Par défaut, il ne peut pas affecter les PNJ : dans les propriétés du Trigger, la propriété bTriggerNPCs (dans l'onglet Trigger) doit d'abord être réglée sur vrai. Le marine réagira alors à l'Event une fois que la commande "ontrigger" aura été ajoutée à son script pour l'intercepter.
- ontrigger (event) gotolabel (label): Saute au label désiré quand le PNJ reçoit l'Event. Un même Event peut être utilisé dans un autre label avec la commande "ontrigger" pour sauter à un troisième label. Un PNJ peut ainsi passer d'un comportement à un autre avec le même Event.
Observez le script suivant :
:MarinePatrol
ontrigger ChangeMarinePatrol gotolabel MarinePatrol2
gotoactor PathNode0
gotoactor PathNode1
sleep 2
gotolabel MarinePatrol:MarinePatrol2
ontrigger ChangeMarinePatrol gotolabel MarinePatrol
gotoactor PathNode2
gotoactor PathNode3
sleep 2
gotolabel MarinePatrol2
En jeu, le marine répète le label MarinePatrol jusqu'à ce que l'Event "ChangeMarinePatrol" soit envoyé par la map. Il exécute alors le label MarinePatrol2 en boucle. S'il reçoit de nouveau l'Event, il reprend sa première routine.
Décisions aléatoires
Un degré de hasard peut être implémenté dans le script avec la commande "testrandom". Lorsqu'elle est exécutée, le script génère un nombre aléatoire entre 0 et 1. Si ce nombre est supérieur ou égal à celui utilisé comme argument, le test est considéré comme réussi et la seconde partie de la commande est exécutée :
testrandom 0.5 gotolabel Outcome1
gotolabel Outcome2:Outcome1
[...]:Outcome2
[...]
Dans cet exemple, si le nombre aléatoire est supérieur ou égal à 0.5, le script passe au label Outcome1. Autrement, le script continue avec la commande suivante, "gotolabel Outcome2" et passe donc au label Outcome2.
N'importe quelle commande peut être utilisée après "testrandom" pour indiquer quoi faire si le test est un échec, mais utiliser "gotolabel" pour se rediriger vers un label séparé est encouragé pour garder le script lisible et organisé.
Plusieurs commandes "testrandom" peuvent être utilisées à la suite pour faire un choix entre plus de deux possibilités :
testrandom 0.66 gotolabel Outcome1
testrandom 0.66 gotolabel Outcome2
gotolabel Outcome3
Ce script a 33 % de chances de passer au label Outcome1. En cas d'échec, il a 33 % de chances de passer à Outcome2. Si les deux tests sont des échecs, il passe au label Outcome3.
La commande "testrandom" peut être combinée avec "call" :
testrandom 0.5 call Outcome1
gotoactor PathNode3
[...]:Outcome1
gotoactor PathNode1
return
Dans cet exemple, le script a 50 % de chances de passer au label Outcome1 (et donc d'amener le Pawn au PathNode1), puis la commande "return" le ramène à la suite du script (et le Pawn se rend au PathNode3). Dans les 50 % de cas restants, le marine se rendra directement au PathNode3 en sautant le label Outcome1.
Rencontres aléatoires avec "setlocation"
Le commande "setlocation" permet de téléporter un Pawn n'importe où dans la map. La ligne "setlocation PathNode11" déplace ainsi le Pawn contrôlé par le script sur le PathNode11. Cette technique peut être utilisée pour ajouter de la variation dans le placement des ennemis.
Si, par exemple, le joueur doit rencontrer un Skaarj dans une pièce parmi trois, la position de l'adversaire peut être déterminée aléatoirement :
testrandom 0.66 gotolabel TeleportToRoom1
testrandom 0.66 gotolabel TeleportToRoom2
setlocation PathNode3 // PathNode dans la pièce 3
sleep:TeleportToRoom1
setlocation PathNode1 // PathNode dans la pièce 1
sleep:TeleportToRoom2
setlocation PathNode2 // PathNode dans la pièce 2
sleep
Le moteur ne vérifie pas si la cible est visible lorsque le Pawn est téléporté, le Skaarj se matérialise donc soudain, sans prévenir. Il est donc préférable que le déplacement se fasse avant que le PathNode de destination ne soit visible par le joueur. Si un test de visibilité est nécessaire, il vaut mieux utiliser un PawnFactory (qui peut lui-même être contrôlé par script) que la commande "setlocation".
Recherche dynamique
La commande "findactor" est un outil puissant qui permet de rechercher un actor dans un rayon déterminé autour du Pawn pendant le jeu. Elle accepte un grand nombre de paramètres :
findactor [TargetName [Min [Max [DistanceType [VisibilityType [Num [gotolabel/call targetlabel]]]]]]]
Les crochets "[]" signifient que les paramètres à l'intérieur sont facultatifs, il n'est donc pas nécessaire de tous les utiliser à chaque fois que "findactor" est utilisé. Voici un exemple simple d'utilisation :
findactor engine.pathnode 32 1024 1
gotoactor found
Le Pawn recherche un PathNode dans un cercle autour de lui, qui doit être au moins à 32 unités mais pas à plus de 1024, et s'y rend si un PathNode est effectivement détecté. Le dernier paramètre (1) indique que le PathNode le plus proche sera sélectionné si plusieurs sont disponibles. Si la recherche est fructueuse, le résultat est stocké dans une variable interne, found.
La commande "findactor" peut être utilisée, par exemple, pour contrôler un scientifique terrifié qui suit le joueur mais qui, en cas de danger, court se mettre à couvert dans la cachette la plus proche (les zones sûres étant prédéfinies avec des ShadowNodes).
:FollowPlayer
onevent SeeEnemy gotolabel CheckForHiding
gotoactor Player 128 // Le PNJ reste dans un rayon de 128 unités autour du joueur
sleep 3
gotolabel FollowPlayer // Quand le PNJ rejoint le joueur, il s'arrête 3 secondes puis le suit à nouveau:CheckForHiding
findactor U2AI.ShadowNode 0 2048 1 gotolabel Hide // Passe au label Hide si un ShadowNode est trouvé
message "No hiding spot found, continue script" // Aucune cachette dans un rayon de 2048 unités
sleep 1
gotolabel FollowPlayer:Hide
gotoactor found 64 // Rejoint le ShadowNode et reste à 64 unités
findactor // Vide la variable found
setstance crouching
onevent SeePlayer gotolabel FollowPlayer
Cette commande a plus de paramètres que les précédentes :
- TargetName: Type d'actor recherché.
- Min: Rayon au-delà duquel les actors sont recherchés.
- Max: Rayon en-deçà duquel les actors sont recherchés. Si ce paramètre est vide, la recherche couvre toute la map.
- DistanceType: Permet de sélectionner le premier actor trouvé (0), le plus proche (1), le plus éloigné (2) ou tous les actors du bon type présents dans le rayon défini (3).
- VisibilityType: Si ce paramètre est 0, aucun test de visibilité n'est effectué. S'il est à 1, le script s'assure que l'actor ciblé est dans le rayon et qu'aucun obstacle n'existe entre lui et le Pawn. S'il est à 2, le jeu essaye autant que possible de s'assurer que l'actor est dans le champ de vision réel du Pawn.
- Num: Nombre d'actors gardés en mémoire.
Comme montré plus haut, utiliser "findactor" sans aucun paramètre permet de vider la variable found.
Voici quelques exemples de combinaisons et ce qu'elles sélectionnent :
findactor u2.alarmtrigger 0.0 4096.0 0 0 0 gotolabel useit // Premier actor dans un rayon de 4000, sans test de visibilité
findactor u2.alarmtrigger 0.0 4096.0 1 0 0 gotolabel useit // Le plus proche dans un rayon de 4000, sans test de visibilité
findactor u2.alarmtrigger 0.0 4096.0 2 0 0 gotolabel useit // Le plus loin dans un rayon de 4000, sans test de visibilité
findactor u2.alarmtrigger 0.0 4096.0 3 0 2 gotolabel useit // Tous dans un rayon de 4000, sans test de visibilité, 2 mis en mémoire
findactor u2.alarmtrigger 0.0 0.0 2 0 0 gotolabel useit // L'actor le plus éloigné, sans test de visibilité
findactor u2.alarmtrigger 0.0 0.0 2 1 0 gotolabel useit // L'actor visible le plus éloigné
Il existe beaucoup d'autres commandes et mêmes des Events internes générés par le jeu lorsque les PNJ détectent d'autres personnages ou interagissent avec. Une explication complète du système de scripts d'Unreal 2 peut être trouvée dans les documents de Legend Entertainement (en anglais), notamment dans le fichier AIScripting.doc, à lire en priorité.
RSS Feed