[Game Maker] Switchs et portes dans un niveau

Pour tout ce qui est fan arts, homebrew, shooters codés à la main, rip de sprites, doujins et toute autre productions artistiques ou logicielles faites maison.
Répondre
Avatar de l’utilisateur
Radigo
Counter Stop
Messages : 7567
Inscription : 22 mai 2003, 17:31
Localisation : Paris
Contact :

Voilà, pour préciser ce que j'ai commencé à dire dans le topic GM "créer un jeu" voici une méthode pour créer facilement un système de switchs/portes.

Je ne connais pas les arcanes secrètes de GM donc j'ai abordé le problème comme si je n'avais aucun outil spécifique à GM pour faire ça, peut-être qu'on peut faire plus simple, je suis preneur d'infos...

L'idée est de pouvoir, dans un niveau, actionner des portes (pour commencer) à partir de switchs. Pour garder une bonne évolutivité il faut que le switch puisse s'activer un peu comme on veut et que la porte réagisse un peu comme on veut. Il s'agit donc d'une machinerie qui lie des actions à des résultats d'instance à instance.

Ma méthode est la suivante, il nous faut au moins tous ces objets :
- OBJ : un objet switch
- SCR_OBJ_INIT : un script d'initialisation unique pour tous les switchs
- SCR_OBJ_ACTION : un script d'action unique pour tous les switchs à appliquer à l'événement de notre choix dans l'objet switch
- switch instance creation_code : un code d'instanciation spécifique à chaque instance de switch

- SCR_MACHINERIE_INIT : l'initialisation de la machinerie
- SCR_MACHINERIE : un script de machinerie unique pour faire le lien entre tout ce bazar

- OBJ_DOOR : un objet récepteur
- SCR_REGISTER_MACHINERIE : un script unique qui enregistre les récepteurs dans la machinerie (le franglais est voulu)
- recepteur instance creation_code: un code d'instanciation spécifique à chaque instance de récepteur


Exemple : un interrupteur sur lequel on marche ouvre une porte, ils sont liés par l'id d'action 1.

On ajoute SCR_OBJ_INIT au 'Create' de l'objet switch qui contient peu ou prou :

Code : Tout sélectionner

self.active = false;
self.action_id = 0;// L'ID qui lie un switch à un récepteur
self.image_index = 1;// On part du principe que le sprite utilisé a 2 frames (inactif/actif)
self.image_speed = 0;// On bloque la lecture des frames du sprite
On ajoute SCR_OBJ_ACTION à son event 'Collision' contre notre sprite de joueur. Le contenu du script est vaguement :

Code : Tout sélectionner

SCR_MACHINERIE(self.action_id);
Pour spécifier l'action_id il faut placer l'objet switch dans la room et ajouter un creation_code, c'est chiant mais je n'ai pas trouvé plus pratique. Le creation_code contient juste :

Code : Tout sélectionner

self.action_id = 1;//L'action 1 est lancée depuis cet objet
Côté machinerie, on initialise une variable globale qui va faire le lien entre les switchs et les récepteurs. Il s'agit du fameux ds_map avec lequel j'avais des soucis. En gros ça permet de stocker des pairs de clé/valeurs. Pour faire simple on a envie de stocker un truc comme ça :

Code : Tout sélectionner

