Partage
  • Partager sur Facebook
  • Partager sur Twitter

[tech] tour Mickeymania

    17 août 2021 à 21:57:22

    Bonsoir,

    Pour mon jeu j'aimerais faire un niveau basé sur une tour (nebulus, mickeymania, super ghouls'n'ghosts...).

    J'ai déjà créé la tour avec 3 méthodes différentes pour voir les différents rendus. Un des plus propre est présenté ici. La méthode présentée utilise un unique tile et une table précalculée puis une mise à l'echelle directe de la texture.

    Il explique comment ça fonctionne ici. Je n'ai pas repris sa méthode pour la tour, mais ce sont les plateformes qui m'intéressent. Alors ok, pas de soucis pour l'animation et l'offset de la plateforme pour donner l'impression que ça tourne autour. Il explique que les plateformes sont des sprites et c'est là que j'ai un souci.

    Je n'arrive pas à imaginer comment il construit son niveau. J'imaginais créer une tile map en hauteur et d'une largeur équivalente au périmètre de la tour et de la faire défiler en modulo, mais les plateformes extérieures (qui apparaissent depuis l'arrière de la tour) stagnent un certain temps et consomment plus d'un tile. Du coup, je devrais avoir un offset variable...

    Bref, je nage un peu, vous auriez une idée ?

    Merci.

    Salutations.

    -
    Edité par drx 17 août 2021 à 21:58:35

    • Partager sur Facebook
    • Partager sur Twitter

    Bonhomme !! | Jeu de plateforme : Prototype.

      17 août 2021 à 22:17:54

      Salut !

      Sujet intéressant !

      Que veux tu dire par "elles stagnent un peu" ?  As tu un passage dans la vidéo ou on voit ça ?

      Comment fais tu ton rendu ? Avec une lib 2D ou bien en réelle 3D ? 

      Si je comprends bien, comme les plateformes dépassent du cylindre, alors évidemment on les voit de profile quand on est a 0° (mettons que l'origine du cylindre soit à droite), elles sont visibles de 180° a 360° ( = 0°), mais aussi on doit les voir passer derrière entre 0 et 10° par exemple et entre 170 et 180°.

      Mais par contre, les plateformes sont toujours en face d'un carreau du cylindre, donc oui, un tilemapping avec un modulo pour que ce soit périodique.

      En mémoire, c'est un bête tilemapping, il y a juste quand tu fais le rendu que tu fais le cylindre.

      • Partager sur Facebook
      • Partager sur Twitter

      Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

        18 août 2021 à 0:01:55

        Salut,

        Par stagner, j'entend que la plateforme se déplace peu en X sur l'écran. Quand elle arrive par derrière, elle reste presque sur place sur un paquet de frames. Seule l'animation change, mais pas vraiment la position.

        De la 2D. Je pense utiliser ma lib pour les sprites, elle a fait ses preuves jusque là. Je suppose que je pourrais fixer le hotspot sur la tilemap et avoir l'image de la plateforme plus ou moins éloignée du hotspot. Par contre ça risque de prendre beaucoup de temps en essais / erreurs pour affiner correctement les positions et que ça ait l'air un peu naturel pendant la rotation.

        Je vais faire un essai en affichant une grille histoire de me faire une idée du placement des tiles. Faut aussi que je pense aux collisions. Mes sprites sont des objets dans une liste que je dois scanner, du coup j'évite d'avoir trop d'objets, les collisions dans la map sont plus simples et rapides.

        Après j'ai un peu tendance à trop vouloir économiser, si ça se trouve avoir 20 ou 500 objets ne ferait pas de différence notable...

        Faut que j'y reflechisse plus que ça. J'aimerais pouvoir placer ce genre de niveau avec mon moteur actuel, j'ai un peu la flemme de refaire un moteur pour un niveau...

        Mais tilemap est une réponse qui me va. On est d'accord, je posais la question juste au cas où j'aurais manqué quelque chose. Les gars faisaient des effets tellement énormes avec tellement rien que je soupconne toujours qu'il y a un truc si simple et astucieux qu'on ne peut pas y penser...

        Après ça je m'attaquerai au problème des lianes, ça se faisait sur Atari 2600 (Jungle hunt) et je n'ai aucune idée de comment m'y prendre non-plus alors que des gamins de 17 ans en faisaient tous les jours sur leur Spectrum... J'ai l'impression qu'on a perdu un truc.

        Merci, je vais essayer de présenter un essai rapidement.

        • Partager sur Facebook
        • Partager sur Twitter

        Bonhomme !! | Jeu de plateforme : Prototype.

          18 août 2021 à 8:46:53

          Salut !

          Quand tu dis "pas vraiment la position", en fait ça vient de la fonction cosinus.

          Ton cylindre a une vitesse angulaire constante, et la position x d'un objet sur le cylindre est donc juste un cosinus

          Regarde cette vidéo à partir de 31s :

          https://youtu.be/w-hXOYZ2gpo?t=31

          Tu vois que de 31s a 36s, le point Q bouge relativement vite, et de 37s a 40s, il "ne change pas vraiment de position" comme tu dis.

          Donc si tu veux, pour un point P(x,y) sur ton tilemap, sa position à l'écran est Q(cos(x),y). Si dans tu fais avancer x de manière constante, alors il avance vite au milieu du cylindre, et lentement sur le bord.

          Pour les lianes de Jungle Hunt, c'est similiaire, c'est de la trigonométrie. C'est typiquement des équations de pendule qu'on voyait en cours de physique :

          https://fr.wikipedia.org/wiki/Pendule_simple

          (dans la partie resolution tu vois qu'il y a un sinus).

          Est ce que tu maitrises bien la trigo ?

          -
          Edité par Fvirtman 18 août 2021 à 8:47:05

          • Partager sur Facebook
          • Partager sur Twitter

          Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

            18 août 2021 à 10:04:08

            Ok...

            Pas trop de souci avec la trigo. Je ne fais pas ça naturellement, mais avec un papier et un crayon, je retrouve mes petits, j'ai des restes du lycée.

            En fait, c'est même comme ça que je fais la tour : je fixe un diametre (l'affichage est ma contrainte), en déduit le périmètre, puis je calcul l'angle (de la part de gâteu) correspondant à chaque brique, puis la largeur visible pour chaque frame (ici 32). Tout ça stocké dans une table pour le faire en semi-précalculé :

            ...
                //settings
                int tileWidth   = 32, //pix
                    tileHeight  = 16, //pix
                    towerDiam   = 192,//pix
                    numOfAnim   = 32; //num of pic in anim
            
                double tileAngle = 360.0/(towerDiam*PI/tileWidth);   //single brick angle on the tower
            
                int matrix[2*towerDiam/tileWidth][numOfAnim]; //precalc matrix// TODO(drx#1#) : alloc
            
            ...
            
            //filling matrix with precalc values
                for(int y = 0; y<numOfAnim; y++)
                {
                    double result   = 0.0,
                           angle    = tileAngle * y / numOfAnim,
                           maxValue = 0.0;
            
            
                    for(int x = 0; x < (2*towerDiam/tileWidth +1); x++)
                    {
                        result = towerDiam -(((towerDiam/2)*(cos(angle*PI/180.0))) + towerDiam/2); //offset from left of tower as 0
                        angle += tileAngle; //goto next tile
            
                        if(result >= maxValue)
                        {
                            result += 0.5; //ceil rounding
                            maxValue = result;
                            matrix[x+1][y] = ((int)result < towerDiam)? result+1 :towerDiam; //complete unfinished values
                        }
                        else
                        {
                            break;
                        }
                    }
                }

            Pas des plus élégant mais ça fait le boulot. Et c'est relativement simple à mettre en place pour un rendu pas trop dégueux.

            Mais tu as raison. Au final, mon problème n'est pas tellement la trigo, mais de penser à en faire usage. Je crois surtout que je sous-estime ces vielles machines en m'imaginant que gérer un peu de trigo aurait été de trop pour elles...

            La liane ne reste pas tendue, du coup cela ressemble plutôt à une succession de pendule, mais la base doit effectivement se trouver autour de ça.

            Merci pour l'info, je potasserai ça le moment venu.

            • Partager sur Facebook
            • Partager sur Twitter

            Bonhomme !! | Jeu de plateforme : Prototype.

              18 août 2021 à 10:29:50

              En fait c'est vrai que pour les vieilles machines il n'y avait pas d'unités de calcul flottant, donc c'était couteux de le faire.

              Du coup, dans pas mal de vieux jeux, ils précalculaient quelques valeurs de cosinus dans un tableau, ou alors faisaient une fonction qui calculaient rapidement un cosinus approximatif (pas exact mais rapide) en évitant au maximum le calcul flottant. Un truc même qui ressemble au cosinus sans en être suffit.

              Bien souvent, les mecs étaient quand même doués en maths, et précalculaient aussi des trucs vachement chiadés sur une feuille, et ensuite implémentaient un résultat en dur dans le code, ou une approximation acceptable. Ils trichaient beaucoup.

              Pour la liane, il se peut même que ce soit tout simplement une trajectoire précalculée, une fonction simple qui renvoie une position en dur en fonction du temps. L'élaboration de cette fonction ou de ce précalcul a surement du se faire sur papier par des matheux, et après ils ont donné à manger à la machine.

              L'essentiel est que ça ait l'air a peu près crédible avec peu de calcul. 

              EDIT :

              Je viens de faire un test pour voir. Juste la partie cylindre pour l'instant.

              Bon mes screenshots ci joints ne donneront rien, il faut le voir animé. Voici la texture périodique que j'ai utilisé (prendre en tant que mur.bmp):

              Ensuite voila le résultat que j'ai :

              Il y a 3 image, l'une c'est un scroll de mur droit (Renderflat), en dessus un mode cylindrique sans ombrage (RenderCyl), en 3e le mode cylindrique avec ombrage (RenderCylShade). Commente et décommente ces fonctions dans le main pour changer.

              #include <assert.h>
              #include <math.h>
              #include "sdl.h"
              
              SDL_Surface* Charger(const char* fic)
              {
                  SDL_Surface* tmp = SDL_LoadBMP(fic);
                  assert(tmp);
                  SDL_Surface* surf32 = SDL_CreateRGBSurface(SDL_SWSURFACE, tmp->w, tmp->h, 32, 0, 0, 0, 0);
                  SDL_BlitSurface(tmp, NULL, surf32, NULL);
                  SDL_FreeSurface(tmp);
                  return surf32;
              }
              
              Uint32 GetPixel32(SDL_Surface* surface, int x, int y)
              {
                  Uint8* p = (Uint8*)surface->pixels + y * surface->pitch + x * 4;
                  return *(Uint32*)p;
              }
              
              void PutPixel32(SDL_Surface* surface, int x, int y, Uint32 pixel)
              {
                  Uint8* p = (Uint8*)surface->pixels + y * surface->pitch + x * 4;
                  *(Uint32*)p = pixel;
              }
              
              void Renderflat(SDL_Surface* mur, SDL_Surface* work, float param)
              {
                  int i, j;
                  int shift = mur->w * param / (2 * M_PI);
                  for (i = 0; i < work->w; i++)
                     for (j = 0; j < work->h; j++)
                          PutPixel32(work, i, j, GetPixel32(mur, (i+shift)%mur->w, j));
              }
              
              void RenderCyl(SDL_Surface* mur, SDL_Surface* work, float param)
              {
                  int i, j;
                  for (i = 0; i < work->w; i++)
                  {
                      float c = (i * 1.0f / (work->w - 1)) * 2 - 1;
                      float angle = acos(c) + param;
                      int x = (int)(((angle / (2 * M_PI)) * mur->w)) % mur->w;
                      for (j = 0; j < work->h; j++)
                          PutPixel32(work, i, j, GetPixel32(mur, x, j));
                  }
              }
              
              void Shade(Uint32* pix, float coeff)
              {
                  Uint8* c = pix;
                  int i;
                  for (i = 0; i < 4; i++)
                  {
                      Uint8 tmp = c[i];
                      tmp = (int)(tmp * coeff);
                      c[i] = tmp;
                  }
              }
              
              void RenderCylShade(SDL_Surface* mur, SDL_Surface* work, float param)
              {
                  int i, j;
                  for (i = 0; i < work->w; i++)
                  {
                      float c = (i * 1.0f / (work->w - 1)) * 2 - 1;
                      float angle = acos(c);
                      float attcoef = sin(angle);
                      int x = (int)((((angle + param)/ (2 * M_PI)) * mur->w)) % mur->w;
                      for (j = 0; j < work->h; j++)
                      {
                          Uint32 pix = GetPixel32(mur, x, j);
                          Shade(&pix, attcoef);
                          PutPixel32(work, i, j, pix);
                      }
                  }
              }
              
              int main(int argc,char** argv)
              {
                  // https://zestedesavoir.com/tutoriels/1014/utiliser-la-sdl-en-langage-c/modification-pixels-par-pixels/
                  SDL_Init(SDL_INIT_VIDEO);
                  SDL_Window* window = SDL_CreateWindow("Tour", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                      1200, 800, SDL_WINDOW_SHOWN);
                  SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
                  SDL_Surface* mur = Charger("mur.bmp");
                  SDL_Surface* work = SDL_CreateRGBSurface(SDL_SWSURFACE, mur->w, mur->h, 32, 0, 0, 0, 0);
                  SDL_Rect d;
                  d.x = 200;
                  d.y = 0;
                  d.w = mur->w;
                  d.h = mur->h;
                  float param = 0.0f;
                  for (;; param += 0.02f)
                  {
                      //Renderflat(mur, work, param);
                      //RenderCyl(mur, work, param);
                      RenderCylShade(mur, work, param);
                      SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, work);
                      SDL_RenderCopy(renderer, texture, NULL, &d);
                      SDL_DestroyTexture(texture);
                      SDL_RenderPresent(renderer);
                      SDL_Event event;
                      while (SDL_PollEvent(&event));
                      SDL_Delay(1);
                  }
                  SDL_FreeSurface(mur);
                  SDL_FreeSurface(work);
                  SDL_DestroyRenderer(renderer);
                  SDL_DestroyWindow(window);
                  SDL_Quit();
                  return 0;
              }
              



              -
              Edité par Fvirtman 19 août 2021 à 0:12:46

              • Partager sur Facebook
              • Partager sur Twitter

              Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                21 août 2021 à 1:57:09

                Salut,

                Je viens seulement de voir que tu avais ré-édité... C'est chiant les textures quand tu veux travailler sur les pixels hein ?

                Le mieux est de se faire une fonction blitSurfaceToTexture(), ça évite de se cogner le createTextureFromSurface() pour libérer la texture juste après tout en permettant d'avoir une surface pour travailler.

                Le rendu est propre, je retiens surtout l'ombrage que je n'ai pas prévu et qui fait vite la différence. Limite, c'est LE truc qui rend la chose tout de suite crédible.

                De mon côté, j'ai commencé à préparer la plateforme pour mes essais. Comme je ne l'ai pas trouvée sur les différents sites de ressources de sprites (que je connais), je l'ai extraite de la vidéo du gars : Il n'y a quand-même pas moins de 150 images à son animation... Ils ont bien profité de leur soft à 30 000$. Mais j'ai trouvé la tour que je ne cherchais pas...

                C'est ouf de se dire que ça t'as pris quelques minutes pour le faire en temps réel alors qu'il leur a fallu une machine et un soft qui ont couté une fortune pour le précalculer. Tout n'était pas mieux avant... :lol:

                • Partager sur Facebook
                • Partager sur Twitter

                Bonhomme !! | Jeu de plateforme : Prototype.

                  22 août 2021 à 15:31:02

                  Un soft a 30000 $ ? 

                  A la rigueur si c'est un ancètre de 3dsmax qui permet de faire des trucs en 3D (pour les petites plateformes qui ont été modélisées en 3D puis rendues en tant que 150 images comme tu dis), ça peut se comprendre.

                  Mais pour le cylindre, tes images précalculées de la tour, la il n'y a pas besoin d'un logiciel puissant pour faire ça. Comme tu as vu dans mon code, c'est des arc-cosinus et des sinus (en encore un par x (abcisse)). Sur nos machines c'est du temps réel. Avant ça aurait pris un peu de temps, peut être une poignée de secondes pour rendre la tour, mais pour fabriquer ton image "la tour" que tu as mis ça aurait été facile et relativement rapide ! Un petit programme sur une vieilles machines, quelques secondes (au pire minutes) de calcul et hop ! voila l'image !

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                    22 août 2021 à 16:34:08

                    Salut drx,

                    Si je comprends bien pour la tour, tu aurais besoin d'un set d' images avec une impression de plaquage de textures sur cylindre qui pourrait également (l'animation) tourner en boucle sans que l'on voit de reprise à l'image 0 au bout de l'animation. Je connais un logiciel (que j'utilise depuis de nombreuses années) qui permet de générer ce genre de textures. Je vais faire un essai de mon côté pour voir si j'y arrive.

                    A plus tard. :)

                    Edit:

                    Bonsoir,

                    Voici ce que j'ai obtenu avec l'image de Fvirtman en utilisant le logiciel POVRay (c'est un Raytracer). J'ai créé un cylindre dans une scène et puis j'ai plaqué une texture modifiée ( 6 * fois répétée sur la largeur pour une taille totale de 4800 x 800 ) dessus:

                    Le code de la scène:

                    #version 3.7;
                    
                    global_settings{ assumed_gamma 1.0 } 
                    
                    #declare FinalView = true;
                    
                    #if( FinalView )
                    	camera{
                    		orthographic
                    		location < 0, 0, -100 >
                    		look_at < 0, 0, 0 >
                    		right 2.02 * x
                    		up 1 * y
                    		direction 100 * z
                    		sky y
                    	}
                    #else
                    	camera{
                    		location vrotate(< 0, 1.2, -2 >, < 0, 90, 0 >)
                    		look_at 0
                    	}
                    #end
                    
                    light_source{ < 1, 1, -4 > * 1000000 color srgb 1 }
                    
                    #declare CylinderRadius = 1;
                    #declare CircleRound = 2 * pi  * CylinderRadius;
                    #declare Repeat = CircleRound / 2;
                    
                    #declare BrickPig = pigment{ image_map{ png "finalWall.png" gamma srgb map_type 2 once interpolate 2 } }
                    
                    
                    cylinder{ < 0, -1, 0 >, < 0, 1, 0 >, CylinderRadius
                    	pigment{ BrickPig translate <-0.5, -0.5, 0 > 
                    		scale < 1, 1, 1 >}
                    }

                    Et l'image:

                    Tower anim

                    Sachant que pour l'animation pas de prise de tête , j' ajoute un 'rotate y * Value' dans le code de la scène pour faire l'animation. :)

                    -
                    Edité par Warren79 22 août 2021 à 18:23:07

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Mon site web de jeux SDL2 entre autres : https://www.ant01.fr

                      23 août 2021 à 16:28:00

                      Vu que je code sur SNES et Mega drive, oui le cos et sinus était pré calculé.

                      "Ils trichaient beaucoup."
                      Je crois que c'est le maître mot , on triche beaucoup , on fait soit beaucoup de precalcul , soit on fait des calculs simple , mais qui donne l'effet voulu.

                      Par exemple les collisions sont souvent des points /rectangle sur ces machines,  mais en grossissant la hitbox , on a l'impression que c'est du rect/rect :)

                      Sinon la MD ne fonctionne que par tilemap donc ce qu'il font , c'est juste uploader chaque tile par rapport à la rotation.
                      tu as 12 tile de 16x16 à uploader soit 1,5ko/frame , la MD peut  transférer  7ko/frame en VRAM.

                      "Je crois surtout que je sous-estime ces vielles machines en m'imaginant que gérer un peu de trigo aurait été de trop pour elles..."
                      Impossible de faire de la trigo sur ces machines , tu n'avais clairement pas le temps pour ça (et puis t'avais pas de flottant non plus ) , le gros soucis c'est de faire rentrer ton jeu sur 16ms ,et je peux t’assurer que sur un vieux proc des années 80 , c'est pas beaucoup...

                      -
                      Edité par HelbaSama 23 août 2021 à 16:42:24

                      • Partager sur Facebook
                      • Partager sur Twitter
                        24 août 2021 à 17:06:26

                        Salut,

                        Merci pour votre aide.

                        Du coup j'ai bien raison de croire qu'il y avait une solution simple et de supposer qu'on ne faisait pas encore ce type d'opérations en temps réel. Je suis effectivement parmi les premiers à dire qu'il ne faut pas forcément le faire mais faire croire qu'on le fait, mais je ne le dis pas trop fort au boulot ^^. ça me rappelle un post ou un gars qui était en 3ième demandait comment faire des sauts et qu'on lui avait répondu polynômes, openGL et shaders pour faire ce qui peut se faire avec une paire d'additions...

                        Je fais beaucoup de précalculé en général, sauf que je le fais calculer par la machine au préalable pour stocker les résultats dans des tables. C'est juste que je n'avais pas envisagé qu'il puisse y en avoir autant.

                        Je me posais la question pour beaucoups de trucs que je voyais ici où là dans les jeux, mais en y réfléchissant bien, une petite table / matrice avec des points / corrections précalculés peut expliquer pas mal de trucs. Mais je suis un peu déçu quand-même du coup :(.

                        Après, je ne vais tout précalculer, je cherche à faire simple, ce qu'on trouve assez souvent à la vieille école, sans non-plus oublier que j'en ai sous le coude si nécessaire.

                        J'ai le temps et je n'ai de compte à rendre à personne, je cherche surtout des solutions qui me semblent élégantes, parce que j'aime quand un algo et son code ont de la classe... Bon, des fois non, je dois me contenter du fait que ça fonctionne :p.

                        Salutations.

                        • Partager sur Facebook
                        • Partager sur Twitter

                        Bonhomme !! | Jeu de plateforme : Prototype.

                          24 août 2021 à 17:42:26

                          Il est clair que precalculer du cos , c'est pas forcément utile de nos jours (surtout qu'on peut avoir le resultat assez rapidement ).

                          "C'est juste que je n'avais pas envisagé qu'il puisse y en avoir autant."
                          Si y'avait un truc où tu avais de la place sur ces machines ,c'était bien la ROM ;, et comme l'acces à la ROM et aussi rapide que la RAM (voir plus rapide sur SNES dans certain cas).
                          Ben il est plus intéressant non seulement de stocker des valeurs,  mais de l'utiliser pour faire des calcul (bon en Read only du coup ).

                          • Partager sur Facebook
                          • Partager sur Twitter

                          [tech] tour Mickeymania

                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                          • Editeur
                          • Markdown