30

Ils l'ont deja fait.

31

Je vais de toute façon refaire le moteur collisionnel dans les prochains jours, et je verrai sur le moment si je tente d'implémenter des courbes et des loopings dans la prochaine version ou si ça devra attendre encore un peu... happy

Sinon en attendant je suis content, je viens de tomber sur une spritesheet juste au bon format que je n'ai plus qu'a convertir pour casio love love
Par contre il va falloir que j'améliore un peu la caméra vu que le perso prend quand même une place non négligeable sur l'écran, et il faut qu'on puisse voir où on va smile
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

32

PpHd :
Ils l'ont deja fait.
Heu... bof j'ai rien pigé parce que non seulement je ne connais pas un mot à l'assembleur mais en plus ton prog est bien trop gros pour que je puisse m'y retrouver... smile
Et même pour Orwell qui connaît l'asm, je ne sais pas si ça lui est vraiment utile de regarder ta source...
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

33

Non à vrai dire je n'ai pas trop essayé non plus, en plus moi je ne connais que l'asm x86 (je devrais commencer le sh3 bientot aussi) donc ben... je garde les sources en réserve pour les longues soirées d'hiver quand j'aurai plus rien à lire tripo

Sinon pour en revenir à mon prog il me reste 3 jours pour boucler la prochaine version sick et j'ai pas encore revu grand chose dans la gestion des collisions dont je vais voir ça maintenant... J'essaierai de mettre une video ou quoi pour ceux qui veulent voir ce que ça donne (mais je promets rien, on n'a pas d'outils comme VTI pour ca sad)
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

34

Il n'y a pas d'émulateur pour cette calculatrice? eek ou bien c'est juste qu'il n'y a pas d'outil comme TIShot pour prendre des captures?
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

35

On a un ému (depuis peu) qui nous sert bien pour les tests et qui permet déjà de faire des snaphots, mais l'auteur s'est envolé dans la nature aux 3/4 du boulot (tout n'est pas encore émulé, et il manque la possibilité de faire des videos) :'(
Faudrait vraiment qu'on le relance un de ces jours lol
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

36

Juste un mot pour dire que je fais subir des "épreuves" à sonic pour tester son adhérence à la route grin J'ai gardé la base de mon ancien système pour le moment (pas le temps de tout reprendre à zéro) et j'approxime les courbes par des sections de pentes droites (ce qui est acceptable avec du 8*8 happy)
Cette version ne permettra pas encore de courir sur les murs ou de faire des loopings, mais ça sera pour bientôt smile

Exemple d'epreuve a passer pour que sonic décroche son permis: triso
test.png
Jusqu'ici le suivi de la courbe est bon, il ne passe pas au travers (c'est déjà ça), par contre il décolle un peu trop vite du sol en remontant, va falloir régler ca grin
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

37

Pas mal smile
Essaie donc de lui faire un dos d'âne comme ceci:
dosdane.png
(ok je n'ai aucun goût pour le mapping grin)
Si ça ne marche pas correctement (i.e. ton personnage va trop vite dans la pente montante), alors il faudra que tu prennes en compte la vitesse x et la vitesse y indépendamment (vy=sin[angle], vy=cos[angle]) wink
Perso j'ai un peu bidouillé. Je modifie juste la vitesse x, -> vx=cos[angle] pour angle<45. Et après (>45°) vx <-> vy et ainsi de suite. Comme Sonic "colle" à la plate-forme, vy sera automatiquement gérée par le moteur de collisions qui va "remonter" Sonic pour le remettre à la surface de la terre smile
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

38

Il faudra que j'essaie des trucs comme ça pour la prochaine version effectivement... je n'ai pas eu le temps d'implémenter tout ça pour cette version-ci happy

Un autre problème aussi c'est que je commence à frôler la limite acceptable pour la taille des exécutables sur g100 (qui est d'un peu moins de 50 ko pour un prog comme ça): J'ai déjà du mettre sonic au régime forcé pour qu'il accepte de fonctionner correctement grin
Donc je vais devoir trouver un code pas trop gros pour gérer tout ça (le cpp c'est bien, mais ca bouffe de la place ça c'est clair)

En attendant, c'est toi qui as créé cet éditeur de maps Brunni? Je pourrais peut-etre m'en inspirer pour rendre le mien plus facile d'usage happy
Sinon pour ceux que ca intéresse j'ai rassemblé quelques screenshots ici, je n'ai malheureusement pas de videos mais bon ça montre déjà à quoi ca peut ressembler (le jeu tourne actuellement à une moyenne d'entre 20 et 30 fps). wink
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

39

bravo!

40

L'éditeur de maps que j'ai utilisé ci-dessus s'appelle GBA Graphics (lien). C'est un éditeur de maps universel, il n'est pas prévu spécialement pour Sonic, même si j'ai codé certaines fonctionnalités dans cet esprit. cheeky
Il est prévu pour la GBA, mais comme le format de maps est universel, il va juste devoir te convertir la bitmap que tu vas utiliser comme tileset au format GBA, mais tu peux l'ignorer et n'utiliser que la map en sortie. smile
Mais sinon pour la limite des 50ko, ça inclut les maps ou non? Parce que sinon il y a des algos simples de "compression" wink (la méthode de base de la sonic team étant quelque peu limitative).
Perso c'est un truc tout con qui s'apparenterait au RLE, mais je ne suis pas sûr. A chaque frame, il faut décompresser la partie de la map dont on a besoin (écran+un peu autour) pour pouvoir s'en servir pour les collisions et l'affichage. wink
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

41

La limite des 50 ko concerne principalement la taille du code, sans les données externes et l'espace mémoire utilisé pour les variables etc. Mon problème était que le code devenait trop gros... Mais j'ai réfléchi à une solution pour ne pas avoir à utiliser les fonctions d'accès aux fichiers externes (fopen, fread, fseek etc), ça devrait me libérer ~15 ko happy

J'ai aussi pensé au fait qu'il faudrait réussir à ne décompresser que ce qui est nécessaire pour la map, seulement je n'ai aucune idée de la manière dont on pourrait s'y prendre pour arriver à retrouver les octets concernés dans les tableaux compressés... Pour ma part je compresse mes maps au moment de leur création avec un RLE assez simple, et puis je décompresse tout en une fois pendant le chargement dans un recoin de la mémoire (en fait selon les méthodes utilisées pour l'enregistrement de matrices, de programmes basic etc). Ca demande pas mal de mémoire disponible, mais c'est encore acceptable... Enfin si je peux faire qq chose de plus économique, je ne me plaindrai pas cheeky
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

42

Bon, quand je dis RLE, je ne sais pas si c'est vraiment ça... mais bon personnellement c'est très simple; je travaille par ligne, et j'ai un index (dire l'octet n° x = bloc compressé n° y) et une petite sauvegarde des variables importantes de la décompression. Après, je compare l'index de chaque ligne et le nouvel index (à cette frame) et je parcours la map dans un sens ou dans l'autre jusqu'à ce que les deux index soient égaux (en me servant des variables internes sauvées). Ensuite, je peux poursuivre la décompression sur la ligne courante sans problème.
Donc en tombant de très haut (et de très loin vers la droite), on peut demander beaucoup de travail, car si certaines lignes qui sont découvertes pour la première fois (leur index est encore 0), il faut que je les parcoure jusqu'à un index relativement élevé avant de commencer à les décompresser puis les afficher.
Sinon tu as déjà un moteur de gestion des objets? Parce qu'il faut en faire un qui soit très performant (plus que le mien je te souhaite parce que c'est pas la joie), dans Sonic tu auras à gérer plusieurs centaines d'objets 60 fois par seconde. A 8 MHz comme sur Mega Drive (sauf que les instructions du 68000 prennent un nombre de cycles multiple de 4 sauf erreur), ça fait ristret' wink
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

43

Brunni :
Bon, quand je dis RLE, je ne sais pas si c'est vraiment ça... mais bon personnellement c'est très simple; je travaille par ligne, et j'ai un index (dire l'octet n° x = bloc compressé n° y) et une petite sauvegarde des variables importantes de la décompression. Après, je compare l'index de chaque ligne et le nouvel index (à cette frame) et je parcours la map dans un sens ou dans l'autre jusqu'à ce que les deux index soient égaux (en me servant des variables internes sauvées). Ensuite, je peux poursuivre la décompression sur la ligne courante sans problème.
Donc en tombant de très haut (et de très loin vers la droite), on peut demander beaucoup de travail, car si certaines lignes qui sont découvertes pour la première fois (leur index est encore 0), il faut que je les parcoure jusqu'à un index relativement élevé avant de commencer à les décompresser puis les afficher.

