La Place des Développeurs MSXgl MSX Game Library

Reprise du message précédent
aoineko :
Désolé, j'ai des trucs plus haut dans ma todo list, mais je n'oublie pas.
En tout cas, il a l'air très chouette ce programme.
Désolé, j'ai des trucs plus haut dans ma todo list, mais je n'oublie pas.

En tout cas, il a l'air très chouette ce programme.
Je risque pas t'attendre si longtemps en fait...
vu qu'apparemment t'es une machine à coder



Voilà, j'ai mise-à-jour une nouvelle version de MSXgl sur GitHub avec le système de collision par tile.
Pour le moment, le module GamePawn ne s'occupe que des collisions ; les déplacements sont laissés coté jeu car ça pourrait être très différent d'un jeu à l'autre.
Ceci dit, je pense ajouter une gestion de la physique qu'on pourra activer au besoin.
Le sample s_game a été mis à jour pour référence.
Alors, voilà comment ça marche :
1) Dans ton msxgl_config.h il faut activer la feature en ajoutant ce define
2) Dans ton code d'initialisation, il faut donner :
- Une function qui va être appelé en cas de collision,
- Une fonction qui dit si un tile donné est bloquant ou non,
- La taille x/y de la collision du personnage (16x16 par ex.) ; pour le moment, la position représente le coin haut-gauche de la zone collision, et la taille permet de déterminer le coin bas-doite.
Par ex., dans le sample :
3) La fonction PhysicsEvent est appelé lorsqu'un event de collision ou de physics ont lieu. Le jeu est libre de réagir comme il le souhaite aux event qu'il souhaite (il suffit d'ignorer ceux qui ne l'intéresse pas).
Voici un exemple qui :
- Stop le saut quand on détecte une collision par le bas (le pawn touche le sol)
- Annule la force ascendante quand on détecte une collision par le haut (le pawn se cogne au plafond)
- Commence une chute quand on est pas en train de sauter et qu'on ne détecte plus de collision par le bas (le joueur avance au dessus du vide)
4) La PhysicsCollision permet au jeu de dire au module de collision si un tile est bloquant ou non.
Dans l'exemple ci-dessous, un numéro de tile inférieur à 8 est bloquant ; tous les autres ne le sont pas.
5) Enfin, pour utiliser la fonctionnalité de collision, il faut utiliser la fonction GamePawn_SetTargetPosition pour déplacement le personnage au lieu de GamePawn_SetPosition.
- GamePawn_SetPosition : téléporte le pawn a une position sans tester les collisions,
- GamePawn_SetTargetPosition : le code de collision essaye de déplacer le personnage entre Position et TargetPosition, et ajuste la position final en cas de collision (en plus de déclencher des events).
Voilà... j'espère que c'est compréhensible.
EDIT: Quelques limitations tout de même :
- La collision se fait à l'échelle d'un tile ; par exemple, pas possible d'avoir une pente qu'on puisse grimper à l'intérieur d'un tile. C'est binaire, un tile est bloquant ou non, c'est tout.
- Avec des déplacements latéraux ou verticaux de plus de 8 pixels en 1 frame, il est "possible" que le test de collision passe à travers un tile (à cette vitesse on traverse l'écran en 0,4 secondes
).
- Enfin, les tests de collisions ne sont fait qu'en 1 point par direction (cf. schéma ci-dessous). Je pourrais faire une version plus précise à 2 points par direction mais qui sera plus lourde. J'en ferait une option à activer via un define.
Pour le moment, le module GamePawn ne s'occupe que des collisions ; les déplacements sont laissés coté jeu car ça pourrait être très différent d'un jeu à l'autre.
Ceci dit, je pense ajouter une gestion de la physique qu'on pourra activer au besoin.
Le sample s_game a été mis à jour pour référence.
Alors, voilà comment ça marche :
1) Dans ton msxgl_config.h il faut activer la feature en ajoutant ce define
Code C :
#define GAMEPAWN_USE_PHYSICS 1
2) Dans ton code d'initialisation, il faut donner :
- Une function qui va être appelé en cas de collision,
- Une fonction qui dit si un tile donné est bloquant ou non,
- La taille x/y de la collision du personnage (16x16 par ex.) ; pour le moment, la position représente le coin haut-gauche de la zone collision, et la taille permet de déterminer le coin bas-doite.
Par ex., dans le sample :
Code C :
GamePawn_InitializePhysics(&g_PlayerPawn, PhysicsEvent, PhysicsCollision, 16, 16);
3) La fonction PhysicsEvent est appelé lorsqu'un event de collision ou de physics ont lieu. Le jeu est libre de réagir comme il le souhaite aux event qu'il souhaite (il suffit d'ignorer ceux qui ne l'intéresse pas).
Voici un exemple qui :
- Stop le saut quand on détecte une collision par le bas (le pawn touche le sol)
- Annule la force ascendante quand on détecte une collision par le haut (le pawn se cogne au plafond)
- Commence une chute quand on est pas en train de sauter et qu'on ne détecte plus de collision par le bas (le joueur avance au dessus du vide)
Code C :
void PhysicsEvent(u8 event) { switch(event) { case PAWN_PHYSICS_COL_DOWN: // Handle downward collisions g_bJumping = false; break; case PAWN_PHYSICS_COL_UP: // Handle upward collisions g_JumpForce = 0; break; case PAWN_PHYSICS_FALL: // Handle falling if(!g_bJumping) { g_bJumping = true; g_JumpForce = 0; } break; }; }
4) La PhysicsCollision permet au jeu de dire au module de collision si un tile est bloquant ou non.
Dans l'exemple ci-dessous, un numéro de tile inférieur à 8 est bloquant ; tous les autres ne le sont pas.
Code C :
bool PhysicsCollision(u8 tile) { return (tile < 8); }
5) Enfin, pour utiliser la fonctionnalité de collision, il faut utiliser la fonction GamePawn_SetTargetPosition pour déplacement le personnage au lieu de GamePawn_SetPosition.
- GamePawn_SetPosition : téléporte le pawn a une position sans tester les collisions,
- GamePawn_SetTargetPosition : le code de collision essaye de déplacer le personnage entre Position et TargetPosition, et ajuste la position final en cas de collision (en plus de déclencher des events).
Voilà... j'espère que c'est compréhensible.

