SFML community forums

Help => Window => Topic started by: Wander on August 15, 2010, 11:21:55 am

Title: Getting Integer Input
Post by: Wander on August 15, 2010, 11:21:55 am
I have a program that displays a map and I need it to allow the user to input coordinates for that map. I'm trying to do the text input, but I've run into problems.


Code: [Select]
           bool PressA = false;
            std::string XCoord;
            sf::String text;


            // Press A : Add coords
            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::A))
            {
                PressA = true;

                // In event loop...
                if (Event.Type == sf::Event::TextEntered)
                {
                    // Handle ASCII characters only
                    if (Event.Text.Unicode < 128)
                    {
                        XCoord += static_cast<int>(Event.Text.Unicode);
                        text.SetText(XCoord);
                    }
                }
            }


            if (PressA == true)
               App.Draw(text);
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 12:52:47 pm
The second if will never be executed 'cause Event.Type will never be sf::Event::TextEntered as it is always sf::Event::KeyPressed in this block.

You have to put the 2nd if outside the first one.
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 12:57:18 pm
Wouldn't that make the first if useless?

EDIT: I put the 2nd one outside the first one and I'm still seeing no text display as I type and I still don't know if it's working.  :?
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 01:00:11 pm
well, if you want to know if A is down or not you can do as above. But you can also use sf::Input and check it's state.
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 01:02:03 pm
I'm not following. :?
Do you mind giving an example or something?
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 01:09:48 pm
you want to do what exactly ? get an int from the user while he's pushing A ?

Code: [Select]

main

create a window

create an empty sf::String/sf::Text for SFML 2.0

while (window is open) {

while (there is some event) {

if (text entred) {

if (A is down, checked with sf::Input) {

check if textentred is some int ('0' to '9')
if so, set up the text of you're String.
otherwise set up the text to "" (empty)

}

}

} // event loop

display all your stuff

} // main loop

end main
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 01:11:06 pm
I want the user to push A, which will activate the choice to Add a Coordinate to the list of coordinates. The I need him to enter the X coord and then the Y coord.
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 01:17:19 pm
ok, so you need to take some paper and pen and write down the state of your application. It will help you to conceptualize your app.

Think «state».
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 01:19:33 pm
This is soo confusing. Haha!

Code: [Select]
// Press A : Add coords
            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::A))
            {
                PressA = true;
                if (Event.Type == sf::Event::TextEntered)
                {
                    // Handle ASCII characters only
                    if (Event.Text.Unicode < 128)
                    {
                        XCoord += static_cast<char>(Event.Text.Unicode);
                        text.SetText(XCoord);
                    }
                }
            }


I'm still not sure what to change it to....

what do you mean by state?

EDIT: I guess I'm trying to find the flashing cursor that displays the text AS I enter it number by number.
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 01:35:48 pm
Look at your code line by line. It can't work that way.

Code: [Select]
if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::A)) If this is true, Event.Type will not be both KeyPressed and TextEntered thus the next if will not be executed. That why you have to put the second if outside the first.

But that not all, of course. If you do only that your app won't do what you want.

When I'm speaking about state I mean these ones : http://en.wikipedia.org/wiki/State_machine

Let's look at your aim :

-First, you're in «state 0» : you're waiting for the user to press A.
-When he press A you go into «state 1» : you're now waiting for an int (let's say to begin an int in range [0,9]).
-When the user gave you this number, you enter «state 2» : it's basically the same as «state 2» except you're waiting for the second coord.
-When you received this second number you're in «state 3» : you do what's appropriate with the two coords (move a piece of cheese on the board, launch a missile to (X;Y), set the character to run into direction (X;Y), … whatever).
-Then, you go back to «state 0» (if it's appropriate, sometimes you only want the user to give one time the coords but let's keep this for another day).

Now you have to create some code to do all that stuff. You can use 'enum' to manage the state.
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 01:39:55 pm
Wait! You just contradicted yourself....
At first you said that I need to put the 2nd if outside the 1st one.
After that you said that's not it and that I should leave the order.
:?
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 01:45:48 pm
hum, sorry. When I said «well, if you want to know if A is down or not you can do as above» I was speaking about sf::Event vs sf::Input, not about your «if» problem.
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 01:47:10 pm
Okay. so I should leave the order alone?

How would I use enum for this? I can't see any good use for it...
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 01:50:52 pm
You do have to make sure all your «if» have sense and can be true.

Enum can be use this way :
Code: [Select]
enum State { s0, s1, … };

State my_state = s0;

Title: Getting Integer Input
Post by: Wander on August 15, 2010, 01:51:50 pm
Well, I know how to write it, but I don't know how I would utilize it.
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 01:58:01 pm
I can't do your app for you.  :wink:

But a little sample :
Code: [Select]

main loop (window is open for example)

 event loop

  if (my_state is s0 and event is KeyPressed and the key is A) then

   my_state is s1

  end if

  if (my_state is s1 and event is TextEntred and the entred value is a number) then

   update my_string or whatever

    my_state is s2

  end if

 end event loop

