Aller au contenu

Moteur physique #1


daemondragon
 Share

Recommended Posts

Je vais faire dans cette série de tutoriels, une construction suivit d'un moteur physique.

Tout d'abord : Qu'est ce qu'un moteur physique ?
Un moteur physique, est un programme qui permet de gerer la physique correctement, et qui déplace les personnages, tout en gérant les collisions.
(tout les problèmes de collisions d'un jeu viennent du moteur physique).

Ce qu'il faut savoir avant de commencer à le faire :
Le moteur physique, que je vais vous apprendre à faire, ne gérera que des rectangles, il est donc parfait pour les jeux de plate-formes, de type mario, mais aussi d'autre styles de jeu avec que des blocs (les jeux en tiles quoi) comme zelda. Et oui le moteur ne sera qu'en 2d !
De plus, le principe majeur d'un moteur physique est la réutilisabilité de celui-ci, ce qui veut dire pas de : IF MUR THEN ... ;)

L'architecture que nous allons utilisé est celle dite "à posteriori" :
-première étape, on génère des forces, comme la gravité, les forces de mouvement...
-deuxième étape, on applique ces forces.
-troisième étape, on détecte les collisions.
-dernière étape, on les corrige.

L'autre architecture, aussi appelé "à priori", utilise des matrices de résolution, afin de détecter l'instant exact de la collision.
Cette architecture est plus précise, mais elle est aussi beaucoup plus lente, c'est pourquoi AUCUN moteur physique de jeu vidéo ne l'utilise, l'architecture "à posteriori" offrant des résultats satisfaisants.
(Ce n'est qu'en cas extrêmes que l'ont remarque des problèmes, mais on ne les vois pas souvent).

Et on va donc commencer par créer un générateur de force, et qui va les stoker dans une structure, afin de les garder en mémoire.
(On attachera ensuite cette structure à un corps, afin de le déplacer)

typedef struct s_force_container
{
    t_force *permanent_force;
    t_force contact_force;
    t_force total_force;
}t_force_container;

Tout d'abord, j'ai distingué deux type de forces : les permanentes (la gravité, les mouvements...), et les forces de contact. celle là seront régénérées à chaque fois que le moteur se mettra à jour, donc on ne va pas créer de listes chaînées pour ça, car le risque qu'un malloc échoue devient très vite important, donc on va uniquement se contenter d'additionner les valeurs entre elles.
Les forces permanentes, elles, seront stockées dans la liste chaînées, afin de pouvoir en modifier une sans impacter les autres.
La force total_force, elle sert uniquement a connaître le total des forces permanentes et de contact, afin de bouger le corps en conséquences.
Les forces sont représentées par la structure suivantes :

typedef struct s_force
{
    float x;
    float y;
    struct s_force *next;
}t_force;

Les forces en x représente normalement l'axe horizontal et l'axe x, vertical. Il n'y a pas de sens ou de direction pour les axes, vous pouvez prendre
celui que vous voulez, il faudra juste adapter les forces en conséquence.

il nous faut maintenant une fonction afin d'ajouter ou d'enlever une force permanente.
La fonction d'ajout :

t_force *create_permanent_force(t_force_container *container, float x, float y)
{
    t_force *add = malloc(sizeof(*add));
    if (add != NULL)
    {
        add->x = x;
        add->y = y;

        add->next = container->permanent_force;
        container->permanent_force = add;
    }
    return (add);
}

la fonction retourne un pointeur vers la force, afin de la modifier quand vous voulez.
Les forces sont empiler les une à la suite des autres (l'ordre d'empilage n'a absolument aucune importance, c'est juste plus simple à programmer :) )
Et maintenant la fonction "d'enlevage" :

void delete_permanent_force(t_force_container *container, t_force *remove)
{
    if (container != NULL)
    {
        if (container->permanent_force != NULL)
        {
            t_force *search = container->permanent_force;
            char finish = 0;
            if (search == remove)
            {
                container->permanent_force = remove->next;
                free(remove);
                finish = 1;
            }
            while (search->next != NULL && !finish)
            {
                if (search->next == remove)
                {
                    search->next = search->next->next;
                    free(remove);
                    finish = 1;
                }
            }
        }
    }
}

Le seul truc dur a faire ici, c'est de penser a enlever la force, tout ne perdant aucun pointeur vers les prochaines forces, tout en ne faisant pas de segfault.

On s’occupe maintenant des forces de contact, les plus faciles :D .
pour en ajouter :

void add_contact_force(t_force_container *container, float x, float y)
{
    if (container != NULL)
    {
        container->contact_force.x += x;
        container->contact_force.y += y;
    }
}

il n'y a pas de fonction pour retirer une force, car pour retirer les forces directement additionner, il suffit juste d'ajouter son contraire.
Mais en revanche, il faut une fonction pour remettre à un certain nombre cette force, car je vous rappelle, il faut réinitialiser les forces de contacts a chaque mise à jour (bah oui sinon vous imaginez, il faudrait retenir a cause de quoi cette force de contact a été créer, vérifier si elle a toujours raison d’exister, le tout avec beaucoup de corps en mouvement, et le moteur va ramer très vite.
Bref la fonction :

void set_contact_force(t_force_container *container, float x, float y)
{
    if (container != NULL)
    {
        container->contact_force.x = x;
        container->contact_force.y = y;
    }
}

Toujours aussi simple, normalement pas de difficulté a comprendre :P .
Et enfin, il nous reste une dernière fonction a voir : celle qui calcule la somme de toutes les forces, afin de savoir la force finale pour bouger le corps.
Elle parcours la liste chaînées des forces permanentes, les additionnent, puis ajoute les forces de contacts et met le résultat dans total_force :

void calc_total_force(t_force_container *container)
{
    if (container != NULL)
    {
        float x = 0;
        float y = 0;
        t_force *force = container->permanent_force;
        while (force != NULL)
        {
            x += force->x;
            y += force->y;
            force = force->next;
        }
        x += container->contact_force.x;
        y += container->contact_force.y;

        container->total_force.x = x;
        container->total_force.y = y;
    }
}

Et voilà ! on peut maintenant ajouter ou enlever facilement des forces, permanentes où de contact.
Évidement, le code comme cela ne sert absolument a rien, il faut ajouter la notion de corps pour comprendre à quoi cela va servir.

  • Upvote 4
Lien vers le commentaire
Partager sur d’autres sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Invité
Répondre à ce sujet…

×   Vous avez collé du contenu avec mise en forme.   Supprimer la mise en forme

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Chargement
 Share

×
×
  • Créer...