EDIT: Quelques limitations tout de même :
- La collision se fait à l'échelle d'un tile ; par exemple, pas possible d'avoir une pente qu'on puisse grimper à l'intérieur d'un tile. C'est binaire, un tile est bloquant ou non, c'est tout.
- Avec des déplacements latéraux ou verticaux de plus de 8 pixels en 1 frame, il est "possible" que le test de collision passe à travers un tile (à cette vitesse on traverse l'écran en 0,4 secondes

- Enfin, les tests de collisions ne sont fait qu'en 1 point par direction (cf. schéma ci-dessous). Je pourrais faire une version plus précise à 2 points par direction mais qui sera plus lourde. J'en ferait une option à activer via un define.

On est toujours ignorant avant de savoir.
C'est juste génial ! je vais m'installer une extension Git dans VS Code et je teste ça.
Merci @aineko pour ces ajouts précieux
EDIT: J'ai fait un clone de ton repo et j'ai encore quelques .cmd avec LF en fin de ligne (notamment 'check_config.cmd') Edité par Gfx Le 05/02/2022 à 12h08
Merci @aineko pour ces ajouts précieux

EDIT: J'ai fait un clone de ton repo et j'ai encore quelques .cmd avec LF en fin de ligne (notamment 'check_config.cmd') Edité par Gfx Le 05/02/2022 à 12h08
Il faut cultiver notre jardin.

Gfx :
C'est juste génial ! je vais m'installer une extension Git dans VS Code et je teste ça.
Merci @aineko pour ces ajouts précieux
Merci @aineko pour ces ajouts précieux

De rien

Tant que c'est assez générique c'est cool car ça pourra aider d'autres personnes aussi.
Gfx :
EDIT: J'ai fait un clone de ton repo et j'ai encore quelques .cmd avec LF en fin de ligne (notamment 'check_config.cmd')
Zut... c'est vraiment relou ce problème

C'est peut-être des fichiers que j'ai pas encore re-push depuis que j'ai essayé de régler le problème avec GitHub.
Je vais essayer de forcer de push tous mes .bat et .cmd.
EDIT: Peux réessayer stp ? J'ai changé la configuration des attribues de fichiers textes. Tu peux me dire si c'est bon pour toi ?
Au fait, tu es sous Windows ? Parce que moi, j'ai déjà cloné MSXgl sur plusieurs machines Windows et j'ai jamais eu de soucis.
Si j'ai bien compris, le comportement par défaut de GitHub c'est de convertir de force les fichiers texte en CRLF sur Windows et en LF pour les autres plateformes.
EDIT2: C'est bon, j'ai réussi à reproduire le problème sur Windows... et à le corriger en pushant tous les BAT et les CMD. La dernière version GitHub devrait fonctionner.
On est toujours ignorant avant de savoir.
Hello,
je me suis amusé avec le game_pawn et les collision et j'aurais besoin de tes conseils pour coder le comportement sur les échelles. Pour l'instant je teste juste si le pawn est sur une tile de type échelle (ou 1 tile au dessus) et je desactive le saut mais lorsque le sprite arrive en haut de l'échelle il saute... en fait j'aimerais pouvoir marcher sur le haut des échelles sans tomber. Dans The Maze of Galious les échelles ne vont pas jusque en haut des plateformes, je commence à comprendre pourquoi...
Si tu veux voir à quoi ça ressemble : wizzl.rom Edité par Gfx Le 06/02/2022 à 01h18
je me suis amusé avec le game_pawn et les collision et j'aurais besoin de tes conseils pour coder le comportement sur les échelles. Pour l'instant je teste juste si le pawn est sur une tile de type échelle (ou 1 tile au dessus) et je desactive le saut mais lorsque le sprite arrive en haut de l'échelle il saute... en fait j'aimerais pouvoir marcher sur le haut des échelles sans tomber. Dans The Maze of Galious les échelles ne vont pas jusque en haut des plateformes, je commence à comprendre pourquoi...
Si tu veux voir à quoi ça ressemble : wizzl.rom Edité par Gfx Le 06/02/2022 à 01h18
Il faut cultiver notre jardin.

Déjà, les décors sont vraiment très jolis !
Comme la callback PhysicsCollision est toujours appelé avant un PhysicsEvent, tu peux ruser :
- Tu sauvegarder le tile qui est testé dans PhysicsCollision,
- Quand tu reçoit l'event PAWN_PHYSICS_FALL dans PhysicsEvent, tu check si le tile sauvegarder est l'échelle et si c'est le cas, tu ne tombe pas.
Et voilà, tu peux marcher sur les échelles
Je pourrais éventuellement renvoyer le dernier tile testé dans les paramètres de le callback PhysicsEvent... à voir si ça vaut le petit surcout que ça aurait.
Pour le saut, c'est gérer dans ton code donc à toi de faire une transition propre entre le moment ou tu es sur l'échelle et quand tu arrives en haut.
Autre petite astuce auquel j'avais pensé : tu peux utiliser PhysicsCollision pour détecter des items à ramasser dans le décors. Leur tile sera non-bloquant, mais si cette callback est appelé c'est que le pawn touche ce tile et tu peux donc ajouter l'objet dans l'inventaire de ton personnage et remplacer le tile de l'objet par un tile de décor de fond.
Tu peux garder par exemple les 2 bits de poids fort pour coder 4 types de tiles (décor bloquant, décor de fond, item et... je sais pas quoi
). Ca te laisse 64 tiles pour chaque catégorie et ça te facilite grandement leur détection.
PS : Tu peux créer facilement un lien vers WebMSX comme ça : https://webmsx.org/?MACHINE=MSX1J&ROM=http://msxvillage.fr/upload/wizzl.rom
Comme la callback PhysicsCollision est toujours appelé avant un PhysicsEvent, tu peux ruser :
- Tu sauvegarder le tile qui est testé dans PhysicsCollision,
- Quand tu reçoit l'event PAWN_PHYSICS_FALL dans PhysicsEvent, tu check si le tile sauvegarder est l'échelle et si c'est le cas, tu ne tombe pas.
Et voilà, tu peux marcher sur les échelles

Je pourrais éventuellement renvoyer le dernier tile testé dans les paramètres de le callback PhysicsEvent... à voir si ça vaut le petit surcout que ça aurait.
Pour le saut, c'est gérer dans ton code donc à toi de faire une transition propre entre le moment ou tu es sur l'échelle et quand tu arrives en haut.
Autre petite astuce auquel j'avais pensé : tu peux utiliser PhysicsCollision pour détecter des items à ramasser dans le décors. Leur tile sera non-bloquant, mais si cette callback est appelé c'est que le pawn touche ce tile et tu peux donc ajouter l'objet dans l'inventaire de ton personnage et remplacer le tile de l'objet par un tile de décor de fond.
Tu peux garder par exemple les 2 bits de poids fort pour coder 4 types de tiles (décor bloquant, décor de fond, item et... je sais pas quoi

PS : Tu peux créer facilement un lien vers WebMSX comme ça : https://webmsx.org/?MACHINE=MSX1J&ROM=http://msxvillage.fr/upload/wizzl.rom
On est toujours ignorant avant de savoir.

L'impact sur les performances est minime du coup j'ai ajouté le tile qui à déclencher l'évènement dans le prototype de la callback.
Le nouveau prototype est :
En fait, c'est surtout l'affichage GamePawn_Draw() qui prend du temps.
Je vais regarder pour optimiser un peu...
Le nouveau prototype est :
Code C :
void PhysicsEvent(u8 event, u8 tile)
En fait, c'est surtout l'affichage GamePawn_Draw() qui prend du temps.
Je vais regarder pour optimiser un peu...
On est toujours ignorant avant de savoir.

@GFX Attention, si tu récupères la dernière version GitHub, j'ai retiré le paramètre DataMultiply de la structure Game_Sprite.
Il y avait une multiplication entre 2 variables très couteuse et inutile.
Par contre ça créé 1 contrainte : Il faut que les différentes couches d'une frame soit les unes derrières les autres ; ce qui est le cas si tu créées tes données avec CMSXimg.
Le seul changement à faire coté code, c'est que le paramètre ID des Game_Frame, doit être le numéro de pattern et plus le numéro de frame.
Par ex., dans mon sample s_game, la ou j'utilisais la frame 1 ou 5, je doit maintenant déclarer 16 ou 80 (frame * 16).
La valeur 16 vient du fait que je suis en 16x16 (4 patterns) et que j'ai 4 couches de sprites.
Le début de la 1re frame est à l'index 0, le 2e à l'index 16, le 3e à l'index 32, etc.
EDIT:
Autre optimisation, j'ai fait disparaitre le SpriteID de la structure Game_Sprite.
Maintenant, le SpriteID est définie dans le Game_Pawn et détermine l'ID du premier layer.
Le layer suivant utilise l'ID suivant et ainsi de suite (ça permet d'optimiser).
L'ID du premier layer se donne via un nouveau paramètre dans la function GamePawn_Initialize() :
Il faut donc retirer le premier paramètre dans ta déclaration des Game_Sprite et mettre la valeur du 1er layer dans GamePawn_Initialize().
Il y avait une multiplication entre 2 variables très couteuse et inutile.
Par contre ça créé 1 contrainte : Il faut que les différentes couches d'une frame soit les unes derrières les autres ; ce qui est le cas si tu créées tes données avec CMSXimg.
Le seul changement à faire coté code, c'est que le paramètre ID des Game_Frame, doit être le numéro de pattern et plus le numéro de frame.
Par ex., dans mon sample s_game, la ou j'utilisais la frame 1 ou 5, je doit maintenant déclarer 16 ou 80 (frame * 16).
La valeur 16 vient du fait que je suis en 16x16 (4 patterns) et que j'ai 4 couches de sprites.
Le début de la 1re frame est à l'index 0, le 2e à l'index 16, le 3e à l'index 32, etc.
EDIT:
Autre optimisation, j'ai fait disparaitre le SpriteID de la structure Game_Sprite.
Maintenant, le SpriteID est définie dans le Game_Pawn et détermine l'ID du premier layer.
Le layer suivant utilise l'ID suivant et ainsi de suite (ça permet d'optimiser).
L'ID du premier layer se donne via un nouveau paramètre dans la function GamePawn_Initialize() :
Code C :
void GamePawn_Initialize(Game_Pawn* pawn, const Game_Sprite* sprtList, u8 sprtNum, u8 sprtID, const Game_Action* actList);
Il faut donc retirer le premier paramètre dans ta déclaration des Game_Sprite et mettre la valeur du 1er layer dans GamePawn_Initialize().
On est toujours ignorant avant de savoir.
@aoineko ça marche, je vais mettre à jour et faire les modifs.
Entre temps j'ai essayé les collisions et j'y suis presque... j'ai toujours un problème si le joueur tourne à droite ou à gauche dans les derniers 8px de l'échelle :
---->WIZZL Edité par Gfx Le 06/02/2022 à 22h49
Entre temps j'ai essayé les collisions et j'y suis presque... j'ai toujours un problème si le joueur tourne à droite ou à gauche dans les derniers 8px de l'échelle :
---->WIZZL Edité par Gfx Le 06/02/2022 à 22h49
Il faut cultiver notre jardin.
Bravo Gfx, c'est super.
Même si je suis tes avancées et celles de MSXgl, je ne participe plus trop car un gros coup au moral dû à un souci de santé.
Tchao les zamis et bonne continuation
Même si je suis tes avancées et celles de MSXgl, je ne participe plus trop car un gros coup au moral dû à un souci de santé.
Tchao les zamis et bonne continuation