end main loop


NB : you may do stuff outside event loop for some states.
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 01:58:49 pm
OH!!! Hold on a second. :D
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 02:05:51 pm
Okay! Here's what I got. Only problem is. Nothing is displaying on the screen still.

Code: [Select]
           // Press A : Add coords
            if (myState == s0 && (Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::A))
            {
                PressA = true;
                myState = s1;
            }
            if (myState == s1 && Event.Type == sf::Event::TextEntered)
            {
                // Handle ASCII characters only
                if (Event.Text.Unicode > 47 && Event.Text.Unicode < 58)
                {
                    XCoord += static_cast<int>(Event.Text.Unicode);
                    text.SetText(XCoord);
                    myState = s2;
                }
                else {
                    text.SetText("");
                }
            }
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 02:08:36 pm
This won't display anything, you have to use Display and Draw.

BTW, you may want to use some smarter names than s0 s1, and so on. It was only for the example.  :wink:
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 02:11:21 pm
I do have a Draw and Display. I just didnt paste em.

Code: [Select]
bool PressA = false;
std::string XCoord;
sf::String text;


if (myState == s0 && (Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::A))
            {
                PressA = true;
                myState = s1;
            }
            if (myState == s1 && Event.Type == sf::Event::TextEntered)
            {
                // Handle ASCII characters only
                if (Event.Text.Unicode > 47 && Event.Text.Unicode < 58)
                {
                    XCoord += static_cast<int>(Event.Text.Unicode);
                    text.SetText(XCoord);
                    myState = s2;
                }
                else {
                    text.SetText("");
                }
            }


if (PressA == true)
   App.Draw(text);

App.Display();


EDIT: I added a cout statement into the if statement with static_cast and found out that the code never even enters that one. Why not?
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 02:17:20 pm
Maybe it's too small, out of screen, … I don't know. But you can use std::cout to check if it working.
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 02:19:17 pm
I did. In my EDIT on the last post I said:

Quote
EDIT: I added a cout statement into the if statement with static_cast and found out that the code never even enters that one. Why not?


So, now I'm stuck...
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 02:22:50 pm
does «if (myState == s0 && (Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::A))» work ?
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 02:24:31 pm
Yes. I have it where it says "ONE" for the first if statement, "TWO" for the second one and "THREE" for the third one.

It never makes it past "ONE"
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 02:26:46 pm
Very strange. Can you give us the whole main function ?
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 02:27:53 pm
Sure.

