Forum de la communauté SFML

Aide => Général => Discussion démarrée par: TheArrow le Avril 07, 2016, 11:58:51 am

Titre: Physique de saut
Posté par: TheArrow le Avril 07, 2016, 11:58:51 am
Salut à tous, je viens vers vous car comme mon titre l'indique j'ai un soucis avec la physique d'un saut 2D.
J'aime bien comprendre quand j'utilise quelques choses donc j'ai commencé à me remémorer mes cours sur la loi de newton.

https://www.kartable.fr/terminale-s/physique-chimie/specifique/chapitres-33/applications-des-lois-de-newton/cours/applications-des-lois-de-newton/22620

Dans ce cours, pour les équations horaires du mouvement on obtient ce système :

OG⎯→{ x(t)=0
          {  y(t)=v0⋅cos(α)⋅t
          { z(t)=−12⋅g⋅t2+v0⋅sin(α)⋅t


Dans le jeu la fonction y(t) correspond à l'axe x et z(t) correspond à l'axe y.
J'ai donc simuler un petit saut, voici le code:

void Game::play()
{
        gState = GAME_STATE::G_RUNNING;
       
        Map map;
        map.load(".\\Data\\Map\\level.map", "tile");

        Character player(sf::Vector2f(0, 0), "player");
        player.setCenter();

        int v_init = 2;
        int angle_init = Utils::pi / 3;
        float t = 0;


        while (getWindow().isOpen() && gState == GAME_STATE::G_RUNNING)
        {
                sf::Event event;
                while (getWindow().pollEvent(event))
                {
                        if (event.type == sf::Event::Closed)
                                getWindow().close();
                }

                if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
                {
                        gState = GAME_STATE::G_PAUSED;
                        break;
                }
                if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
                {
                        getView().move(3, 0);
                }

                sf::Vector2f jump;

                jump.x = cos(angle_init) * v_init * t;
                jump.y = -0.5 * Utils::g*pow(t, 2) + v_init*sin(angle_init)*t;

                getView().move(jump);
                t += 0.001;


                getWindow().clear(sf::Color::Black);

                getWindow().setView(getView());
                getWindow().draw(map);

                getWindow().setView(getWindow().getDefaultView());
                getWindow().draw(player);

                getWindow().display();
        }
}

Le soucis c'est que mon personnage monte bien mais il ne redescend jamais ou alors il redescendra dans quelques décennie.

Je ne vois pas trop d'ou peut venir ce soucis, j'ai mis l'incrémentation de t avec des valeurs très petite pour avoir le temps de bien voir la trajectoire.

Si quelqu'un pourrait m'aiguiller sur ce sujet, merci d'avance !
Titre: Re : Physique de saut
Posté par: Laurent le Avril 07, 2016, 12:53:58 pm
Citer
t += 0.001;
A moins que ton temps entre deux frames soit calé à 1 ms par un procédé qui n'est pas montré dans ce code, il faudra prendre le temps réel plutôt qu'une valeur arbitraire potentiellement très éloignée de la réalité. Utilise sf::Clock par exemple.
Titre: Re : Physique de saut
Posté par: TheArrow le Avril 07, 2016, 01:17:11 pm
J'ai mis le framerate à 60 avec la méthode de RenderWindow, du coup j'ai essayé de mettre 1/60 = 0.016 mais c'est pareil.

Titre: Re : Physique de saut
Posté par: kimci86 le Avril 07, 2016, 01:22:30 pm
Il me semble que le problème vient surtout de la façon dont tu positionnes ta View.
Tu appelles la méthode move alors que les formules te donnent un position.
Tu dois choisir : soit utiliser la méthode move et indiquer effectivement un déplacement, soit utiliser setCenter avec une position.
Titre: Re : Physique de saut
Posté par: TheArrow le Avril 07, 2016, 01:32:48 pm
J'ai essayé en déplacement le sprite avec setPosition mais le soucis reste le même.
Ca vient surement de mes paramètres utilisés dans la formule mais je trouve pas.
Titre: Re : Physique de saut
Posté par: G. le Avril 07, 2016, 02:21:01 pm
C'est combien g ?

Avec g = 10 ça monte jusqu'à y = 0.15 (https://www.google.com/#q=-0.5+*+10*t*t+%2B+2*sin(pi%2F3)*t), donc un sixième de pixel si t'as une vue où 1 unité = 1 pixel donc en gros tu devrais rien voir monter puis descendre tout le temps. (enfin l'inverse, car dans SFML y augmente vers le bas)
Et si g est négatif ça fait que monter (ou descendre) après t = 0

Ensuite déplacer la vue avec move avec ces valeurs là comme tu le fais c'est très douteux. Quand tu dis que tu déplace le sprite (sprite qui ne bouge jamais dans ton code d'ailleurs) avec setPosition tu parles de la vue ?
Titre: Re : Physique de saut
Posté par: TheArrow le Avril 07, 2016, 02:31:10 pm
g = 9.81

Sinon oui pour le fait que ça descend je n'ai pas édité mon code mais j'avais simplement ajouter "-" devant jump.y vu que c'est inversé.

void Game::play()
{
        gState = GAME_STATE::G_RUNNING;
       
        Map map;
        map.load(".\\Data\\Map\\level.map", "tile");

        Character player(sf::Vector2f(0, 0), "player");
        player.setCenter();

        float v_init = 0.15;
        int angle_init = Utils::pi/3;
        float t = 0;

        while (getWindow().isOpen() && gState == GAME_STATE::G_RUNNING)
        {
                sf::Event event;
                while (getWindow().pollEvent(event))
                {
                        if (event.type == sf::Event::Closed)
                                getWindow().close();
                }

                if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
                {
                        gState = GAME_STATE::G_PAUSED;
                        break;
                }
                if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
                {
                        getView().move(3, 0);
                }

                sf::Vector2f jump, lastPos, newPos;

                jump.x = cos(angle_init) * v_init * t;
                jump.y = -(-Utils::g*pow(t, 2)/2000 + v_init*sin(angle_init)*t);

                lastPos = player.getPosition();

                newPos = lastPos + jump;
                player.setPosition(newPos);
                t += 0.2;


                getWindow().clear(sf::Color::Black);

                getWindow().setView(getView());
                getWindow().draw(map);

                getWindow().setView(getWindow().getDefaultView());
                getWindow().draw(player);

                getWindow().display();
        }
}
 

Voici le code modifié, ou je déplace le sprite avec setPosition mais plus la vue.
Ça fait bien une parabole depuis que j'ai diminué la vitesse initiale à 0.15 et t avec une incrémentation de 0.2.

Ce qui me pose maintenant soucis c'est que j'aimerais bien savoir comment avoir mathématiquement la bonne valeur de t et de v_init, sans faire ça au pif x)
Titre: Re : Physique de saut
Posté par: Laurent le Avril 07, 2016, 03:04:41 pm
Tu fais toujours un move, sauf que maintenant il est déguisé (getPosition() + jump). Il faut juste faire setPosition(jump).
Titre: Re : Physique de saut
Posté par: TheArrow le Avril 07, 2016, 03:10:37 pm
Je ne comprends pas trop là, je dois obligatoirement ajouter la position actuelle en plus de celle du saut, sinon là mon sprite commence son saut aux coordonnées 0;0, il ne prends pas en compte le placement avant le saut.
Titre: Re : Physique de saut
Posté par: nicox11 le Avril 07, 2016, 04:22:39 pm
La loi de newton te donne la position "absolue" (je vais me faire tapper dessus par les vrais physiciens mais tant pis !) en fonction de temps. Elle ne dépends en aucun cas de la position précédente. De cette fait, comme le dit Laurent, il suffit de positionner ton sprite aux valeurs calculées par tes formules.
Titre: Re : Physique de saut
Posté par: TheArrow le Avril 07, 2016, 04:27:03 pm
Oui j'ai bien compris mais quand mon personnage saute il se trouve à des coordonnées x,y dans mon monde 2D et donc les positions du sauts calculées doivent être ajoutées aux positions pour que le saut soit dans la continuité du mouvement non ?

Pour preuve, si je fais setPosition(jump), mon personnage fait bien l'hyperbole mais en partant de 0,0 vu que je calcule les coordonnées du saut sans me baser sur sa position, tandis que si j'y ajoute la position actuelle le saut se fait en partant de là ou il a commencé.


Titre: Re : Physique de saut
Posté par: nicox11 le Avril 07, 2016, 04:33:58 pm
Citer
Oui j'ai bien compris mais quand mon personnage saute il se trouve à des coordonnées x,y dans mon monde 2D et donc les positions du sauts calculées doivent être ajoutées aux positions pour que le saut soit dans la continuité du mouvement non ?

Pas avec les formules que tu utilises en tout cas. Tu utilises le temps depuis le début de ton programme. Alors en effet à t=0, ton programme va faire ce que tu demandes. Par contre si tu attends un peu avant de faire le saut, tu vas te rendre compte du problème. Il faut que tu procède par incrément de temps.

Pour la valeur de v_init, on ne peut pas deviner ce que tu veux faire.

Je suppose que tu veux faire un jeu où tu as la possibilité de sauter, si oui voici un bon début de réponse (en anglais mais c'est case obligatoire dans le developpement !) :
http://gamedev.stackexchange.com/questions/29617/how-to-make-a-character-jump
Titre: Re : Physique de saut
Posté par: G. le Avril 07, 2016, 04:36:12 pm
Ouais mais là ton lastPos, c'est le lastPos + jump au t d'avant, auquel tu ajoutes encore le nouveau t, et ainsi de suite.
En gros ta position à t=0.6 c'est lastPos + jump(t=0) + jump(t=0.2) + jump(t=0.4) + jump(t=0.6)
Au lieu d'être juste lastPos + jump(t=0.6)

Ta formule là elle calcule la position dans un saut à partir du point de départ du saut, pas à partir de la position dans le saut à un t inférieur.

PS: c'est pour un jeu de plateforme ?
Titre: Re : Physique de saut
Posté par: TheArrow le Avril 07, 2016, 04:43:24 pm
Ah oui je vois merci du coup je dois simplement ajouter la position de départ (t = 0) du saut à chaque fois !
En faite c'est comme si le saut recommencé à chaque fois du coup.

Ça fonctionne parfaitement, merci beaucoup pour votre aide !

Oui c'est pour un jeu de plateforme.


Voici le code final pour ceux qui aurait le même soucis :

void Game::play()
{
        gState = GAME_STATE::G_RUNNING;
       
        Map map;
        map.load(".\\Data\\Map\\level.map", "tile");

        Character player(sf::Vector2f(0, 0), "player");
        player.setCenter();

        float v_init = 2;
        float angle_init = Utils::pi/3;
        float t = 0;

        sf::Vector2f lastPos = player.getPosition();

        while (getWindow().isOpen() && gState == GAME_STATE::G_RUNNING)
        {
                sf::Event event;
                while (getWindow().pollEvent(event))
                {
                        if (event.type == sf::Event::Closed)
                                getWindow().close();
                }

                if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
                {
                        gState = GAME_STATE::G_PAUSED;
                        break;
                }
                if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
                {
                        getView().move(3, 0);
                }

                sf::Vector2f jump, newPos;

                jump.x = cos(angle_init) * v_init * t;
                jump.y = -(-Utils::g*pow(t, 2)/2000 + v_init*sin(angle_init)*t);


                newPos = lastPos + jump;

                player.setPosition(newPos);
                t += 10;


                getWindow().clear(sf::Color::Black);

                getWindow().setView(getView());
                getWindow().draw(map);

                getWindow().setView(getWindow().getDefaultView());
                getWindow().draw(player);

                getWindow().display();
        }
}
 
Titre: Re : Physique de saut
Posté par: G. le Avril 07, 2016, 04:50:54 pm
En général on n'utilise pas de formule aussi rigide pour faire un simple jeu de plateforme. On part plutot sur du
position = position + vitesse * delta
vitesse = vitesse + acceleration * delta
mais c'est complètement autre chose
Titre: Re : Physique de saut
Posté par: TheArrow le Avril 07, 2016, 04:57:14 pm
Oui c'est sûr que ça aurait été moins compliqué mais je voulais mettre en oeuvre la loi de Newton :p
Titre: Re : Physique de saut
Posté par: Laurent le Avril 07, 2016, 06:08:55 pm
Citer
position = position + vitesse * delta
vitesse = vitesse + acceleration * delta
mais c'est complètement autre chose
En réalité c'est exactement la même formule, gérée différemment ;)
Titre: Re : Physique de saut
Posté par: Cpl.Bator le Avril 07, 2016, 10:33:14 pm
une remarque qui n'a rien n'a voir avec le sujet, mais vu dans le code :

 map.load(".\\Data\\Map\\level.map", "tile");

cette manière de faire n'est pas portable, autant utilisé '/' que '\\' , c'est portable et sa pique moins les yeux  ;D
Titre: Re : Physique de saut
Posté par: TheArrow le Avril 07, 2016, 10:43:55 pm
Au sujet du visuel je suis d'accord donc rien que pour ça je vais procéder comme tu me l'a dit merci, mais pourrait-tu me dire ce que ça change au niveau de la portabilité ? Je pensais que "\\" ce qui équivaut à "\" c'était pareil que "/"
Titre: Re : Physique de saut
Posté par: Laurent le Avril 08, 2016, 08:02:13 am
Il n'y a que sous Windows que le système de fichier comprend l'antislash \, sous Unix (Linux et Mac) c'est uniquement le slash /. Sous Windows c'est les deux, donc la conclusion est facile ;)
Titre: Re : Physique de saut
Posté par: TheArrow le Avril 08, 2016, 10:30:20 am
Ah oui effectivement, le sujet est donc résolu, je vous remercie pour votre aide.