Thursday, December 10, 2009

Descente (aux enfers ?)

J'ai beau avoir pris le temps de tester conceptuellement et méticuleusement le petit algorithme de gestion des pentes que je présentais la semaine dernière, je me bats toujours avec mon code pour l'intégrer au game engine.

Le plus intéressant dans ce combat, c'est sans doute que jusqu'ici, aucun des problèmes ne provient directement de l'algorithme ...

Détails du Standard
J'en parlais tout dernièrement: prendre pour acquis et "standard" un comportement que l'on a rencontré sur une plate-forme est une erreur facile à faire pour qui utilise le C ou le C++ dont la définition est pleine de "comportement indéfini" ou (pire?) "définis par l'implémentation".

Interaction avec l'ancien code
En particulier, le système qui contrôle le déplacement pas-à-pas et les test-points contrôlés par les animations peuvent conduire à des décisions contradictoire du système de contrôleurs qui appelle doslopes(), d'où l'introduction d'une commande "move x *" pour ne placer une contrainte que sur le déplacement horizontal et laisser le déplacement vertical libre.

Fournir les bons arguments
L'algorithme reçoit vitesse et position en pixels. Dans mon moteur de jeu, pourtant, certains éléments travaillent en 256emes de pixels (pour mieux gérer les vitesses) et d'autres directement en tiles. Le système de types de C++ étant ce qu'il est, on a vite fait de prendre l'un pour l'autre et d'avoir une implémentation incorrecte parce qu'elle essaie instantanément d'envoyer le joueur à l'autre bout du niveau au lieu de le faire monter d'un pixel.

Le code de base n'était pas prêt !
Comment ça, la pente gauche et la pente droite ont les même propriétés ? Et le bloc semi-perméable ne laisse pas passer les monstres ?

Je ne serais pas surpris que ce soit le genre d'erreurs que rencontrent couramment ceux qui programment "en entreprise" et doivent déployer telle ou telle nouvelle solution dans une base de code pré-existante assez large. J'en suis réduit à "sortir l'artillerie lourde" :

  • d'abord vérifier que le nouveau code ne pose pas de soucis au éléments plus anciens (est-ce que les 2 niveaux fonctionnent correctement si je n'y mets aucune pentes ?)
  • construire un test-case minimal (un seul appleman, placé directement au bord d'une pente)
  • suivi méthodique de l'exécution (ddd avec du code -O0, placer des breakpoints dans toutes les fonctions succeptibles de modifier l'état de l'appleman, inspecter le "stack trace" pour comprendre pourquoi ces modifications d'état se sont produites).
  • Corriger "à la volée" les calculs erronés ("set value ..." dans ddd) pour poursuivre le déroulement du programme le plus loin possible sans passer par un nouveau cycle de compilation (j'avais plus fait ça depuis Crazy Brix, tiens !)
  • Procéder par élimination. "Une fois l'impossible éliminé, ce qui reste -- même improbable -- est forcément vrai, mon cher Watson".
Encore un peu de patience, donc. Quand les causes seront parfaitement identifiées, il restera à chercher une manière élégante d'intégrer les nouvelles contraintes au moteur de jeu ...

No comments: