❤ 0 Zones de combat en Ruby
Ceci est un tutoriel pour vous apprendre comment coder vos zones de combat en Ruby sous RMXP, pas un script prêt à être copié-collé. La théorie est exactement la même que celle expliquée dans cet excellent tuto de Joke que je vais vous demander d'aller lire.
...
Vous l'avez compris et assimilé ? Bien, nous allons pouvoir ajouter une couche de Ruby par dessus tout ça !
I. Comment ça marche, une liste de monstres ?
Ouvrez votre éditeur de script et allez farfouiller dans Game_Map. A la ligne 177 se trouve le code suivant :
1
2
3
| def encounter_list
return @map.encounter_list
end |
Quoi qu'ça fait ? Lisons ensemble.
def encounter list : Définition d'une fonction nommée "encounter_list". Notez comme le nom est prometteur pour ce qui nous intéresse...
return : Renvoie la valeur contenue dans ce qui suit.
@map.encounter_list : Ce qui suit. Il s'agit de la liste des monstres contenue dans les propriétés de la carte (si, si, vous savez, dans l'éditeur...). Cette variable (car c'est une variable) est un tableau contenant toutes les ids des groupes de monstres "rencontrables" sur une carte, sous la forme [x, y, z].
end : Fin de la définition de notre fonction (car même les meilleures choses ont une fin...)
Vous l'aurez compris, tout ce que fait le programme par défaut pour définir la liste des monstres présents sur une carte, c'est d'aller chercher la-dite liste dans les propriétés de la carte. Et ça, ça ne nous plait pas. Eh bien ! Qu'attendons-nous pour changer les choses ?
II. Nos premières zones
1) Zones définies par deux points
Si le titre ne vous dit rien, retournez lire le tutoriel de Joke sur les zones par variables.
Vous vous souvenez de ce code pour savoir si le joueur est dans une zone ou pas ?
modifier variable : "X héros" rendre égal à coordonnée X du héros
modifier variable : "Y héros" rendre égal à coordonnée Y du héros
condition : si "X héros" supérieur ou égal à "56"
--condition : si "X héros" inférieur ou égal à "88"
----condition : si "Y héros supérieur ou égal à "40"
------condition : si "Y héros inférieur ou égal à "77"
[...]
Nous allons le traduire en Ruby. ^^
If et coordonnées du joueur
Voici la première condition :
1
2
| # condition : si "X héros" supérieur ou égal à "56"
if $game_player.x >= 56 |
Lisez "Si la valeur de $game_player.x est supérieure ou égale à 56". Et la valeur de $game_player.x est tout simplement la valeur de la coordonnée en x (comptée en carreaux) de $game_player, le joueur. De la même façon, la coordonnée en y du joueur sera désignée par $game_player.y
Facile, non ?
Avec plusieurs conditions
C'est pas tout ça, mais nous, on voudrait bien les quatre conditions simultanées... Et c'est pour ça qu'on est bien contents que les opérateurs logiques marchent en Ruby. Si vous voulez une codition de la forme "Si ça et ça", ça s'écrit "if ça and ça".
Pouvez-vous écrire les quatre conditions simultanées sans regarder ce qui suit ?
1
2
3
4
| if $game_player.x >= 56 and
$game_player.x <= 88 and
$game_player.y >= 40 and
$game_player.y <= 77 |
Alors, ça ressemble à ce que vous aviez fait ?
NB : En général, en Ruby, un saut de ligne représente une fin d'instruction, ma condition devrait donc se finir à la fin de ma première ligne de code. Cependant, comme la ligne se finit par l'opérateur "and" qui appelle nécessairement une suite, le programme comprend que ma condition se poursuit sur la ligne suivante et ne s'arrête qu'a la première ligne qui n'appelle pas de suite, ici la dernière ligne de mon code. C'est important de ne pas sauter des lignes n'importe comment, ça conduit à des erreurs de syntaxe.
Au fait, faudrait pas un peu changer notre liste de monstres, aussi ?
Si la condition est remplie...
Le conditionnement est fait, faudrait peut-être faire quelque chose quand notre condition est remplie, non ? Examinons le code à écrire...
1
2
3
4
5
6
| if $game_player.x >= 56 and
$game_player.x <= 88 and
$game_player.y >= 40 and
$game_player.y <= 77
return [7, 8]
end |
Le code est tout simplement calqué sur la fonction originale de Game_Map. Si nos quatre conditions sont remplies, alors on renvoie [7, 8], les groupes de monstres aux ids 7 et 8 sont maintenant ceux rencontrés dans la zone.
Le "end" est important car il indique au programme de n'effectuer que les actions situées avant celui-ci quand les conditions sont remplies, et pas le reste du programme. De toute façon, si vous l'oubliez, vous aurez une erreur de syntaxe lors de l'exécution. ^^'
Le beau code complet
1
2
3
4
5
6
7
8
9
10
11
| def encounter_list
if $game_map.map_id == 1 and
$game_player.x >= 56 and
$game_player.x <= 88 and
$game_player.y >= 40 and
$game_player.y <= 77
return [7, 8]
else
return @map.encounter_list
end #du if
end #du def |
Quelques petites choses ont été rajoutées :
$game_map.map_id == 1 : Le signe "==" sert à vérifier une égalité et $game_map.map_id désigne tout simplement l'id d'une carte. Si vous ne le précisez pas, votre zone sera créée sur toutes les cartes du jeu ! Cette condition existait de façon implicite dans la programmation en évènement, puisque les évènements sont propres à une carte.
else : "sinon". Ben oui, faut bien dire à la bestiole ce qu'elle doit faire si on n'y est pas, dans la zone créée... Sinon vous aurez un beau bug dès que vous en sortirez. J'ai remis la définition par défaut de la liste de monstres dans ce "else", mais si un coup de folie vous prend, libre à vous de changer cela.
Une traduction "littérale" du code, pour être sûre que même les dissipés du fond suivent :
<>définir la fonction "encounter_list"
<><>si l'id de la carte est 1
<><>et que la coordonnée x du joueur est supérieure ou égale à 56
<><>et que la coordonnée x du joueur est inférieure ou égale à 88
<><>et que la coordonnée y du joueur est supérieure ou égale à 40
<><>et que la coordonnée y du joueur est inférieure ou égale à 77
<><><> alors on rencontre les groupes de monsstres aux ids 7 et 8
<><>sinon
<><><>on rencontre la liste spécifiée dans les propriétés de la carte
<><>fin
<>fin
2) Zones définies par un point et une distance
Maintenant que vous avez assimilé les bases (*ahem* ...), je vais pouvoir aller un peu plus vite.
Reprenons le code de Joke dans la section correspondante :
<>modif variable "X diff" = coord "X perso 2"
<>modif variable "Y diff" = coord "Y perso 2"
<>modif variable "X diff" - (soustraire) coord X "perso 1"
<>modif variable "Y diff" - (soustraire) coord Y "perso 1"
condition : si "X diff" >= -3
--condition : si "X diff" <= 3
----condition : si "Y diff" >= -3
------condition : si "Y diff" <= 3
[...]
Et sa traduction (l'explication suit, pas d'inquiétude) :
1
2
3
4
5
6
7
| if $game_map.map_id == 1 and
$game_player.x - $game_map.events[1].x >= -3 and
$game_player.x - $game_map.events[1].x <= 3 and
$game_player.y - $game_map.events[1].y >= -3 and
$game_player.y - $game_map.events[1].y <= 3
return [3, 4]
end |
Utiliser une variable "différence" ? Pah, on fait les calculs directement, nous. Ca ressemble furieusement à notre code d'avant, avec toutefois l'apparition d'une nouvelle variable.
$game_map.events[1] : L'évènement avec l'id 1. Tous les évènements du jeu avec l'id 1. Vous comprenez l'importance de la condition sur l'id de la carte... Et nous utilisons ses coordonnées x et y comme nous utilisons celles de $game_player.
N.B. : Contrairement au tuto de Joke, nous travaillons bien ici avec des coordonnées absolues et non pas avec des coordonnées écran.
Voilà notre nouveau "code complet" qui crée une zone de 3 carreaux de large autour de l'évènement avec l'id 1 :
1
2
3
4
5
6
7
8
9
10
11
| def encounter_list
if $game_map.map_id == 1 and
$game_player.x - $game_map.events[1].x >= -3 and
$game_player.x - $game_map.events[1].x <= 3 and
$game_player.y - $game_map.events[1].y >= -3 and
$game_player.y - $game_map.events[1].y <= 3
return [3, 4]
else
return @map.encounter_list
end #du if
end #du def |
Rien de nouveau sous le soleil, mais traduisons quand même :
<>définir la fonction "encounter_list"
<><>si l'id de la carte est 1
<><>et que (joueur.x - évènement 1.x) est supérieur ou égal à -3
<><>et que (joueur.x - évènement 1.x) est inférieur ou égal à 3
<><>et que (joueur.y - évènement 1.y) est supérieur ou égal à -3
<><>et que (joueur.y - évènement 1.y) est inférieur ou égal à 3
<><><> alors on rencontre les groupes de monsstres aux ids 3 et 4
<><>sinon
<><><>on rencontre la liste spécifiée dans les propriétés de la carte
<><>fin
<>fin
3) Les deux en même temps !
Une seule zone par jeu, ça craint un peu... La clé pour réunir nos deux zones précedentes ? Le elsif !
La démonstration en image :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| def encounter_list
if $game_map.map_id == 1 and
$game_player.x >= 56 and
$game_player.x <= 88 and
$game_player.y >= 40 and
$game_player.y <= 77
return [7, 8]
elsif $game_map.map_id == 1 and
$game_player.x - $game_map.events[1].x >= -3 and
$game_player.x - $game_map.events[1].x <= 3 and
$game_player.y - $game_map.events[1].y >= -3 and
$game_player.y - $game_map.events[1].y <= 3
return [3, 4]
else
return @map.encounter_list
end #du if
end #du def |
Vous avez maintenant sur votre carte 1 deux zones : une zone rectangulaire définie par deux points dans laquelle on rencontre les groupes 7 et 8 et une zone de 3 carreaux de large autour de l'évènement 1 dans laquelle on rencontre les groupes 3 et 4.
Attention ! Le programme vérifie d'abord le premier jeu de conditions, si elles ne sont pas remplies, celles du 1e elsif, si celles-ci ne sont pas remplies non plus, celles du 2nd elsif, etc. L'ordre dans lequel vous écrivez votre échelle de elsif définit donc la priorité des conditions les unes par rapport aux autres. Si je suis dans les deux zones à la fois, je rencontrerai les monstres 7 et 8, ceux qui correspondent au premier jeu de conditions à être rempli.
Si ce n'est pas très clair, je vous invite à tester vous-même.
Vous pouvez ajouter autant de elsif que vous voulez.
III. Variantes
1) Sur les coordonnées
Il y a en Ruby deux autres manières de désigner les coordonnées des objets.
$game_player.screen_x
C'est ce qui est appelé la "coordonnée écran" en évènements et qui désigne la coordonnée x du joueur par rapport au bord de l'écran. Cette coordonnée est au pixel près.
De la mêmz manière, il existe
$game_player.screen_y
$game_map.events[1].screen_x
$game_map.events[1].screen_y
$game_player.real_x
La coordonnée absolue du joueur... au quart de pixel près ! Comme $game_player.x mais 128 fois plus précis.
Bien sûr, on peut écrire :
$game_player.real_y
$game_map.events[1].real_x
$game_map.events[1].real_y
2) Sur les conditions
Pourquoi se limiter à de bêtes zones ? Lâchez vous ! Quelques exemples de conditions que vous pourrez réutiliser ailleurs :
if $game_party.item_number(1) > 0
Si l'équipe a au moins un exemplaire de l'objet avec l'id 1
if $game_party.actors[0] == $game_actors[1]
Si le premier membre de l'équipe est le héros avec l'id 1
$game_actors[1].weapon_id == 1
Si le héros avec l'id 1 est équipé de l'arme 1
$game_party.actors.include?($game_actors[1])
Si le héros avec l'id 1 est dans l'équipe
if $game_variables[1] == 1
Si la variable 1 est égale à 1
if $game_switches[1] == true
Si l'interrupteur 1 est sur ON
Enfin bref, toutes les conditions disponibles en évènements, plus toutes celles qui vous passent par la tête.
3) Sur la forme des zones
Vous décidez des conditions à remplir, vous décidez de la forme de vos zones ! Utilisez des "and" et des "or" pour faire quelque chose de bien.
Dans les choses qui marchent, j'avais fait ça :
1
2
3
4
5
| if game_map.map_id == 1 and
($game_player.x - 12)*($game_player.x - 12) +
($game_player.y - 12)*($game_player.x - 12) < 9
return [4, 5]
end |
C'est l'équation d'un disque. ^^ (Il n'était pas très rond, il faudrait essayer avec des coordonnées au pixel... Mais pas de message d'erreur, donc ça marchait !)
4) Et si on veut changer la fréquence des rencontres ?
Devinez quoi ? Juste en dessous de notre terrain de jeu sur Game_Map figure la fonction suivante :
1
2
3
| def encounter_step
return @map.encounter_step
end |
Ca ressemble à ce qu'on sait déjà modifier, non ? Ben oui, ça marche exactement pareil, sauf que ce n'est plus une liste mais un nombre seul qui doit figurer après return.
1
2
3
| def encounter_step
return 10
end |
Je vous laisse vous amuser pour mettre des conditions.
IV. Le mot de la fin
Ce tutoriel m'a permis de vous montrer par l'exemple quelques trucs faisables en Ruby, et de vous expliquer quelques fonctions et variables présentes de base. Je vous encourage à vous plonger dans l'éditeur de script et à essayer de comprendre comment ça marche par vous-mêmes. Il faut juste de la logique, des bases d'anglais et un peu de rigueur. ^^
Merci de votre attention.
|