15 février 2010 - 14:27

Vite Dit

  • Readability, un bookmark à garder en barre personnel pour rendre les pages web plus agréables à lire
  • La grande liste des intrigues de JdR, ça sonne comme une caricature mais c'est plutôt complet
  • Un tutoriel très efficace sur le bloom dans le rendu 3D... Ha non c'est bien une caricature ce coup-ci
  • Séquence nostalgie pour beaucoup

Du léger pour cette semaine :)

Publié dans : | Laisser un commentaire »

8 février 2010 - 16:53

Brêve

  • Les jeux d'infiltrations existent-ils ?
  • Parfois ce qui va sans dire va mieux en étant dit
  • Un pas à pas d'illustration numérique qui m'auras motivé à me remettre au dessin
  • "nous seront enfermés dans des clichés socio-culturels"

Publié dans : | Laisser un commentaire »

5 février 2010 - 12:59

Lecture : L’intelligence et le calcul

L'intelligence et le calcul : De Gödel aux ordinateurs quantiques
par Jean-Paul Delahaye

Publié en 2002, ce livre aborde de nombreux domaines, des graphes à la théorie des nombres en passant par la physique quantique, la cryptographie et même des notions plus philosophique comme l'intérêt des résultats mathématiques ou la simulation de la conscience. C'est une vrai mine d'or à informations, tout y est bien expliqué avec une légère pointe d'humour qui compense la difficulté de lecture progressive.

Le livre est un regroupement d'articles ce qui le rends assez facile à lire, j'ai juste un petit reproche à faire sur le chapitre expliquant le théorème d'incomplétude de Gödel qui est placé après plusieurs articles y faisant référence (on se retrouve à googler tant bien que mal des théories qui sont très bien expliquées quelques pages plus loin).

Accessible pour un étudiant post-bac interessé par les sciences, ce bouquin couvre de nombreux domaines et ouvre la voie à pas mal de réflexions. En somme, un joli ouvrage qui vaut ses 23€, à lire ou à offrir.

Publié dans : , , | Laisser un commentaire »

2 février 2010 - 16:57

Vite Dit

  • Le post-mortem du Monde Des Ronrons, un jeu indé, français
  • Bastard Tetris, le Tetris qui sait quels pièces vous voulez... et donne celles que vous ne voulez pas
  • 62 logos basés sur la typo, joli et inspirant
  • Une présentation au Siggraph 2009 d'ID Tech sur leurs techno de meta-texture

Publié dans : | 2 commentaires »

1 février 2010 - 17:43

Hiérarchie de modules pour une bibliothèque C

A la conception d'une bibliothèque C-OCaml, j'ai voulus mettre en place des moyens d'y accéder en C via une simulation de hierarchie/modules du genre : MonModule.maFonction. Je savais que c'était possible avec des structs mais impossible de retrouver l'article à ce propos, voilà donc une technique simplissime pour le faire, tout se passe dans le .h principal :

On définit les différents pointeurs sur fonctions qui nous serons utiles :

typedef void (*t_func_void) ();
typedef int (*t_func_int) ();
typedef double (*t_func_double) ();
typedef char (*t_func_char) ();

typedef double** (*t_func_doublestarstar) ();
typedef SDL_Surface* (*t_func_sdlsurf) ();

Puis on définis les structures

typedef struct __Image {
t_func_doublestarstar diamondSquare;
t_func_doublestarstar perlinNoise;
} _Image;

typedef struct __Tools {
t_func_doublestarstar bigArrayToMatrixDouble;
t_func_void printMatrix;
t_func_sdlsurf imgFromMatDouble;
t_func_int saveImg;
} _Tools;

Ne reste plus qu'à "instancier" les structs :

static const _Image Image = {unefonctiondiamondSquare, unefonctionperlinNoise};
static const _Tools Tools = {unefonctionbigArrayToMatrixDouble, unefonctionprintMatrix, unefonctionimgFromMatDouble, unefonctionsaveImg};

J'ai préfixé les fonctions par "unefonction" pour souligner la différence entre le champ de la structure et les fonctions qu'on lui donne mais on peut conserver les même noms, ça ne pose pas de problème et ça évite d'alourdir son code. Ça foire pas mal en utilisant des floats par contre (des Warnings de fonctions mal définie à la compilation,...).

Merci à Sébastien pour m'avoir montré la démarche.

Publié dans : , , , | 2 commentaires »

27 janvier 2010 - 19:52

PyRatp, pour ne plus louper son bus

