我目前正在尝试使用SFML构建游戏引擎的框架,并且正在学习如何利用Gamestate堆栈结构来将代码划分为可读部分。
我创建了一个基本的TestGameState类,该类扩展了一个抽象类GameState,其他Gamestate类将在其上构建。在我的Game类中,我仅创建一个窗口,运行一个基本的游戏循环,并调用Gamestate更新方法。每个类的代码是:
GameState.h
#pragma once
#include "Game.h"
class GameState {
public:
Game* game = NULL;
virtual void update() = 0;
virtual void draw() = 0;
virtual void handleInput() = 0;
};
TestState.cpp ,它是GameState类的扩展#include "TestState.h"
#include "testGameplayState.h"
using namespace sf;
TestState::TestState(Game* g){
game = g;
texture.loadFromFile("graphics/grass.png");
sprite.setTexture(texture);
sprite.setPosition(Vector2f(0, 0));
}
void TestState::handleInput(){
Event event;
while (game->window.pollEvent(event)) {
if (event.type == Event::KeyPressed) {
if (event.key.code == Keyboard::O) {
game->pushState(new TestState(game));
}
else if (event.key.code == Keyboard::P) {
game->popState();
}
}
}
}
void TestState::update(){}
void TestState::draw(){
game->window.draw(sprite);
}
最后是游戏对象,它处理状态:Game.cpp
#include "Game.h"
#include "GameState.h"
using namespace sf;
//Please note that states is a private stack variable.
Game::Game(){
window.create(VideoMode(1920, 1080), "GameState Test", Style::Fullscreen);
}
Game::~Game() {
while (!states.empty()) {
popState();
}
}
void Game::run() {
while (window.isOpen()) {
if (currentState() == nullptr) {
std::cout << "Nullptr" << std::endl;
window.close();
}
//Handle input
currentState()->handleInput();
//Update
currentState()->update();
//Draw
window.clear();
currentState()->draw();
window.display();
}
}
GameState* Game::currentState() {
if (this->states.empty()) {
return nullptr;
}
else {
return this->states.top();
}
}
void Game::pushState(GameState* state) {
this->states.push(state);
}
void Game::popState() {
delete this->states.top();
this->states.pop();
}
每当我尝试创建新的游戏状态对象时,都可以将它们添加到堆栈中,并可以毫无问题地使用它们。但是,当我尝试弹出当前游戏状态时,它立即退出并在 TestState.cpp 中的while (game->window.pollEvent(event))
行上抛出错误,说:Exception thrown: read access violation. **this** was 0xDDDDDDDD.
错误中的“this”大概是每个状态都持有的游戏对象指针,因为在调试器中它表明游戏对象的值为0xDDDDDDDD。我知道0xDDDDDDDD表示在该地址读取的内存已被删除,但是,我不知道为什么会这样。我希望只有游戏状态会被删除,但是由于某种原因,似乎游戏指针也被删除了。我使用this和this作为如何构造游戏状态类的指南。
我如何能够解决此问题?非常感谢您的帮助。
最佳答案
使用@ OS2和@Some程序员的提示,我能够解决此问题。添加检查以确保我永远不会对空指针进行操作后,我在主游戏循环中更改了方法调用的顺序。这是新循环的样子:
Game.cpp
void Game::run()
{
while (window.isOpen())
{
//Handle input
currentState()->handleInput();
//Check if there are more states
if (currentState() == nullptr)
{
std::cout << "Nullptr, exiting program" << std::endl;
window.close();
break;
}
//Update
currentState()->update();
//Draw
window.clear();
currentState()->draw();
window.display();
}
}
发生的事情是我弹出了堆栈,该堆栈工作正常,但随后立即继续对空指针进行操作。通过检查输入处理后是否存在空指针,可以避免此问题。更重要的是-修复0xDDDDDDDD错误-只需一行即可修复内存错误。
如果您通过用户输入来弹出状态,就像我在上面提到的那样,请确保一旦弹出状态就跳出循环。否则,while()循环将在状态终止后继续执行,并且由于状态不再存在而将引发错误。我编辑的输入处理代码如下所示:
TestState.cpp
void TestState::handleInput()
{
std::cout << "Handling input" << std::endl;
Event event;
while (game->window.pollEvent(event))
{
if (event.type == Event::KeyPressed)
{
if (event.key.code == Keyboard::O)
{
game->pushState(new TestState(game));
}
else if (event.key.code == Keyboard::P)
{
game->popState();
break;
}
}
}
}
希望对其他有此问题的人有所帮助。感谢@ OS2和@Some编程人员为您发现问题提供的帮助。
关于c++ - “这”为0xDDDDDDDD:弹出堆栈时发生读取访问冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63092188/