Accueil Articles Tutoriels Forums
Astuces indispensables pour MMF2
Créé par Zoglu le 01 Oct 2008 à 23:48, dernière modification le 12 Oct 2008 à 20:46
Astuces indispensables pour MMF2 : Comment écrire un code efficace?


Cet article est une traduction/adaptation d'un article écrit sur The Daily Click (le site anglophone incontournable quand il s'agit de création de jeux avec Multimedia Fusion 2, http://www.create-games.com/)par PixelThief. L'article original est disponible ici : http://www.create-games.com/article.asp?id=1937

Il s'adresse aux utilisateurs de Multimedia Fusion 2 ou The Games Factory 2 d'un niveau confirmé. Il faut en particulier connaître le fonctionnement des Fast Loops (boucles rapides) pour comprendre l'article.





Aux yeux de certains utilisateurs, les logiciels Click (The Games Factory 1 & 2, Multimedia Fusion 1 & 2 pour ne citer que les plus connus) apparaissent parfois comme lents et peu efficaces. Les programmes les plus complexes fonctionneront, mais seront souvent d'une lenteur à s'arracher les cheveux. Voici quelques astuces pour accélérer vos jeux et vous faciliter la vie lors de la création de jeux plus approfondis.

Les noms anglais des actions et conditions seront employés ici (les noms français sont souvent des traductions "simples", mais je préfère vous donner les noms anglais pour éviter de me tromper)



1: Fast Loops (Boucles rapides)
En résumé: Mettez le code de vos Fast Loops, individuellement, dans des groupes, et placez des actions "Open Group" et "Close Group" en haut et en bas de l'action "Start Loop". Ceci peut rendre votre programme au moins dix fois plus rapide !

Les Fast Loops dans MMF2 sont lents de nature. Il en est de même de l'objet Fast Loop dans TGF, les Fast Functions... Pour peu que vous utilisiez beaucoup de Fast Loops, la vitesse de votre jeu dégringolera. Voici une astuce (trouvée par Nifflas) qui résout le problème.

Quand un Fast Loop est lancé, MMF2 regarde tous les évènements munis d'une condition "On Loop", puis il les copie plusieurs fois, les lance tous, et retourne à l'évènement qui était muni de l'action "Start Loop". Le détail qui pose problème est qu'il utilise et copie toutes les fonctions munies de la condition "On Loop", même si le nom de la boucle ne correspond pas. Donc au lieu de lire seulement les lignes dont il a besoin, il lit toutes les lignes des Fast Loops en faisant des comparaisons entre le nom du Fast Loop que vous voulez lancer et celui de la ligne "On Loop".
C'est catastrophique en termes de vitesse : si l'on utilise la notation O, à la place d'un O(n) où n est le nombre de Fast Loops dans l'application, cela fait une complexité temporelle en O(n²). Donc avec un Fast Loop, la complexité est juste en O(1), mais pour 20 Loops, cela fait un O(400), ce qui est énorme.

La clé de ce problème réside dans le fait que MMF2 ne regarde que les conditions "On Loop" qui sont dans la liste des évènements actifs. Autrement dit, si les conditions "On Loop" sont placées dans un groupe désactivé, MMF2 ne les lira pas.
Il suffit donc de mettre chacun de vos évènements munis de "On Loop" dans un groupe différent, ne contenant QUE cet unique évènement, et de désactiver tous ces groupes. Ensuite, il vous faudra placer des actions "Open Group" et "Close Group" en haut et en bas de chaque action "Start Loop", qui ouvriront/fermeront le groupe contenant l'évènement "On Loop". La seule exception viendra des Fast Loops qui lancent d'autres Fast Loops, que vous devrez placer dans le même groupe.


Mais dans la plupart des cas, à la place de ceci :

(placez ici vos conditions...)
=Start loop "MonLoop" 100 times


utilisez ceci

(placez ici vos conditions...)
=Activate group "GroupeMonLoop"
=Start Loop "MonLoop" 100 times
=Deactivate group "GroupeMonLoop"



Notez bien que cela sert juste à optimiser le code. Les programmes et jeux qui tournaient lentement à cause des Fast Loops fonctionneront vraiment mieux, tandis que les programmes ralentis à cause d'autres facteurs (chargement de fichiers au démarrage, dessin de graphismes, trop d'objets actifs) ne tourneront pas mieux.



2: Récursivité
En résumé : MMF2 peut faire de la récursivité, grâce aux Fast Loops.

