IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Physique Discussion :

Sauter, tomber.. et avancer


Sujet :

Physique

  1. #1
    Membre habitué Avatar de poussinphp
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    428
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 428
    Points : 176
    Points
    176
    Par défaut Sauter, tomber.. et avancer
    Bonjour à tous !

    Suite aux petits soucis que j'avais eu, j'ai réussis grâce à vos conseil à pouvoir gerer les collisions dans mon petit jeu

    Maintenant le personnage bouge, si il y a du vide il tombe, je fais la distinction entre "murs" et "objets decoratif" et "paysage en fond" ce qui fais que le personnage ne passe pas à travers les murs mais à travers le reste. Le système de collision est en pixel perfect.

    J'ai néanmoin quelques soucis concerant certaines actions.
    Le personnage avance, si il y a un vide, il tombe mais instantanément (du à ma boucle). J'ai essayé de mettre un SDL_DELAY mais sans resultat. De plus, ça bloque les actions quand il tombe. impossible de le deplacer un peu sur la droite histoire d'eviter les pics

    Voici mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
     
        while (continuer)
        {
         // on efface l'ecran
       SDL_FillRect(ecran, NULL, SDL_MapRGBA(joueur->format, 0, 0, 0, 0));
       // on affiche la carte juste pour le test
       appliquer_carte(taille_carte_x, taille_carte_y, Position_Carte_X, ecran);
       // on attend l'evenement                   
       SDL_WaitEvent(&event);
       switch(event.type)
       {
        case SDL_QUIT:
             continuer = 0;
             SDL_EnableKeyRepeat(0, 30);
        break;
        case SDL_KEYDOWN:
             switch(event.key.keysym.sym)
             {
              case SDLK_ESCAPE:
                   continuer = 0;
                   SDL_EnableKeyRepeat(0, 30);
              break;
              case SDLK_LEFT:
                   if (run < 12)
                   {
                       if ((cle == 0) || (cle == 17) || (cle == 25)) {cle=18;}
                       if (cle < 25) {cle++;}
                       collision = test_collision_cote(ecran, taille_carte_x, taille_carte_y, cle, Position_Carte_X, -5); 
                       if ((position_sonic_X > TILE) && (collision != 1))
                       {
                         position_sonic_X = position_sonic_X-5;
                       }                   
                       if ((Position_Carte_X <= 0) && (collision != 1))
                       { 
                         Position_Carte_X = Position_Carte_X+4;
                       }  
                       run++;
                   }
                   if (run == 12) 
                   {
                       if (cle <= 29) {cle++;}
                       if (cle > 29) {cle=26;}
                       collision = test_collision_cote(ecran, taille_carte_x, taille_carte_y, cle, Position_Carte_X, -10); 
                       if ((position_sonic_X > TILE) && (collision != 1))
                       {
                         position_sonic_X = position_sonic_X-10;
                       }                   
                       if ((Position_Carte_X <= 0) && (collision != 1))
                       { 
                         Position_Carte_X = Position_Carte_X+8;
                       }  
                   }
              break;
              case SDLK_RIGHT:
                   if (run < 12)
                   {
                       if ((cle == 0) || (cle == 17) || (cle == 8)) {cle=1;}
                       if (cle < 8) {cle++;}
                       collision = test_collision_cote(ecran, taille_carte_x, taille_carte_y, cle, Position_Carte_X, 5); 
                       if (position_sonic_X < (L_FENETRE-(TILE*2)) && (collision != 1))
                       {
                         position_sonic_X = position_sonic_X+5;
                       }                   
                       if ((Position_Carte_X <= 0) && (collision != 1))
                       { 
                         Position_Carte_X = Position_Carte_X-4;
                       }  
                       run++;        
                   }
                   if (run == 12)
                   {
                       if (cle <= 12) {cle++;}
                       if (cle > 12) {cle=9;}
                        collision = test_collision_cote(ecran, taille_carte_x, taille_carte_y, cle, Position_Carte_X, 10);
                        if (position_sonic_X < (L_FENETRE-(TILE*2)) && (collision != 1))
                       {
                         position_sonic_X = position_sonic_X+10;
                       }                   
                       if ((Position_Carte_X <= 0) && (collision != 1))
                       { 
                         Position_Carte_X = Position_Carte_X-8;
                       }  
                   }
              break;
              case SDLK_DOWN:
                   if (cle == 17) { cle = 31; }
                   if (cle == 0) { cle = 14; }
              break;
     
              case SDLK_UP:
                   if (cle == 17) { cle = 32; }
                   if (cle == 0) { cle = 15; }
              break;
     
              case SDLK_SPACE:
                   position_sonic_Y = position_sonic_Y - 20;
                   cle = 9;
                   saut = 1;
              break;
     
              default:
                   // l'utilisateur appuis sur une touche non attribué
                   // On met l'image de sonic au repos par défaut
                   if (cle > 17) { cle = 17; }
                   if (cle < 17) { cle = 0; }        
              break;     
             }
        break;
        default:
            // Si rien ne ce passe on met l'image de sonic au repos
            if (cle > 17) { cle = 17; }
            if (cle < 17) { cle = 0; }
            run = 0;    
        break;
        }
     
    // si l'utilisateur saute pas, on test si ya un vide
        if ( saut == 0)
        {
          test_collision_bas(ecran, taille_carte_x, taille_carte_y, cle, Position_Carte_X);
        }
     
     
      // Dans tout les cas on test la collision avec le sol
      SDL_FillRect(ecran, NULL, SDL_MapRGBA(joueur->format, 0, 0, 0, 0));
      SDL_BlitSurface(bg, NULL, ecran, &PositionFond);
      appliquer_carte(taille_carte_x, taille_carte_y, Position_Carte_X, ecran);  
      appliquer_surface( position_sonic_X, position_sonic_Y, joueur, ecran, &clip[cle]); 
      // Si le bout de la carte depasse le début de l'ecran alors on dit qu'il colle l'ecran
      if (Position_Carte_X > 0) { Position_Carte_X = 0; }
      SDL_Flip(ecran);
      SDL_Delay(28);
      saut = 0;
    Coté collision j'ai ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    void test_collision_bas(SDL_Surface *ecran, int taille_carte_x, int taille_carte_y, int cle, int deplacement)
    {
    // Declaration des variables de couleur
    Uint32 pixel;
    Uint8 rouge,vert,bleu,trans;
    int u = 0;
    int i = 0;
    int j = 0;
    int case_collision_x = 0;
    int case_collision_y = 0;
    int case_collision_xx = 0;
    int case_collision_yy = 0;
    // on obtient les cases
    case_collision_y = ((-Position_Carte_X+position_sonic_X)/64)+1;
    case_collision_x = ((-Position_Carte_Y+position_sonic_Y)/64)+1;
    // position exacte
    case_collision_xx = case_collision_x + 1;
    case_collision_yy = case_collision_y - 1;
    int test_1 = tableau_donnee_carte[case_collision_x][case_collision_y];
    int test_2 = tableau_donnee_carte[case_collision_xx][case_collision_yy];    
        // ***************************************
        // Gestion des collisions avec le sol
     
        while (u == 0)
        {
            pixel=couleur_pixel(ecran,(position_sonic_X+16),(position_sonic_Y+TILE));
            SDL_GetRGBA(pixel, ecran->format, &rouge, &vert, &bleu, &trans);
            if ((rouge == 0) && (vert == 0) && (bleu == 0))
            {
              position_sonic_Y = position_sonic_Y+3;
            }
            else if ((test_1 >= 7) && (test_1 <= 12))
            {
              u=1;
            }
            else if ((test_2 >= 7) && (test_2 <= 12))
            {
              u=1;
            }
            else if (u == 0)
            {
              position_sonic_Y = position_sonic_Y-2;
              u=1;
            }
        }
        u=0;
    }
    Désolé si c'est un peut long mais je pense qu'un simple bout de code n'aurais pas suffis

    Comme on peut le voir, si le personnage ne saute pas alors on tombe mais ça lance une boucle dans la partie collision. Donc l'event est bloqué pendant le while. Si je met un SDL_DELAY dedans, ça va bloquer pendant un plus grand moment et si je met un if, si on appuis sur rien le personnage bouge pas puis tombe (je dirais descend) quand on fais quelque chose.

    Je voit pas comment je pourrais faire pour qu'on le voye tomber et qu'on puisse interragir en même temps

    Et je sait pas si la methode expliqué dans ce post http://www.developpez.net/forums/sho...d.php?t=146167 est vraiment adapté pour ça

  2. #2
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Si j'ai bien compris ton code, lorsqu'il saute, il monte directement et après retombe aussi sec, non?

    Pour faire correctement (mais en simplifiant un peu). Utilise plutôt une vitesse verticale pour faire monter et descendre ton joueur.

    Ce que tu fais :

    Si le joueur appuie sur le bouton saute, donne une vitesse qui fera monté le perso.

    A chaque boucle, on vérifie le déplacement vertical:

    - Mettre à jour la vitesse du joueur (dû à la gravité la vitesse diminiue toujours même si y a un mur en dessous du perso).

    - Mettre à jour la position du joueur en fonction de la vitesse.

    - Si y a une collision avec un mur en dessous, remettre la position du joueur et la vitesse à 0

    - Si y a une collision au dessus, mettre a jour la position et la vitesse à 0.

    - Pour les collisions à droite ou à gauche, y a rien de spécial à faire... Juste mettre la position à jour...

    Avantage de ce système par rapport au tien:

    - Si le joueur appuie sur la barre d'espace, tu mets la vitesse à -10 (je crois que dans ton code plus c'est petit plus c'est haut). L'algorithme va donc faire monter le joueur et la vitesse va progressivement se rapprocher de 0 et de valeurs positives, ce qui fera descendre le joueur...
    Donc en mettant juste à jour la vitesse, on a une jolie animation de saut.

    Pour faire encore mieux, on travaille sur les accélérations à la place de la vitesse. Donc on met à jour la vitesse puis la position. Le principe est le même mais il permet plus de choses...

    Jc

  3. #3
    Membre habitué Avatar de poussinphp
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    428
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 428
    Points : 176
    Points
    176
    Par défaut
    J'ai pu résoudres certains de mes soucis mais pas tous.

    Pour pouvoir gerer plusieurs evenements clavier je suis passé à keystates (merci Loka pour le tutoriel ) car je ne pouvais pas gerer plusieurs evenements à la fois avec le wait event.

    Ensuite, pour le saut en lui-même j'ai crée un système qui récupère la position lorsque la touche est appuyé puis je fais une monté depuis ce point puis je redescend. Par defaut il descend et la gestion par keystate permet une souplesse de mouvement que ne permettais pas le wait event.

    Mon personnage bouge, il saute et je peut en même temps le faire avancer (je contrôle mon saut).

    Mon problème se situe maintenant sur la gestion des images (clipping) de mon personnage. Effectivement, je ne sais pas comment faire une condition si on appuis sur rien.

    Exemple :
    J'appuis sur droite, je charge l'image du personnage qui avance (la ça marche). Quand j'appuis sur aucune touche, le personnage se met en position repos par defaut (là j'arrive pas)

    J'ai essayé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    if (touche[])
    if (touche[void])
    if (touche[null])
    le ELSE
     
    Touche etant déclaré par :
    touche = SDL_GetKeyState(NULL);
    Mais sans résultat. Je voit pas comment faire

  4. #4
    Rédacteur
    Avatar de MrDuChnok
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2002
    Messages
    2 112
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 112
    Points : 4 240
    Points
    4 240
    Par défaut
    moi j'aurai bien vu un truc du style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    if (touche[haut]) then
      ...
      afficher(sprite_haut);
      ...
    elseif (touche[bas]) then
      ...
      afficher(sprite_bas);
      ...
    elseif (touche[gauche]) then
      ...
      afficher(sprite_gauche);
      ...
    elseif (touche[droite]) then
      ...
      afficher(sprite_droite);
      ...
    elseif (touche[saut]) then
      ...
      afficher(sprite_saut);
      ...
    else
      afficher(sprite_repos); /*aucune des touches "réactives" n'est pressées, alors le personnage ne fait rien*/
    tu as peu être déjà essayé ?
    Si vous jugez mon post utile dans la résolution de votre problème, n'hésitez pas à utiliser le système de vote afin d'améliorer la qualité du forum

  5. #5
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Citation Envoyé par MrDuChnok
    moi j'aurai bien vu un truc du style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    if (touche[haut]) then
      ...
      afficher(sprite_haut);
      ...
    elseif (touche[bas]) then
      ...
      afficher(sprite_bas);
      ...
    elseif (touche[gauche]) then
      ...
      afficher(sprite_gauche);
      ...
    elseif (touche[droite]) then
      ...
      afficher(sprite_droite);
      ...
    elseif (touche[saut]) then
      ...
      afficher(sprite_saut);
      ...
    else
      afficher(sprite_repos); /*aucune des touches "réactives" n'est pressées, alors le personnage ne fait rien*/
    tu as peu être déjà essayé ?
    Non, l'idée est bonne mais c'est trop simpliste.

    Chaque état aura sûrement une animation (le mec qui marche, le mec qui saute, etc.) voir même plusieurs animations pour la même chose (genre le sprite au repos, on peut avoir plusieurs versions)...

    Comment ferais-tu pour gérer ça?
    Jc

  6. #6
    Rédacteur
    Avatar de MrDuChnok
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2002
    Messages
    2 112
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 112
    Points : 4 240
    Points
    4 240
    Par défaut
    Oui bien sur c'est pas forcément la solution la mieu pour gérer les animations et tout, mais d'après ce que j'avais lu :

    Exemple :
    J'appuis sur droite, je charge l'image du personnage qui avance (la ça marche). Quand j'appuis sur aucune touche, le personnage se met en position repos par defaut (là j'arrive pas)
    Il charge une image pour montrer que le personnage avance. Mais bon c'est peut être moi qui est mal compris

    Et surtout ce que je voulais montrer par le petit code cité, c'était qu'il devait tester toutes les touches qui correspondaient à une action, et si aucune n'est sur l'état "pressé" alors on charge l'image du personnage au repos. Et eventuellement il serait utile de stocker un état du personnage pour vérifier qu'il n'est pas en train de se déplacer (comme par exemple pendant un saut : aucune touche n'est appuyée, mais il se déplace)

    Enfin je sais pas, peut être que le problème est plus compliqué que je pense
    Si vous jugez mon post utile dans la résolution de votre problème, n'hésitez pas à utiliser le système de vote afin d'améliorer la qualité du forum

  7. #7
    Rédacteur

    Avatar de loka
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2004
    Messages
    2 672
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Service public

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 672
    Points : 5 509
    Points
    5 509
    Par défaut
    Exemple :
    J'appuis sur droite, je charge l'image du personnage qui avance (la ça marche). Quand j'appuis sur aucune touche, le personnage se met en position repos par defaut (là j'arrive pas)
    Si les differents etats de ton perso sont decoupés à partir d'une feuille de sprite, tu pourrais faire quelque chose de ce style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    //If Perso is moving left
        if( velocity < 0 )
        {
            //Set the animation to left
            status = PERSO_LEFT;
     
            //Move to the next frame in the animation
            frame++;
        }
        //If Foo is moving right
        else if( velocity > 0 )
        {
            //Set the animation to right
            status = PERSO_RIGHT;
     
            //Move to the next frame in the animation
            frame++;
        }
        //If Perso is moving left
        else
        {
            //Restart the animation
            frame = 1;
        }
    Je sais pas si ça regle ton probleme, normalement oui si j'ai bien compris :p

    Si tu veux j'ai un code où un perso se deplace à gauche ou à droite, si ça peux t'aider je te la mettrais à disposition

  8. #8
    Membre éprouvé
    Avatar de Sivrît
    Profil pro
    Inscrit en
    Février 2006
    Messages
    953
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2006
    Messages : 953
    Points : 1 249
    Points
    1 249
    Par défaut
    Si à terme il y a plusieurs frames par animation (attente, saut, marche...) un système d'états pourrait bien aider. Ca permettrait au moins d'y voir plus clair dans la gestion des mouvements en distingant les différents cas.

    Sur le principe on déclare un ensemble d'états (un enum serait bien) : MARCHE _DROIT, MARCHE_GAUCHE, SAUT, ATTENTE...
    On peut aussi distinguer les phases montante et descendante des sauts et tout ce qui pourrait être nécessaire.

    Après il faut décider de comment on passe d'un état à l'autre. Par exemple si on appuie sur saut depuis ATTENTE, MARCHE _DROIT ou MARCHE_GAUCHE on passe à SAUT. MARCHE _DROIT ou MARCHE_GAUCHE avec un personnage qui n'a plus de vitesse (si l'on a de l'inertie) ou si l'on relache la touche droite ou gauche donne ATTENTE. Etc.

    Ensuite à chaque frame on switch sur l'état, on traite et si besoin on change l'état. Par ex en pseudo C, et seulement pour donner une idée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    SAUT:
        vitesse_y -= 2; // La gravité fait son oeuvre
        sonic.y += vitesse_y; // mise à jour du perso
        /* Ici il faudrait mettre de quoi se déplacer sur la droite ou la gauche mais je fais au plus simple */
        if(est_au_sol())
            etat=ATTENTE; // ou MARCHE si on appuie sur gauche:droite ?
        break;
    Pour chaque état on a une série d'étapes d'animation. Pour faire tout beau il faudrait mettre dans des tableaux indexés par l'enum des états les numéros des premières et dernières étapes par état (disons max_frame[] et min_frame[]).
    Comme ça on affiche via clip[cle], on incrémente cle, et si cle vaut plus que max_frame[etat] on remet cle à min_frame[etat].
    Et quand on change d'état il suffit de mettre cle à min_frame[etat].

    Pour pousser encore plus loin on pourrait indiquer combien de frame chaque étape d'animation va passer à l'écran mais je pousse peut-être un peu

Discussions similaires

  1. [Makefile] [Avancé]Récupération de dépendances
    Par Ruok dans le forum Systèmes de compilation
    Réponses: 4
    Dernier message: 06/02/2004, 12h52
  2. [JSP] thread ? Message d'avancement des operations en cours
    Par buffyann dans le forum Servlets/JSP
    Réponses: 14
    Dernier message: 18/12/2003, 11h39
  3. Réponses: 14
    Dernier message: 01/09/2003, 22h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo