Efficient way to detect mouseover in SFML - c++

I recently started to work on a 2D Tower Defense game in SFML, and I intend to put in several visual gimmicks and other functionalities that occur when the mouse hovers over certain objects (menu items, enemies, etc.). To that end, I have to constantly check whether the mouse is hovering over such an object, many of which may be moving around and have varying sizes and shapes. Does anyone know of a fast and efficient way to accomplish this?
A brute force method to solve this would be to simply check for every single object in the game world whether the mouse position intersects their bounding rectangle. My game is rather simple, so normally it would be overkill to optimize it here, but I also intend to implement more complex components elsewhere, and I wish to make sure the program wastes as little resources on the graphics as possible.
Beyond that, I've read a number of various solutions that might work, such as keeping track of objects in a grid/quadtree and only checking the area where the mouse is. There was also a solution through raycasting, but as far as I know, SFML itself doesn't have it built in. Since I assume I'm not the only one who had to work this out, I'm hoping there is some kind of solution for this that I missed. Any ideas?
Thanks in advance for helping out!

I'm also writing TD game right now, i started it this month using SFML too. that was also my problem last last day, and came up with this idea. i dont know if this is the standard way to do this but this is better than my first attempt of testing the entire game objects. and hoping to came up with better solution lol
i have 3 areas of my game window, which is:
MAP - the place where map,enemy is and where you build tower
SHOP - where you buy towers
INFORMATION - if you click enemy or tower or something, the information will appear in this area
then i wrote a Boundary class which defines the boundary of an area.
Example:
Boundary shopBoundary;
Boundary mapBoundary;
Boundary infoBoundary;
i can also add another Boundary if i want to add another area ( maybe area where i can click special buffs for tower? ) then i will just do this
Boundary buffsBoundary;
so this is how i do the trick
i created an enum which defines mouse location
enum AREAS { NONE, SHOP, MAP, INFO }
Areas mLoc = NONE;
i created a struct that stores an AREAS which will be use to name that area and a boundary object for the boundary of that area.
struct _Boundary
{
Areas area;
Boundary boundary;
bool isMouseInside(const sf::Vector2i v) const
{
return boundary.isMouseInside(v);
}
}
std::vector<_Boundary> boundaries; // now put all your boundary to a container
now everytime mouse move, i will only have to check where the mouse is using only 3 iteration ( for map, shop and information )
if ( mouse moved )
{
for ( int a = 0; a < boundaries.size(); a++ )
{
if ( boundaries[a].isMouseInside(mousePos) )
{
mLoc = boundaries[a].area;
break;
}
}
}
with that loop, i will be able to track where ever the mouse go by checking mLoc, by having to know the location while the clicked is occured it will narrow the game objects you need to check, (if mouse location is in shop area and then when clicked occured,check only the game objects on that area)
if ( mouse button pressed )
{
if ( click mouse left )
{
if ( mLoc == SHOP )
{
// the click has been occured in shop
// check the game objects relative to shop
}
else if ( mLoc == MAP )
{
// the click has been occured in map
// check the game objects relative to map
}
else if ( mLoc == INFO )
{
// the click has been occured in information
// check game objects relative to that area
}
}
}

Related

C++ How to animate graphics (POO)

