Stick arcade

Partie 1 : menuiserie

IMG_2314

Première visualisation :IMG_2315

Limage et ponçage des planches :IMG_2317 On fixe le cadre :IMG_2318

Découpage du top & bottom panelIMG_2321

Test du perçage du plexiglas et rendu avec un bouton :IMG_2323

Perçage de la plaque de plexi :IMG_2324

Partie 2 : électronique

Repérage des signaux et du plan de masse :IMG_2949

 

Soudure et consolidation à la colle :IMG_2951 Mise en place du PCB et première partie du câblage :IMG_2954 Câblage du stick et des boutons :IMG_2956Le produit fini !
IMG_2958

Pense-bête SDL et OpenGL

SDL

Mon IDE est déjà lié à la bibliothèque SDL sur mon disque dur. A partir de là, il semble que les étapes suivantes soient nécessaires et suffisantes pour démarrer un nouveau projet utilisant la SDL :

> Démarrer un projet en mode console

> Project / Build Options / onglet Linker Settings, bloc « other linker settings » : AJouter les paramètres suivants : -lmingw32, -lSDLmain, -lSDL

> Ajouter le fichier SDL.dll dans le dossier du projet

> Pour être plus cohérent, on peut rebasculer le projet en « GUI application » (par opposition au mode console) : Project / Properties / Build targets, Type : GUI application

OpenGL

Il suffit de rajouter -lopengl32 et -lglu32 dans Project / Build Options / onglet Linker Settings, bloc « other linker settings »

Projet de jeu (7… et match)

Je mets officiellement fin au projet ! (même si des ajustements cosmétiques ne sont pas à exclure). Après une dernière ligne droite plus relevée que prévue, et à l’issue d’une semaine relativement intensive mon jeu est terminé. Voici donc l’écran d’accueil :

…l’écran de jeu, que vous commencez à connaître :p :

…et l’écran d’affichage du score : L’idée était d’arriver à un produit fini, qui fonctionne, il est vrai que la création graphique n’a pas été mon focus principal.

BILAN

Premier constat : jouer avec les librairies tierces, les .dll et autres soucis de compatibilités est finalement bien plus usant que le développement du programme à proprement parler (surtout lorsque c’est la première fois que l’on utilise lesdites librairies, et que le projet est encore relativement modeste et tourne autour de 250 – 300 lignes :p)

PLAN 

Du point de vue de l’organisation, j’ai fait les choses simplement. Il y a trois fonctions, une par écran :

  • main (écran d’accueil)
  • jeu (écran de jeu)
  • score (écran d’affichage du score)

Pour illustrer :

Voici un petit plan qui schématise la boucle principale du jeu :

GESTION DES COLLISIONS

La gestion des collisions s’appuie sur la gestion des cas extrêmes, en sachant que les éléments sont définis par la position de leur coin supérieur gauche. Le repère absolu (en pixels) est le coin supérieur gauche de l’écran (w = width et h = height) :

…ce qui se traduit par le code suivant. On rentre dans le bloc si les conditions de collision sont respectées, on attribue de nouvelles coordonnées aléatoires au coeur et on incrémente le compteur (score) :

Projet de jeu (6)

Et bien c’est un succès ! Enfin c’est un peu austère en l’état, il faudrait un écran d’accueil et un affichage du score, mais le coeur du jeu fonctionne bel et bien !

Le gameplay est très simple, il s’agit de déplacer le personnage à l’aide des flèches directionnelles pour attraper un coeur. A chaque fois que c’est le cas, un nouveau coeur apparaît. Il s’agit d’en attraper un maximum en 30 secondes, à la suite de quoi la partie est terminée.

Projet de jeu (5)

Je suis entré de plein pied dans le vif du sujet, la programmation à proprement parler.Voici un aperçu des enjeux majeurs du moment :

  • Gestion d’évènements et animation

La première version de mon test fonctionnait sur une gestion d’évènements en « push », c’est à dire que le programme était en pause par défaut, et lorsqu’un évènement prévu (appui sur une touche de déplacement par exemple) survenait, le programme sollicitait le processeur pour exécuter l’action en question.

Pour tout un tas de raison, je suis passé sur une gestion d’évènements en « pull » : le programme regarde en permanence les évènements qui se produisent (quelles touches sont enfoncées), et agit si nécessaire. Cette vigilance permanente étant gourmande en ressources, il est nécessaire d’organiser les périodes d’activité / inactivité du programme, en mettant en place une gestion du temps. Concrètement, il faut explicitement demander au programme de se reposer 20, 30 millisecondes (ou toute autre valeur), avant de s’actualiser et d’afficher l’image à l’écran.

