Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: [Résolu] Lecture de deux Joystick  (Lu 2037 fois)

0 Membres et 1 Invité sur ce sujet

litelawliet1

  • Newbie
  • *
  • Messages: 6
    • Voir le profil
[Résolu] Lecture de deux Joystick
« le: Mars 11, 2016, 10:00:42 pm »
Bonjour/Bonsoir,

Je travail actuellement sur un jeu de combat entre 2 joueurs, chacun disposant de son gamepad.
Je suis confronté à un problème assez difficile (pour moi) à résoudre, en effet j'essaie de lire le joystick de chacun des joueurs pour pouvoir traiter leurs mouvement indépendamment de l'autre.
J'entends par là cet exemple : Si le joueur 1 effectue un saut (en comptant l'animation du saut cela durera un certain temps) alors le joueur 2 doit aussi être capable d'effectuer son mouvement indépendamment du mouvement du joueur 1.

C'est justement cette condition de gameplay que je n'arrive pas à réalisé.

Précision pour la suite : Je lis les valeurs du pavé directionnel du Joystick uniquement pour le moment, afin de déplacer le joueur.
Voici comment j'ai tenté la chose :

1 - Créer un personnage (j'ai nommé class Character), disposant de l'ID du joystick à entrer dans le constructeur et de pleins d'autres informations au sujet du personnage.

2 - Un thread nommé : controllerThreaded à l'intérieur de l'objet Character lance par la suite ma méthode "Move()".
(1)Cette méthode lis les informations du pavé directionnel du joystick et les insèrent dans un Vector2f nommé m_controller.
(2)La méthode "Move()" utilise par la suite une méthode privé qui "filtrera" les données et me renverra une valeur (0,1,2,ect...) correspondant à un état de mouvement.
Exemple : La méthode qui filtre les données me renvoie "1", je considère cette valeur comme faisant référence à un "saut". Tout cela à été parfaitement défini en commentaire dans mon code.
(3)Une fois cette valeur renvoyé je peux commencé à traité le mouvement, en fonction de ce qui ma été renvoyé un mouvement s'effectuera et le personnage bougera.

3 - Dans le main.cpp je créé un Thread nommé tw1 qui lancera (en principe) le thread programmé dans mon objet

C'est ici que le problème arrive, ayant testé ces méthode au cours du développement avec un unique personnage, aucun problème en vue, tout bougeaient parfaitement.
Mais maintenant que je veux adapter cela pour 2 joueurs l'utilisation du Thread ma paru obligatoire, le programme se comporte assez bizarrement, parfois il se bloque et ne fait plus rien, parfois il plante.

C'est que j'ai besoin de vous, chère communauté ! :)
 - Est-ce que je tente de résoudre le problème correctement en passant à un Thread la méthode Move() ?
 - Est-ce que l'appel de la seconde méthode qui filtre les valeurs lue par le Joystick pose problème ?
 - Ai-je autre chose à faire en plus (voir code) pour que cela fonctionne ou ma façon d'utiliser les Thread sont un peu bancal ?

Je vous avouerai que je ne suis pas très à l'aise avec l'utilisation des Thread surtout avec l'utilisation d'un objet, même après avoir pas mal lu d'informations et exemples à ce sujet.

Je vous remercie d'avance avoir lu jusqu'ici et pour l'aide que vous pouvez m'apportez pour résoudre ce problème.

Pour les intéressé voici visuellement ce que j'expliquais plus haut :

Character.hpp
#include <SFML\Graphics.hpp>
#include <thread>
#include <iostream>

class Character : public sf::Drawable
{
public:
        Character(sf::RenderWindow & window, float const xPosition, float const yPosition, int8_t const joystickNumber);    // Pour positionner le sprite et avoir l'ID du Joystick
        void Move();    // Méthode qui effectue le mouvement du personnage + lecture des données Joystick
        std::thread controllerThreaded() {    // Le thread qui lance la méthode "Move()"
                return std::thread([this] { this->Move(); });
        }
        ~Character();
private:
        virtual void draw(sf::RenderTarget & target, sf::RenderStates states) const {
                target.draw(m_sprite);    // Permettra d'afficher le sprite via le main.cpp
        }
        short m_movementFilter(sf::Vector2f & controller);    // Le filtre en question pour savoir quel mouvement est effectué
// Des attributs...
};
 