Code: [Select]
int main()
{
    //sf::Thread PrintFile(&PrintFile);
    //PrintFile.Launch();

    //ifstream inFile; // Declare inFile
    //ofstream outFile; // Declare outFile

    bool PressA = false;
    std::string XCoord;
    sf::String text;

    sf::RenderWindow App(sf::VideoMode::GetMode(0), "Laz's Interactive Map :: The Wrath... :: PvP Created");
    App.ShowMouseCursor(true);
    bool windowed = true;
    sf::VideoMode DesktopMode = sf::VideoMode::GetDesktopMode();

    sf::Font TypeKnight;
    if (!TypeKnight.LoadFromFile("Knights Templar.ttf"))
    {
        return EXIT_FAILURE;
    }
    sf::String TopLeft("Text Input: ________________");
    TopLeft.SetFont(TypeKnight);
    TopLeft.Move(10,10);
    TopLeft.SetColor(sf::Color::White);

    sf::String Main("Press F12 to toggle the help menu");
    Main.SetFont(TypeKnight);
    Main.Move(10.f, 600.f);
    Main.SetColor(sf::Color::White);

    bool help = false;
    sf::String Help("Type A to add a coordinate\n\nType R to remove a coordinate\n\nType F to find a coordinate\n\nPress F1 to toggle FullScreen mode\n\nPress ESC to exit the program\n\nPress F12 to toggle the help menu");
    Help.SetFont(TypeKnight);
    Help.Move(10.f,300.f);

    sf::String CopyRight("CopyRight 2010 Tyler Petresky :: All program code is subject to CopyRight Laws");
    CopyRight.SetFont(TypeKnight);
    CopyRight.SetColor(sf::Color::White);
    CopyRight.Move(1300.f, 125.f);
    CopyRight.Scale(0.5f, 0.5f);
    CopyRight.Rotate(-90);

    // Creates the PE map :: 7000x3000
    sf::Shape MapPh;
    MapPh.AddPoint(0,0,sf::Color(0,100,0));
    MapPh.AddPoint(7000,0,sf::Color(0,100,0));
    //MapPh.AddPoint(3500,1500,sf::Color(0,125,0));
    MapPh.AddPoint(7000,3000,sf::Color(0,100,0));
    MapPh.AddPoint(0,3000,sf::Color(0,100,0));
    MapPh.EnableFill(true);
    MapPh.EnableOutline(false);
    MapPh.SetOutlineWidth(10);

    sf::Shape PhMid = sf::Shape::Line(3000, 0, 3000, 3000, 20, sf::Color::Black);
    sf::Shape DrMid = sf::Shape::Line(4000, 0, 4000, 3000, 20, sf::Color::Black);

    sf::Vector2f Center(3500, 1500);
    sf::Vector2f HalfSize(1750, 750);
    sf::View View(Center, HalfSize);
    View.Zoom(0.35f);

    // Main loop
    while (App.IsOpened())
    {
        /*int AdjWid;
        int AdjHei;
        int newWidth;
        int newHeight;
        int origWidth = App.GetWidth();
        int origHeight = App.GetHeight();*/
        // Event loop
        sf::Event Event;
        while (App.GetEvent(Event))
        {
            /*if (Event.Type == sf::Event::Resized) {
                newWidth = App.GetWidth();
                newHeight = App.GetHeight();
                AdjWid = newWidth - origWidth;
                AdjHei = newHeight - origHeight;



            }*/

            // Close window : exit
            if (Event.Type == sf::Event::Closed)
                App.Close();

            // Press escape : exit
            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
                App.Close();

            // Press F1 : Switch video mode
            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::F1)) {
                if (windowed == true) {
                    App.Create(DesktopMode, "Laz's Interactive Map :: The Wrath... :: PvP Created", sf::Style::Fullscreen);
                    windowed = false;
                }
                else {
                    App.Create(sf::VideoMode::GetMode(0), "Laz's Interactive Map :: The Wrath... :: PvP Created");
                    windowed = true;
                }
            }

            // Press F12 : Toggle help menu
            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::F12)) {
                if (help == false) {
                    help = true;
                }
                else {
                    help = false;
                }
            }

            enum State { State0, State1, State2, State3 };
            State myState = State0;


            // Press A : Add coords
            if (myState == State0 && (Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::A))
            {
                std::cout << "ONE" << std::endl;
                PressA = true;
                myState = State1;
            }
            if (myState == State1 && (Event.Type == sf::Event::TextEntered))
            {
                std::cout << "TWO" << std::endl;
                // Handle ASCII characters only
                if (Event.Text.Unicode > 47 && Event.Text.Unicode < 58)
                {
                    std::cout << "THREE" << std::endl;
                    XCoord += static_cast<int>(Event.Text.Unicode);
                    text.SetText(XCoord);
                    myState = State2;
                }
                else {
                    text.SetText("");
                }
            }
        }



        float ElapsedTime = App.GetFrameTime();

        // Move the map around the screen
        float Offset = 2000.f * App.GetFrameTime();
        if (App.GetInput().IsKeyDown(sf::Key::Up))    View.Move( 0,      -Offset);
        if (App.GetInput().IsKeyDown(sf::Key::Down))  View.Move( 0,      Offset);
        if (App.GetInput().IsKeyDown(sf::Key::Left))  View.Move(-Offset,  0);
        if (App.GetInput().IsKeyDown(sf::Key::Right)) View.Move(Offset,  0);

        // Zoom and unzoom using + and - keys
        if (App.GetInput().IsKeyDown(sf::Key::Add))      View.Zoom(1.005f);
        if (App.GetInput().IsKeyDown(sf::Key::Subtract)) View.Zoom(0.994f);

        App.SetView(View);

            App.Clear();

            App.Draw(MapPh);
            App.Draw(PhMid);
            App.Draw(DrMid);

        // Reset to the default view to draw the interface
        App.SetView(App.GetDefaultView());

            App.Draw(TopLeft);

            if (help == true)
                App.Draw(Help);
            else
                App.Draw(Main);

            if (PressA == true)
                App.Draw(text);

            App.Draw(CopyRight);

            App.Display();
    }



    return 0;
}
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 02:30:49 pm
Each time the loop restart your state returns to s0. You have to create the var outside the loop.
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 02:33:26 pm
IT WORKS!!!!! YEAH!!!! YOU'RE AWESOME!!!!!!! HAHAHA
Now, I need to make it accept up to four digits in the number and submit the number when the user hits ENTER.
Title: Getting Integer Input
Post by: Hiura on August 15, 2010, 02:39:47 pm
have fun!  :)

PS : there are so many way to do it, but you may want to use two state machine  :wink: (=> less brain damage for you)

Code: [Select]
enum STATEMACHINE1 { waiting_for_A, waiting_for_four_digits_first_time, *_second_time, ...};
enum STATEMACHINE2 { waiting_for_digits_1, *_2, ... };

--

if (myState == s1 && Event.Type == sf::Event::TextEntered) {
 do stuff with my_state_2



or use a counter, here it's much more light.

Code: [Select]

if (myState == s1 && Event.Type == sf::Event::TextEntered) {
if my_count < 4 then get the number and ++my_count.
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 02:41:01 pm
Sweet! A For Loop sounds very nice right now. ;) Thanks again!
Title: Getting Integer Input
Post by: Wander on August 15, 2010, 02:55:15 pm
UGH! I won't stay on the screen. The number that is. It just flashes whenever I type.