0

我有 2 个类,一个完全是菜单设置和渲染,另一个是在 main() 中调用的主游戏类。我制作了一种获取用户鼠标位置的方法,如果它位于其中一个菜单文本上,它将“选择”菜单项并播放声音。现在的问题是声音不会播放一次,而是会一直重复,除非您将鼠标悬停在任何文本上。

我尝试过使用我在网上找到的另一个人的时钟,但它似乎并不能完全按照它应该的方式工作,因为我有他分成 2 个类的东西,而不是全部放在一个地方。

这是我正在谈论的解决方案:https ://en.sfml-dev.org/forums/index.php?topic=15297.0

这是在主类中运行程序的代码,在 main.cpp 中的 main() 中调用。

void Terraria::Run()
{
    Menu Menu(mTerraria, mTerraria.getSize().x, mTerraria.getSize().y);
    Menu.mMainTheme.play();


    while (mTerraria.isOpen())
    {
        sf::Event event;
        Menu.GetMousePosition(mTerraria);

        while (mTerraria.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::MouseButtonReleased:
            {
                    switch (event.key.code)
                    {
                    case sf::Mouse::Left:
                        switch (Menu.GetPressedItem())
                        {
                        case 0:
                        {
                            break;
                        }
                        case 1:
                        {
                            break;
                        }
                        case 2:
                        {
                            break;
                        }
                        case 3:
                        {
                            break;
                        }
                        case 4:
                        {
                            Menu.mMenuOpen.play();
                            mTerraria.close();
                            break;
                        }
                        }
                    }
                }
            default:
                HandlePlayerInput(event.key.code);
                break;

            case sf::Event::Closed:
            {
                mTerraria.close();
            }
            }

            mTerraria.clear();
            Menu.Render(mTerraria);
            mTerraria.display();
            }
        }


}

这是它在 while 循环的第 10 行调用的函数。它在名为 Menu 的第二个类中。

void Menu::GetMousePosition(sf::RenderWindow& mTerraria)
{
    UnSelect();

    if (mMenu[0].getGlobalBounds().contains(sf::Mouse::getPosition(mTerraria).x, sf::Mouse::getPosition(mTerraria).y))
    {
        Select(mMenu[0]);
        OnSP = true;
        OnMP = false;
        OnAchievements = false;
        OnOptions = false;
        OnExit = false;
        SelectedItemIndex = 0;
    }

    else if (mMenu[1].getGlobalBounds().contains(sf::Mouse::getPosition(mTerraria).x, sf::Mouse::getPosition(mTerraria).y))
    {
        Select(mMenu[1]);
        OnSP = false;
        OnMP = true;
        OnAchievements = false;
        OnOptions = false;
        OnExit = false;
        SelectedItemIndex = 1;
    }

    else if (mMenu[2].getGlobalBounds().contains(sf::Mouse::getPosition(mTerraria).x, sf::Mouse::getPosition(mTerraria).y))
    {
        Select(mMenu[2]);
        OnSP = false;
        OnMP = false;
        OnAchievements = true;
        OnOptions = false;
        OnExit = false;
        SelectedItemIndex = 2;
    }

    else if (mMenu[3].getGlobalBounds().contains(sf::Mouse::getPosition(mTerraria).x, sf::Mouse::getPosition(mTerraria).y))
    {
        Select(mMenu[3]);
        OnSP = false;
        OnMP = false;
        OnAchievements = false;
        OnOptions = true;
        OnExit = false;
        SelectedItemIndex = 3;
    }
    else if (mMenu[4].getGlobalBounds().contains(sf::Mouse::getPosition(mTerraria).x, sf::Mouse::getPosition(mTerraria).y))
    {
        Select(mMenu[4]);
        OnSP = false;
        OnMP = false;
        OnAchievements = false;
        OnOptions = false;
        OnExit = true;
        SelectedItemIndex = 4;
    }
    else
    {
        OnSP = false;
        OnMP = false;
        OnAchievements = false;
        OnOptions = false;
        OnExit = false;
    }
}

这是每次鼠标悬停在任何文本上时调用的 Select() 函数。再次在 Menu 类中。

void Menu::Select(sf::Text &mMenu)
{
    mMenu.setColor(sf::Color::Yellow);
    mMenu.setScale(sf::Vector2f(1.1f, 1.1f));
    mMenuTick.play();
}

当您将鼠标悬停在任何文本上时,我只需要播放一次声音,然后在您悬停并悬停到下一个文本或悬停在下一个文本上之前不播放。我知道由于 while 循环,它被调用了数百万次。

4

1 回答 1

0

一个非常简单的方法是检查当前选定的 gui 元素的 id,并且仅当您的鼠标悬停在不是当前选定的元素上时才调用 select()。

然后,您的 GetMousePosition 检查将更改为以下内容:

if (mMenu[0].getGlobalBounds().contains(sf::Mouse::getPosition(mTerraria).x, sf::Mouse::getPosition(mTerraria).y))
{
    if SelectedItemIndex == 0 then return;        

    Select(mMenu[0]);
    OnSP = true;
    OnMP = false;
    OnAchievements = false;
    OnOptions = false;
    OnExit = false;
    SelectedItemIndex = 0;
}

这样,当鼠标悬停在已选择的按钮上时,您只需退出整个功能。

然而,虽然这可行,但我强烈建议改为使用正确的 MouseEnter 和 MouseLeave 事件。还使用一堆 if/else 语句进行选择并将按钮传递给选择函数并不是很好。Select() 应该是您的按钮的成员。然后,您只需编写一个函数,让您获得鼠标悬停的按钮,并可以在其上调用 button.select()。从长远来看,这会使您的代码更加简洁。

于 2019-09-05T11:02:21.623 回答