Character.cpp
#include "Character.hpp"

Character::Character(sf::RenderWindow & window, float const xCharacterPosition, float const yCharacterPosition, int8_t const joystickNumber)
        : m_speedMovement(0.0f), m_maxSpeed(3.0f),
        m_right(false), m_left(false), m_jump(false), m_crouch(false), m_rightCrouch(false), m_leftCrouch(false), m_rightJump(false), m_leftJump(false),
        m_joystickNumber(joystickNumber)
{
        // Rien qui nous intéresse
}


void Character::Move()
{
// Lis les données du Joystick et les stockent dans m_controller
        m_controller.x = sf::Joystick::getAxisPosition(m_joystickNumber, sf::Joystick::PovX);
        m_controller.y = sf::Joystick::getAxisPosition(m_joystickNumber, sf::Joystick::PovY);

// Moyen de voir dans la console si la méthode fonctionne et lit bien les données du Joystick
        std::cout << m_controller.x << " | " << m_controller.y << "\n";

// Le fameux filtre qui me renvoie ladite valeur correspondant au mouvement
        short movementType = Character::m_movementFilter(m_controller);

// Interprétation du mouvement
        switch (movementType) {
        case 0:
        {    // Saut + droite

        }
        case 1:
        {    // Saut + gauche

        }
        case 2:
        {    // Saut

        }
        case 3:
        {    // Accroupi + droite
       
        }
        case 4:
        {    // Accroupi + gauche

        }
        case 5:
        {    // Accroupi

        }
        case 6:
        {    // Droite

        }
        case 7:
        {    // Gauche

        }
        case 8:
        {    // Debout

        }
        }
}
 

main.cpp
#include <SFML/Graphics.hpp>
#include <thread>
#include "Character.hpp"

int main()
{
        // ##### INITIALISATION DE LA FENÊTRE #####
        sf::RenderWindow gameWindow(sf::VideoMode(800, 600, 32), "Game ISN", sf::Style::Default);
        gameWindow.setVerticalSyncEnabled(true);        // Active la synchronisation vertical (60 fps en général)
               
        // ##### CRÉATION PERSONNAGES #####
        Character firstPlayer(gameWindow, 100.0f, 140.0f, 0);    // fenêtre, positionX, positionY, ID Joystick
        Character secondPlayer(gameWindow, 150.0f, 300.0f, 1);    // fenêtre, positionX, positionY, ID Joystick

// C'est LÀ que je lance ce fameux Thread tw1 qui est supposé résoudre mon problème de mouvement indépendant.
        std::thread tw1 = firstPlayer.controllerThreaded();

        // ##### BOUCLE DU JEU #####
        sf::Event event;
        while (gameWindow.isOpen())
        {
                // Gestion des événements
                while (gameWindow.pollEvent(event))
                {
                        switch (event.type) {

                        case sf::Event::EventType::Closed:
                        {
                                gameWindow.close();
                                break;
                        }
                        }       // Fin : switch(event.type)
                }       // Fin : boucle événements


                gameWindow.clear();
                gameWindow.draw(firstPlayer);
                gameWindow.draw(secondPlayer);
                gameWindow.display();
        }

        return 0;
}
 
« Modifié: Mars 12, 2016, 10:44:28 pm par litelawliet1 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Lecture de deux Joystick
« Réponse #1 le: Mars 11, 2016, 10:12:15 pm »
Je ne vois pas à quel moment ta fonction Move est appelée en boucle. Pour moi elle n'est appelée qu'une seule fois, au lancement du thread; ensuite il ne se passe plus rien.

Ensuite, le même code sans thread fonctionnerait tout aussi bien, les problèmes en moins. Je ne sais pas quel problème tu pensais résoudre avec des threads, mais oublie.
Laurent Gomila - SFML developer

litelawliet1

  • Newbie
  • *
  • Messages: 6
    • Voir le profil
