samedi 4 septembre 2010

Dev d'un GTD

Depuis que j'ai décider de coder mon moteur de jeu, il m'arrive la même chose qu'avec beaucoup de projets : la motivation du début tombée, je n'y touche plus.

C'est un beau problème psychologique commun que j'ai là. Heureusement, il y a des solutions qui existent.
En parcourant le net avec des mots clef du genre "motivation" "procrastination", je suis tombé sur pas mal d'articles donnant des conseils visant personnes à tendances dépressives. De très bon conseils la plupart du temps, que j'applique souvent déjà depuis longtemps. Mais le conseil le plus intéressant et récurrent que j'ai pu trouver est celui d'utiliser une technique Getting Things Done (GTD).

Bon OK. Pour un geek comme moi le meilleur moyen d'appliquer ca est d'utiliser mon ordinateur. Et donc on tombe sur pas mal de logiciels, du genre Remember The Milk.
Problème: j'ai déjà utilisé ce logiciel et déjà tenté de résoudre mon problème avec. Ca n'a pas du tout marché. Le problème, c'est qu'il faut se fixer soi-même des dates limites. Généralement, les dates limites marchent bien avec moi. Sauf que la façon dont je les gère est celle d'utiliser le stress généré par l'approche de la date pour me motiver à bosser. Et je stresse car j'ai des ennuis si jamais je ne fait pas ce qui est à faire. Donc quand c'est moi qui me fixe une date limite, qui plus est sur un projet totalement personnel (le moteur 3D ici), la date n'a donc aucun sens et je finis par n'avoir rien fait.

Donc je me pose un instant pour réfléchir. Ce que je veux, ce n'est pas rendre quelque chose mais faire quelque chose. Donc avoir un système qui me dise de devoir faire telle ou telle tache tel ou tel jour. Un emplois du temps quoi.

Et si au final je ne fait pas la tache? Je n'ai pas envie que cette tâche soit reportée tout comme c'est le cas avec Remember The Milk. De plus, si elle reportée avec l'état "en retard" et qu'elle s'accumule avec toutes ses jumelles suivantes, tout cela perds encore de son sens et je finis par effacer toutes les taches et oublier le projet.

Donc je veux une tache récurrente, qui puisse être ratée, même complétée à un certain pourcentage. Voilà ce que ca a donné!


Code couleurs des tâches :
- Vert : pas à faire ce jour là
- Bleu : complétée à 100%
- Orange : entre 20% et 80%
- Rouge : en dessous de 20% (ratée)
- Cyan : A rapporter

On se rend compte que je n'ai pas beaucoup bossé sur le projet depuis longtemps ... Mais j'ai une bonne excuse, c'était justement pour programmer ce GTD.
En tout cas, le résultat est probant pour le ukulélé! J'ai énormément progressé cette semaine. Sauf que raconter ce détail sort du contexte du blog.

jeudi 19 août 2010

Avancement

Une note rapide pour présenter l'avancement du projet :

Rien de mieux qu'une image pour expliquer ça. Les classes entourées de bleu représentent celles avec un début d'implémentation. Cette couleur signifie que l'idée générale du rôle de la classe et son interface est présente dans le code, donc rien de complet, juste "prêt à être rempli".
D'autres couleurs sont à venir pour représenter un meilleur avancement, donc! Et puis le diagramme lui même peu changer parfois.
Ce qui est sûr, c'est qu'on se rend bien compte qu'il faut beaucoup de boulot pour achever tout ça. Car même ce petit bout d'avancement nécessite du temps.

Mes prochains objectifs sont:
- Implémenter quelques classes de graphismes
- Implémenter les classes InputDispatcher et InputUpdated
- Afficher deux ou trois cubes et pouvoir en contrôler un!

Ca demandera donc au minimum huit nouvelles classes. Ca fera donc probablement seize nouveaux fichiers. Raah, c'est pas le plus marrant d'écrire juste de la structure. Et ca prend du temps également. Allez, une grande inspiration et puis je m'y met.

mardi 17 août 2010

Moteur de jeu 3D

Allez hop-là un nouveau message ... parce que j'ai envie. Non pas que je suspecte ce blog de revenir à la vie mais bon, y'a des jours comme ca, on est d'humeur à faire des updates.

En réalité, la seule raison qui me pousse à faire ça est que je me suis remis à la programmation. Les examens de Teesside étant terminés depuis longtemps, la glandouille des vacances n'étant pas applicable (en plein mois d'Août, ah bon?), peu de choses sont donc en travers de ma route pour que ma motivation s'épanouisse.

Pour faire court, j'ai commencé un nouveau projet. Un moteur de jeu 3D, rien que ça. Ceci n'étant pas une mince affaire, j'ai d'abord commencé par m'organiser un minimum. Alors j'ai produit ce diagramme de classes :


