Hugger Games

Ca faisait un moment que je n'avais rien posté ici, je pensais le faire pour la dernière Ludum Dare mais coup de grisou et manque de fun, je n'ai pas pu aller au bout de ma création du week-end.

Quoiqu'il en soit, je me suis dit que ça pouvait être une bonne idée de partager les quelques petites astuces sur Unity que j'ai dû mettre en place pour l'occasion !

Bon alors, de l'image ci-dessus, vous n'allez pas me croire mais la partie qui correspond à mon jeu c'est la partie du dessus:

Le principe du jeu c'était un croisement entre le monde de l'Athletisme et celui d'Alien. Oui le truc orange a gauche c'est sensé être le fameux Facehugger d'Alien et le truc bleu à droite c'est sensé être un Marine. Ils sont dans leur toute première version placeholder pour tester le jeu... sans même de queue pour le pauvre petit Alien, bouh. Je me faisais une joie de les affiner et les animer mais je n'ai pas eu le temps... je le ferai quand même peut-être un jour !

Quoiqu'il en soit, dans le cadre du thème "You are the monster", le principe de base c'était de faire un jeu d'Athletisme dans la vieille tradition où le joueur doit cliquer comme un malade pour faire avancer le Face Hugger et une fois arrivé devant l'obstacle de cliquer au bon moment pour faire un triple saut et finir sur la tête du Marine.

Avec quelques bras d'Alien avec des panneaux sortant du plafond pour donner des notes bien sûr.

Le nom du jeu:
Hugger Games

Dans l'idée, je trouvais ça pas mal... mais en pratique... le triple saut, il faut laisser tomber, quand on commence les 3 sauts, on ne voit pas le marine, donc difficile de donner l'opportunité de bien viser pour atterrir en pleine face.

Autre soucis aussi, passer en l'espace d'une seconde du clic,clic,clic,clic,clic,clic bourrin pour prendre de la vitesse, à un unique clic bien calculé pour finir sur la face, c'est rudement ardu pour le joueur. J'ai essayé plein de trucs et tourné ça dans tout les sens finalement le jeu était pas fun.

Quoiqu'il en soit dans mon idée originale je voulais pouvoir visualiser la trajectoire parabolique du facehugger, du coup j'ai cherché comment on pouvait faire ça dans Unity sans passer par des trucs trop tordus.

Attention, à partir de maintenant, si vous n'êtes pas développeur,
ça va ressembler à du chinois

Finalement, en cherchant sur le net je suis tombé sur une technique de rendu dans le OnPostRender de la Camera qui m'a fait aboutir à ce petit code:

    void OnPostRender()
    {
        GL.PushMatrix();
        m_linemat.SetPass(0);
        GL.LoadIdentity();
        GL.MultMatrix(Camera.main.worldToCameraMatrix);
        GL.Begin(GL.QUADS);
        GL.Color(m_curve_color);
 
        for (int i = 0; i < CURVE_SEGMENTS; i++)
        {
            if ((i & 1) == 1)
                continue;
            float _dx = (m_marine_x - m_jump1_x)*2.0f/3.0f;
            float _speedy = _dx * GRAVITY_HALF / m_speedx;
 
 
            float dt = _speedy / GRAVITY_HALF;
            float t1 = ((float)i * dt) / (float)CURVE_SEGMENTS;
            float t2 = (((float)i + 1.0f) * dt) / (float)CURVE_SEGMENTS;
            float x1 = m_jump1_x + m_speedx * t1;
            float x2 = m_jump1_x + m_speedx * t2;
 
            float y1 = _speedy * t1 - GRAVITY_HALF * t1 * t1;
            float y2 = _speedy * t2 - GRAVITY_HALF * t2 * t2;
 
            Vector3 _dir = new Vector3(y2 - y1, x1 - x2, 0).normalized*0.03f;
 
            GL.Vertex(new Vector3(x1, y1, 0) - _dir);
            GL.Vertex(new Vector3(x1, y1, 0) + _dir);
            GL.Vertex(new Vector3(x2, y2, 0) + _dir);
            GL.Vertex(new Vector3(x2, y2, 0) - _dir);
 
            if ((x1 + _dx) < m_marine_x)
            {
                GL.Vertex(new Vector3(x1 + _dx, y1, 0) - _dir);
                GL.Vertex(new Vector3(x1 + _dx, y1, 0) + _dir);
                GL.Vertex(new Vector3(x2 + _dx, y2, 0) + _dir);
                GL.Vertex(new Vector3(x2 + _dx, y2, 0) - _dir);
            }
        }
        GL.End();
        GL.PopMatrix();
    }
Pas très digeste hein ?

Quelques explications pour ceux qui suivent encore. Alors dans ce OnPostRender, on va en fait pouvoir afficher un tracé OpenGL par dessus tout le reste.
 
Ce qu'on trace c'est une parabole définissant le saut et la retombée par gravité. C'est quoi cette parabole, en fait c'est assez simple, on a une super formule en fonction du temps:
x = vitessex * temps
y = vitessey initiale * temps - coefficient de gravité  * temps²
Et je passe les détails mais on peut facilement trouver que notre bon vieux Facehugger retouchera le sol à l'instant:
t = vitessey initiale / coefficient de gravite
Du coup, on découpe ce delta temps en autant de morceau que l'on souhaite et en utilisant chaque t dans la super formule, on se retrouve avec une liste de points (x,y) et accessoirement une liste de segments qui définissent la parabole !
 
 
Ensuite ici on traçe des quads... des quads ? ce sont pas des lignes plutôt qu'il faut tracer ? Oui on peut tracer des lignes sauf qu'elles feront 1 pixel de largeur et seront moches, du coup il faut se rabattre sur des quads pour faire comme une ligne mais avec de l'épaisseur !
 
C'est grâce à notre petit Vector3 _dir qui est en fait le vecteur perpendiculaire au segment que l'on peut trouver les 4 coins de notre "ligne".
 
 
Autre point, dans le OnPostRender, on est sur de l'OpenGL brut, si on est pas dans le repère Camera, on doit jouer avec les matrices pour faire un tracé dans des coordonnées monde. Et là la petite astuce c'est le:
GL.MultMatrix(Camera.main.worldToCameraMatrix);
 
Dernier point, pour le rendu on utilise un material spécial qui permet de rendre une ligne colorée tout simplement. Le plus simple c'est de créer le material dans le Start du Behavior de la Camera:
m_linemat = new Material( "Shader \"Lines/Colored Blended\" {" +
   "SubShader { Tags { \"RenderType\"=\"Transparent\" } Pass { " +
   "    Blend SrcAlpha OneMinusSrcAlpha " +
   "    ZWrite On ZTest LEqual Cull Off Fog { Mode Off } " +
   "    BindChannels {" +
   "      Bind \"vertex\", vertex Bind \"color\", color }" +
   "} } }" );

 

Voilà c'est tout pour ce premier post un peu technique. On verra peut-être que j'en referrai si ça intéresse les gens.