【问题标题】:Efficient way to detect mouseover in SFML在 SFML 中检测鼠标悬停的有效方法
【发布时间】:2017-01-29 12:45:46
【问题描述】:

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

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

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

提前感谢您的帮助!

【问题讨论】:

  • @TheBeginningProgrammer 我希望能够将建议的方法也用于其他事情,例如碰撞检测。鼠标悬停功能只是一种特殊情况。

标签: c++ 2d mouseover sfml


【解决方案1】:

我现在也在写 TD 游戏,这个月我也开始使用 SFML。这也是我最后一天的问题,并提出了这个想法。我不知道这是否是执行此操作的标准方法,但这比我第一次尝试测试整个游戏对象要好。并希望提出更好的解决方案大声笑

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

地图 - 地图、敌人所在的位置以及你建造塔的位置
商店 - 你在哪里买塔
INFORMATION - 如果你点击敌人或塔什么的,信息会出现在这个区域

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

示例:

Boundary shopBoundary;
Boundary mapBoundary;
Boundary infoBoundary;

如果我想添加另一个区域,我也可以添加另一个边界(也许我可以点击塔的特殊增益的区域?)然后我会这样做

Boundary buffsBoundary;

这就是我的诀窍

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

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

我创建了一个结构,该结构存储了一个 AREAS,该 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
          }
      }
}

【讨论】:

  • 感谢您的回复。这绝对是一个开始,但它是一个非常高级的解决方案,因为它只会沿着更大的区域缩小范围。但是,如果游戏区域(代码中的“MAP”)包含数百个对象,则排除几十个菜单项不会节省那么多时间。也许最好的方法是以某种方式分析像素数据,以防它“知道”任何绘制的多边形是否包含它,然后将其追溯到相关对象的绘制函数。这样我只需要查看鼠标当前悬停在哪个像素上。
  • @ID_13 即使您知道该像素上是否绘制了某些东西,是不是追溯仍需要检查所有游戏对象?
猜你喜欢
  • 1970-01-01
  • 2023-01-09
  • 1970-01-01
  • 2014-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-03
相关资源
最近更新 更多