-
Hi there, I'm relatively new to SFML and I have successfully made a pong clone, and I'm working on my own 2d game engine. So far, I have implemented a texture manager, a state machine for the actual engine, and a bounding box collision system. Everything works, I have tested it all already. The one thing I'm having trouble with though, is how the main menu buttons are going to work. I need some help figuring out a class for the main menu, and it's methods that will check if the mouse is clicking or hovering over some text. For example, I want 2 buttons, which are play and exit, that when you hover over the text, it will change colors and when you click it, it will either start the actual game, or exit the program.
Any help is hugely appreciated, and thank you for your time.
-
There are quite many possibilites you can use.
The easy but bit messy solution is to have all the checking and action code in your menu state. For example you just need to check if the mouse position is within in the wanted rectangle where your text is located.
A nicer solution is to write your own button class that can perform some action like text highlighting or reacte to clicks. Then you add the code for managing the buttons and passing on the events to your menu state or if wanted to another class.
The third solution is to use a GUI library like SFGUI, TGUI, libRocket or GWEN (use google to find them).
-
+1 on Xploit post.
If you meant purely code wise, the way I usually do it is to use getGlobalbounds().contains like this (http://www.sfml-dev.org/documentation/2.0/classsf_1_1Text.php#a95d732f58bd12bf7ec388b106f3729ba) for example.
if you go the simple dirty way, just do one of these boundaries checks on mouse move (for highlight) and on mouse button press (for the actual action) and if they're true, do whatever you need to.
-
Thanks for such great replies guys! I develop on my Mac, and I'm looking into using SFGUI because it looks the most promising. Do you guys know if it is available on Mac?
-
I was having some trouble writing a isSpriteClicked class, and I need some help. Here is what I have so far.
bool Button::isSpriteClicked(Sprite* spr, RenderWindow* rw) {
}
Could anybody help me write something that would check if the mouse was in the area, or clicking on a sprite? Thanks.
-
Could anybody help me write something that would check if the mouse was in the area, or clicking on a sprite?
People will not write code for you. Please read the documentation http://www.sfml-dev.org/documentation/2.0/annotated.php (http://www.sfml-dev.org/documentation/2.0/annotated.php)
It´s very simple. Get the mouse position relative to the window. If the left button is pressed and the mouse pos is inside the sprite dimension, do something.
-
Oh no, I wasn't asking for anybody to write code for me. I just needed help visualizing how it would work. What you have told me is sufficient, thank you.
-
Ok, I will "explain" it a bit for you. First I would not check every frame for "IsButtonClicked". Simply handle the mouse event (http://www.sfml-dev.org/documentation/2.0/structsf_1_1Event_1_1MouseButtonEvent.php) and then check if the mouse is inside the bounding area of your button. The 4 things to check are MouseX >= ButtonLeft, MouseY >= ButtonTop, MouseX <= (ButtonWidth - ButtonLeft), MouseY <= (ButtonHeight - ButtonTop).
Now try writing some code on top of this. If you still do not understand I can post some C# code to give you a better idea.
-
I wouldn't rely on the mouse moved event, since I think it's better to check every frame. So you should use sf::Mouse and getPosition(), additionally it's not needed to check all the positions, instead you create a sf::Rect of the position and size of the button and then you can easily use the function contains() of the sf::Rect to check if the mouse pointer is within the rect/button. ;)
-
bool Button::isSpriteClicked(Sprite *spr, IntRect *rect, Vector2i *rectPosition, RenderWindow *rw) {
Mouse mouse;
Vector2i mousePosition = mouse.getPosition();
//If mouse position is in the rectangle do whatever
if (rect->contains(mousePosition)) {
return true;
}
//Otherwise, don't do anything
else {
return false;
}
}
Does this look correct to you guys?
-
Well I wrote the methods, but I'm kind of confused on how to put the rect around the sprite. I read the documentation on rect, but I'm still kind of confused.
-
A sf::Rect is just a normal rectangle defined through a point and it's size. Thus you'll just do something like:
Does this look correct to you guys?
Not quite and you shouldn't use pointers...
bool Button::isSpriteClicked(sf::Sprite &sprite) {
sf::IntRect rect(sprite.getPosition().x, sprite.getPosition().y, sprite.getGlobalBounds().width, sprite.getGlobalBounds().height);
//If mouse position is in the rectangle do whatever
if (rect.contains(sf::Mouse::getPosition())) {
return true;
}
//Otherwise, don't do anything
return false;
}
The use of the else isn't needed since the function will either exit through the return true; or it will keep going and exit with false.
-
Your code works... somewhat.. Only about a quarter of the button sprite I'm loading actually responds. Heres my modified code:
bool Button::isSpriteClicked(Sprite& sprite, RenderWindow* window) {
sf::IntRect rect(sprite.getPosition().x, sprite.getPosition().y, sprite.getGlobalBounds().width, sprite.getGlobalBounds().height);
if (rect.contains(Mouse::getPosition()) && (Mouse::isButtonPressed(Mouse::Left))) {
TextureManager tm;
Sprite sprite1;
sprite1.setTexture(tm.getTexture("cute_image.jpg"));
tm.drawSprite(sprite1, *window);
return true;
}
return false;
}
Pretty much, what I want is if the mouse is in the area AND clicking then using my texture manager I coded draw another image as long as the user is holding down the left mouse button. Like I said before, only about half of it works because when I click in the left quarter of the button sprite, it will respond perfectly. But anywhere else on the sprite? It won't do a thing. I don't know why it's doing this....
-
Because I've forgot again what I always forget when writing code like that, you need to use:
sf::Mouse::getPosition(window)
So you'll get the mouse position relative to the window instead of relative to the screen. ;)
Also you really need to read a good book about C++! I've already pointed it out before, you should use references and not pointers! It also makes you're life way easier since you don't have to dereference the pointer everytime you need to pass it as reference to a SFML function.
Additionally you shouldn't use: using namespace sf; neither should you use: using namespace std; It's bad practice to do so, not (only) because there could be some name conflicts but because it's hard to tell which class is now yours and which is now from SFML and which from the STL. And if makes easier to differenctiate what is now a class and what's an object. (e.g. sf::Sprite& sprite vs Sprite& sprite).
An another remark about your use of those temporary variables for the textures and sprite. You know that those will only get drawn once and every iteration when you call window.clear() (at least that's what you should do) everything will be gone again...
-
Thank you so much for your help! You're right I need to get better with pointers :P.