Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Controlling a window in multiple threads  (Read 2820 times)

0 Members and 1 Guest are viewing this topic.

mantracker

  • Newbie
  • *
  • Posts: 5
    • View Profile
Controlling a window in multiple threads
« on: June 17, 2013, 09:51:57 pm »
Hi, I am currently using SFML 2.0 and having trouble trying to access the same window in two different methods of the same class. So basicly, method A creates a window, and method B of that class is a "Checkifuserlost" method. What I'd like to do is to allow A to first create a window and run the game, and then let method B run in another thread and constantly check if user lost, if he did, then access the same window that A created and display "you lost" or something.

I've read the multithreading tutorials on SFML and googled this. I haven't found much answers that are relevant to mine. I'd appreciate it if I can get some helps on how exactly do we create two threads where each runs different methods, and allow one of the methods in one thread access the window created the method created in another thread.

Thanks
« Last Edit: June 18, 2013, 01:05:46 pm by Laurent »

tbop

  • Newbie
  • *
  • Posts: 34
    • View Profile
Re: Controlling a window in multiple threads
« Reply #1 on: June 18, 2013, 12:30:34 pm »
Hi mantracker,


First I hope this is no more than a study case because at first sight your solution seems very fussy.
You don't need an extra thread in your model to check whether one's lost or not, this must be done in the main thread likely unless you've got a good reason not to do it.

So basically unless you've got that reason you'd better not dive into the hectic multi-threading world at the moment.

Otherwise, you just have to make sure the second thread shares a reference to the same window object.
Although usually if you want to do this properly you should use an asynchronous messaging system here, that is you will send a message with a specific flag that will get postponed until the next rendering cycle.
Then a "mailing center" will pop up the stack of incoming mails and will notify your main thread.
The main thread will then checks whether this message is relevant or not : "Oh, somebody from another thread informs me that the user's lost. I must draw a you-are-a-loser dialog box now."
« Last Edit: June 18, 2013, 01:06:14 pm by Laurent »

mantracker

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Controlling a window in multiple threads
« Reply #2 on: June 20, 2013, 05:55:26 am »
I'm not quite sure I understand you tbop, but to clarify, this is my code

void mymaze::runstuff()
{
       
        sf::RenderWindow window( sf::VideoMode(800,600), "Somegame", sf::Style::Close);
        window.setFramerateLimit(60);
        maze.setPosition(150,200);
        sprite.setPosition(346,205);
        myfont.loadFromFile("arial.ttf");
        sf::Text text("Welcome To Maze 101", myfont, 18 );
        sf::Text text2("Press up, down, left and right to move your red dot",myfont,18 );
        sf::Text text3("Maneover through the maze to the end to win", myfont, 18 );
        sf::Text text4("If you touch the maze walls, you lose instantly", myfont, 18 );
        sf::Text text5("Enjoy!!",myfont, 58 );
        sf::Text textWIN("YOU WIN!",myfont, 70 );
        textWIN.setStyle(sf::Text::Bold);
        textWIN.setColor(sf::Color::Cyan);
        text.setStyle(sf::Text::Bold);
        text5.setStyle(sf::Text::Underlined);
        text.setPosition(0,0);
        text2.setPosition(0,20);
        text3.setPosition(0,40);
        text4.setPosition(0,60);
        text5.setPosition(0,80);
        textWIN.setPosition(150,300);
       
        while(window.isOpen())
        {
                sf::Event event;
                while(window.pollEvent(event))
                {
                        if(event.type==sf::Event::Closed)
                        {
                                window.close();
                        }
                }
               
        //*Windows cleanup and input*//
                window.clear();
                window.draw(maze);
                window.draw(sprite);
                window.draw(text);
                window.draw(text2);
                window.draw(text3);
                window.draw(text4);
                window.draw(text5);

                controllogics();

        //*Check if user won *//
                if((sprite.getPosition().x >= 461 && sprite.getPosition().x<=467) && (sprite.getPosition().y >= 469 && sprite.getPosition().y <=475) )
                {
                        window.clear();
                        window.draw(textWIN);
                        window.display();
                        delay1sec();
                        window.clear();
                        while(!sf::Mouse::isButtonPressed(sf::Mouse::Left))
                        {
                                window.draw(tryagain);
                                window.display();
                        }
                        sprite.setPosition(346,205);
                }
               
                window.display();

        }
}

