【问题标题】:Selecting Sprites, that were created "ingame"选择“游戏内”创建的精灵
【发布时间】:2014-07-16 03:51:16
【问题描述】:

我已经在网上彻底搜索了几天,但无法为以下问题找到任何解决方案:它是关于 C++ 和 SFML 2.1。我希望能够通过中间(按钮)单击它们(然后对它们做一些事情)来选择“游戏内”生成的单个精灵。如果在任何给定位置(重叠)有多个精灵,那么我想选择最上面的一个。我正在使用一个列表,每当我尝试选择任何 Sprite 时,只有最后创建的那个“反应”正确(即打印控制台文本)。非常感谢您的帮助。

完整代码:

#include <SFML/Graphics.hpp>
#include <iostream>
#include <list>

int main()
{
    sf::RectangleShape rectangle;
    rectangle.setSize(sf::Vector2f(1000, 600));
    rectangle.setFillColor(sf::Color(100,80,100,100));
    rectangle.setPosition(0, 0);

    sf::Sprite newSprite;

    sf::FloatRect rightBound = rectangle.getGlobalBounds();
    sf::FloatRect unitrect = newSprite.getGlobalBounds();

    sf::RenderWindow mMainWindow(sf::VideoMode(1000, 600), "Map");
    mMainWindow.setFramerateLimit(60);
    sf::Texture unittexture;
    unittexture.loadFromFile("warrior.png");

    std::list<sf::Sprite> EnemyList;
    std::list<sf::Sprite>::iterator EnemyIt;

    while (mMainWindow.isOpen())
    {
        sf::Event event;

        while (mMainWindow.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            {
                mMainWindow.close();
            }
            if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Middle)
                if(newSprite.getGlobalBounds().contains(mMainWindow.mapPixelToCoords(sf::Mouse::getPosition(mMainWindow))))
                    std::cout << "Unit selected" << std::endl;

            if(event.type == sf::Event::MouseButtonPressed)
                if(event.mouseButton.button == sf::Mouse::Right)
                {
                    sf::Vector2f mousecoords(mMainWindow.mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y)));
                    EnemyList.remove_if([=](sf::Sprite unitsprite){return unitsprite.getGlobalBounds().contains(mousecoords); });
                }
            if(event.type == sf::Event::MouseButtonPressed)
                if(event.mouseButton.button == sf::Mouse::Left)
                    if (rectangle.getGlobalBounds().contains(mMainWindow.mapPixelToCoords(sf::Mouse::getPosition(mMainWindow))))        
                    {
                        newSprite.setTexture(unittexture);
                        newSprite.setPosition(sf::Mouse::getPosition(mMainWindow).x,sf::Mouse::getPosition(mMainWindow).y);
                        EnemyList.push_back(newSprite);
                    }
        }

        for(EnemyIt = EnemyList.begin();EnemyIt != EnemyList.end();EnemyIt++)
        {
            mMainWindow.draw(*EnemyIt);
        }
        mMainWindow.display();
        mMainWindow.clear(sf::Color(0, 200, 0, 255));
    }

    return 0;
}

【问题讨论】:

  • 检查鼠标中键事件时,您似乎只检查点击是否在最新创建的精灵的范围内。这是故意的吗?
  • 暂时是故意的,因为我不知道。但我希望它检查是否在“最顶层”精灵的范围内。
  • 等等,有什么问题? “我正在使用一个列表,每当我尝试选择任何 Sprite 时,只有最后创建的那个,“反应”正确......”似乎只检查最新的 sprite 会导致这种情况,但它是故意的?
  • 好吧,不,这不是故意的 :-) 这只是为了表明我走了多远。 (不是很远:-))

标签: c++ stl sprite sfml


【解决方案1】:

在您的事件循环中,您有以下代码:

if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Middle)
    if(newSprite.getGlobalBounds().contains(mMainWindow.mapPixelToCoords(sf::Mouse::getPosition(mMainWindow))))
        std::cout << "Unit selected" << std::endl;

newSprite 设置为您最后添加到列表中的精灵,因此您检查中间点击的唯一精灵是您添加到列表中的最后一个精灵。如果你想检查所有精灵的点击,你必须遍历列表并检查每个精灵的点击。

