SFML community forums
Help => Window => Topic started 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.
1) The text doesn't display on the screen as you input
2) It doesn't display on the screen after you input it either
3) I doubt it's even working
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);
-
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.
-
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. :?
-
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.
-
I'm not following. :?
Do you mind giving an example or something?
-
you want to do what exactly ? get an int from the user while he's pushing A ?
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
-
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.
-
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».
-
This is soo confusing. Haha!
// 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.
-
Look at your code line by line. It can't work that way.
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.
-
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.
:?
-
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.
-
Okay. so I should leave the order alone?
How would I use enum for this? I can't see any good use for it...
-
You do have to make sure all your «if» have sense and can be true.
Enum can be use this way :
enum State { s0, s1, … };
State my_state = s0;
…
-
Well, I know how to write it, but I don't know how I would utilize it.
-
I can't do your app for you. :wink:
But a little sample :
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.
-
OH!!! Hold on a second. :D
-
Okay! Here's what I got. Only problem is. Nothing is displaying on the screen still.
// 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("");
}
}
-
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:
-
I do have a Draw and Display. I just didnt paste em.
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?
-
Maybe it's too small, out of screen, … I don't know. But you can use std::cout to check if it working.
-
I did. In my EDIT on the last post I said:
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...
-
does «if (myState == s0 && (Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::A))» work ?
-
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"
-
Very strange. Can you give us the whole main function ?
-
Sure.
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;
}
-
Each time the loop restart your state returns to s0. You have to create the var outside the loop.
-
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.
-
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)
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.
if (myState == s1 && Event.Type == sf::Event::TextEntered) {
if my_count < 4 then get the number and ++my_count.
-
Sweet! A For Loop sounds very nice right now. ;) Thanks again!
-
UGH! I won't stay on the screen. The number that is. It just flashes whenever I type.