Suivez l'évolution du framework !

Suivez moi sur Github pour vous tenir informé des dernières nouveautés du framework : https://github.com/Asthegor/Dina_SDL



1

2 3 4

2022-03-06

Nouveau package NuGet v1.0.9

Aujourd'hui, j'ai voulu faire un petit exemple pour le mettre sur le site.

Après avoir créé un nouveau projet avec le modèle Dina, j'ai récupéré le code pour afficher le logo.
Cependant, un grand nombre de modifications ont été faite qui ne me permettait pas de compiler le projet.

J'ai rajouté des fonctionnalités mais surtout, j'ai refait la totalité de l'arborescence des répertoires !

 

Souci d'utilisation du package

Lorsque j'installe le nouveau package de mon moteur et que je compile la solution, j'ai systématiquement l'erreur suivante :

error : Ce projet fait référence à des packages NuGet qui sont manquants sur cet ordinateur. Utilisez l'option de restauration des packages NuGet pour les télécharger. Pour plus d'informations, consultez http://go.microsoft.com/fwlink/?LinkID=322105. Le fichier manquant est : ..\packages\sdl2.nuget.redist.2.0.18\build\native\sdl2.nuget.redist.targets.

 

Cette erreur provenait du fait que mon projet et ma solution étaient dans le même répertoire.
C'est plutôt embêtant mais je verrais plus tard pour corriger cela.

Donc, au bout de 4 versions du package, j'ai enfin pu avoir un version fonctionnelle !

Je vais donc pouvoir enfin mettre à disposition un exemple de projet utilisant mon moteur.

 


Vous pouvez télécharger les nouveaux exemples ici : Exemples


2022-02-20

MapGenerator - Générateur de cartes

Pour un de mes jeux, je voulais avoir une île assez grande.
Pour cela, j'ai commencé à créer une carte sous Tiled. Et c'était long, très long... pour ne faire qu'une partie du tour de l'île... moins du quart du rivage...

Ce n'était pas réaliste si je voulais vraiment avoir une carte correcte.

Je me suis dis : "Et si je générais ma carte de manière aléatoire ?"

 

Bruit de Perlin

Une des façons de générer une carte aléatoire, c'est d'utiliser le Bruit de Perlin (Perlin noise).

J'ai suivi un tutoriel utilisant Love2D qui a le bruit de perlin déjà codé.
Petit problème de mon côté, je ne l'avais pas dans mon framework... J'ai donc dû le rajouter.


Au départ, j'ai voulu concevoir ma propre classe pour gérer tout ça.
Je me suis documenté sur ce qu'était le bruit de Perlin et le pseudo-code fourni sur Wiki m'a beaucoup aidé (merci à celui ou ceux qui l'ont mis en ligne).

Cependant, les performances n'étaient pas vraiment là (surtout en mode Debug) :

Perlin Noise CPP vs Love2D

 

Pour contrôler la vitesse de traitement, j'ai affiché le deltatime.

Pas vraiment fameux : 0.3s pour afficher une image au lieu que je devrais afficher une image en environ 0,01s.

 

J'ai alors vérifié si le temps d'exécution était lié à la mise à jour des points ou à l'affichage des points :

 

Il n'y a pas photo : le souci provient de l'affichage.

Après vérification sur Internet, il s'avère que la fonction de SDL permettant d'afficher un point à l'écran est lente... surtout lorsqu'on souhaite afficher plus de 1 million de points (fenêtre de 1280x800). Cela génère plus de 2 millions d'instructions (1 pour la couleur du point et une autre pour le point).

C'est donc plutôt normal que cela prenne du temps. 😆😆😆

 

J'ai donc fait plusieurs simulations avec des librairies différentes :

"Noise 1234" est le même code utilisé dans Love2D. Ce qui fait qu'il me sert de référence pour mes comparaisons.

 

Comme je pouvais avoir 2 points au même endroit, j'ai alors utilisé une tableau de bool pour stocker si le point devait ou non être dessiné.
Un léger mieux mais ce n'était toujours pas ça...

L'avancée la plus importante a été d'utiliser une surface pour pré-dessiner mes points.
Mes points étaient mis sur la surface et ensuite, il ne me restait plus qu'à la dessiner.

En cumulant les 2 améliorations j'ai pu obtenir quelque chose d'un peu mieux mais toujours pas optimal.

Résultats :

 


2022-02-03

LevelManager - Gestionnaire de cartes

LevelManager

Maintenant que j'ai réussi à charger une animation, il faut encore que je puisse charger une map.

Donc j'ai commencé à regarder ce qui existe comme librairies sur le site de Tiled.
Il existe plusieurs librairies : tileson, tinytmx, tmxlite, etc, (liste disponible ici).

Et après plusieurs recherches, je suis tombé sur la librairie LibTMX.

Tout d'abord, contrairement aux autres librairies, elle est bien documentée (c'est déjà un gros plus pour moi).
Ensuite, la façon dont l'auteur a géré les différents éléments est presque identique à ma façon de faire (et de penser).