Article mis à jour de l'ancien site.
Avec mon installation sur Paris pour mes études, j'ai aussi découvert un nouveau genre de transport en commun, le Bus Quantique : Le principe est similaire à celui d'un bus classique excepté que sa présence reste toujours fortement aléatoire.

L'arrêt en bas de chez moi ne possède pas de panneau d'affichage, et le suivant est à 5 minutes de marche, c'est frustrant de subir le dilemme "j'y vais et je le loupe ? Ou je reste et j'arrive en retard ?"

Par chance la Ratp propose de consulter les prochains passages des bus via internet. Ni une ni deux, voilà un petit script Python qui récupère les temps de passage et émet une alerte à un certain seuil histoire de ne pas avoir à s'habiller avec un doigt sur la touche actualiser de son navigateur.

J'utilise WConio pour nettoyer le prompt Windows et winsound pour émettre un beep, mais le script est prévu pour tourner sur n'importe quelle plateforme. Pour ajouter ses bus il faut ajouter les adresses des pages de passage directement dans le script avec un éditeur notepad (c'est super simple, ligne 111, dans le __main__). La Ratp utilise un vieux système de cadre pour son site (c'était trop beau), pensez a faire clic droit, afficher ce cadre uniquement pour récupérer autre chose que 'ratp.fr' en guise d'url.