Cette nouvelle façon de faire a eu des effets positifs. D’une part, cela permet de gérer l’appui continue sur une touche. On ne s’intéresse plus à l’envoi unique d’un signal au moment où une touche est enfoncée, on s’intéresse en temps réel à l’état de la touche (enfoncée ou non). Tant que l’état de la touche est « enfoncé », l’action est maintenue. D’autre part, cela permet de gérer les appuis sur plusieurs touches en même temps. Concrètement, mon personnage peut désormais se déplacer en diagonale :p

  • Organisation du code

Ma première idée de découpage de code en fichiers n’est clairement pas optimale, et il va falloir que je remette de l’ordre. Néanmoins, la situation actuelle m’a permis de tester l’envoi de pointeurs en paramètre. En l’état, j’ai une fonction qui sert à déplacer mon personnage (ou « sprite », enfin le crâne, quoi). Elle a besoin de modifier la position dudit personnage, position qui est stockée dans une structure. Il faut donc envoyer à la fonction un pointeur sur cette structure.

Projet de jeu (4)

Progrès toujours !

Cette fois-ci ça y est, on rentre dans le vif du sujet avec la gestion des évènements ! On commence relativement simple en déplaçant un sprite (merveilleusement dessiné :p) sur le fond :

…et ça marche ! Pour le moment mon « personnage » peut aller sur les rochers, et le mouvement n’est pas des plus souples, mais ça fonctionne et c’est déjà pas mal ! Maintenant il va falloir relire le code à tête reposée, voire comment l’améliorer à la marge et surtout comment l’organiser. Pour le moment tout se passe dans un seul fichier et ça devient tout doucement illisible :p

Projet de jeu (3)

Installation du plug-in SDL_image :

> Ajouter le header SDL_image.h au dossier « include » de SDL

> Ajouter le fichier SDL_image.lib au dossier « lib » dans CodeBlocks\Mingw\SDL

> Copier l’ensemble des .dll dans le dossier de chacun des projets utilisants SDL_image (utiliser le folder x86)

> Project -> Build Options -> Linker Settings : Se positionner sur le nom du projet dans l’arborescence (cadre de gauche). Link librairies : indiquer le chemin vers SDL_image.lib. Other linker options : il doit y avoir -lmingw32, -lSDLmain, -lSDL.

> Dans le fichier source : utiliser #include <SDL/SDL_image.h>

Projet de jeu (2)

Je progresse, mais ça prend largement autant de temps que prévu :p

Il faut dire que mon organisation est un peu vrac : je développe avec Code::Blocks, sous Windows (j’y ai installé SDL), mais Inkscape est installé sous Linux. Ce dernier exporte les images rastérisées en .png, alors que SDL travaille avec du .bmp…

Quoi qu’il en soit, j’ai pu dessiner une base et l’intégrer à mon projet : voici la fenêtre de base, avec laquelle je vais pouvoir expérimenter :

Projet de jeu : it’s on !

Bon, allez, c’est parti : vu que mon projet parallèle risque de prendre un peu de temps, je me lance : Je vais essayer d’explorer les mécaniques permettant d’arriver à un petit jeu, 2D et sans prétentions. Pour le moment je ne connais pas encore toutes les mécaniques, donc mon but est déjà d’arriver à faire bouger quelque chose dans une fenêtre. Je vais utiliser la bibliothèque SDL pour ne pas avoir à jouer avec l’API Windows (et éventuellement envisager un portage en douceur par la suite sur Linux par exemple, SDL étant multi-plateforme).

L’heure est aux premières décisions : je choisis de démarrer avec une résolution de 800×600. J’ai pu créer la fenêtre, mais il va me falloir un fond. Deux options s’ouvrent à moi a priori : soit je procède comme souvent en jeux 2D, avec des « tiles » (petits carrés de décors que l’on assemble comme une mosaïque) ou avec un fond unique. Pour le moment je vais tenter cette approche là. Il ne me reste plus qu’à dessiner un fond en 800×600 à l’aide d’Inkscape. Je vais faire rapide et bateau pour le moment, l’objectif étant de voir comment ça peut marcher plutôt que de viser la réalisation parfaite.

Mémo SDL

La librairie SDL semble un petit peu capricieuse à faire fonctionner. Outre le SDL.dll à ajouter au dossier de chaque projet, il faut paramétrer le linker en ajoutant les mentions suivantes au champ « link librairies » :

-lmingw32

-lSDLmain

-lSDL

Par ailleurs, il est nécessaire de définir la fonction main comme suit :

int main(int argc, char *argv[])

…et non simplement comme le tolère le langage lorsqu’il ne recourt pas à SDL :

int main()