【问题标题】:Why do my button class items share the same lambda functions?为什么我的按钮类项共享相同的 lambda 函数?
【发布时间】:2023-04-04 16:51:01
【问题描述】:

我正在尝试在 SFML 中创建自己的可重用按钮类。这将允许我创建一个按钮并为其添加一个回调函数,以便更轻松地创建按钮。

这是我的 hpp 文件:

#ifndef Button_hpp
#define Button_hpp

#include <stdio.h>
#include <SFML/Graphics.hpp>
#include "View.hpp"
#include "State.hpp"
#include "Window.hpp"
namespace kge {
  class Button: public View{
  private:
    sf::RectangleShape* _buttonOutline;
    sf::RenderWindow* _window;
    sf::Clock _clock;
    std::string _textString;
    sf::Text* _text;
  public:
    Button(Window*, std::string);
    ~Button();
    virtual void update(float td);
    std::function<void(void)> callback;
    void setPosition(float x, float y);
  };
}
#endif /* Button_hpp */

这里是我生成按钮的地方:

_restartButton = new kge::Button(_window, "Restart");
_restartButton->setPosition(getCenterOfScreen().x-((11*fontSize)/2), 300);
_restartButton->callback = ([this](){
  State::instance().currentView = new GameView(this->_window);
  this->_window->setView(State::instance().currentView);
});
_exitButton = new kge::Button(_window, "Quit");
_exitButton->setPosition(getCenterOfScreen().x-((11*fontSize)/2), 500);
_exitButton->callback = ([this](){
  this->_window->close();
});

最后,我告诉按钮更新并检查我的窗口更新,button-&gt;update(td)

我所有的按钮似乎都执行了上次设置回调的操作。在这种情况下,我的重启按钮会执行我的退出代码。

为什么会发生这种情况,我该如何解决?

编辑

这是我的生成代码:

#ifndef GameOver_hpp
#define GameOver_hpp

#include <stdio.h>
#include "View.hpp"
#include "Button.hpp"
#include "GameView.hpp"
#include "State.hpp"

namespace kge{
  class View;
};

class GameOver: public kge::View{
private:
  sf::Text* _text;
  kge::Button* _restartButton;
  kge::Button* _exitButton;

  void restartFunction(void){

  }
public:
  GameOver(kge::Window* screen) : View(screen){
    int fontSize = 50;
    _text = new sf::Text();
    _text->setFont(kge::AssetManager::mainBundle().getFontNamed("mainfont"));
    _text->setString("Game Over");
    _text->setCharacterSize(fontSize);
    _text->setPosition(getCenterOfScreen().x-((9*fontSize)/2), 100);
    _text->setFillColor(sf::Color(255,0,0));

    _restartButton = new kge::Button(_window, "Restart");
    _restartButton->setPosition(getCenterOfScreen().x-((11*fontSize)/2), 300);

    _exitButton = new kge::Button(_window, "Quit");
    _exitButton->setPosition(getCenterOfScreen().x-((11*fontSize)/2), 500);

    _restartButton->callback = ([this](){
//      State::instance().currentView = new GameView(this->_window);
//      this->_window->setView(State::instance().currentView);
      puts("Restart");
    });

    _exitButton->callback = ([this](){
//      this->_window->close();
      puts("Restart");
    });


    this->addItemToView(_text);
    this->addItemToView(_restartButton);
    this->addItemToView(_exitButton);
  }

  void update(float td){
    _restartButton->update(td);
    _exitButton->update(td);

  }

  ~GameOver(){
    delete _text;
    delete _restartButton;
  }
};

#endif /* GameOver_hpp */

注意,kge::View 只是一个自定义的 sf::Drawable 类(我如何创建自己的“视图”)

编辑 2 按钮更新功能:

  void Button::update(float td){
    if(_clock.getElapsedTime().asMilliseconds() < 400) return;
    if(!sf::Mouse::isButtonPressed(sf::Mouse::Left)) return;
    if(mouseIsIn(*_buttonOutline, _window)){
      callback();
      _clock.restart();
    }
  }

请注意:_clock 是一个 sf::Clock 私有存储在按钮类中。

【问题讨论】:

  • 您能否通过附加调试器并在两个 lamdbas 中放置断点来确认这种情况?这可能会告诉你为什么会发生这种情况。
  • @Botje 我可以确认通过使用断点,IDE 显示它处于正确的回调中,但它总是在执行退出事件。如果我删除我的退出按钮,我的重启按钮就可以正常工作。
  • @Botje 有趣的是,当我输入一条消息时,该消息会正确显示,如果我删除 this->_window->close();行,它有效。
  • 会不会是 all 回调正在执行?显示应该触发回调的代码。
  • 不是MCVE。你是如何存储按钮的?你如何迭代它们并调用回调?更新定义在哪里?按钮在哪里生成,您正在捕获this,所以它发生在一些成员函数中......等等。

标签: c++ class sfml


【解决方案1】:

问题已在聊天中解决。综上所述,@iProgram 发布的mouseIsIn 函数没有正确检测碰撞,导致多个按钮同时触发。

原函数:

bool mouseIsIn(sf::RectangleShape shape, sf::RenderWindow* window){
    sf::FloatRect shapeBounds = shape.getGlobalBounds();
    sf::Vector2i mousePos = sf::Mouse::getPosition(*window);
    sf::FloatRect mouseRect = sf::FloatRect(mousePos.x, mousePos.y, mousePos.x+shapeBounds.width, mousePos.y+shapeBounds.height);
    return mouseRect.intersects(shapeBounds);
}

固定函数:

bool mouseIsIn(sf::RectangleShape shape, sf::RenderWindow* window){
    sf::FloatRect shapeBounds = shape.getGlobalBounds();
    sf::Vector2i mousePos = sf::Mouse::getPosition(*window);
    return shapeBounds.contains(mousePos.x, mousePos.y);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-13
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多