MMF2 est capable de faire de la récursivité, par le biais des Fast Loops. Par récursivité, on entend ici le fait qu'un Fast Loop peut se relancer lui-même, tant que les conditions sont satisfaites. En voici un petit exemple (la scène contient deux compteurs, Compteur1 et Compteur2, qui ont la valeur 0 au début) :


*Upon Pressing "Space bar"
=Start loop "Ajout" 1 times

*On Loop "Ajout"
+Compteur1 < 3
=Add 1 to Counter "Compteur1"
=Start loop "Ajout" 1 times
=Add 2 to Counter "Compteur2"



Lors de l'appui sur la barre espace, les actions vont s'effectuer dans cet ordre :

- Add 1 to Counter "Compteur1"
- Add 1 to Counter "Compteur1"
- Add 1 to Counter "Compteur1"
- Add 2 to Counter "Compteur2"
- Add 2 to Counter "Compteur2"
- Add 2 to Counter "Compteur2"


Notez bien une chose importante (visible dans ce premier exemple) : si MMF2 lance un Fast Loop au beau milieu d'une liste d'actions, il fera d'abord les actions du Fast Loop qu'il vient de lancer puis continuera avec les actions de la liste précédente. Ceci peut causer des problèmes d'appels récursifs infinis, comme dans cet exemple un peu modifié :


*Upon Pressing "Space bar"
=Start loop "Ajout" 1 times

*On Loop "Ajout"
+Compteur1 < 3
=Start loop "Ajout" 1 times
=Add 1 to Counter "Compteur1"
=Add 2 to Counter "Compteur2"



Comme vous pourrez le tester, ça plante, sans aucun message d'erreur.
En fait, MMF2 exécute le Fast Loop une première fois, le compteur ayant une valeur inférieure à 3, et la première action qu'il voit est : "lancer le Fast Loop "Ajout" une fois". Pas de problème, il le lance, le compteur a toujours, une valeur inférieure à 3, et la première action qu'il voit est...
Ainsi, le loop se lancera lui-même plusieurs fois, à l'infini. MMF2 ne pouvant gérer que 8351 niveaux de récursivité (allez savoir pourquoi... en tout cas ce sera sans doute suffisant pour tous vos programmes), le programme finit par planter.

Pourquoi le premier programme n'a-t-il pas planté? Parce que ce premier programme ajoute 1 au Compteur1 AVANT de relancer le Fast Loop "Ajout" ! Ainsi, quand le Fast Loop est relancé, le Compteur1 a la valeur 1, puis 2, puis 3... ce qui met fin à la récursivité.

La récursivité peut se révéler assez utile dans certains cas. A vous d'expérimenter !



3: Lancer des vieux projets (faits avec The Games Factory 1, Click and Create ou Klik and Play)
En résumé : Activez le mode de compabilité Windows 95.

