TankRockett Ответов: 1

Нужна помощь с исключением "нарушение доступа на чтение" в проекте SFML/C++ :


Недавно я учусь делать 2d-игру на SFML, используя учебную серию на youtube от Suraj Sharma(видео 57):

https://www.youtube.com/watch?v=kwd_AVCkvXE&list=PL6xSOsbVA1ebkU66okpi-KViAO8_9DJKg&index=57

Его Исходный Код:

https://github.com/Headturna/SFML_RPG

Прямо сейчас он учит меня упрощать систему меню игры, создавая мини-класс "StateData" в родительском классе "State", чтобы любой унаследованный класс мог получить доступ к параметрам "State" через "StateData" (например:MainMenu(StData* Stdata){}).

После отладки игра, кажется, работает нормально.Но каждый раз,когда я нажимаю на что-то в меню(Пуск,Настройки и т. д.), В конструкторе класса "состояние" возникает "нарушение доступа на чтение:Stdata was nullptr".

Вот этот код:

Государства.ч:
<pre>#pragma once

#ifndef STATE_H
#define STATE_H

#include "Player.h"
#include "GrphSettings.h"

class Player;
class GrphSettings;
class State;

class StData {
public:
	StData(){}

	//Vars
	float GridSize;
	sf::RenderWindow* Window;
	GrphSettings* GSettings;
	std::map<std::string, int>* SupportedKeys;
	std::stack<State*>* states;
};

class State
{
private:

protected:
	StData* Stdata;
	std::stack<State*>* states;
	sf::RenderWindow* window;
	std::map<std::string, int>* SupportedKeys ;
	std::map<std::string, int> Keybinds;
	bool quit;
	bool pause;
	float keyTime; 
	float keyTimeMax;
	float GridSize;

	sf::Vector2i MousePosScr;
	sf::Vector2i MousePosWind;
	sf::Vector2f MousePosView;
	//Resources
	std::map<std::string,sf::Texture> texture;
	//Funcs
	virtual void InitKeybinds() = 0;
public:
	State(StData* Stdata);
	virtual~State();
	//Access
	const bool getKeytime();
	const bool& getquit()const;
	//Funcs
	void Endstate();
	void PauseSt();
	void UnPauseSt();

	virtual void UpdateInput(const float& dt) = 0;
	virtual void UpdateMousePos();
	virtual void UpdateKeyTime(const float& dt);
	virtual void Update(const float& dt) = 0;
	virtual void Render(sf::RenderTarget* target = nullptr) = 0;
};
#endif // !1


State.cpp:
<pre>#include "pch.h"
#include "State.h"

State::State(StData* Stdata)
{ 
	this->Stdata = Stdata;
	this->window = Stdata->Window;//Read access violation
	this->SupportedKeys = Stdata->SupportedKeys;
	this->states = Stdata->states;
	this->quit = false;
	this->pause = false;
	this->keyTime = 0.f;
	this->keyTimeMax = 10.f;
	this->GridSize = Stdata->GridSize;
}

State::~State()
{
}
//Access
const bool State::getKeytime()
{
	if (this->keyTime >= this->keyTimeMax) {
		this->keyTime = 0.f; 
		return true;
	}
	return false;
}

const bool& State::getquit() const
{
	// TODO: insert return statement here
	return this->quit;
}
//Funcs
void State::Endstate()
{
	this->quit = true;
}

void State::PauseSt()
{
	this->pause = true;
}

void State::UnPauseSt()
{
	this->pause = false;
}

void State::UpdateMousePos()
{
	this->MousePosScr = sf::Mouse::getPosition();
	this->MousePosWind = sf::Mouse::getPosition(*this->window);
	this->MousePosView = this->window->mapPixelToCoords(sf::Mouse::getPosition(*this->window));
}

void State::UpdateKeyTime(const float& dt)
{
	if (this->keyTime < this->keyTimeMax)
		this->keyTime += 100.f * dt;
}


Каждая кнопка меню(Пуск,выход...)является наследуемым состоянием от класса "состояние".Это,например,состояние "редактировать".

Редактировать.ч:
<pre>#pragma once
#ifndef EDIT_H
#define EDIT_H

#include "State.h"
#include "Gui.h"
#include "PauseMenu.h"
#include "TileMap.h"

class State;
class Gui;
class PauseMenu;
class TileMap;

class Edit:public State
{
private:
	//Vars
	sf::Font Fnt;
	PauseMenu* PMenu;
	std::map<std::string, gui::Button*> buttons;
	TileMap Map;

	//Functions
	void InitVars();
	void InitBackGrnd();
	void InitFonts();
	void InitKeybinds();
	void InitPauseMenu();
	void InitBtn();
public:
	Edit(StData* Stdata);
	virtual~Edit();
	//Functions
	void UpdateInput(const float& dt);
	void Update(const float& dt);
	void UpdatePButtons();
	void UpdateBtn();

	void Endstate();