Et c'est assez rapide tout ça? neutral
Brunni
: Sinon tu as déjà un moteur de gestion des objets?
Toi t'as pas regardé mes screenshots tongue

Perso je ne gère pas tous les objets de la map en même temps, je traite seulement ceux qui sont dans la région de l'écran que j'ai appelée le "scope": c'est une zone centrée sur l'écran mais plus large de quelques tiles de chaque côté. En fait c'est surtout pour cette gestion des objets que le cpp est très utile...
J'ai attribué un id à chaque objet (selon son type, son plan etc), et j'utilise une des trois couches de la map pour contenir les id des objets à créer sur tel ou tel tile; à chaque déplacement de 8 pixels sur la map je scanne la ligne de tiles qui est apparue sur le coté du scope, et si je tombe sur un id d'objet il me suffit d'allouer une nouvelle instance de la classe correspondant à cet objet happy

Ensuite chaque objet gère lui-meme ses déplacements, ses interactions avec le perso etc et vérifie s'il se trouve toujours dans le scope; s'il en est sorti je replace son id à sa position initiale dans la map (si nécéssaire) et je delete son instance.

Le point positif est que je n'ai donc que peu d'objets à gérer simultanément, par contre le fait que leur nombre (et leur taille) soit tres variable a de grosses influences sur le framerate (notamment lorsque sonic est blessé et qu'il faut faire voler des anneaux dans tous les sens); c'est pour ça que les timers me sont très précieux, puisque grâce à eux on ne décèle aucun ralentissement dans le jeu même si j'ai tout à coup 3 fois plus d'objets à gérer happy
Un autre point négatif à ma méthode est que les objets sont incapables d'interagir entre eux... mais je n'ai pas encore trouvé de cas où cela serait nécessaire.
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

44

Et c'est assez rapide tout ça?
Oui. Tout compris ça donne 4% d'une frame (à 60 frames/secondes donc) sur GBA, pour décompresser 23x18 blocs 16 bits sur une map de 1024x512. Comme je te l'ai dit, il y aura des ralentissements dans certains cas, mais même s'ils peuvent être importants, ça passe inaperçu (une seule frame ratée ne se remarque même pas). Bon, comme il y a deux plans, total: 8%. Ca reste vivable, et surtout mon code C largement optimisable. tongue
Toi t'as pas regardé mes screenshots
Sans vouloir la jouer boulet, je peux les trouver où? black
Perso je ne gère pas tous les objets de la map en même temps, je traite seulement ceux qui sont dans la région de l'écran que j'ai appelée le "scope": c'est une zone centrée sur l'écran mais plus large de quelques tiles de chaque côté. En fait c'est surtout pour cette gestion des objets que le cpp est très utile...
Je suis d'accord avec toi sur le principe, en revanche pas pour ce qu'il s'agit de l'utilité du C++. Perso j'utilise des structures, et je suis plus que satisfait, en plus d'être sûr que le code est rapide (puisqu'il y en a besoin tongue). Sans compter que le C++ est réputé pour générer de très gros codes, donc si tu es limité en place, ce n'est pas non plus l'idéal.
Le point positif est que je n'ai donc que peu d'objets à gérer simultanément, par contre le fait que leur nombre (et leur taille) soit tres variable a de grosses influences sur le framerate (notamment lorsque sonic est blessé et qu'il faut faire voler des anneaux dans tous les sens); c'est pour ça que les timers me sont très précieux, puisque grâce à eux on ne décèle aucun ralentissement dans le jeu même si j'ai tout à coup 3 fois plus d'objets à gérer
En effet, mais bon perso j'ai du abandonner. J'en ai marre de passer tant de temps à l'optimisation. S'il pourrait éventuellement y avoir peut-être parfois des ralentissements à certains moments, ça ne me démonte pas, sinon je n'en aurai jamais fini grin. Et au pire, le jeu peut toujours tourner à 30 fps grâce au frameskip, ça n'est pas trop gênant.
Un autre truc: bien que tu utilises des timers, la gestion des objets reste vitale hm? Enfin si tes bagues volent (tiens pas encore implémenté ça moi), tu dois continuer de les gérer, hors écran ou non, sinon elles vont être dépendantes du framerate... donc ton moteur d'objets (hors affichage) se doit d'être optimisé, timer ou non (ou bien j'ai rien pigé?).
Un autre point négatif à ma méthode est que les objets sont incapables d'interagir entre eux... mais je n'ai pas encore trouvé de cas où cela serait nécessaire.
D'ailleurs je crois bien que les jeux originaux non plus ne le font pas. La vitesse de leur moteur est déjà assez impressionnante comme ça, ajouter ce genre de détection serait du suicide.
Sinon, je ne sais pas si tu y avais pensé, mais bon pour la gestion de tes persos, il y a une méthode assez simple à mettre en oeuvre. A la place de mon gros switch habituel de bourrin:
switch (objets[i].type)
{
   case ENNEMI_ROULANT:
       [...]
       break;
}
Qui est très lent, mon handler actuel ressemble alors à ça. void IN_IWRAM GerePersos(SONIC *sonic, ECRAN *ecr)        {     int i, x,y;     unsigned short dehors_ecran;     unsigned int msg;     //Prend beaucoup de temps car gère des persos inutiles.     //Optimisable, en ne gérant que le nombre d'objets actifs.     for (i=0;i<LIMITE_PERSOS;i++)   {         if (!persos[i].type)             continue;         x=persos[i].x-ecr->scrlX;         y=persos[i].y-ecr->scrlY;         if (x<-64 || y<-64 || x>=240 || y>=160)             dehors_ecran=TRUE;         else             dehors_ecran=FALSE;         if (dehors_ecran && persos[i].instructions&INSTR_SEULEMENT_ECRAN)       {             persos[i].nObj=0;             continue;         }         msg=0;         if (!dehors_ecran)      {             if (persos[i].instructions&INSTR_COLLISION_DECOR)       {           //Requiert un moteur de collisions standard                 Exec(MoteurCollisionObjets,&persos[i],0,2);             }             if (persos[i].instructions&INSTR_COLLISION_SONIC)       {           //Requiert une détection de collision avec Sonic                 if (CollisionEntreDeuxSprites(sonic,&persos[i]))                     msg|=MSG_COLLISION_SONIC;                                   //Enverra un message signalant la collision             }             msg|=MSG_AFFICHER;         }         persos[i].fHandler(sonic,&persos[i],msg);                    //Exécute le handler qui retournera le numéro d'un nouveau sprite         if (dehors_ecran)             persos[i].nObj=0;         else             persos[i].nObj=objetsUtilises;     } }
Tu noteras que c'est beaucoup plus souple (mais bon ça reste largement optimisable), puisque chaque perso a son propre "handler" et que les instructions y sont envoyées. Les handlers (code) se trouvent en ROM (accès lent), alors que le code du handler standard se trouve en IWRAM (accès rapide), j'ai donc fait cela principalement pour économiser de l'IWRAM.
Et comme les handlers d'objets reçoivent un pointeur sur Sonic et sur leur objet ainsi qu'un message, il y a tout ce qu'il faut pour gérer ce dont on a besoin.
Sinon pour une décompression (vraiment) rapide, tu peux envisager d'utiliser la méthode originale dans les Sonic sur Mega Drive. En fait c'est très simple: tu as des tiles de 16x16 (composées de 4 tiles hardware 8x8) groupées en grandes tiles de 256x256. Les maps contiennent donc ces grosses tiles, et fonctionnent de la même manière que la "compression" pixels -> tiles. Sauf que là c'est tiles -> écrans, un niveau supplémentaire quoi. Ainsi, tu peux trouver la tile voulue très simplement (et rapidement): tiles[map[x>>8,y>>8],y&7,x&7], sans avoir à prendre du temps pour la décompression. cool
notamment lorsque sonic est blessé et qu'il faut faire voler des anneaux dans tous les sens); c'est pour ça que les timers me sont très précieux, puisque grâce à eux on ne décèle aucun ralentissement dans le jeu même si j'ai tout à coup 3 fois plus d'objets à gérer
Pas si tu codes comme moi! grin Mon premier essai de moteur de Sonic sur TI ne pouvait tout simplement pas atteindre le full speed! Il bloquait (frameskip infini, temps-frame-skippée>temps-requis). bang
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

45

J'ai mis quelques screenshots ici: http://orwell01.free.fr/Sonic/ wink
Un autre truc: bien que tu utilises des timers, la gestion des objets reste vitale hm? Enfin si tes bagues volent (tiens pas encore implémenté ça moi), tu dois continuer de les gérer, hors écran ou non, sinon elles vont être dépendantes du framerate... donc ton moteur d'objets (hors affichage) se doit d'être optimisé, timer ou non (ou bien j'ai rien pigé?).
Quel que soit l'objet, les mouvements sont basés sur le temps et pas sur le framerate... Je n'ai donc pas besoin de savoir si les anneaux sont visibles ou non ou si leur nombre a changé etc

Je n'ai malheureusement pas la possibilité de choisir où vont se trouver mes fonctions dans la mémoire... Tout est en accès rapide par défaut normalement.
Il me semble que ma méthode est plus souple que ton code (enfin c une question de point de vue lol) pour gérer les différents comportements prores aux objets... Un petit bout de code pour illustrer: grin /* GESTION DES LISTES D'OBJETS */      // gestion des 3 plans d'objets "derriere" le perso void ObjGroup::gereArrierePlan() {      GestionListe(m_listes[0]);      GestionListe(m_listes[1]);      GestionListe(m_listes[2]); }      // gestion d'un des 4 plans d'objets void ObjGroup::GestionListe(Objet* &liste) {      if(liste==NULL) return;            bool reste = liste->estGere();     // appelle le handler de l'objet      GestionListe(liste->next);     // passe au suivant            if(!reste)     // suppression si nécessaire      {           Objet* vict = liste;           liste = liste->next;           delete vict;      } }      // ajoute un objet supplementaire a gerer void ObjGroup::add(Objet* nouv) {      nouv->next = m_listes[ nouv->m_liste ];      m_listes[ nouv->m_liste ] = nouv; } /* GESTION DES RINGS SIMPLES */ struct Ring : public Objet {      Ring(int X,char Y,uchar Type,Tile tile);      bool estGere();      void apparait();      bool interagitAvecPerso();      static Timer m_timerRotation;     // timer commun à tous les rings      Timer m_timerDisparition;      bool m_estAttrape; }; Ring::Ring(int X,char Y,uchar Type,Tile tile) : Objet(X,Y,Type,tile,1,POS_SPR_RING)      , m_estAttrape(false)      , m_timerDisparition(TIMER_OFF) {} bool Ring::estGere() {      bool peutRester = true;      bouge();      if(m_sortDuScope)      {           if(m_estAttrape==false) incrusteDansMap();           peutRester=false;      }      else      {           if(m_estAttrape==false) interagitAvecPerso();           else if(m_timerDisparition>48) peutRester=false;           apparait();      }      return peutRester; } void Ring::apparait() {      if(m_estAttrape) draw(4+((m_timerDisparition/10)&1));      else draw(m_timerRotation/10); } bool Ring::interagitAvecPerso() {      setNewPos(m_timerRotation/10);      if(persoEnContact())      {           lePerso->ajouteRings();           m_estAttrape=true;           m_timerDisparition.start(); // on commence a compter le temps qui s'écoule      }      return true; } void Objet::bouge() // on utilise la version par defaut: objet attache a la map {       m_x+=laMap.m_depH;      m_y+=laMap.m_depV;      if(m_x < -40 || m_x > 168 || m_y < -40 || m_y > 108) m_sortDuScope=true; }
J'ai mis les fonctions générales pour gérer les différents plans des objets (par ordre d'affichage à l'écran selon le type), et puis l'ensemble du code que j'ai du écrire pour gérer les rings fixes sur la map. Je trouve que le principe est assez simple: le handler (ici la fonction estGere() ) a à peu près la même forme pour tous les objets avec quelques modifs par ci par là... En tout cas, avec çà je définis entièrement le comportement de mon objet "ring". happy
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

46

waah... Tu veux pas le porter sur TI ? grin
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

47

nan grin
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

48

Pas mal, en effet et tu es bien avancé pour le moment. Tes screenshots sont très sympas.
Donc en fait si j'ai bien compris, tu pourrais (par exemple) ne gérer tes objets qu'une fois par seconde? C'est pas mal comme méthode, je m'y étais penché au départ mais j'ai été contraint d'abandonner car si le déplacement de Sonic (entre deux gestions d'objet) dépassait les 16 pixels, il pouvait passer au travers. Tu n'as pas ce problème toi? Quelle est la vitesse max de Sonic possible? (et la vitesse max sans que tu aies besoin de gérer les objets?).
Sinon ta méthode est plus souple en effet, mais en voyant ça, je me dis la même chose que toi pour la décompression:
Et c'est assez rapide tout ça? neutral
Tu as été jusqu'à combien d'objets (en tout, y compris ceux qui ne sont pas affichés) dans tes tests? (avant que ça ne rame trop). C'est vrai que pour dans ton cas le C++ est assez utile.
J'ai mis les fonctions générales pour gérer les différents plans des objets (par ordre d'affichage à l'écran selon le type), et puis l'ensemble du code que j'ai du écrire pour gérer les rings fixes sur la map. Je trouve que le principe est assez simple: le handler (ici la fonction estGere() ) a à peu près la même forme pour tous les objets avec quelques modifs par ci par là... En tout cas, avec çà je définis entièrement le comportement de mon objet "ring". happy
En effet. Mes handlers sont beaucoup plus compliqués, et il faut même gérer les collisions soi-même à partir du handler, mais je vais heureusement écrire des fonctions pour ça. Voici un exemple si ça t'intéresse: void hRoller(SONIC *s, PERSO *p, u32 msg)      {            //Handler pour l'ennemi roulant     if (msg&MSG_COLLISION_SONIC)                //Il doit mourir?         p->type=0;     if (msg&MSG_AFFICHER)     {                 //Faut-il afficher le personnage?         //Le déplacement ne doit s'effectuer que dans ce cas (car le moteur de collisions est sauté sinon)         p->x--;                                 //Le déplace sur la gauche         CreeObjetStandard(pAjSprite(ennemis_tiles,32*64),1,1,3);     }     return; }
Mais bon, je vais très certainement réimplémenter le handler d'objets en ASM, car c'est la seule chose qui doit être optimisée, alors je peux bien y passer un peu de temps grin
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

49

C'est assez rapide, contrairement à ce qu'on pourrait croire... Ma gestion des listes d'objets est plus efficace qu'un simple tableau dans lequel on devrait chercher des emplacements libres pour rajouter des nouveaux objets par exemple; quant aux appels de fonctions membres (meme virtuelles) utilisées dans les handlers, ca n'est jamais qu'un petit accès en mémoire supplémentaire par appel, et honnetement je ne pense pas que ça soit vraiment plus lourd que d'utiliser des pointeurs sur fonctions par exemple... mais bon je ne suis pas expert dans ce domaine, je sais juste utiliser le cpp pour implémenter des trucs plus "facilement" qu'avec le C... cheeky

Je reconnais par contre qu'on a vite fait de générer des codes énormes en C++. J'ai d'ailleurs eu la blague il n'y a pas longtemps en dépassant la taille maximum pour mon exe tongue Mais ce qu'il se passe en fait c'est qu'on a tendance à définir une quantité impressionante de fonctions inline (surtout avec les fonctions membres de classe), et qu'on les utilise sans vraiment se rendre compte du nombre d'opérations qu'elles contiennent...

C'est le cas par exemple avec des constructeurs qui ne contiennent quasiment aucune initialisation "explicite" : on le laisse dans la déclaration de la classe pour ne pas encombrer le fichier .cpp, du coup il devient inline et on est tout étonné de découvrir les dizaines d'opérations qui apparaissent dans le code généré, à un endroit du code où on veut "bêtement" allouer une nouvelle instance par exemple...

Idem pour les autres petites fonctions inline etc smile le tout c'est de connaitre les "dangers", et de surveiller que tout se passe comme on veut (on apprend bcp de choses intéressantes avec le code asm généré par le compilo grin)

Sinon pour le moment le framerate se situe entre 20 et 40 fps, donc je n'ai pas trop de problèmes de vitesse jusqu'ici happy J'ai essayé d'estimer la vitesse maximale que pourrait avoir sonic, et je dirais qu'à tout casser il pourrait se déplacer à une vitesse de 15 pix/frame mais ça c'est tellement rapide qu'on a a peine le temps de voir où on va... tongue le sprite de sonic lui-même fait un peu plus de 16 pixels de large, mais mon moteur de collisions entre sprites est également prévu pour les cas extrêmes donc je n'ai pas trop à m'inquiéter smile

En attendant, je peux gérer une trentaine d'objets sans problèmes et c'est largement suffisant pour le petit écran de la g100; mais bon honnetement j'ai déjà remarqué que ce n'est pas la rapidité du code qui compte, c'est plutôt la rapidité d'affichage des sprites... Le simple fait d'afficher un ring à l'écran est une opération bien plus lourde que de le gérer, crois-moi sad
(avant que ça ne rame trop)

Mouarf cheeky Le jeu ne ramera jamais. Par contre il pourra être moins fluide vu qu'un même mouvement devra par exemple être effectué en un nombre de frames moins élevé...
Pour donner un exemple de mouvement indépendant du framerate, voici le code de déplacement des projectiles lancés par les ennemis (boule de feu pour le crabe et noix de coco pour le singe): ils suivent une trajectoire pseudo parabolique et passent à travers les obstacles de la map. smile      // dep horiz: vitesse constante int time = m_timer>>1;    // time donne la position théorique;    // on se deplace de 1 pixels toutes les 2 unités de temps    // ( -> ~25 pix/sec ) char dep = time - m_distParcX;     // dep a effectuer m_x+=(m_speedX>0 ? dep : -dep); m_distParcX+=dep;      // dep vertic: subit la "gravite" int postheo = (m_speedY*time - 4*time*time)/32;     // v0 = m_speedY/16 , g = -8/16  m_y += m_posReelle - postheo; // les y sont comptés à l'envers m_posReelle=postheo;

Au fait la totalité de mon code est disponible avec le prog, si ca t'intéresse wink
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

50

Je vois... ben au début j'ai fait la même chose, mais j'ai été contraint d'abandonner. Par exemple, si mon objet n'était pas géré assez souvent et que Sonic tombait de haut, Sonic pouvait avoir avancé de plus de 30 pixels entre deux! Et comme le bumper (par exemple) fait 16 pixels de haut, Sonic passera inmanquablement au travers.
En fait si ta méthode fonctionne chez toi, c'est qu'il doit y avoir un truc auquel je n'ai pas pensé. Pour moi le problème principal est que certains ennemis (ceux qui requierent INSTR_COLLISION_DECOR par exemple) ne peuvent être gérés hors écran puisque la partie correspondante n'est pas décompressée sad tu as une solution? smile
Mouarf Le jeu ne ramera jamais.
Le mien oui, avec 512 objets de type plate-forme mobile par exemple, le temps CPU demandé pour la gestion (hors affichage) est déjà très proche du 100% (95% exactement), donc il est impossible dans ce cas-là de tenir une vitesse correcte, donc l'affichage ne se fera jamais puisqu'il n'y a pas le temps pour, donc le jeu rame, oui. tongue
C'est assez rapide, contrairement à ce qu'on pourrait croire... Ma gestion des listes d'objets est plus efficace qu'un simple tableau dans lequel on devrait chercher des emplacements libres pour rajouter des nouveaux objets par exemple
Je reconnais que ta méthode est bien meilleure.
Mais ce qu'il se passe en fait c'est qu'on a tendance à définir une quantité impressionante de fonctions inline (surtout avec les fonctions membres de classe), et qu'on les utilise sans vraiment se rendre compte du nombre d'opérations qu'elles contiennent...
Tu définis volontairement tes fonctions en inline? Perso je n'utilise vraiment jamais ce mot-clé. Sur ARM, l'appel des fonctions est assez rapide, et lorsque j'en ai besoin, j'utilise une macro.
main:
   b   fonction
   b   main
fonction:
   bx  lr
Comme tu le vois, un appel de fonction est très rapide (2 cycles), le retour également (3 cycles async). Je crois que les registres r0-r3 restent disponibles avec GCC sans qu'on aie besoin de les sauver/restaurer, donc c'est assez pour les petites routines.
le sprite de sonic lui-même fait un peu plus de 16 pixels de large, mais mon moteur de collisions entre sprites est également prévu pour les cas extrêmes donc je n'ai pas trop à m'inquiéter
Sonic avance combien de fois par seconde(indépendamment du framerate)? En fait qu'entends-tu par ces cas extrêmes?
mais bon honnetement j'ai déjà remarqué que ce n'est pas la rapidité du code qui compte, c'est plutôt la rapidité d'affichage des sprites... Le simple fait d'afficher un ring à l'écran est une opération bien plus lourde que de le gérer, crois-moi sad
Oui oui, mais ce que je voulais dire, c'est que la lenteur d'affichage des sprites n'est pas "grave", car ce n'est pas une partie vitale du jeu. En revanche, la gestion des objets se doit d'être rapide puisque tu ne peux pas y appliquer de "frameskip", et sans ça, ton jeu ne pourra rien faire.
Pour l'avancement de Sonic, tu es à combien de pixels par passe (de combien de pixels il avance avant de faire une détection de collisions sur la map? avec les objets?). Perso, c'est 2 px/passe sur la map, 16 px/passe avec les objets.
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

51

Pour moi le problème principal est que certains ennemis (ceux qui requierent INSTR_COLLISION_DECOR par exemple) ne peuvent être gérés hors écran puisque la partie correspondante n'est pas décompressée tu as une solution?

Décompresser entièrement la map ou bien ne gérer que les ennemis dans la zone de l'écran (celle dans laquelle la map est décompressée) je suppose grin
Le mien oui, avec 512 objets de type plate-forme mobile par exemple, le temps CPU demandé pour la gestion (hors affichage) est déjà très proche du 100% (95% exactement), donc il est impossible dans ce cas-là de tenir une vitesse correcte, donc l'affichage ne se fera jamais puisqu'il n'y a pas le temps pour, donc le jeu rame, oui.
Oui oui, mais ce que je voulais dire, c'est que la lenteur d'affichage des sprites n'est pas "grave", car ce n'est pas une partie vitale du jeu. En revanche, la gestion des objets se doit d'être rapide puisque tu ne peux pas y appliquer de "frameskip", et sans ça, ton jeu ne pourra rien faire.
C'est là qu'on voit la différence de philosophie Ti >< Casio cheeky
En fait j'avais déjà remarqué que vous faisiez attention au temps CPU utilisé par vos progs... les processeurs motorola supportent le multi-threading? confus J'avoue que je ne me casse pas trop la tête pour tout ça: à chaque frame, je gère tout et j'affiche tout, point barre. happy Evidemment au plus il y a de choses à gérer et au plus il y a à afficher, au plus le temps mis pour préparer le frame en buffers sera long, et donc au moins je pourrai en afficher par seconde... J'ai donc intérêt à optimiser la geston des objets et surtout les méthodes d'affichage de sprites si je veux garder un framerate élevé.

Il n'est donc pas question de frameskip dans mon prog... J'ai peut-etre une vision un peu simpliste de la prog en temps réel (pour moi c'est du tour par tour avec temps_tour -> 0), mais ça m'a donné de bons résultats jusqu'ici smile
En fait comme tu l'as dit il m'est tout a fait possible théoriquement de ne gérer tous mes objets qu'une fois par seconde (voire même moins), mais ça sera crade évidemment vu que chez moi la fréquence d'affichage est identique a la fréquence de gestion des objets. J'essaie donc de me maintenir autour de 20 fps au minimum.

La boucle principale de mon prog ressemble à ca:

Debut:
- affichage de l'arriere plan de la map
- affichage des tiles de la partie visible de la map
- gestion puis affichage du premier objet sur le plan 0
- idem avec l'objet suivant etc, puis avec les plans 1 et 2
- gestion des déplacement de sonic et interaction avec le clavier, puis affichage de sonic
- gestion et affichage du plan 3 pour les objets en avant plan
- affichage des indicateurs de score etc
- refresh
- vérifie si on ne demande pas d'afficher le menu de pause
goto Debut.

Donc chez moi c'est bien l'ensemble des instructions qui se trouvent dans cette boucle qui vont déterminer le nombre de frames par secondes (cad le nombre de passage dans la boucle par secondes)...
Pour l'avancement de Sonic, tu es à combien de pixels par passe (de combien de pixels il avance avant de faire une détection de collisions sur la map? avec les objets?). Perso, c'est 2 px/passe sur la map, 16 px/passe avec les objets.
En fait j'aurais du mal à te répondre exactement vu que je ne le sais pas moi-même... La vitesse de sonic est utilisée par le jeu en pixels par secondes, à un certain facteur multiplicatif près pour la précision. Et comme mon framerate n'est pas constant, je peux difficilement te donner l'équivalent en pix/frame.
Pour déterminer le mouvement que sonic doit effectuer, j'utilise la même technique que pour les projectiles selon la vitesse de sonic, sa position et le temps écoulé depuis le frame précédent. Ensuite j'effectue le déplacement pixel par pixel en testant les collisions avec la map. Pour les collisions avec les objets, j'ai une méthode qui utilise les "anciens" et "nouveaux" rectangles occupés par sonic et par chaque objet avant et après leur déplacement, et qui me sort des infos du genre "Sonic est entré de 3 pixels par la droite dans le sprite de l'objet": cet appel se fait dans la fonction persoEnContact() que tu peux voir dans le code de mes rings par exemple, et donc chaque objet peut savoir où se trouve le perso par rapport à lui si des interactions sont nécessaires en cas de contact. smile
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

52

Orwell :
C'est là qu'on voit la différence de philosophie Ti >< Casio cheeky
En fait j'avais déjà remarqué que vous faisiez attention au temps CPU utilisé par vos progs... les processeurs motorola supportent le multi-threading? confus J'avoue que je ne me casse pas trop la tête pour tout ça: à chaque frame, je gère tout et j'affiche tout, point barre. happy Evidemment au plus il y a de choses à gérer et au plus il y a à afficher, au plus le temps mis pour préparer le frame en buffers sera long, et donc au moins je pourrai en afficher par seconde... J'ai donc intérêt à optimiser la geston des objets et surtout les méthodes d'affichage de sprites si je veux garder un framerate élevé.
Il n'est donc pas question de frameskip dans mon prog...

Ben nan, c comme ça aussi pour la majorité des jeux TI...

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

53

En fait j'avais déjà remarqué que vous faisiez attention au temps CPU utilisé par vos progs... les processeurs motorola supportent le multi-threading? J'avoue que je ne me casse pas trop la tête pour tout ça: à chaque frame, je gère tout et j'affiche tout, point barre. Evidemment au plus il y a de choses à gérer et au plus il y a à afficher, au plus le temps mis pour préparer le frame en buffers sera long, et donc au moins je pourrai en afficher par seconde... J'ai donc intérêt à optimiser la geston des objets et surtout les méthodes d'affichage de sprites si je veux garder un framerate élevé.
Non, les TI ne supportent pas le multi-threading, mais le processeur est très peu performant, bien qu'il tourne à une fréquence élevée (12 MHz). Optimiser le dessin de sprites, c'est bien, mais si le jeu rame même s'il n'y a aucun sprite sur l'écran à cause du nombre d'objets trop élevé, ça ne va pas non plus. Mais sur TI ce n'est pas un problème en général non plus.
Donc si j'ai bien compris pour ton système d'objets, à chaque fois que Sonic avance, tu envoies un signal à tous les objets dans le scope? Pas mauvaise idée tiens. Je vais y réfléchir. smile
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

54

A la fois dans la plupart des jeux "temps réel" (par opposition aux jeux qui dépendent d'évênements blocants), et particulièrement pour un jeu de plate-forme, l'affichage des sprites prend la quasi-totalité du CPU, aussi optimise l'affichage des sprites est une priorité quand un jeu ramm.
avatar
Que cache le pays des Dieux ? - Forum Ghibli - Forum Littéraire

La fin d'un monde souillé est venue. L'oiseau blanc plane dans le ciel annonçant le début d'une longue ère de purification. Détachons-nous à jamais de notre vie dans ce monde de souffrance. Ô toi l'oiseau blanc, l'être vêtu de bleu, guide nous vers ce monde de pureté. - Sutra originel dork.

55

J'oubliais:
Tu définis volontairement tes fonctions en inline? Perso je n'utilise vraiment jamais ce mot-clé. Sur ARM, l'appel des fonctions est assez rapide, et lorsque j'en ai besoin, j'utilise une macro.
En fait en C++ toutes les fonctions définies dans la déclaration d'une classe sont automatiquement traitées comme étant inline: c'est un énorme atout pour encourager le principe d'encapsulation.

Par exemple en cpp il est déconseillé d'utiliser des variables publiques dans une classe, on préfere implémenter une fonction membre qui renverra la valeur de la variable. Exemple:
class C
{
public:
A(int x) : val(x) {} // constructeur inline
int val;
int valeur() { return val; }
setValeur(int x) { val=x; } // fonctions inline
}

C montruc;
montruc.val = 3; // déconseillé
montruc.setValeur(3); // ok
int x = montruc.val; // déconseillé
int x = montruc.valeur(); // ok

Pour quelqu'un qui a l'habitude du C, ca parait aberrant d'utiliser des fonctions valeur() et setValeur() plutot que de passer directement par la variable val. Par contre pour quelqu'un qui est habitué à la prog orienté objet, c'est vital! happy
L'avantage est que si à un certain moment je décide de ne plus utiliser de variable val et que je veux employer une autre variable membre, ou si simplement je veux la renommer en m_val par exemple, je n'aurai qu'à modifier le code de ces 2 fonctions, sans jamais devoir modifier le reste du prog. C'est ce qu'on entend par "encapsulation" des données wink

Là où je voulais en venir, c'est que le fait de devoir effectuer des appels de fonctions pour faire ça peut sembler très lourd (et ce n'est pas faux), c'est pour cela que les concepteurs du cpp ont décidé que toutes ces petites fonctions seraient inline par défaut. Et donc en fait au niveau du code machine généré, écrire montruc.val=3 ou montruc.setValeur(3), ça revient exactement au même! smile

Donc voilà pourquoi les fonctions inline sont si présentes en cpp, et à mon avis c'est en partie pour ça qu'on dit qu'il génere de gros codes vu qu'on a souvent tendance à définir des fonctions "trop grosses" directement dans la déclaration de la classe...
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

56

Brunni :
Donc si j'ai bien compris pour ton système d'objets, à chaque fois que Sonic avance, tu envoies un signal à tous les objets dans le scope? Pas mauvaise idée tiens. Je vais y réfléchir. smile


Ce n'est pas vraiment un signal... Les objets peuvent connaitre le dernier déplacement que sonic a effectué (tout comme ils peuvent savoir comment la map s'est déplacée pour y rester accrochés (je travaille en relatif tongue)), et donc simplement en regardant les intersections de leurs sprites au frame suivant, on peut savoir si un contact est apparu ou pas smile
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur

57

Et tu as combien "d'objets" par map, environ ?
avatar
Que cache le pays des Dieux ? - Forum Ghibli - Forum Littéraire

La fin d'un monde souillé est venue. L'oiseau blanc plane dans le ciel annonçant le début d'une longue ère de purification. Détachons-nous à jamais de notre vie dans ce monde de souffrance. Ô toi l'oiseau blanc, l'être vêtu de bleu, guide nous vers ce monde de pureté. - Sutra originel dork.

58

Pour quelqu'un qui a l'habitude du C, ca parait aberrant d'utiliser des fonctions valeur() et setValeur() plutot que de passer directement par la variable val. Par contre pour quelqu'un qui est habitué à la prog orienté objet, c'est vital!
Ah ok. J'utilise parfois le C++ sur PC, mais je ne me doutais pas de ça.
A la fois dans la plupart des jeux "temps réel" (par opposition aux jeux qui dépendent d'évênements blocants), et particulièrement pour un jeu de plate-forme, l'affichage des sprites prend la quasi-totalité du CPU, aussi optimise l'affichage des sprites est une priorité quand un jeu ramm.
En effet, mais comme je code comme un porc, le dessin des sprites ne représente quasi rien comparé au reste du code :]
Ce n'est pas vraiment un signal... Les objets peuvent connaitre le dernier déplacement que sonic a effectué (tout comme ils peuvent savoir comment la map s'est déplacée pour y rester accrochés (je travaille en relatif )), et donc simplement en regardant les intersections de leurs sprites au frame suivant, on peut savoir si un contact est apparu ou pas
Tu peux donc savoir si sonic a "traversé" l'objet, même si avec sa vitesse il est à présent à une distance de 100 pixels de cet objet?
Et tu as combien "d'objets" par map, environ ?
Je crois qu'il avait dit une trentaine, ce qui semble assez peu, je pense qu'il voulait parler du nombre max. sur l'écran.
Orwell> Essaie-voir d'en mettre 500 comme moi pour voir si ça rame aussi... wink
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

59

>En effet, mais comme je code comme un porc, le dessin des sprites ne représente quasi rien comparé au reste du code :]

A ce point là c'est inquiétant grin

>Je crois qu'il avait dit une trentaine, ce qui semble peu. Essaie-voir d'en mettre 500 comme moi pour voir si ça rame aussi...

Et ses maps sont elles-même divisées en sous-maps ou pas (oui j'ai pas lu tous les pavés de ce topic, désolé grin)
avatar
Que cache le pays des Dieux ? - Forum Ghibli - Forum Littéraire

La fin d'un monde souillé est venue. L'oiseau blanc plane dans le ciel annonçant le début d'une longue ère de purification. Détachons-nous à jamais de notre vie dans ce monde de souffrance. Ô toi l'oiseau blanc, l'être vêtu de bleu, guide nous vers ce monde de pureté. - Sutra originel dork.

60

Tu peux donc savoir si sonic a "traversé" l'objet, même si avec sa vitesse il est à présent à une distance de 100 pixels de cet objet?
Non bien entendu, mais ce n'est pas censé arriver souvent neutral
Et tu as combien "d'objets" par map, environ ?

J'ai compté les objets que j'ai placés sur une des maps 150*40 actuelles, et j'en ai à peu près 150. Evidemment cette map n'est pas grande du tout (comparée aux maps dans le vrai jeu), mais de toute manière le nombre total d'objets n'a aucune influence sur la fluidité du jeu... ce qui importe ce sont les objets que je dois gérer, et je n'en ai jamais + que 25~30 simultanément smile
avatar
Un ptit gars qui programme en C/asm sur sa casio et qui vient voir de temps en temps comment ça se passe par ici :)
Un peu de verdure dans ce monde obscur