Coincé entre deux générations de "game engine" de la série commander keen, on trouve un jeu étrange, faisant presque figure de "lost levels": Keen Dreams. Une grande part du design global de l'excellente série "Goodbye Galaxy" est présent: décor en perspective cavalière, personnage de 40 pixels de haut, environnements variés et son SoundBlaster. En revanche, keen se promène en pijama et en pantoufle et ne dispose ni de son neurolaser, ni de son célèbre pogo. A la place, Keen peut lancer en cloche des mines transformant les ennemis en fleurs à leur contact. Le gameplay demande donc beaucoup plus de précision que dans les autres épisodes, d'autant plus que les ennemis ne resteront pas transformés éternellement. Ça n'est pas sans rappeler le lancer de taille-crayon dans Bilou, je l'avoue, mais si je vous en parle, c'est surtout à cause de ses sources, ajoutées sur github début septembre, et que je suis occupé à analyser. Les sources sont essentiellement en C avec quelques blocs d'assembleur en ligne, chose plutôt rare pour l'époque.
Bien sûr, j'aurais préféré que Javier et Chuck nous proposent le code de Goodbye Galaxy, notamment à cause de l'absence de pogo dans cet opus, mais c'est le premier Keen à proposer des pentes, ce qui n'est déjà pas si mal.
N² with high N could turn Nightmare. |
scaninfoplane
et HandleInfo
). Les monstres de l'ensemble du niveau sont conservés dans une liste liée, mais seuls sont "actifs" ceux qui sont assez proche dans l'écran. Leurs collisions sont gérées par un parcours imbriqué de la liste (N²) -- rien d'équivalent à mon système de "castes", donc -- mais vu le nombre réduit de monstres par écran dans le level design, celà ne pose pas de réelle difficulté, sauf peut-être dans le niveau des vignes. Funny enough, although everything may have its own contact() function and both are invoked when two objects come in contact, there is no passive/active role... yet, monsters typically don't use their contact() function at all, and whether Keen should die or be granted more points is all encoded in Keen's own contact() function, and contact() function for the flower-power seeds has knowledge of which monster can be stunned and which object shouldn't be affected.
Casts make it linear and scalable |
Ça vaut aussi la peine de regarder de plus près le système des "ticks" qui règle le comportement des personnages. Ce type de code est le plus souvent absent sur console. La vitesse du CPU est connue et la mise à jour de l'image à l'écran assez rapide vu la structure choisie pour le processeur graphique. Mais on est ici sur (vieux) PC, avec une vitesse quelque part entre 6 et 40MHz pour le processeur principal et un système de rafraîchissement de l'écran passablement complexe. Le jeu ne tournera certainement pas à 60 images par secondes, ni même à 30 ou à 12. On aura plus que probablement un temps de rendu (entre l'instant où la logique du jeu a fini sa mise à jour et le moment où la nouvelle image est effectivement visible à l'écran) variable.
StateMachine()
function then compensates by stepping the characters by (xspeed,yspeed) the appropriate number of time, invoking the think() function when needed. Rather than experiencing slow downs, we'd experience a drop in the frame rate, but no kid on earth would complain about that from a sharewareL'idée (toujours présente dans les Quake modernes, pour ce que j'en sais) consiste à mesurer le temps qui s'est écoulé depuis la dernière demande d'affichage et à exécuter k "pas" (les ticks) de la logique de jeu, où k * durée_d'un_pas = temps_écoulé. Ainsi, la fluidité varie mais le timing du jeu reste constant et on ne perçoit pas de réel "ralentissement". Ce qui témoigne de la qualité du design, c'est le fait que le code du comportement des personnages peut être écrit sans devoir se soucier de ce mécanisme: les fonctions DoActor et StateMachine prennent intégralement ce comportement en compte et sont capables de gérer une transition d'état au milieu du laps de temps à simuler sans pour autant faire N appels aux fonctions think() des personnages. Autre élément qui se retrouve aussi dans les FPS d'ID software: la fonction "think" n'est pas forcément appelée à chaque moment. Selon les besoin, elle peut être invoquée sur les étapes d'animations, à intervalle régulier ou aléatoire.
Dernier traît intéressant dans les grandes lignes de l'organisation du code: la fonction think() d'un personnage ne se préoccupe généralement pas des collisions avec les murs. Elle se contente de lire l'état du jeu et de décider de la direction/vitesse/animation à suivre. Une deuxième fonction, react(), associée elle aussi aux états du personnage, sera appelée après que le déplacement ait eu lieu et s'occupe d'aligner un personnage qui aurait rencontré un mur. J'y reviendrai dans le volet prochain.
1 comment:
C'est plus parlant que directement Githlub ;)
Post a Comment