Re : Lecture de deux Joystick
« Réponse #2 le: Mars 11, 2016, 10:25:29 pm »
Au départ j'utilisais ceci dans le main.cpp :

#include <SFML/Graphics.hpp>
#include "Character.hpp"

int main()
{
    // ##### INITIALISATION DE LA FENÊTRE #####
    sf::RenderWindow gameWindow(sf::VideoMode(800, 600, 32), "Game ISN", sf::Style::Default);
    gameWindow.setVerticalSyncEnabled(true);    // Active la synchronisation vertical (60 fps en général)
       
    // ##### CRÉATION PERSONNAGES #####
    Character firstPlayer(gameWindow, 100.0f, 140.0f, 0);    // fenêtre, positionX, positionY, ID Joystick
    Character secondPlayer(gameWindow, 150.0f, 300.0f, 1);    // fenêtre, positionX, positionY, ID Joystick

    // ##### BOUCLE DU JEU #####
    sf::Event event;
    while (gameWindow.isOpen())
    {
        // Gestion des événements
        while (gameWindow.pollEvent(event))
        {
            switch (event.type) {

            case sf::Event::EventType::Closed:
            {
                gameWindow.close();
                break;
            }
            }   // Fin : switch(event.type)
        }   // Fin : boucle événements

// Mes tout début
        firstPlayer.Move();

        gameWindow.clear();
        gameWindow.draw(firstPlayer);
        gameWindow.draw(secondPlayer);
        gameWindow.display();
    }

    return 0;
}
 

Je me disais donc que si je rajoutai à la suite de "firstPlayer.Move();" : secondPlayer.Move(); je devrai attendre que le joueur 1 ai fini son mouvement pour que le second joueur puisse effectuer le sien.
Dans l'idée ou j'ai conçu la méthode Move(), j'avais prévu que la méthode me fasse le mouvement d'un coup avec animation (en fonction du temps écoulé donc), du coup sur cette idée si le joueur 1 fait un saut (ce qui durerai au environ d'une seconde à peu près le temps d'animer cela à ma guise) alors le joueur 2 ne ferai plus rien pendant ce temps étant donné que tout cela est séquentiel ?

En effet ma fonction Move est pas appelée en boucle dans le code fournis, je pensais que l'utilisation de mon Thread était déjà "en boucle", je me rends compte maintenant que non.

Vous m'avez dit que l'on pouvait faire sans, mais au vu de ce que j'ai dis avant cela est toujours possible ? :o

Cordialement,
litelawliet1.


Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Lecture de deux Joystick
« Réponse #3 le: Mars 12, 2016, 09:47:25 am »
Ta boucle de jeu doit toujours tourner à vitesse constante, il ne faut pas qu'une fonction la bloque pendant une seconde. L'idée c'est de gérer tout ce qui prend du temps par incréments, et en stockant l'état dans lequel se trouve l'entité.

Exemple :

void Character::update(sf::Time elapsed)
{
    switch (m_state)
    {
        case Jumping:
            // quelque chose du genre position += velocity * elapsed.asSeconds()

        case Idle:
            // ne fait rien

        ...
    }

    // maintenant met à jour l'état en fonction des entrées joystick
}

...

sf::Clock clock;
while (gameWindow.isOpen())
{
    ...

    auto elapsed = clock.restart();
    player1.update(elapsed);
    player2.update(elapsed);

    ...
}

A peu près tous les programmes similaires sont écrits de cette façon, tu ne devrais pas avoir de mal à trouver d'autres exemples si nécessaire ;)
« Modifié: Mars 12, 2016, 11:07:32 pm par Laurent »
Laurent Gomila - SFML developer

litelawliet1

  • Newbie
  • *
  • Messages: 6
    • Voir le profil
Re : Lecture de deux Joystick
« Réponse #4 le: Mars 12, 2016, 10:43:31 pm »
Et bien merci beaucoup pour ces précisions, ça ma permis de comprendre bien des choses pour la suite ! :)
Problème résolu en somme, je n'ai plus qu'à coder correctement cette foi-ci.

Merci encore Laurent pour m'avoir sorti de là ! :D