Donc, je vais partir sur cette librarie.

J'ai dans l'optique de permettre un chargement simple et rapide des niveaux.

Pour cela, le développeur ne devra renseigner que le nom du fichier du niveau (et avoir positionné les images là où il faut) et il pourra l'afficher, récupérer chaque layer/objet/image comme bon lui semblera.

Pour l'instant, concentrons-nous sur LibTMX.

 

LibTMX

Après quelques essais, je n'ai pas réussi à intégrer simplement cette librairie dans mon projet.

J'ai plusieurs options qui s'offrent à moi :

Si je pars sur la 3ème option, je créditerais toutes les classes pour indiquer la provenance (ben oui, j'aurais fait que du copier/coller).


2022-02-01

Animations

Après la mise en place du gestionnaire d'événements, j'avais décidé de m'attaquer aux animations.

Animation simple

Pour me faciliter le travail, j'ai voulu que chaque animation correspond à un nombre d'images à charger.

Donc, j'ai conçu une classe Animation qui me permet de stocker les images (de type Texture) et la mécanique pour passer d'une frame à l'autre.
C'est également cette même classe qui se charge de dessiner la bonne image.

Voici le code nécessaire pour charger une animation :

m_Animations["Down"] = new Dina::Animation("Datas/Images/Game/Player/Player_Down_", ".png", 4, 0.35);

N.B. : Les fichiers se nomment Player_Down_0.png jusqu'à Player_Down_3.png

 

 

 

Souci technique...

Pour faire cette animation, j'avais changé le contenu du projet SandBox et j'ai pensé qu'il serait bien de ne pas "polluer" mon GitHub avec ces données.
En plus, je pouvais utiliser des images non libres de droit pour faire mes tests.

J'ai donc voulu supprimer le projet de mon repository via GitKraken....
Aïe ! Aïe ! Aïe !
Des petites erreurs de manipulations ont abouti à ce que je refasse l'intégralité de mon repository. 😱

 

Mise en place (douloureuse) des Spritesheet

La suite directe de l'animation simple était de pouvoir charger une spritesheet contenant l'animation.
C'est ce que j'ai voulu implémenter.

Mais là, le drame... J'ai bloqué pendant plusieurs jours sur ce point sans pouvoir me débloquer.😫
Habituellement, en faisant une pause de 2-3 jours, j'arrive à me débloquer en trouvant une piste.

Mais là, rien ! Nada ! La panne sèche ! 😱
Pas la moindre petite idée pour me lancer.

Puis, ce matin, tout m'est apparu simple. Plus je codais, plus ça s'enchaînait exactement (ou presque) comme il le fallait !
Je n'en revenais pas moi-même ! 😮

Voici ce qu'on a besoin d'utiliser pour 4 animations (une pour chaque direction) :

m_Animations["Duck_Down"] = new Dina::Animation("Datas/Images/Game/Player/Duck_Down.png", 52, 72, 0.35, true);
m_Animations["Duck_Left"] = new Dina::Animation("Datas/Images/Game/Player/Duck_Left.png", 52, 72, 0.35, true);
m_Animations["Duck_Right"] = new Dina::Animation("Datas/Images/Game/Player/Duck_Right.png", 52, 72, 0.35, true);
m_Animations["Duck_Up"] = new Dina::Animation("Datas/Images/Game/Player/Duck_Up.png", 52, 72, 0.35, true);

 

Il y a seulement 5 paramètres :

  1. Le nom du fichier contenant l'ensemble des images de l'animation
  2. La largeur d'une image dans le spritesheet
  3. La hauteur de l'image dans le spritesheet
  4. La vitesse de l'animation
  5. Un témoin pour indiquer si on veut :
    • une animation normale : on incrémente le numéro de la frame courante de 0 jusqu'au nombre d'images trouvées et on revient à 0.
    • une animation en zig-zag : on incrémente le numéro de la frame courante de 0 jusqu'au nombre d'images trouvées - 1 puis on décrémente le numéro de la frame courante jusqu'à revenir à 0.

Dans les animations présentes dans la capture ci-dessous, il y a 3 images par animation.
Lorsque l'on affiche l'animation en mode zig-zag (comme ci-dessous), le numéro de la frame courante suit cet ordre : 0 1 2 1 0 1 2 . . .

 

 

Spritesheet multiple

Lors de la mise en place de cette fonctionnalité, je craignais de me retrouver face à un autre blocage.
Toutefois, j'ai réussi à franchir cet obstacle pour parvenir à utiliser une spritesheet avec un grand nombre d'images et à en utiliser que quelques unes pour l'animation.

La manipulation est différente de celle avec une spritesheet ne contenant qu'une seule animation complète.
Il faut tout d'abord charger la spritesheet en entier comme ceci :

Dina::Spritesheet* playerSheet = new Dina::Spritesheet("Datas/Images/Game/Player/sheet_winnersa_2.png", 52, 72);

Le découpage des sprites se fait automatiquement avec la largeur et la hauteur indiquées (le premier sprite est à l'indice 0).

Ensuite, il suffit d'indiquer les numéros des sprites à utiliser pour l'animation (stocké dans un vector), la vitesse de l'animation et si on doit utiliser le mode classique ou zig-zag (désolé, j'ai pas trouvé d'autre nom et je ne sais pas s'il y en a un qui existe pour ça).

m_Animations["Duck_Down"] = playerSheet->GetAnimation({ 0, 1, 2 }, 0.35, true);
m_Animations["Duck_Left"] = playerSheet->GetAnimation({ 12, 13, 14 }, 0.35, true);
m_Animations["Duck_Right"] = playerSheet->GetAnimation({ 24, 25, 26 }, 0.35, true);
m_Animations["Duck_Up"] = playerSheet->GetAnimation({ 36, 37, 38 }, 0.35, true);

On peut alors obtenir exactement la même chose que ci-dessus.


2022-01-09

Gestionnaire d'événements - 7ème jour

J'ai enfin réussi à gérer les événements comme je le voulais !

Maintenant, chaque scène est responsable de ses propres actions lorsqu'on appuie sur une touche ou qu'on déplace la souris (pour ne citer que ces deux-là).

J'ai également fait en sorte que le MenuManager puisse, lors de la création d'un item avec AddItem, recevoir 2 fonctions (facultatives) : une première lorsqu'on valide ou actionne l'item et la seconde lorsqu'on passe la souris dessus.

J'avais aussi un souci lorsque je laissait une touche appuyée longtemps. Ma compréhension de la documentation m'a induit en erreur...
Ce qui a fait que lorsque je maintenais la touche Echap appuyée depuis la scène du jeu, je revenais vers le menu principal comme voulu MAIS...(oui, un grand MAIS)... comme il se génère un Event tous les X secondes, dépendant de la vitesse de répétition du clavier, ça quittait quand même le jeu sans rester sur le menu principal.

Donc, mon système ne fonctionnait pas comme je le souhaitais.

 

J'ai donc mis en place un booléen pour tracer l'appui d'une touche.
Cela fait que je peux gérer désormais l'appui sur une touche de façon normale ou l'appui maintenu.

Pour la souris, c'est un peu différent. Je voulais pouvoir répéter l'action si je gardais le bouton de la souris appuyé. Cependant, contrairement au clavier, il n'y a qu'un seul Event qui est généré. J'ai rajouté un booléen puis, tant que le bouton n'est pas relâché, l'action sera répétée.

 

Voici le résultat de ce travail :


1

2 3 4