	void RenderBtn(sf::RenderTarget& target);
	void Render(sf::RenderTarget* target = nullptr);
};
#endif // ! EDIT_H


Edit.cpp:
<pre>#include "pch.h"
#include "Edit.h"

void Edit::InitVars()
{
}

void Edit::InitBackGrnd()
{
}

void Edit::InitFonts()
{
	if (!this->Fnt.loadFromFile("Fonts/SPACEMAN.ttf")) {
		throw("Error::Edit::Couldn't load font");
	}
}

void Edit::InitKeybinds()
{
	std::ifstream ifs("Config/EditKeys.ini");

	if (ifs.is_open()) {
		std::string key = "";
		std::string key2 = "";
		int keyval = 0;
		while (ifs >> key >> key2)
		{
			this->Keybinds[key] = this->SupportedKeys->at(key2);
		}
	}
	ifs.close();

	this->Keybinds["Close"] = this->SupportedKeys->at("ESC");
	this->Keybinds["Left"] = this->SupportedKeys->at("A");
	this->Keybinds["Right"] = this->SupportedKeys->at("D");
	this->Keybinds["Up"] = this->SupportedKeys->at("W");
	this->Keybinds["Down"] = this->SupportedKeys->at("S");
}

void Edit::InitPauseMenu()
{
	this->PMenu = new PauseMenu(*this->window, this->Fnt);
	this->PMenu->addButtons("Quit", 800.f, "Quit");
}

void Edit::InitBtn()
{
}

Edit::Edit(StData* Stdata)
	:State(Stdata)
{
	this->InitVars();
	this->InitBackGrnd();
	this->InitFonts();
	this->InitKeybinds();
	this->InitPauseMenu();
	this->InitBtn();
}

Edit::~Edit()
{
	auto it = this->buttons.begin();
	for (it = this->buttons.begin(); it != this->buttons.end(); ++it) {
		delete it->second;
	}
	delete this->PMenu;
}

//Funcs
void Edit::UpdateInput(const float& dt)
{
	if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key(this->Keybinds.at("Close")))
		&& this->getKeytime()) {
		if (!this->pause)
			this->PauseSt();
		else this->UnPauseSt();
	}

}

void Edit::Update(const float& dt)
{
	this->UpdateMousePos();
	this->UpdateKeyTime(dt);
	this->UpdateInput(dt);

	if (!this->pause) {//Unpaused
		this->UpdateBtn();
	}
	else {//Paused
		this->PMenu->Update(this->MousePosView);
		this->UpdatePButtons();
	}

	this->UpdateBtn();

	std::cout << this->MousePosView.x << " " << this->MousePosView.y << "\r";
}

void Edit::UpdatePButtons()
{
	if (this->PMenu->isPressed("Quit"))
			this->Endstate();
}

void Edit::UpdateBtn()
{	//Update buttons and handle their functions
	for (auto& it : this->buttons) {
		it.second->Update(MousePosView);
	}
}

void Edit::Endstate()
{
	std::cout << "Ending State" << "\n";
}

void Edit::RenderBtn(sf::RenderTarget& target)
{
	for (auto& it : this->buttons) {
		it.second->Render(target);
	}
}

void Edit::Render(sf::RenderTarget* target)
{
	if (!target)
		target = this->window;

	this->RenderBtn(*target);

	this->Map.Render(*target);

	if (this->pause) {//Pause Menu
		this->PMenu->Render(*target);
	}
	
	sf::Text MText;
	MText.setPosition(this->MousePosView);
	MText.setFont(this->Fnt);
	MText.setCharacterSize(12);
	std::stringstream ss;
	ss << this->MousePosView.x << ' ' << this->MousePosView.y;
	MText.setString(ss.str());

	target->draw(MText);
}


Кто-нибудь может мне помочь ?

Что я уже пробовал:

Я пробовал отлаживать проект,кажется, что с другими состояниями все в порядке.После того, как все параметры класса "State" были помещены в мини-класс "StData", это происходит.

TankRockett

Еще одна информация,оказывается, что в 'государстве.файл h конструктор 'StData()' имеет предупреждение 'C26495' , жалующееся на то, что следующие переменные 'Windows', 'GSettings', 'SupportedKeys' , 'states' , 'GridSize' неинициализированы.Этого не было в учебнике.

1 Ответов

Рейтинг:
2

KarstenK

Вы не можете использовать nullptr в качестве входных данных в этом конструкторе

State::State(StData* Stdata)
{
	this->Stdata = Stdata;
	this->window = Stdata->Window;//access memory at zero is totally wrong
}
В своем коде вы ВСЕГДА НУЖНО какой-то допустимый указатель.

Вам нужно думать о nullptr как о частном случае: имеет ли смысл создавать объект состояния?

Если да то проверьте наличие nullptr вот так
if( pState != nullptr ) {//changed your problematic var
  this->window = pState->Window;
} else {
  this->window = nullptr;
}
Кстати: это плохой стиль-писать переменную с тем же написанием, что и класс