gpt4 book ai didi

c++ - 重新初始化父类时,SFML 对象不会绘制

转载 作者:行者123 更新时间:2023-11-30 02:21:30 25 4
gpt4 key购买 nike

我正在开发一个新项目并实现基本的场景更改。我将不同的场景设置为它们自己的类,使用初始化函数来创建和重新定位不同的 SFML 对象。我看到了this answer并类似地编写了我的场景切换器:

// Create scene monitoring variable
int scene[2];
scene[0] = 0; // Set current scene to menu
scene[1] = 0; // Set scene change to no

...

// Check for scene change
if(scene[1] == 0) {
// Run tick function based on current scene
switch(scene[0]) {
case 0:
// Main menu - run tick function
menu.tick();
}
}
if(scene[1] == 1) {
// Reset scene that you've changed to
switch(scene[0]) {
case 0:
// Main menu - reset it
menu = Menu(window, scene); // <-- Reinitialise menu here
}
// Set change variable to 0
scene[1] = 0;
}

您可以在 github repository 上查看完整代码.

但是,这似乎无法正常工作 - 一旦场景发生变化,屏幕就会变黑。该类被重新初始化(我添加了一个 cout 来检查),绘图函数仍在运行并且鼠标点击仍在处理,但窗口中没有任何显示。

我是不是做错了什么?

最佳答案

以这种方式做事会导致内存泄漏错误。我建议您采用不同的方法:StateStack

这是如何运作的?

拥有 StateStack 对象的基础是将游戏/应用程序的每个可能状态存储到堆栈中。这样,您可以按堆栈顺序处理每一个。

什么是状态?

状态是可以更新绘制处理事件的东西。我们可以创建一个接口(interface)或一个抽象类,使我们的屏幕表现得像一个状态。

有哪些优势?

通过堆栈结构,您可以轻松控制您的不同场景将如何处理三种不同的处理方法。例如。如果您在暂停菜单中单击鼠标,则不会通过该单击事件进入菜单状态或“游戏”状态。要实现这一点,解决方案非常简单,如果您不希望事件进一步达到此特定状态,只需在您的 handleEvent 方法中返回 false。请注意,这个想法也可以扩展到 drawupdate 方法。在您的暂停菜单中,您不会更新您的“游戏”状态。在您的“游戏”状态下,您不会绘制游览菜单状态。

例子

考虑到这一点,这是一种可能的实现方式。首先是State界面:

class State{
public:
virtual bool update() = 0;
virtual bool draw(sf::RenderTarget& target) const = 0;

// We will use a vector instead a stack because we can iterate vectors (for drawing, update, etc)
virtual bool handleEvent(sf::Event e, std::vector<State*> &stack) = 0;
};

按照这个接口(interface)我们可以有一个例子MenuStatePauseState:

菜单状态

class MenuState : public State{
public:
MenuState(){
m_count = 0;

m_font.loadFromFile("Roboto-Regular.ttf");
m_text.setFont(m_font);
m_text.setString("MenuState: " + std::to_string(m_count));
m_text.setPosition(10, 10);
m_text.setFillColor(sf::Color::White);

}

virtual bool update() {
m_count++;
m_text.setString("MenuState: " + std::to_string(m_count));
return true;
}

virtual bool draw(sf::RenderTarget &target) const{
target.draw(m_text);
return true;
}

virtual bool handleEvent(sf::Event e, std::vector<State*> &stack){
if (e.type == sf::Event::KeyPressed){
if (e.key.code == sf::Keyboard::P){
stack.push_back(new PauseState());
return true;
}
}
return true;
}

private:
sf::Font m_font;
sf::Text m_text;
unsigned int m_count;
};

暂停状态

class PauseState : public State{
public:
PauseState(){
sf::Font f;
m_font.loadFromFile("Roboto-Regular.ttf");
m_text.setFont(m_font);
m_text.setString("PauseState");
m_text.setPosition(10, 10);
m_text.setFillColor(sf::Color::White);

}

virtual bool update() {
// By returning false, we prevent States UNDER Pause to update too
return false;
}

virtual bool draw(sf::RenderTarget &target) const{
target.draw(m_text);
// By returning false, we prevent States UNDER Pause to draw too
return false;
}

virtual bool handleEvent(sf::Event e, std::vector<State*> &stack){
if (e.type == sf::Event::KeyPressed){
if (e.key.code == sf::Keyboard::Escape){
stack.pop_back();
return true;
}
}
return false;
}

private:
sf::Font m_font;
sf::Text m_text;
};

顺便说一句,当我这样做时,我注意到您必须将字体作为类的属性 以保留引用。如果没有,当你绘制文本时,它的字体会丢失,然后它就会失败。面对这个问题的另一种方法是使用 resource holder ,这更加高效和稳健。

说到这里,我们的 main 将如下所示:

主要

int main() {
// Create window object
sf::RenderWindow window(sf::VideoMode(720, 720), "OpenTMS");

// Set window frame rate
window.setFramerateLimit(60);

std::vector<State*> stack;

// Create menu
stack.push_back(new MenuState());

// Main window loops
while (window.isOpen()) {
// Create events object
sf::Event event;
// Loop through events
while (window.pollEvent(event)) {
// Close window
if (event.type == sf::Event::Closed) {
window.close();
}

handleEventStack(event, stack);
}

updateStack(stack);
// Clear window
window.clear(sf::Color::Black);
drawStack(window, stack);
// Display window contents
window.display();
}

return 0;
}

堆栈函数 是简单的 for 循环,但具有向后 迭代 vector 的细节。这是模仿堆栈行为的方式,从顶部(size-1 索引)开始,到 0 结束。

堆栈函数

void handleEventStack(sf::Event e, std::vector<State*> &stack){
for (int i = stack.size()-1; i >=0; --i){
if (!stack[i]->handleEvent(e, stack)){
break;
}
}
}

void updateStack(std::vector<State*> &stack){
for (int i = stack.size() - 1; i >= 0; --i){
if (!stack[i]->update()){
break;
}
}
}

void drawStack(sf::RenderTarget &target, std::vector<State*> &stack){
for (int i = stack.size() - 1; i >= 0; --i){
if (!stack[i]->draw(target)){
break;
}
}
}

您可以了解有关 StateStacks 和 gamedev 的更多信息 with this book

关于c++ - 重新初始化父类时,SFML 对象不会绘制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48267528/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com