Saturday, August 26, 2023

Apple Bop ?

Une pomme qui vous fonce dessus, ça fait mal. Forcément. Une qui vous tombe sur la cafetière également. Surtout quand elle est aussi grande que vous. Si vous lui tombez, dessus, là, c'est elle qui tombe dans les pommes. En disant ça, j'ai couvert 75% des interactions possibles entre Bilou et les Applemen dans Apple Assault.

If you get an apple on your head, that hurts. If you're thrown an apple in the face, that will hurt too -- especially if the apple is almost as large as yourself. Chances you won't get hurt if you stomp on an apple while falling but that will likely do the apple no good. All these cover 75% of the interactions between Bilou and the Applemen in Apple Assault.

Now, what if Bilou run into an apple. Should he still get hurt ? I know it is the default behaviour in platformers: if Mario runs into a koopa, it gets hurt no matter what direction the koopa was facing. You can only kick a koopa shell if you stomped the koopa first. You can create stories about it like "yeah, as you kicked the koopa, it clawed to the ground, turned back so fast you couldn't react and bite you. You're dead", and by '86 standards, they would work. But does it mean we should continue like that ? Can't we find something more fun ? It's an apple, after all. It's not all covered with deathly spikes!

Mais si c'est Bilou qui arrive dans le dos de la pomme ? Est-ce que le choc devrait aussi lui faire mal (à Bilou) ? dans Apple Assault, la réponse est "oui". Dans la plupart des jeux de plate-formes, la réponse serait "oui" aussi. Un koopa qui bouge, c'est un blesse, qu'on l'approche par-devant ou par-derrière. Mais est-ce que c'est forcément la bonne chose à faire ? Est-ce qu'il n'y a pas moyen d'être plus *fun* que ça ? C'est une pomme, après tout. Pas une chataigne couverte de pics.
En plus, maintenant, il y a un précédent avec les Pendats de School Rush: on est blessé quand ils nous foncent dedans ou quand on tombe sur leur pointe. C'est plutôt logique. on est blessé aussi quand ils font demi-tour, mais de nouveau, vu la violence du mouvement, un mauvais coup est vite parti. Par contre, tant qu'on est dans leur dos, on pourrait presque les pousser, on ne se fait pas mal. Alors si c'est vrai avec des soldats, ça devrait aussi être vrai avec des pommes, non?

When you consider that, in School Rush, pendats -- despite their aggressive and spiky appearance -- will not harm Bilou (only block him) if he comes in their back, it would make the whole game more coherent if we would equally have the back of Applemen harmless. Plus, it could actually be pretty fun to see an Appleman slightly bounce forward on such a collision, as if Bilou had kicked him in the back while walking, and only then actually turning back, being surpised to see Bilou and finally attacking.

Voilà donc ce que j'ai envie de faire pour Bilou: Dreamland (et la green zone dans le futur): si Bilou bouscule un Appleman dans le dos, c'est l'Appleman qui fera un bond et Bilou ne subira aucun dommage ... dans l'immédiat. Parce qu'en revenant sur le sol, l'Appleman fera alors demi-tour et, voyant Bilou, lui foncera dessus (comme il fait depuis 2009). Ce qui n'empêche pas le joueur de sauter par-dessus l'Appleman, peut-être même suffisamment tôt avant que celui-ci ne se retourne, et qu'il ne se rende donc compte de rien. ça,, ça a le potentiel pour être bien fun ^_^

Saturday, August 12, 2023

Swinging animations

Plus le design de Bilou: Dreamland avance, plus la possibilité de s'accrocher et se balancer prend de l'importance dans le gameplay envisagé. Et c'est tant mieux sauf pour une chose: mon moteur d'animations est actuellement très mal adapté pour ce genre de chose. Comprenez, on risquerait plus de se retrouver avec quelque-chose de raide comme Mickey Magical Quest plutôt que les mouvements souples de Fury of the Furries. Ce serait d'autant plus dommage que Spongebop ne souffre pas de ce genre de limitation et que ça rend furieusement bien. Mais voilà, l'image de Spongebop est indépendante de l'angle de sa corde.

