Créer des zones d'intéraction avec l'Event-Extender
Attention, ce tutoriel utilise la version 4.5.6 de l'Event Extender (ou ultérieur), je vous invite à mettre vos EE à jours (en cliquant
ici) si la version ne correspond pas.
Sachez, pour information, que la mise en forme des évènements est gérée par
l'Event-Printer, un excellent script de Zangther, qui permet d'exporter les évènements en HTML/BBcode et qui offre à ce tutoriel cet excellent rendu visuel !
Introduction
Après le tutoriel sur
la création d'une jauge avec l'Event-Extender, j'ai décidé de continuer de présenter certains de ses outils au moyen d'un nouvel article. Cette fois, nous allons apprendre à nous servir des zones.
Les zones sont un outil très utile et nous allons voir de quoi il s'agit et comment s'en servir. Sachez que mon estimé collègue, Joke, en avait déjà rédigé
un qui ne tirait pas partit de l'Event-Extender, vous verrez que l'Event-Extender rend la création/utilisation des zones (dites, par variables) beaucoup plus concise et aisée.
Tout d'abord, qu'est ce qu'une zone?
Les zones permettent de représenter une portion de la carte. Une fois cette portion définie, on peut l'utiliser pour tester des choses. Par exemple, est-ce que ces points (référencés par x et y) y sont inscrits, ou encore, est-ce que la zone est survolée par la souris, cliqué par la souris. C'est donc un outil puissant pour effectuer des Point&Click ou déclencher des actions spécifiques si un évènement traverse une zone.
Il existe plusieurs type de zones :
• Les zones rectangulaires
• Les zones circulaires
• Les zones elliptiques
• Les zones polygonales (convexes ou non)
Concrètement, une zone c'est juste une portion de la carte... qui peut avoir plusieurs formes. POINT !
A l'assaut de notre première zone
Nous allons aborder les zones par la pratique, nous allons donc voir un premier cas de figure (honteusement plagié du tutoriel original de Joke). Imaginons cette carte, au climat... étrange (et totalement réaliste
) :
Notre objectif sera de nous servir d'une zone pour que quand le héros se trouve dans la partie enneigée de la carte, on change le climat de la carte pour afficher une chute de neige et que quand il en sorte, le climat redevienne normal !
Création de la zone
Pour créer une zone rectangulaire, nous aurons besoin des coordonnées de son point
haut-gauche (H-G) et des coordonnées de son point
bas-droit (B-D) :
Maintenant que nous avons récupéré les coordonnées, il nous suffit de créer une zone qui correspond à ces coordonnées. Pour ce faire, je crée un évènement en processus parallèle qui va construire la zone et la placer dans une variable (pour que l'on puisse l'utiliser dans les commandes de test de zones).
Code (Ruby): SV[1] = create_rect_area(14, 4, 21, 15)
Ici, je dis que la zone référencée par les coordonnées (14,4) et (21,15) se trouve dans la variable locale 1. (J'utilise une variable locale pour que ma zone ne soit accessible que de l'évènement dans lequel je me trouve
).
Maintenant que notre zone est définie, on peut créer une boucle qui va tester si le héros s'y trouve !
Détecter si un point se trouve dans une zone
A partir de maintenant, notre zone est construite. Pour tester la présence d'un point dans une zone. Il suffit d'utiliser la commande
in_area?(ZONE, X, Y) qui va vérifier si un point référencé par (X,Y) se trouve dans la zone passée en premier argument (c'est pour ça qu'on stocke la zone dans une variable, pour pouvoir la relayer dans les commandes, par après).
Pour savoir si notre héros marche dans la zone. Nous pourrons nous servir des commandes
player_x et
player_y :
Event - EV001| > Commentaire : Nous sommes dans un évènement en processus parallèle, on |
| > Commentaire : initialise les données : |
| > Commentaire : Création de la zone dans la variable locale 1 |
| > Appeler Script : SV[1] = create_rect_area(14, 4, 21, 15) |
| > Commentaire : Initialisation de l'interrupteur pour dire s'il neige |
| > Opération : Interrupteur [0001:IlNeige] Désactivé |
| > Commentaire : Boucle de vérification |
| > Boucle |
| >| > Attendre : 1 Frames |
| >| > Condition : Script : in_area?(SV[1], player_x, player_y) |
| >| >| > Commentaire : Si on est dans la zone, on peut vérifier qu'il faille activer la neige. |
| >| >| > Commentaire : Soit activer la neige si l'interrupteur est désactivé ! |
| >| >| > Condition : Interrupteur [0001:IlNeige] == Désactivé |
| >| >| >| > Commentaire : On active l'interrupteur et on lance la neige ! |
| >| >| >| > Opération : Interrupteur [0001:IlNeige] Activé |
| >| >| >| > Effet Météorologique : Neige, 9, 60 Frames, Attendre |
| >| >| >| > |
| >| >| > Fin - Condition |
| >| >| > |
| >| > Sinon |
| >| >| > Commentaire : Si on n'est pas dans la zone, vérifions que l'on vient d'en sortir, |
| >| >| > Commentaire : soit si l'interrupteur neige est toujours activé ! |
| >| >| > Condition : Interrupteur [0001:IlNeige] == Activé |
| >| >| >| > Commentaire : On désactive l'interrupteur et on lance la neige ! |
| >| >| >| > Opération : Interrupteur [0001:IlNeige] Désactivé |
| >| >| >| > Effet Météorologique : Aucun, 60 Frames, Attendre |
| >| >| >| > |
| >| >| > Fin - Condition |
| >| >| > |
| >| > Fin - Condition |
| >| > |
| > Fin - Boucle |
| > |
Comme en court de route, j'ai perdu, malheureusement, le projet sur lequel je faisais mes démonstration, voici tout de même un petit gif qui correspond "plus ou moins" à l'effet attendu :
Le code n'est à priori pas trop complexe à comprendre. Techniquement, on crée un évènement en processus parallèle pour qu'il se déclenche automatiquement (mais sans bloquer le héros). Ensuite on initialise les données. Puis on crée une boucle (qui s'exécute plus vite, donc elle rafraichit plus vite les modifications) et dedans on vérifie si on vient de rentrer dans la zone, ou si on vient de sortir de la zone. (Cette vérification "plus raffinée", se fait au moyen de l'interrupteur).
Un mini champ de vision
Maintenant que nous avons vu comment créer une zone simple et fixe, nous allons aller un peu plus loin en concevant un "petit champ de vision", au moyen des zones circulaires. Vous allez voir, c'est très très simple !
Il est important de noter que la modification/création d'une zone est une opération très peu gourmande. On peut donc modifier une zone en l'écrasant !
Création et mise à jours de la zone
La première étape est de construire une zone circulaire. Elle est aussi simple à créer qu'une zone rectangulaire, si ce n'est qu'elle demande moins d'argument. En effet, une zone circulaire n'a besoin que d'un point (x, y) pour définir son centre et un rayon. Par exemple :
Code (Ruby): V[1] = create_circle_area(x, y, rayon)
.
Concrètement, cette fois, nous allons créer un évènement qui initialisera une zone circulaire, dans une variable globale car nous aurons besoin de la zone en dehors de l'évènement qui l'appelle. Et ensuite, comme toujours, viendra une boucle, qui écrasera la zone par une nouvelle zone placée aux coordonnées du héros. Voici à quoi peut ressembler notre évènement parallèle :
Event - EV002| > Commentaire : On initialise la zone |
| > Appeler Script : V[1] = create_circle_area(player_x, player_y, 3) |
| > Commentaire : Vient notre habituelle boucle !!! |
| > Boucle |
| >| > Attendre : 1 Frames |
| >| > Commentaire : On met à jours la boucle ! |
| >| > Appeler Script : V[1] = create_circle_area(player_x, player_y, 3) |
| >| > |
| > Fin - Boucle |
| > |
On crée une première fois la zone pour être sur qu'elle existe quand nous la testerons sur les PNJ's qui devront réagir à la zone. J'ai choisi un rayon de trois mais vous êtes évidemment libre de choisir le rayon de votre choix !
Faire apparaître et disparaître les PNJ's
Maintenant qu'à chaque frame de notre carte, notre zone est mise à jours avec les bonnes coordonnées, il suffit de créer un évènement (que nous pourrons dupliquer) qui, s'il se trouve dans la zone, devient visible, s'il ne l'est pas devient invisible ! Rien de très compliqué
Event - EV001| > Boucle |
| >| > Attendre : 1 Frames |
| >| > Condition : Script : in_area?(V[1], event_x(@event_id), event_y(@event_id)) |
| >| >| > Déplacer évènement : Cet événement (Attendre la fin) |
| >| >| > Déplacer évènement : > Transparent OFF |
| >| >| > Afficher une émoticône : Cible - Cet événement, Exclamation |
| >| >| > |
| >| > Sinon |
| >| >| > Déplacer évènement : Cet événement (Attendre la fin) |
| >| >| > Déplacer évènement : > Transparent ON |
| >| >| > |
| >| > Fin - Condition |
| >| > |
| > Fin - Boucle |
| > |
Cette fois, on se sert des coordonnées de l'évènement courant et non du héros, pour voir s'il se trouve dans la zone.
J'utilise @event_id qui signifie "Cet évènement ci", soit l'évènement appelant! Comme ça je peux dupliquer comme un sauvage mon évènement :D
Voyons tout de suite ce que cela donne :
Comme vous pouvez le voir, c'est très facile à utiliser et les ça réduit tout de même une grande partie des calculs :)
Attaquons les zones polygonales: système d'infiltration !!!
Les zones polygonales... elles sont... ahem... trop cool ! C'est une des composantes de l'Event Extender que je préfère ! Non seulement parce que je trouve leur implémentation (la manière dont elles sont codées) trop cool, mais aussi parce qu'elles ouvrent des perspectives de programmation assez cools !
Une fois n'est pas coutume, je vais vous montrer ce que nous allons programmer avant que nous le fassions, soit un tout petit système d'infiltration tout mignon, basé sur un champ de vision un peu plus précis !
Il est possible que ce Gif lag un petit peu mais je suppose que vous voyez l'idée !
Cette fois l'exercice sera un petit peu plus complexe. Voyons voir étape par étape comment j'ai fait !
Créer une zone polygonale
La construction d'une zone polygonale (potentiellement non convexe) est une tâche un petit plus complexe, il faut lui passer une liste de points :
Code (Ruby): V[1] = create_polygon_area([[x1,y1],[x2,y2],[x3,y3],[x4,y4]])
.
On peut évidemment mettre autant de points que l'on désire ! Le premier point est lié avec le second, le second avec le troisième, qui lui même est lié avec le quatrième etc. Le dernier point est toujours lié avec le premier. Il est donc important d'encoder ses points dans un ordre cohérent :)
La construction des images
J'ai d'abord mappé ma carte fort minable, ensuite, j'ai pris une capture d'écran et dans photoshop, j'ai construit mes deux images de zones (celle de gauche et celle de droite). J'ai pu récupérer leurs coordonnées via Photoshop (bouuuuh, un logiciel non libre !!!). Je les aies soigneusement notée et j'ai exportée mes deux images.
Construction de l'évènement principal
Une fois de plus, on commence par un évènement en processus parallèle ! Je vous montre le code puis je l'explique :
Event - EV002| > Commentaire : On affiche les deux images. Dont la seconde (la vue a droite) |
| > Commentaire : est transparente car elle ne doit pas être visible ! |
| > Afficher une image : 1, 'left', H.G. (0,0), (100%,100%), 255, Normale |
| > Afficher une image : 2, 'right', H.G. (0,0), (100%,100%), 0, Normale |
| > Commentaire : On fixe les images sur la carte au moyen de la commande |
| > Commentaire : picture_pin ! |
| > Appeler Script : picture_pin(1) |
| > Appeler Script : picture_pin(2) |
| > Commentaire : On initialize les variables |
| > Commentaire : SV[1] sera un compteur |
| > Commentaire : SS[1] est un interupteur désactivé, il correspondra au changement |
| > Commentaire : d'axe |
| > Appeler Script : SV[1] = 0 |
| > Appeler Script : SS[1] = false |
| > Commentaire : On stocke la liste des coordonnées |
| > Commentaire : V[2] = les coordonnées de la zone de gauche |
| > Commentaire : V[3] = les coordonnées de la zone de droite ! |
| > Appeler Script : V[2] = [[350, 192], [350, 217], [192, 310], [192, 126]] |
| > Appeler Script : V[3] = [[382, 192], [392, 217], [541, 310], [541, 126]] |
| > Commentaire : Au début le méchant regarde à gauche ! Donc la zone de gauche |
| > Commentaire : est basé sur la variable 2 |
| > Appeler Script : V[4] = create_polygon_area(V[2]) |
| > Boucle |
| >| > Attendre : 1 Frames |
| >| > Commentaire : On incrémente le compteur et on le limite à la valeur 400 |
| >| > Commentaire : grâce au MODULO ! (N'hésitez pas à lire le tuto de Joke si |
| >| > Commentaire : c'est flou, le modulo) |
| >| > Appeler Script : SV[1] += 1 |
| >| > Appeler Script : SV[1] %= 400 |
| >| > Commentaire : Si le compteur est inférieur à 200, le personnage regarde à gauche |
| >| > Commentaire : et son interrupteur doit être désactivé. |
| >| > Commentaire : Si le compteur est superieur ou égal à 200, le personnage regarde |
| >| > Commentaire : à droite et son interrupteur doit être activé ! |
| >| > Condition : Script : SV[1] >= 200 |
| >| >| > Commentaire : Il regarde a droite |
| >| >| > Condition : Script : not SS[1] |
| >| >| >| > Afficher une image : 1, '', H.G. (0,0), (100%,100%), 0, Normale, 60 Frames |
| >| >| >| > Déplacer évènement : [EV001] (Attendre la fin) |
| >| >| >| > Déplacer évènement : > Regarde vers la Droite |
| >| >| >| > Afficher une image : 2, '', H.G. (0,0), (100%,100%), 255, Normale, 60 Frames, Attendre |
| >| >| >| > Appeler Script : V[4] = create_polygon_area(V[3]) |
| >| >| >| > Appeler Script : SS[1] = true |
| >| >| >| > |
| >| >| > Fin - Condition |
| >| >| > |
| >| > Sinon |
| >| >| > Commentaire : Il regarde a gauche |
| >| >| > Condition : Script : SS[1] |
| >| >| >| > Afficher une image : 2, '', H.G. (0,0), (100%,100%), 0, Normale, 60 Frames |
| >| >| >| > Déplacer évènement : [EV001] (Attendre la fin) |
| >| >| >| > Déplacer évènement : > Regarde vers la Gauche |
| >| >| >| > Afficher une image : 1, '', H.G. (0,0), (100%,100%), 255, Normale, 60 Frames, Attendre |
| >| >| >| > Appeler Script : V[4] = create_polygon_area(V[2]) |
| >| >| >| > Appeler Script : SS[1] = false |
| >| >| >| > |
| >| >| > Fin - Condition |
| >| >| > |
| >| > Fin - Condition |
| >| > |
| > Fin - Boucle |
| > |
La phase d'initialisation consiste à afficher les deux images des zones. Comme le méchant commence en regardant à gauche, l'image de gauche est visible, celle de droite est invisible (au moyen de l'opacité). Ensuite, comme la map est plus grande que l'écran. J'utilise la commande
picture_pin(ID), pour dire que l'image référencée par l'ID passé en argument défile avec la carte (comme si elle était attachée).
Ensuite j’initialise un compteur (via une variable locale
) et un interrupteur!
Ensuite je crée les points dans des variables pour n'avoir qu'a changer la valeur de la zone en fonction de la direction où regarde le méchant !
Il existe des manières d'effectuer des projections matricielles sur les zones, et de les déformer, cependant, c'est un petit peu (de mon point de vue), trop complexe, donc pour l'usage nous n'allons que préparer deux collections de coordonnées pour notre zone et fonction de la direction de l'ennemi, nous lui attribueront les bonnes valeurs!
Ci fait, nous pouvons créer la zone en lui donnant les coordonnées de la zone de gauche (car notre grand méchant regarde d'abord vers la gauche). Puis s'en suit une petite boucle qui alterne toutes les 200 frames de côté. Changeant la zone, l'opacité des images et activant/désactivant l'interrupteur (pour ne modifier la zone que quand c'est nécessaire).
Bref, rien de très compliqué, le contenu de la boucle est "un peu long" car il y a un tout petit peu d'habillage.
Il ne nous reste plus qu'a détecter si le héros est dans la zone, car il n y en a qu'une seule (qui change en fonction du regard de l'antagoniste).
Vérifier si le héros est prit ou non!
Cette partie ressemble fortement aux autres, cependant il y a une petite nuance. En effet, par soucis de précision, j'ai utilisés les coordonnées en pixels et non en cases de la zone. Il faudra donc se servir des commandes
player_pixel_x et
player_pixel_y (qui existent aussi pour les évènements
).
Je me suis servi d'un autre évènement en processus parallèle qui boucle :
Event - EV003| > Boucle |
| >| > Attendre : 1 Frames |
| >| > Condition : Script : in_area?(V[4], player_pixel_x, player_pixel_y) |
| >| >| > Déplacer évènement : [EV001] (Attendre la fin) |
| >| >| > Déplacer évènement : > Saut : 0 en X, 0 en Y |
| >| >| > Déplacer évènement : > Attendre : 10 Frames |
| >| >| > Déplacer évènement : > Saut : 0 en X, 0 en Y |
| >| >| > Message : Ø, Ø, Normal, Haut |
| >| >| > Message : VU ! VU ! VU ! |
| >| >| > Téléporter l'équipe : [003:30], (X:002, Y:004) |
| >| >| > |
| >| > Fin - Condition |
| >| > |
| > Fin - Boucle |
| > |
Rien de bien compliqué de ce côté non plus !!
Conclusions
C'en est fini de cette introduction aux zones d'interactions. J'espère de tout coeur que ce didacticiel aura été formateur et que cela vous ouvrira des perspectives amusantes! Car je n'ai évidemment pas survolé toutes les possibilités offertes par cette fonctionnalité ! (Vous pourriez par exemple, rapidement mettre en place un système de "Point And Click").
Mais je vous laisse à votre imagination pour impressionner le MONDE ENTIER !
Je conclurai par ...
YEAH ! On est de
RETOUR !
Je passe donc un Bigup à Zangther pour l'Event Printer, Nuki pour l'avoir corrigé pour la Biloucorp, Joke pour être là
et à tous mes camarades bilouteux et tous les makers qui aiment créer et qui s'amuse INTO DA LIFE !
Good night and Good Luck !
Posté le : 20/01/2016 à 15h37