不过,由于您只想选择最顶层的精灵,因此有点棘手。首先,您必须定义“最高”的含义;如果您的意思是视觉上“在另一个”之上的单位,只需选择列表中包含鼠标的最后一个敌人。这样做的原因是 SFML 只是将图像粘贴在已经渲染的内容之上。也就是说,如果两个精灵相互叠加渲染,最后绘制的精灵会显示在顶部。由于您是从前到后绘制列表,因此最后面的元素将是在顶部绘制的元素。

大致上应该是这样的:

if(event == middle mouse click) {
    for(sprite in list.reverse()) {
        if(mouse in sprite.bounds) {
            //clicked sprite
            break;
        }
    }
}

请注意,尽管如此,这并不是一种特别稳健的做事方式。逻辑不应与渲染绑定;我们依赖于特定的绘图顺序来达到正确的效果。您可能应该找到一种更好的方法来定义单位的绘制顺序。

【讨论】:

    【解决方案2】:
    if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Middle)
                {
                for(EnemyIt = EnemyList.begin();EnemyIt != EnemyList.end();EnemyIt++)
                    if (newSprite.getGlobalBounds().contains(mMainWindow.mapPixelToCoords(sf::Mouse::getPosition(mMainWindow))))
                    {
                    EnemyList.reverse();
                    std::cout << "Inside Sprite " << std::endl;
                    }
                }
    

    到目前为止,我已经有了这个,但似乎不可能告诉他不要只关心最后创建的精灵。

    【讨论】:

      【解决方案3】:

      好的,非常感谢。 只是为了记录我的解决方案:

      #include <SFML/Graphics.hpp>
      #include <iostream>
      #include <list>
      
      int main()
      {
          sf::RectangleShape maprect;
          maprect.setSize(sf::Vector2f(500, 500));
          maprect.setFillColor(sf::Color(0,0,255,255));
      
          sf::Sprite newSprite;
      
          sf::FloatRect mapbound = maprect.getGlobalBounds();
      
          sf::RenderWindow mMainWindow(sf::VideoMode(500, 500), "Map");
          mMainWindow.setFramerateLimit(60);
          sf::Texture unittexture;
          unittexture.loadFromFile("warrior.png");
      
          std::list<sf::Sprite> EnemyList;
          std::list<sf::Sprite>::iterator EnemyIt;
      
          while (mMainWindow.isOpen())
          {
              sf::Event event;
      
              while (mMainWindow.pollEvent(event))
              {
                  if (event.type == sf::Event::Closed)
                      {
                      mMainWindow.close();
                      }
                      if (event.type == sf::Event::KeyPressed)
                          if (event.key.code == sf::Keyboard::A)    
                              {
                                  newSprite.setTexture(unittexture);
                                  newSprite.setPosition(mMainWindow.mapPixelToCoords(sf::Vector2i(sf::Mouse::getPosition(mMainWindow).x,sf::Mouse::getPosition(mMainWindow).y))); 
                                  EnemyList.push_back(newSprite);
                                  std::cout << EnemyList.size() << std::endl;
                              }
                  for (auto &EnemyIt = EnemyList.rbegin(); EnemyIt != EnemyList.rend(); ++EnemyIt)
                      if (EnemyIt->getGlobalBounds().contains(mMainWindow.mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y))))
                          if(event.type == sf::Event::MouseButtonPressed)
                              if(event.mouseButton.button == sf::Mouse::Left)
      
                              {
                                  EnemyList.rbegin();
                                  std::cout << EnemyIt->getPosition().x << std::endl;
                                  std::cout << EnemyIt->getPosition().y << std::endl;
                                  break;
                              }
      
              }
              mMainWindow.clear();
              mMainWindow.draw(maprect);
      
              for(EnemyIt = EnemyList.begin();EnemyIt != EnemyList.end();++EnemyIt)
                  {
                      mMainWindow.draw(*EnemyIt);
                  }
              mMainWindow.display();
      
      
          }
      
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-29
        • 2015-05-10
        • 1970-01-01
        • 1970-01-01
        • 2023-03-09
        • 1970-01-01
        相关资源
        最近更新 更多