I'm working on a game project in c++ using programming oriented object and classes but I can't figure out a way to animate the following graphics.
What I need is while the player is holding left key or the right key, the graphics should be appearing to make the character like moving and when they stop holding the key it'll turn to idle graphic.
I can't paste the whole source code here, i have many classes, and functions.. All I need is a BASIC idea of how to implement it, an example or a function anything useful. I don't need libraries because i just have two sprites to animate so it's not necessary.
As an example be Sprites the class that creates the object and Koala the one that moves it and prints it in a certain position.
Sprites idleSprite, walkingSprite;
Koala koala;
These declarations are just for avoiding other explanations.
I would appreciate your help.
PD: Don't worry about the keyboard keys, or other classes all I need is how to animate a sprite.
Koala should have two states:
a direction state: enum Direction {Left,Right};
a movement state. enum Movement { Idle, Walk };
As you have only one picture for the walking status, moving graphically the picture around will give the impression of a floating body. I'd recomment that you'd really have at least two walking positions to show that the foots are moving:
a movement step counter
a constant for the maximum number of steps.
Then the states should be updated in your game loop according to keyboard status and elapsed time. The pseudo code would be something like:
if (!arrow_key_pressed()) {
status_movement = Idle;
lasttimer = gametimer(); // keep track of last event
}
else {
status_movement = Walk;
if (left_arrow_pressed() )
status_direction = Left;
else if (right_arrow_pressed() )
status_direction = Right;
if (gametimer() - lasttimer > 2 ms ) { // if enough time,
if (status_direction==Left)
position_x -= step_increment;
else if (status_direction==Right)
position_x += step_increment;
movement_step = (movement_step+1) % maxi_steps;
lasttimer = gametimer();
}
}
All you have then to do is to restore te background of the picture at tis old position, and draw the picture at the position. For this, youd could call a function with paramters position_x, direction, movement status and status step, to return/draw the sprite at the right place.

How to move an object with the mouse in c++?

I have a problem trying to create a script that moves an object with the mouse. The object is supposed to move when I hold the mouse button (which button does not really matter, so let us leave it there. I use SDL, so I have no trouble implementing this). I could of course have a variable moving = true when I start the move and then update position until moving = false, but this seems to be possibly messy. What I want is instead to be able to call a function grab_piece and then let the piece follow the mouse until I call the release function (I am creating a chess game, from where piece comes).
So the ideas, and relevant code this far: The idea is to assign a pointer to the mouse x and y positions and this would of course move the piece at the same time as the mouse. However, this seems tedious since shifting around pointers seems to be highly error prone. Is it possible to do this in a safe way? Otherwise I am open for other proposals.
Example code
SDL_Event e; //Event queue more or less
while (!quit) //Main loop, a little simplified
while (SDL_PollEvent( &e ) != 0){
if (e.type == SDL_QUIT){
quit = true;
}
if(e.type == SDL_MOUSEMOTION){
SDL_GetMouseState(&mouseX, &mouseY);
//do irrelevant things
} else if (e.type == SDL_MOUSEBUTTONDOWN){
//get mouse position
SDL_GetMouseState(&mouseX, &mouseY);
//get the board position
mouseBinPos = misc::screen2idx(mouseX, mouseY);
//location in the piece vector (hard coded)
currentPieceIdx = chess_board.getMappedPiece(mouseBinPos);
if (currentPieceIdx>=0){
chess_board.getPiece(currentPieceIdx)->grab_piece(mouseX, mouseY);
}
} else if ((e.type == SDL_MOUSEBUTTONUP)) {
//will release the piece and snap to nearest bin. Not implemented yet.
snap2bin(in args);
}
}
}
void Piece::grab_piece(int mouseX, int mouseY){
//Set pixel positions
setPixX(mouseX);
setPixY(mouseY);
}
All the variables are integers except the event queue, the board and the pieces which is a struct, user defined class and user defined class.
This is actually more a design issue, so I do not require executable code. More tips on how to do the design, if I should assign a pixX and pixY should be pointers to mouseX and mouseY and so on.
If anyone have an idea I would be happy. I have tried to describe the problem as good as possible, but if you have any questions please comment. I would describe further attempts if I had any, but I do not really know where to start. Also, this is not work, or school and I have been thinking about this for some days now and not found a good way to do it. So I am not just trying to get away easily.
Your ideas about pointers seem ill-defined, and are probably leading you down a path that isn't useful.
You need to use the same event loop as always when you're moving a piece. That means that MOUSEMOTION sometimes has to adjust the location of a piece, and sometimes not. That means that somehow you need to track the "moving a piece" state.
Here's the basic recipe:
On button down, save the idx of the piece that you've clicked on, maybe in a variable called "piece_being_dragged", or something. You also need to save the offset of mouse pointer to object center, so that the object doesn't recenter itself right on the pointer. You'll see what I mean when you get there.
On button up, zero the drag state variables, and handle the "done moving" logic.
On mousemotion, when piece_being_dragged is non-zero, look the piece up from the index, and set the new location based on the mouse pointer, and on the previously saved center offset.
Is this all a little messy? Yes. Is it necessary? Yes.