The more I sketch some design ideas for Bilou: Dreamland, the more swinging with a rope-like object occurs. I won't claim it will be a primary game mechanic, but it will certainly be an important one. There's just one drawback : so far my game engine offers no support for that kind of animation. Oh, sure, I could go the Mickey Magical Quest way of hard-coding a few frames and the positions Bilou should take to swing, but given that I have a freely-swinging Spongebop in the previous game, I'd prefer go for something like what I've enjoyed in Fury of the Furries: game physics that allows 360° swinging, with free positioning anywhere on the circle defined by the current rope length and almost free extension / reduction of the rope length (Mickey can only climb).

One picture every 10° to swing a tiny
Pour Fury on a pas moins de 36 images différentes et la possibilité de faire un tour complet de son point d'accroche si la physique le permet, soit 10° entre chaque image. Mickey n'offre que 7 images différentes pour un angle de balancier de 90°, soit 15° entre chaque image. La différence devrait être légère (on passe quand-même de 60 fps à 40 fps avec un rapport pareil), mais là où ça change tout, c'est que les angles de la corde elle-même sont discrets à 15° près avec Mickey, dû au fait du hardware 'par tiles' de la super NES. Du coup, les positions de Mickey deviennent elle-même discrètes (bien qu'il puisse remonter sa corde). 

Je me suis donc repenché là-dessus pendant mes p'tites vacances, à l'abri dans mon épave de bateau pirate et j'ai peut-être bien une solution. L'idée serait de compléter les deux modes d'animation actuels (l'un qui suit une ligne du temps, l'autre qui colle à une série de déplacements) pour faire un système dans lequel on va choisir d'avancer ou non dans l'animation selon le vecteur-déplacement actuel. En gros, je fais une animation dans laquelle Bilou se balance autour de sa main et le moteur passera à l'image suivante quand Bilou va dans la même direction que celle suivie par cette image dans l'animation.

The summer idea about it was to handle that with a new way of playing back an animation: rather than enforcing a delay between two frames or a specific motion, we would compare the in-game speed vector (xg, yg) against inter-frame motion vectors (xa, ya). You'd then step to the next frame in the animation only if (xg, yg) is "beyond" the expected motion to the next frame. A bit of maths done in a sandbox (literally) shown that we can tell that just by two integer multiplications per frame. It will need separate animation for swing-to-the-left and swing-to-the-right, but I'm perfectly fine with that.

Mais comment savoir si un vecteur effectif (xg, yg) est plus proche de l'ancien vecteur de l'animation (xa, ya) ou de celui de l'étape suivante (xa', ya') ? Je suis parti de mon vieux cours d'analyse math avec "l'extrémité du nouveau vecteur (xg, yg) doit être au-dessus de la droite définie par k*xa' = k*ya' (que l'on peut réécrire y = (ya' / xa') * x). Mathématiquement parlant, on sera au-dessus si yg > ya' / xa' * xg. Programmatiquement parlant, c'est moins drôle, à cause des divisions par zéro dans les verticales et du manque de précision des divisions / multiplications quand on se contente de travailler avec des nombres entiers. J'ai donc voulu ruser et faire un peu d'algèbre pour passer à yg * xa' > ya' * xg, qui ne fait que des nombres plus grands que 1. En fait, je venais de retomber sur l'expression de l'aire signée d'un triangle, bon vieux truc du cours d'algo II à l'unif (merci, feu PAdM). ça tombe bien: elle sert justement à calculer si un point est à gauche ou à droite d'un vecteur donné.

Il faudra vérifier expérimentalement si je dois modifier le sens de l'inégalité pour le balancier-retour, trouver un moyen d'intégrer ça au scripts (probablement avec un 'speedmove' comme on a déjà un 'selfmove'). La bonne nouvelle, c'est que le même système pourrait probablement marcher aussi pour une voiture vue du haut, des segments de lianes qui se balancent et segments de ponts qui s'inclinent :-P

extra bonus with the anim.x * gob.y > anim.y * gob.x expression, is that a faster motion (e.g. longer rope) or a slower motion (e.g. shorter rope) will not affect things, because it would affect both gob.x and gob.y by an identical factor k and thus their effects will compensate in the comparison.