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
v0
est la vitesse horizontale etv1
la 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 (:1
signifie "é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.
1 comment:
bon, 15 ans plus tard, l'éditeur graphique de comportements sur DS n'est toujours qu'un doux rêve :P
Post a Comment