PyRATP (Visible dans la suite de l'article)

Lire le reste de cet article »

Publié dans : , , , , | 2 commentaires »

25 janvier 2010 - 16:50

Vite Dit

  • Débugger notre manière de penser ?
  • Al.Chemy, un outil de griffonnage expérimental et intéressant
  • Une conférence avec l'inventeur de Twitter
  • Une vidéo symmmmmmpppppaaaaaaaa....

Publié dans : | Laisser un commentaire »

21 janvier 2010 - 22:15

Procédurons : Villes

La génération procédurale consiste à produire du contenu via des algorithmes ce qui permet de créer rapidement beaucoup de données. La plupart des Roguelikes par exemple ont un monde généré entièrement en procédural. C'est d'ailleurs le blog du journal d'Elderlore, un Roguelike en Python qui m'a mis les pieds dans ce domaine avant que la densité de Dwarf Fortress ne m'achève.

J'ai réussi à en faire le sujet de mon projet scolaire de l'année ce qui me permet de fait, d'avoir plus de temps pour travailler dessus, voilà aujourd'hui ma première expérimentation :

Le but était de se baser sur une carte d'altitude pour produire un système routier cohérent, pour ce faire j'utilise des agents qui se déplacent le long du terrain :

Chacun d'eux possède une direction ω, un angle de variation Ω, une durée de vie L et un coefficient d'intersection I et Random() génère des nombres pseudo-aléatoire entre 0 et 1.

A chaque pas de la génération, ils choisissent la prochaine position la plus avantageuse en essayant de conserver leur direction et de limiter les variations d'altitudes suivant l'équation :

Valeurs = D \times ( \Delta_{Denivele} \times K_{1} + \Delta_{Angle} \times K_{2})

Avec

  • \Delta_{Angle} = \frac{\omega_{actuel} -\omega_{point etudie}}{2\pi}
  • \Delta_{Denivele} = altitude_{actuel} - altitude_{point etudie} (sur une heightmap de valeurs entre 0 et 1)
  • D la distance euclidienne entre la position de l'agent et le point étudié (1 ou \sqrt{2} en principe)
  • K_{1} et K_{2} des coefficients fixés arbitrairement (20 et 1.3 dans la plupart de mes tests)

L'agent choisis donc le point dont la valeurs est la plus faible et s'y déplace puis on pose \omega = \omega_{choisi} + \frac {\Omega} {100} et on retire 1 à la durée de vie (jusqu'à 0 pour sa mort).

Réglage de la variable Ω

Réglage de la variable Ω

On essaye ensuite d'engendrer un nouvel agent, si un Random() est supérieur au coefficient I.

Si c'est le cas, on crée un nouvel agent avec comme nouveaux coefficients :

  • K' = Random()
  • L' = \frac{1} {3} ( 2 \times L + K \times L)
  • I' = K \times I
  • \Omega' = K \times \Omega - 1 + 2 \times round(Random())
  • \omega ' = \omega + \frac {\pi} {2} \times RandomGauss() (RandomGauss génère un nombre suivant une distribution Gaussienne centrée en 1 pour favoriser les intersection perpendiculaires)
Suivis du dénivelé ou non

Suivis du dénivelé ou non

On ajoute quelques règles comme "si un agent croise une route, il meurs immédiatement" et "un agent doit laisser au moins deux étape entre deux intersections", on jette le tout dans Domyno et ses évènements, on secoue et on obtiens des résultats comme :

Quelques résultats, contournement du dénivelé, forme de quartiers

Contournement du dénivelé, forme de quartiers,...

Un détail pas forcément remarquable au premier abords, toutes les routes sont générées vers la droite, pour une raison simple, cela permet d'éviter une explosion de la population d'agent qui envahit toute la map en attendant d'ajouter un réglage efficace de la mort des agents et du rebouclage des routes (pour éviter une structure d'arbre).

Explosion d'agents lors de la génération dans les deux directions

Explosion d'agents lors de la génération dans les deux directions

Il y a encore de nombreuses choses à régler, ajouter d'autres coefficients réglables pour les différentes variables, retravailler les connexions et utiliser un graphe plutôt qu'une carte de pixel, je suis encore bien loin des résultats de chez Introversion mais c'est plutôt joli non ?

Sources

Publié dans : , , , , , , | 2 commentaires »

18 janvier 2010 - 19:16

En Bref

Publié dans : | Laisser un commentaire »

16 janvier 2010 - 20:01

Un Nouveau Moteur

Toujours dans mes pomodoros de dev, j'en profite pour rédiger un petit billet sur mes dernières expérimentations. Bon normalement, la règle est de continuer à travailler jusqu'à la fin des 25 minutes mais après plusieurs heures, une exception ne fait pas de mal.

Je bosse sur l'IA et la génération procédurale, ces sujets étant largement plus digestes quand ils sont "graphiques", j'ai toujours un moteur de jeu sous le coude. Pas bien terminé mais destiné à me simplifier la vie pour le prototypage, c'est ce bon vieux Kwark que j'ai bricolé en Python. Un moteur de jeu assez classique composé de différents modules de rendu, d'entrées utilisateurs, de gestionnaire de ressources qui travaillent sur des objets héritants de sprites, IA,... Le problème c'est que simplifier la vie, avec cette architecture, globalement ça se résume à accéder aux objets un peu n'importe comment grâce à Python et son Duck Typing ("si l'objet en cours a bien le champ que j'ai demandé, c'est bon ça tourne") et utiliser des variables globales camouflées à travers un Singleton Handler-Poubelle.

En sus, j'ai pu assister à la GameCamp qui s'est déroulée il y a un bon mois, avec quelques amis. C'était super intéressant d'ailleurs, mais je n'ai pas réussi à en écrire un résumé convenable, l'intérêt résidait principalement dans les anecdotes/histoires personnelles des participants, trop éparses pour être synthétisées. Bref, au fil des discussions je me suis rendu compte de l'importance de se séparer du code lors du prototypage (architecture orienté donnée) et me voilà en train de retravailler Kwark pour en faire un moteur plus flexible, orienté donnée et plus rapide à mettre en place.

Eviter le Blobbing

Le premier objectif était de se débarrasser d'un problème qui s'est présenté pendant le développement de mon projet scolaire dans un langage un peu moins permissif que Python, Delphi, qui nous a obligé à modifier la hiérarchie de nombreuses fois jusqu'à voir quasiment disparaitre la l'organisation de l'héritage dans un seul gros objet générique. Je l'ai aussi ressentis dans Kwark sous une forme plus pernicieuse qui fait écrire, en exagérant à peine, autant de code "utile" que de code "adapte le résultat de l'appel de la fonction mère".

C'est quelque chose qui est déjà bien connu et qui alimente pas mal d'articles, le blobbing de la hiérarchie est du en partie à l'héritage d'implémentation, qui dans certains cas nous force à faire remonter des parties de code dans les parties supérieur de la hiérarchie lors d'ajouts de fonctions nécessaire pour tel ou tel objet. Par chance, une solution très intéressante est aussi bien connue à travers l'agrégation de composants.

Le principe est de remplacer la hiérarchie par un système de composants agrégés ce qui permet de les intervertir et les spécialiser simplement sans toucher à l'héritage.

Architecture Classique

Agrégation de controlleurs

La transformation est coule pour deux raisons :

  • On allège le poids de l'héritage dans son code
  • On peut facilement intervertir des contrôleurs, un exemple concret est présenté dans AI for Computer Games où l'auteur explique qu'il est aisé de changer de personnage jouable grace à un simple switch de controlleur EntréesJoueur-IntelligenceArtificielle.

Communiquer facilement sans "globaliser" tout le jeu

Pour résoudre ce problème, j'ai décidé d'aller à l'opposé de l'interconnexion des objets et de concevoir un système qui n'utilise QUE des évènements émis et reçus par les objets sans qu'aucun d'eux n'ai conscience de ses petits copains. Puisqu'on est dans un moteur de prototypage, le travail de conception ne devrais pas s'arrêter sur des questions du type "qui doit communiquer avec qui ?", "comment faire pour accéder à mon objet X depuis mon objet Y ?".
Dans sa version la plus stricte, tout les objets sont des "RegisteredObject" qui écoutent/émettent des évènements, sauf le Directeur qui se charge de les récupérer et les transmettre.

Plutôt que de faire interagir les objets directement entre eux avec des scripts tels que "if player.collideWith(ennemi.Head) then ennemi.Dead()" qui engendrent de nombreuses interdépendances et beaucoups de difficultés dès lors qu'il faut modifier les actions, Domyno utiliseras uniquement des évènements.

Les objets sont enregistrés auprès du Directeur et déclarent les évènements qu'ils écoutent, puis lors du fonctionnement, les différentes actions du jeux engendrerons de nouveau évènements du basique "update" dans la boucle du Directeur à des "playerJump". Ainsi il deviens enfantin d'engendrer de nouveaux évènements et de modifier ceux existants via ce système de dominos (haaaa... c'est donc de là que viens le nom !)

RegisteredObjects dans Domyno

RegisteredObjects dans Domyno

Même les moteurs principaux sont sous forme de contrôleurs ce qui les rend interchangeables et bricolable à volonté. Il ne reste plus qu'à faire tomber la premier pièce du domino : démarrer le directeur pour qu'il commencent à émettre les évènements de base (création, mise à jour, dessin) que les autres objets vont récupérer, traiter, retransmettre.

Détail

Détail

Évidemment les différents contrôleurs représentants le même objet doivent rester d'accord entre eux sur la représentation actuelle de l'objet (position entre le contrôleur d'affichage et le contrôleur physique par exemple), j'ai donc introduit les entities. Les entities sont des conteneurs de données, possédants des champs bateaux, tels que position, image, que chaque contrôleur va créer dans son entité puis modifier/utiliser. Un objet est donc représenté par son entitie qui est sa représentation "abstraite" et ses contrôleurs qui se chargent de l'exécution du code et lui donne sa "réalité physique" dans le moteur.

Synchronisation des entities

Synchronisation des entities

C'est un système assez loin de mes petits moteurs sous C# ou AS3.0 et c'est plutôt inquiétant de l'utiliser en se débarrassant de ses habitudes de stockage de référence mais jusqu'à présent l'utilisation est plutôt sympathique.

En théorie, la complexité de création des communications entre les objets devrait suivre une courbe logarithmique : beaucoup d'évènements de base à créer mais au fur et à mesure, quasiment plus aucun puisqu'ensuite ce sont juste des objets qui vont catcher des évènements déjà présent. Contrairement à un système de références directes qui tendrais plutôt vers l'exponentiel : n^n références des n objets entre eux.

Pour finir la conception orientée données (Data Oriented)

C'est Jackamikaz avec les premières versions de son jeu qui m'a donné la pichenette finale pour me lancer dans l'utilisation d'un moteur Data Oriented : il a stocké ses modèles 3D sous forme de fichiers xml contenants les données du modèle (couleurs, vertex,...) ce qui en rendait l'édition enfantine. C'est justement l'objectif du prototypage, partir de la masse brute pour l'affiner vers une représentation plus ou moins polie du résultat final.

Le principe de l'orienté donnée est de limiter l'écriture de code pour favoriser la création de données (haaaa...) par exemple, dans un moteur classique, je créerais ma classe Joueur que je ferais hériter de Sprite, PhysicObject,... et je coderais à l'intérieur l'image à utiliser, la vitesse de déplacement,....

Avec la donnée, j'écrirais un descriptif de mon objet, un xml avec des balises du type image, vitesse,... que je parserais ensuite pour génèrer mon nouvel objet. On poursuit l'idée de la flexibilité et le système de controlleur est du coup un point de départ avantageux : c'est justement l'ensemble des controlleurs paramètrés qui définis un objet, il ne reste plus qu'à les charger depuis un xml :)

Fin ? Début !

Voilà donc une première présentation de Domyno et surtout de concepts super utiles. Pour le moment les deux premières parties sont déjà en place et fonctionnent assez bien, j'ai encore de nombreuses itérations prévues pour avoir un moteur suffisamment générique et puissant pour servir à quelque chose mais cela se résume à l'ajout de nouveaux contrôleurs et l'ajout d'autres concepts dont j'aimerais tester l'efficacité. Puis viendra le parsing du jeu entièrement sous forme de xml.

A dans plusieurs dizaines d'heures de développement :)

Sources

Publié dans : , , , , , , , | Laisser un commentaire »