在SFML中检测鼠标悬停的有效方法

Efficient way to detect mouseover in SFML

本文关键字:有效 方法 悬停 鼠标 SFML 检测      更新时间:2023-10-16

我最近开始在SFML中开发2D Tower Defense游戏,我打算在鼠标悬停在某些对象(菜单项、敌人等)上时加入一些视觉噱头和其他功能。为此,我必须不断检查鼠标是否悬停在这样的对象上,其中许多可以四处移动并且具有不同的尺寸和形状。有人知道一种快速有效的方法来实现这一点吗?

解决这个问题的一种暴力方法是简单地检查游戏世界中的每个对象的鼠标位置是否与它们的边界矩形相交。我的游戏相当简单,所以通常在这里优化它会有些过头,但我也打算在其他地方实现更复杂的组件,我希望确保该程序在图形上浪费尽可能少的资源。

除此之外,我还阅读了许多可能有效的解决方案,例如跟踪网格/四叉树中的对象,只检查鼠标所在的区域。还有一个通过光线投射的解决方案。但据我所知,SFML本身并没有内置它。由于我认为我不是唯一一个必须解决这个问题的人,我希望有某种解决方案,我错过了。有什么想法吗?

提前感谢您的帮助!

我现在也在写TD游戏,我这个月也用SFML开始了。这也是我最后一天的问题,我想出了这个主意。我不知道这是否是标准的方法,但这比我第一次尝试测试整个游戏对象要好。并希望能想出更好的解决方案lol

我的游戏窗口有三个区域,它们是:

MAP-地图、敌人所在的地方和你建造塔的地方
商店-你购买塔的地方信息如果你点击敌人或塔或其他东西,信息将出现在这个区域中

然后我写了一个Boundary类,它定义了一个区域的边界。

示例:

Boundary shopBoundary;
Boundary mapBoundary;
Boundary infoBoundary;

如果我想添加另一个区域(也许是我可以点击塔的特殊buff的区域?),我也可以添加另一条边界,那么我只会做这个

Boundary buffsBoundary;

这就是我的技巧

我创建了一个枚举,它定义了鼠标位置

enum AREAS { NONE, SHOP, MAP, INFO }  
Areas mLoc = NONE;

我创建了一个结构,它存储了一个将用于命名该区域的AREAS和一个用于该区域边界的边界对象。

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

现在,每次鼠标移动,我只需要检查鼠标的位置,只需使用3次迭代(用于地图、商店和信息)

if ( mouse moved )
{
for ( int a = 0; a < boundaries.size(); a++ ) 
{
if ( boundaries[a].isMouseInside(mousePos) )
{ 
mLoc = boundaries[a].area;
break;
}
}
}

有了这个循环,我将能够通过检查mLoc来跟踪鼠标的去向,通过必须知道点击发生时的位置,它将缩小你需要检查的游戏对象,(如果鼠标位置在商店区域,然后点击发生时,只检查该区域上的游戏对象)

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
}
}
}