Pour les curieux ignorants, c'est fait avec le logiciel StarUml.
Les normes UML ne sont pas totalement respectées, il y aura certainement plus de classes que ça au final, mais l'idée générale est présente.

La plupart des composants habituels sont là pour un moteur 3D standard. On distingue plusieurs groupes :
- Le coté matériel
- Les graphismes
- L'acquisition de données
- Le monde virtuel

Il ne pas confondre le matériel vidéo et les graphismes ici (même principe pour le son et input). Les classes "device" sont là pour faire abstraction du système utilisé. Pour "VideoDevice" par exemple, j'utiliserais certainement OpenGL. Mais il pourrait être remplacé par n'importe quoi, comme DirectX. Les classes de graphismes utilisent seulement la même interface.

Là où ça devient curieux, c'est que les graphismes sont actualisés (héritent de la classe "FrequentlyUpdated") en dehors du monde virtuel. J'ai voulu séparer clairement ces choses là. Et c'est même plutôt logique d'après moi. Mais il faut quand même qu'ils affichent quelque chose, d'où l'idée d'une classe "Feedback", qui contiendrait tout ce qu'il y a à savoir sur le coté visuel de ce monde virtuel.
Voilà un petit diagramme pour mieux comprendre :


(là pas de secret, c'est fait avec Paint)

Ca a l'air on ne peut plus logique non? C'est un cycle symétrique! (j'invente, ca sonne bien) . Le principe "une entité communique avec le monde" en ressort. L'intelligence est séparée de la réalité. L'intelligence stimule la réalité et la réalité stimule l'intelligence en retour. "L'intelligence" ici étant une entité, comme le joueur ou une IA.
Malgré mes faibles connaissances de communication réseau en temps-réel, je vois là le potentiel d'adapter facilement ce système pour du multijoueur en ligne.

Bon mine de rien je m'emballe un peu. Je suis certainement en train de réinventer la roue, comme toujours. Sauf que je n'ai pas vraiment lu, vu ou entendu quoi que ce soit qui ressemble à ce principe de "feedback". Si vous lisez ce post et que vous connaissez un quelconque article traitant de cette idée, faites-le moi savoir!

lundi 25 janvier 2010

Portage du jeu et anecdote

Cela fait un petit moment déjà que je n'ai pas posté de nouveau billet.
La raison est que j'ai n'ai pas vraiment de nouvelles choses à dire, si ce n'est que j'ai travaillé énormément sur mon projet GS1. Il est terminé, c'est sûr, mais dans le cadre des études. Je n'ai ajouté aucun élément de gameplay ou autre fonctionnalité, loin de là.

Non, le plus intéressant est que maintenant il marche totalement avec SDL comme librairie graphique, et FMod pour les sons. Le renderer software est toujours présent et marche parfaitement avec SDL (sauf que ce n'est certainement pas codé proprement, j'ai eu la flemme de faire les appels aux fonctions lock surface pour écrire directement dans le buffer).

J'ai également amélioré le renderer software en ajoutant les plans de clipping de la caméra. Ca a permis de supprimer quelques bugs d'affichage de triangles, produisant des aberrations dans le depth buffer parfois (par exemple, dans the death corridor, si vous vous collez sur les bords vous remarquerez que les murs s'affichent partiellement par dessus le vaisseau avec une forme ronde). J'ai d'ailleurs une anecdote intéressant sur le sujet :
Au départ, j'ai voulu trouver une solution pour le clipping moi même (comme toujours, j'ai envie de réinventer la roue. C'est dans quel contexte déjà? Ah oui! Je fais un renderer 3D en software ... réalisé un millier de fois par un million de personnes depuis déjà 20 ans au moins). J'avais beau retourner le problème dans tout les sens, le clipping semblait fonctionner mais certains polygones disparaissaient toujours mystérieusement ... A force de tourner en rond je finis par m'avouer vaincu et décide d'adopter une méthode déjà existante : l'algorithme de clipping de Sutherland Hodgman. Je l'implémente, tout fier de moi, et j'obtiens le même résultat! En fait mon propre clipping marchait parfaitement, c'est juste que j'avais oublié un détail en dehors de cet algorithme. Mon code ressemblait à ca:
récupérer le triangle T à afficher
appliquer la matrice de transformation à T
clipper T pour obtenir un polygone P
appliquer la matrice de projection à T
test du backface culling en fonction de T
...
appliquer la matrice de transformation à P
afficher P
Vous voyez le problème? Un indice : les aberrations surviennent lorsque la projection est appliquée sur des points situés hors caméra. Toujours pas? Autre indice : le backface culling vérifie si un triangle doit être affiché ou non (mon problème vient de polygones qui ne s'affichent pas). Je saute quelques lignes pour éviter de spoiler la réponse ;)
















Le problème était que je testais le backface culling avec T, non clippé, qui pouvait donc avoir des valeurs totalement fausses après l'application de la matrice de projection. La solution consistait donc à ignorer totalement T cette fois (car d'autres calculs étaient faits dessus) en le remplaçant par l'un des triangles que compose P .

Le clipping en lui même marche bien maintenant, mais il nécessite encore quelque optimisations. Le fait est que j'implémente l'algorithme de Sutherland-Hodgman avec des std::list. Du coup pleins d'allocations et désallocations mémoire en plus de copies inutiles sont effectuées. Ce qui donne un fort ralentissement lorsque la caméra passe à l'intérieur d'un polygone (au début de fighting above the earth). Mais le soulagement d'avoir enfin trouvé et réparé ce bug, précédé par quelques crises de nerf, m'ont incité à passer à autre chose :

Le portage du jeu vers OpenGL.
Cette fois, je garde SDL comme base, mais je remplace toutes mes opérations de rasterisation et calcul de matrice fait main avec des appels à l'API. Le plus dur n'est pas vraiment savoir quoi utiliser, mais plutôt savoir quels réglages appliquer pour obtenir le bon affichage. Voilà l'état d'avancement en images :

L'affichage de mes modèles fonctionne correctement, le chargement des textures aussi (sauf que c'est mal paramétré dans ce cas là donc on ne voit rien, juste un carré blanc pour les astéroïdes). Mes astéroïdes sont affichés en tant que billboards (ce qui fera certainement l'objet d'un prochain billet), et il reste à ajouter l'éclairage. Enfin, je n'aurais plus qu'à remettre en place le fond étoilé puis la planète et le tour sera joué.

Quand le portage OpenGL sera effectué, je tenterais de porter tout ca sur DS! Je suis trés confiant pour OpenGL, mais en ce qui concerne la DS, j'ai beaucoup de choses à apprendre et ca risque de prendre beaucoup de temps. Mais j'avoue que voir son propre jeu en 3D tourner sur sa petite console est une grande motivation.

vendredi 15 janvier 2010

Shooter 3D

Et le voilà! L'aboutissement du module à Teesside, Game Software Development 1.
Comme je vous l'ai dit à propos du moteur 3D sur un post précédent, j'ai développé un jeu 3D pour un projet qui en demande un en 2D et interdit toute librairie graphique. C'est comme ca que j'en suis venu à faire un moteur 3D en software.

Donc voilà le résultat!





Si vous devenez ultra fan de ce jeu, jetez un oeil aux fichiers xml, et si vous en comprenez le fonctionnement vous pourrez créer vos propres niveaux. Bon ok il faudra faire ça à la main mais ça peut devenir amusant.

Par ici pour le télécharger

samedi 9 janvier 2010

Génération procédurale : Perlin

Tout geek dans la programmation jeux vidéo qui se respecte doit forcément en venir là un jour : la génération procédurale.
Premièrement, ca simplifie et accélère le processus de création dans un jeu vidéo. De deux, ca consiste seulement à utiliser de la programmation pour prétendre qu'on est créatif. De trois, "génération procédurale" ca sonne bien et ca donne l'air intelligent.

Le point de départ lorsqu'on s'intéresse à la génération procédurale, c'est Perlin. Vous n'allez peut-être pas le croire, mais même si son nom ressemble à un de ces vieux grecs (Thalès, Pythagore...) qui sont toujours aussi utiles de nos jours, Perlin lui, n'as pas 2000 ans d'avance. Il est même encore en vie.

Ce qu'il nous a apporté, c'est le bruit de Perlin. C'est à dire une fonction aléatoire pas si aléatoire. On peut dire aussi du bruit cohérent. Bon alors c'est quoi la différence entre un bruit non cohérent et un autre qui l'est? Rien de mieux qu'une image pour expliquer:

Une belle texture pour un nuage!
Ca peut également servir de heightmap.
Avec ça comme base, on peut générer des tas d'autres choses.

Vous voulez faire pareil?
Alors vous aurez besoin de la fonction de bruit de Perlin, ici sur son site. Attention, ça ne donne pas le résultat nuage que je vous ait montré.
Pour avoir ce résultat, il faut combiner plusieurs bruits de perlin. Ici il y a un tutorial qui explique bien comment faire.

Attention! Si vous voulez utiliser la fonction du bruit de perlin, celle qui est donnée sur son site retourne une valeur entre -1 et 1. Alors que pour produire une image les composants red green et blue sont entre 0 et 255. L'erreur serait de multiplier uniquement par 255, mais ca donnerait quelque chose entre -255 et 255. Soit ca fait bugger votre programme, soit vous obtiendrez une image avec des zones noires uniformes (car les valeurs entre -255 et 0 sont transformées en 0).



Pourquoi je vous parle de ça? En 3GS on a commencé les textures générées procéduralement, et comme je vous l'ait dit, il faut bien commencer par le commencement. Et donc chez moi ça donne ceci :