"machinerie" : {
  "1" : door_1,
  "2" : door_2
}
(On ne le voit jamais écrit comme ça dans GM à priori, je donne juste l'idée...)

La variable 'machinerie' est un ds_map dont chaque clé est l'action_id et dont la valeur est l'objet récepteur lui-même. Pour ça l'init de la machinerie ne comporte que ça d'important :

Code : Tout sélectionner

ds_map_create(global.machinerie);
Ensuite, côté récepteur c'est plus compliqué... Il faut savoir que Game Maker éxécute les scripts d'un objet dans un ordre défini :

1/ Event Create > défini dans le champ Events -> Create de l'objet en lui-même (le modèle de l'objet dans la liste de gauche de l'interface)

2/ Creation code > défini lors de l'instanciation de l'objet dans la room, il faut faire un clic droit sur l'objet posé dans le niveau pour accéder à ses propriétés et son 'creation code'.

3/ Step, collisions, etc... > définis dans les champs events correspondants, là c'est plus free style.

Ce qui est important à voir ici, c'est que l'on peut initialiser des variables par défaut dans l'événement Create et affecter des valeurs pour chaque instance individuellement dans la room, en fonction de leur placement, etc... pour ensuite s'en servir dans les scripts de collision, d'IA, etc...

Tout ça pour dire que ma porte elle s'initialise avec rien de particulier, mais dans son creation_code on exécute le script SCR_REGISTER_MACHINERIE. Le creation code contient :

Code : Tout sélectionner

SCR_REGISTER_MACHINERIE(1);// On s'enregistre avec l'ID 1 dans la machinerie en tant que récepteur
Et le script unique dit vite fait :

Code : Tout sélectionner

var action_id = argument0;
ds_map_add(global.machinerie, action_id, self.id);
Et c'est là que j'ai appris le truc le plus what the fuck de GM jusque là : une instance se récupère avec son ID, l'ID EST l'instance, ce n'est pas juste une suite de chiffres. Donc on enregistre l'ID dans le ds_map et en lisant l'ID, on pourra affecter la valeur à une variable qui SERA notre instance.

Une fois qu'on entre en collision avec le switch on lance le script SCR_MACHINERIE sans aucun paramètre. On va se servir du self initialisé dans le creation_code. Et c'est là que j'ai eu du mal à trouver comment récupérer les données du ds_map sans debugger. Il faut utiliser la fonction ds_map_find_value pour récupérer la valeur telle qu'elle.

Et donc la machinerie est un peu plus compliqué mais ressemble à ça :

Code : Tout sélectionner

if (self.action_id != 0)// Je vérifie toujours mes données pour ne pas faire de moulinette inutile
{
  var door = ds_map_find_value(global.machinerie, self.action_id);
  instance.destroy(door);// Parceque on accède à notre instance depuis son ID
}
Et voilà ! Il ne reste plus qu'à mettre des switchs partout et des portes partout pour commencer à faire des puzzles rigolos dans un jeu d'action. J'ai même envie de dire que c'est un point de départ pas trop dégueux pour un possible action/rpg/rogue/zelda.

Pour l'instant la porte disparaît salement, je dois trouver un moyen élégant et raffiné de lancer une anim d'ouverture/fermeture, et surtout supporter autre chose que des portes (des pièges !), mais là ça risque de devenir trop compliqué pour être décrit comme ça dans un post à l'arrache.

PS: je corrigerai les éventuelles erreurs, là je poste en speed depuis le boulot, je suis censé coder autre chose que du GM... Mais n'hésitez pas à me corriger.
"HYPER GAGE : 500%"
Image
Gunny
Empereur Bydo
Messages : 3404
Inscription : 15 mai 2006, 15:26
Localisation : Rayon chaussettes du Kiabi du coin
Contact :

Ok c'était donc ca que tu voulais faire...

Hummmm...

Certains mécanismes auraient pu bénéficier de l'héritage et du polymorphisme non ?
En tout cas, une partie du truc aurait été simplifié je pense...

Après il reste le problème de liaison switch <-> porte qui nécessite soit de coder en dur dans les objets les couples associés, soit d'utiliser un tableau ( plus léger et rapide qu'une ds_map ) pour les associations...
Si t'as un truc électronique cassé, ça se passe par là https://www.atelier-electrodd.fr/

-Je comprend rien à ce que tu dis...
-Pas grave... C'est pas en vivant plus longtemps qu'on deviens moins con.
Avatar de l’utilisateur
Radigo
Counter Stop
Messages : 7567
Inscription : 22 mai 2003, 17:31
Localisation : Paris
Contact :

Gunny a écrit :l'héritage et du polymorphisme non ?
Ah bah si je peux lire des trucs là dessus applicables au GML je suis preneur.

La population du ds_map se fait au chargement du niveau, donc si c'est lent c'est pas grave, ensuite la lecture se fait une fois qu'on active le switch, dans le pire des cas on peut avoir un freeze au moment d'activer un truc dans un niveau. Ça ne me dérange pas mais dans le doute je demande quand même : un tableau à 2 dimensions ? C'est vraiment plus rapide ? J'avoue qu'accéder à des données avec des clés c'est tellement pratique que je suis prêt à sacrifier un peu de perfs...
"HYPER GAGE : 500%"
Image
Gunny
Empereur Bydo
Messages : 3404
Inscription : 15 mai 2006, 15:26
Localisation : Rayon chaussettes du Kiabi du coin
Contact :