void mymaze::CheckIfLost2( void)
{
                sf::Text textLOSE("YOU LOSE!",myfont, 70 );
                        textLOSE.setStyle(sf::Text::Bold);
        textLOSE.setColor(sf::Color::Magenta);
                textLOSE.setPosition(100,300);
        sf::RenderWindow window( sf::VideoMode(800,600), "Somegame", sf::Style::Close);
        window.setFramerateLimit(60);
        while(window.isOpen())
        {
                sf::Event event;
                while(window.pollEvent(event))
                {
                        if(event.type==sf::Event::Closed)
                        {
                                window.close();
                        }
                }
        if(CheckIfLost()==TRUE)
                {
                                if( Lives == 0 )
                                {
                                        window.clear();
                                        window.draw(textLOSE);
                                        window.display();
                                        delay1sec();
                                        window.clear();
                                        while(!sf::Mouse::isButtonPressed(sf::Mouse::Left))
                                        {
                                                window.draw(tryagain);
                                                window.display();
                                        }
                                                sprite.setPosition(346,205);
                                                restoreLives();
                                        }
                                        else
                                        {
                                                Lives--;
                                                cout<<"YOU LOST A LIFE!!"<<endl;
                                        }
                }
        }
}

Basicly, what I'm trying to do is that in runstuff(), I'm doing the logic checking and all the usual game control stuff. In checkiflost2(), I'm using another method, checkiflost(), 's output to determine whether or not the user lost. If he did, checkiflost2() is supposed to print the "you lost" message on the window that runstuff() created.

Outside the two methods in the class header, I have got two threads that control each of those two methods.

The problem with this code right now is that each method opens its own window( obviously). What I'm trying to do is to allow the checkiflost2() method use the window that runstuff() has already created. I'm stuck on that part cuz I don't quite know how to do it. AND, at the same time, checkiflost2() has to be continously running independently of runstuff(), so that's why I thought of using threads.

For my program, it will not work if I just throw the code in checkiflost2() into runstuff(). I can't merge them together because of reasons I'd like to not get into(it's complicated).

Any help would be appreciated, thanks
« Last Edit: June 20, 2013, 05:59:38 am by mantracker »

Mario

  • SFML Team
  • Hero Member
  • *****
  • Posts: 879
    • View Profile
Re: Controlling a window in multiple threads
« Reply #3 on: June 20, 2013, 09:41:49 am »
You should really look into some simple finite state machines. The way you're doing it is rather unconventional (and essentially wrong). You'll run into even more issues, e.g. lost events or unresponsive windows, even if you're able to solve the multithreading issues.

You should only have one main loop and then do things based on your state.

Simplified example:

while (window.isOpen()) {
    while (window.pollEvent(event)) {
        ...
    }

    switch (gamestate) {
    case GAME_LOAD:
        texture1.loadFromFile(...);
        texture2.loadFromFile(...);
        ...
        gamestate = GAME_MENU;
        break;
    case GAME_MENU:
        handleMenu();
        renderMenu();
        break;
    case GAME_GAMEOVER:
        handleGameOver();
        renderGameOver();
        break;
    }
}
 

The functions above would then handle things like updating or drawing the actual game or menu etc. but they'll all be called once per iteration.

mantracker

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Controlling a window in multiple threads
« Reply #4 on: June 20, 2013, 09:58:12 am »
You should really look into some simple finite state machines. The way you're doing it is rather unconventional (and essentially wrong). You'll run into even more issues, e.g. lost events or unresponsive windows, even if you're able to solve the multithreading issues.

You should only have one main loop and then do things based on your state.

Simplified example:

while (window.isOpen()) {
    while (window.pollEvent(event)) {
        ...
    }

    switch (gamestate) {
    case GAME_LOAD:
        texture1.loadFromFile(...);
        texture2.loadFromFile(...);
        ...
        gamestate = GAME_MENU;
        break;
    case GAME_MENU:
        handleMenu();
        renderMenu();
        break;
    case GAME_GAMEOVER:
        handleGameOver();
        renderGameOver();
        break;
    }
}
 

The functions above would then handle things like updating or drawing the actual game or menu etc. but they'll all be called once per iteration.

Alright, always willing to learn. Do you happen to have any links to good tutorials on state machines? Also are they usable on SFML?

EDIT: nvm found it, all it takes is some googling, thanks anyways
« Last Edit: June 20, 2013, 09:59:55 am by mantracker »