Ricco59 :
Même si je suis tes avancées et celles de MSXgl, je ne participe plus trop car un gros coup au moral dû à un souci de santé.
Bon courage
On est toujours ignorant avant de savoir.

J'ai ajouté 2 options au module PSG de MSXgl :
- On peut choisir un accès direct (aux registres) ou indirect (via un buffer en RAM). Chacune de ces méthodes à ses intérêts. Je vous expliquerai si vous voulez.
- On pout choisir entre le PSG interne du MSX ou un PSG externe (dans une cartouche... comme celui de la MegaFlashROM SCC+ SD).
J'ai aussi ajouté un define pour ajouter/supprimer toutes les fonctions helpers (PSG_SetTone, PSG_SetNoise, PSG_SetVolume, etc.).
C'est sur GitHub.
Je prévois d'ajouter une option pour utiliser et le PSG interne, et un PSG externe, mais c'est pas prio et ça attendra.
- On peut choisir un accès direct (aux registres) ou indirect (via un buffer en RAM). Chacune de ces méthodes à ses intérêts. Je vous expliquerai si vous voulez.
- On pout choisir entre le PSG interne du MSX ou un PSG externe (dans une cartouche... comme celui de la MegaFlashROM SCC+ SD).
J'ai aussi ajouté un define pour ajouter/supprimer toutes les fonctions helpers (PSG_SetTone, PSG_SetNoise, PSG_SetVolume, etc.).
C'est sur GitHub.
Je prévois d'ajouter une option pour utiliser et le PSG interne, et un PSG externe, mais c'est pas prio et ça attendra.

On est toujours ignorant avant de savoir.
Répondre
Vous n'êtes pas autorisé à écrire dans cette catégorie