D'accord d'accord.
L'héritage et le polymorphisme fonctionne comme dans le C++.
Y a juste la surcharge des fonctions qui est un peu bordélique.

Par exemple, dans le cas de Metroid, tu as des portes de différentes couleurs. La seule chose qui change , c'est le trigger. Donc tu fais un objet parent "Porte", tes enfants "Porte_bleue" "Porte_rouge".

Tu actives l'héritage et tu as juste à surcharger ( réécrire ) la fonction qui vérifie les conditions du trigger pour que la porte s'ouvre avec une bombe, missile, coup de boule au lieu du tir normal. Tout le reste est hérité automatiquement.

Faut que je lise à nouveau la doc, car la mise en place de la surcharge et de l'héritage est un peu bizarre et mes souvenirs pas très frais.

L'héritage multiple est supporté aussi il me semble.
Si t'as un truc électronique cassé, ça se passe par là https://www.atelier-electrodd.fr/

-Je comprend rien à ce que tu dis...
-Pas grave... C'est pas en vivant plus longtemps qu'on deviens moins con.
Avatar de l’utilisateur
Guts
Modérateur
Messages : 10027
Inscription : 22 mai 2003, 19:02
Localisation : 28
Contact :

C'est quoi le langage utilisé dans Game Maker ?
Toaplan Legendary Series
** Image **
Image
Gunny
Empereur Bydo
Messages : 3404
Inscription : 15 mai 2006, 15:26
Localisation : Rayon chaussettes du Kiabi du coin
Contact :

Le GML.

Un langage de script multi-paradigme ( mais on fait plus d'objet et de procédural que d'évènementiel ).

Ca ressemble à du C++ et du php.

Il bénéficie depuis peu d'un compilateur ( 100$ quand même le compilo quoi ).

La partie orienté objet est tronquée, j'ai pas vu comment faire de l'encapsulation correcte, le système d'héritage et de polymorphisme a une partie tronquée comparée à ce qu'il se fait dans le C++

La partie évènementielle... Je la cherche toujours... On est quand même obligé d'en tenir compte pour le comportement du moteur central.
Si t'as un truc électronique cassé, ça se passe par là https://www.atelier-electrodd.fr/

-Je comprend rien à ce que tu dis...
-Pas grave... C'est pas en vivant plus longtemps qu'on deviens moins con.
Avatar de l’utilisateur
Radigo
Counter Stop
Messages : 7567
Inscription : 22 mai 2003, 17:31
Localisation : Paris
Contact :

Le compilateur est fourni avec GM Studio ? Si oui, c'est 49$ pour une license PC de base (ça monte vite quand on veut faire du Steam, iOS et autres).

Pour l'événementiel, je suppose qu'il s'agit de la partie drag'n drop des paramètres d'objets. On ajoute des événements Create ou Collision, il s'agit en fait d'écouteurs d'événements.

Pour ma part, la partie objet du GML se limite à des variables locales pour mes instances... mais je vais me renseigner sur l'héritage, ça peut servir.
"HYPER GAGE : 500%"
Image
Gunny
Empereur Bydo
Messages : 3404
Inscription : 15 mai 2006, 15:26
Localisation : Rayon chaussettes du Kiabi du coin
Contact :

Le compilo pour produire des exécutables natifs est un module a 300$ !
Autrement, on conserve le système normal de code interprété.

Faut dire aussi que l'EDI commence à fournir pas mal de services et se professionnalise, mais je trouve quand meme certains prix clairement abusés...

Alors que GM s'orientait vers les petits dév à petit budget et débutant, on commence à aborder les prix de delphi et C++builder avec des offres à 800$...
Si t'as un truc électronique cassé, ça se passe par là https://www.atelier-electrodd.fr/

-Je comprend rien à ce que tu dis...
-Pas grave... C'est pas en vivant plus longtemps qu'on deviens moins con.
Répondre