Si vous lancez The Games Factory ou d'autres jeux faits avec ce dernier, les jeux planteront tout comme TGF. Cela vient du fait que TGF a été crée avec les anciennes architectures de Windows, ce qui fonctionne mal sous Windows XP ou Vista. En cliquant avec le bouton droit sur le fichier .exe, choisissez "Propiétés" puis "Compatibilité". Cochez "Exécuter ce programme en mode de compatibilité" et choisissez "Windows 95" dans le menu déroulant. Cela réduira beaucoup le nombre de plantages, même si ils ne seront pas inexistants.
Le problème est que ce mode doit être activé sur chaque ordinateur qui lance le jeu (si vous l'activez, puis que vous mettez le programme sur un autre ordinateur, cela ne marchera plus), donc il vous faudra dire aux autres joueurs d'activer le mode de compatibilité.



4: Effectuer des actions complexes sur toutes les copies d'un même objet actif.
En résumé: Parcourrez tous vous objets avec un Fast Loop, en utilisant des Flags et en en choisissant un au hasard à chaque Loop, pour sélectionner chaque copie de l'objet actif et y appliquer une action.

De nombreux utilisateurs de MMF2 sont souvent confrontés au même problème : leur moteur, assez complexe, n'est applicable qu'à un seul objet à la fois. Ainsi, après avoir fait un mouvement de jeu de plate-forme applicable à un objet, on se rend compte que ça ne marche pas quand le même objet est présent plusieurs fois. Il va encore falloir utiliser des Fast Loops !

Voici un exemple simple, qui devrait vous faire comprendre le fonctionnement de la chose : vous voulez appliquer une même fonction 100 fois aux mêmes objets. Supposons, que votre scène contient 100 ennemis et 100 épées. Vous voulez que chaque épée se place dans les mains de chaque ennemi, par le biais d'une action "Set Position". Avec une action "Spread Value", vous avez donné à chaque Ennemi et Epée une valeur différente pour tous, comprise entre 1 et 100 (pour les indexer).

Le codage suivant peut faire irruption dans votre esprit :


*Alterable Value A of "Epée" = Alterable Value A of "Ennemi"
=Set Position of "Epée" at (0,0) from "Ennemi"



Et que se passe-t-il? Les 100 Epées se placent toutes sur un seul et unique Ennemi. Frustrant, n'est-il pas? En fait, ce sera celui dont l'Alterable Value A est 100, MMF2 choisit juste la dernière copie de chaque objets. Cela vient du fait que la condition qui vérifie la velur d'une Epée et qui la positionne, ne s'applique qu'à un seul objet. Et MMF2 applique donc l'action aux 100 Epées, mais en ne choisissant qu'un seul ennemi en guise de "cible".

Pour résoudre ce problème, il faudra parcourir les 100 objets avec un Fast Loop. Il faut donc créer un Fast Loop qui lancera la même commande, mais qui ne l'appliquera qu'une fois à chaque Epée et Ennemi. Cela se fait ainsi :


*Always:
="Ennemi" : Set Flag 0 Off
="Ennemi" : Set Flag 1 Off

*Always:
=Start Loop "PlacementEpées" NObjects( "Ennemi" ) times
[cela lancera autant de Loops qu'il y a d'ennemis]

*On Loop "PlacementEpées"
+ "Ennemi" : internal flag 0 is Off
+ Pick one of "Ennemi"
="Ennemi" : Set Flag 0 On
="Ennemi" : Set Flag 1 On
[prend un Ennemi au hasard qui n'a pas déjà été sélectionné, (ce qui se voit avec le Flag 0) le "sélectionne" (active le Flag 1) et le marque comme "déjà sélectionné" (active le Flag 0)]

*On Loop "PlacementEpées"
+ "Ennemi" : internal flag 1 is On
* Alterable Value A of "Epée" = Alterable Value A of "Ennemi"
=Set Position of Sword (0,0) to Position of Bad Guy
[prend l'unique ennemi sélectionné, et place l'Epée qui a la même valeur que lui]

*On Loop "PlacementEpées"
="Ennemi" : Set Flag 1 Off
[déselectionne l'Ennemi sélectionné]



Regardons cet exemple.
- Le 1er évènement, dont la condition est "Always", remet les Flags 0 et 1 de tous les Ennemis à Off. A noter que le Flag 1, à ce moment, n'est de toute façon jamais en On.
- Quand les Flags sont remis à Off, on lance le Fast Loop 100 fois.
- On regarde la liste de tous les Ennemis de la scène. Parmi ceux que l'on n'a pas encore sélectionnés (ceux dont le Flag 0 est en Off), on en choisit un (en activant son Flag 1)...
- ...et on place l'Epée qui lui correspond à sa position...
- ...puis on le désélectionne (en désactivant son Flag 1) mais on se souvient qu'il a déjà été sélectionné (via son Flag 0).

On répète ces actions jusqu'à ce que tous les objets aient été sélectionnés. Aucun objet ne sera sélectionné deux fois, et tous seront sélectionnés.

D'une manière générale, vous pouvez construire votre code à partir de cette base :


*Always:
="Actif" : Set Flag 0 Off
="Actif" : Set Flag 1 Off

*Always:
=Start Loop "MonLoop" NObjects( "Actif" ) times

*On Loop "MonLoop"
+ "Actif" : internal flag 0 is Off
+ Pick one of "Actif"
="Actif" : Set Flag 0 On
="Actif" : Set Flag 1 On

*On Loop "MonLoop"
+ "Actif" : internal flag 1 is On
(placez ici vos conditions...)
(...puis vos actions)

*On Loop "MonLoop"
="Actif" : Set Flag 1 Off




5: Commentez votre code !

Renommez les variables de vos obejts (et les objets eux-mêmes), organisez votre code dans des groupes, et mettez des commentaires expliquant qui fait quoi. Quand vous travaillerez à nouveau sur votre jeu un an après, vous vous souviendrez du fonctionnement du code. Ces complications dans le code sont surtout dues à l'absence de "fonctions" dans MMF2.
Mais organisez bien votre code, cela vous permettra de gagner beaucoup de temps.