J'avais envie de mettre côte à côte "comment je me représente le comportement de Funky Funghi" et "comment je réalise ce comportement avec mes outils actuels.
state12 :anim15 {
using stopper
}
state13 :anim6 {
using gravity(24,1536);
testpoint off (16,32)
}
state12->state13 on done [t] (v4 0 = 200 * 500 + ~ :1)
state13->state12 on fail [t] (v4 1 + 4 % :4 0 :1)
[square brackets]) and an action that alters the object before it enters its new state.
Voilà donc à la fois un "mockup" futuriste de l'éditeur de monstres sur DS et le genre de script que je bricole en attendant pour quand-même avoir des monstres qui se balladent dans mes niveaux. Histoire que vous suiviez :
- Funghi a deux états: au sol (
12) ou en saut (13). Ca me permet notamment d'avoir une animation spécifique à l'état "au sol" et synchroniser la "déformation" du sprite avec la collision au sol (chose dont le RSD Game-Maker était incapable). - Comme tous les objets que j'ai jusqu'à présent, Funky Funghi respecte la convention que
v0est la vitesse horizontale etv1la vitesse verticale. A priori, ces valeurs sont gérées par le contrôleur et utilisées par la classe SimpleGob pour mettre les coordonnées à jour. Elles sont aussi accessibles dans la machine d'état (:1signifie "écrire la valeur dansv1) - Chaque "gob" possède 12 compteurs sous son entier contrôle. Funghi utilise le premier d'entre-eux (
v4) pour compter ses rebonds. "v4 1 + 4 % :4" est une expression post-fixée (pensez 'calculatrice HP' qui doit se lire "prendv4, ajoute 1, calcule le reste de la division par 4 et stocke le résultat dansv4à nouveau". Ce calcul est effectué chaque fois que Funghi entre en contact avec le sol.
2 3 +, as on a HP calculator). Hopefully, the existence of predicates allow me to compensate the lack of conditional expressions in actions by multiple transitions, each with a predicate and a separate action. See the code below, it's actually clearer (sort of) with similar efficiency.
A la fin de l'animation "déformation", la nouvelle vitesse verticale est définie. "500 ~ :1" donnerait à chaque fois la même implusion (~ est utilisé ici pour prendre l'opposé d'un nombre, donc v1 reçoit -500 ... eh non, je n'ai pas implémenté les constantes négatives. Sue me).
Pas d'expressions conditionnelles genre "si(test, réussi, échec)" comme on en trouverait dans Excel ici (ou test?réussi:échec pour les programmeurs); c'est une restriction délibérée, et sans doute la plus contraignante de mon évaluateur d'expressions jusqu'ici. Or, je dois décider de fixer la vitesse après rebond à 700 ou 500 selon qu'on est au 4eme saut ou pas. Ma première approche était de tenir compte du fait que v4 0 = teste la valeur du compteur de rebonds et laisse 0 ou 1 sur la pile selon le résultat, et de jouer sur la multiplication absorbante : t 200 * 500 + vaut 700 quand t=1 et 500 quand t=0. D'où v4 0 = 200 * 500 + ~ :1.
En fait, il y a plus simple puisqu'à défaut d'expressions conditionnelles, j'ai séparé prédicats et actions. Rien ne m'empèche donc de réécrire la machine d'état sous la forme suivante:
Alors oui, bien sûr, c'est horrible à relire. L'idée n'est évidemment pas d'obliger l'utilisateur final de GEDS à écrire des expressions de ce genre-là, mais plutôt de se donner un "langage intermédiaire" (un bytecode, quoi) comme résultat d'un éditeur de monstres plus graphique.state12->state13 on done [v4 0 =] (700 ~ :1) state12->state13 on done [t] (500 ~ :1) state13->state12 on fail [t] (v4 1 + 4 % :4 0 :1)
J'aurai donc quand-même mis un an entre "l'idée sur papier" et le protoype qui tient la route pour la définition des contrôleurs (bon, j'ai fait d'autres trucs entre-temps, évidemment). Et l'intégration des "test de possibilité de déplacements" dans le contrôleur (reléguant les testpoints au rang de sophistication optionnelle) n'est pas la moindre des décisions.



Bon. J'aurais été en C, j'aurais ajouté "GOB* prev=0; GOB* next=0;" dans ma structure et on en aurait plus parlé. Mais je suis en C++. Mes sprites (Graphic OBjects) doivent être listés par "caste" (héro ou vilain) pour les tests de collisions et je cherchais désespérément une manière simple d'effacer un élément donné d'un vecteur C++ dans le desctructeur. Je dis bien "simple", donc
La prison, "retaillée" pour DS
Le manoir, "retaillé" également à l'exception de Badman







Vote for your favourite post