How to add "invisible walls" with SDL2

Se we are programming a game and in the center of the map there's area where the player cant go.
How we should create that area?
Game is top down perspective.
Assuming you are using some kind of collision detection that stops the player from going certain places (like off screen), all you have to do is to add an object that you can check for collisions with for the area where you don't want to player to go. Given that you haven't provided any specific information on how your game works this is the most specific answer you're likely to get.
Make an SDL_Rect that encompasses the entrance to the area, then check the collision of the SDL_Rect and the player
You will need some kind of collision detection as already mentioned above.
Then when moving the player, just check if the new position would collide with the rectangle in the middle of the screen.
Something like...
if( Input == Walk_Right)
{
//Move Player
MovePlayerRight();
//If Player collides with MiddleRect, move back
if (CheckCollison(&PlayerRect, &BoxRect) == true) MovePlayerLeft();
}
Check online for Collusion Detection. Simple Box Method should be enough to check if two Rectangles touch.

Map Editor Performance Advice

First of all don't think I'm making a "SFML and/or C++ performance Issue" type question. I'm not satisfied with the performance of this map editor I've been working on and I'm 99% percent sure I'm at fault for it.
Currently how I place tiles on the map is basically I have a function that loops through every single tile on the map and checks if the mouse is hovering over it. I call this function inside another function simply titled handleMouseClick()
This is plenty functional if you were just clicking each time you wanted to place a tile, however I have it sort of like a paintbrush. Even if there's only 500 tiles on the map, it will skip tiles if you drag it across the screen quickly. I need to be able to create maps that have 5000+ tiles and I can't afford so-so performance.
I've looked over my code and made sure I'm not making unnecessary copies. I'm pretty sure that the best way to increase performance would be to change how I check which tile the mouse is changing.
The only idea I have is to have the map in "chunks" so that it will check the tiles of the "chunk" the mouse is in.
Use math. Lets say you have tiles with pixel dimensions {tile.width, tile.height}. And your application's window is a view of the map, and the top left corner of the window is on pixel {view.x, view.y}. And the mouse position, relative to the top left corner of the window is {mouse.x, mouse.y}. You can calculate which tile the mouse is pointing to with the following:
transformed_mouse.x = mouse.x + view.x;
transformed_mouse.y = mouse.y + view.y;
mouse_tile.x = transformed_mouse.x / tile.width;
mouse_tile.y = transformed_mouse.y / tile.height;
For handling a dragging effect where the event system doesn't update fast enough, keep track of where the mouse was for the previous iteration, and use Bresenham's line algorithm to fill in all the tiles between the tile which the mouse is currently pointing to, and the tile which the mouse was pointing to previously.

C++ Win32 Owner Drawn Button's Down State

I had this working in my previous program that got lost when my hard drive crashed.
I vaguely remember how I did it, but haven't been able to find any solutions on google or msdn.
case WM_DRAWITEM: {
// pointer to items draw structure and the id
LPDRAWITEMSTRUCT pDIS = (LPDRAWITEMSTRUCT)lParam;
int ctlResID = pDIS->CtlID;
if (ctlResID == IDC_TEST) {
// button drawn here to pDIS->hDC // this works fine
// now I want to draw the button differently if it is in its down state (holding the button down or w/e)
}
Is what I have, I think I remember one of the values in the draw item struct tells, but I cant find anything about it online.
Does anyone happen to know how to do this?
Thanks.