Click here to Skip to main content
15,889,909 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm recently learning to make a 2d game in SFML using a tutorial series on youtube by Suraj Sharma(Video 57):

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

His Source Code:

https://github.com/Headturna/SFML_RPG

Right now he's teaching me to symplify the game's menu system by making a mini class 'StateData' in the parent class 'State' so any inherited class can access 'State' parameters via 'StateData'(Ex:MainMenu(StData* Stdata){}).

After debugging the game seems to runs fine.But everytime i click on something on the menu(start,settings,etc...) a 'Read access violation:Stdata was nullptr' occurs in the 'State' class constructor.

Here's the code:

State.h:
C++
<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:
C++
<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;
}


Every button one the menu(start,exit...)is an inherited state from 'State' class.This is,for example,the 'Edit' state.

Edit.h:
C++
<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:
C++
<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);
}


Can anyone help me ?

What I have tried:

I've tried debugging the project,it seems that nothing is wrong with the other states.After all the 'State' class parameters were put into 'StData' mini class this happens.
Posted
Updated 17-Nov-19 19:49pm
Comments
TankRockett 18-Nov-19 10:58am    
One more information,it appears that in the 'State.h' file the 'StData()' constructor are having warning 'C26495' complaining that the following variables 'Windows' , 'GSettings' , 'SupportedKeys' , 'states' , 'GridSize' are uninitialized.That didn't happen in the tutorial.

1 solution

You cant use the nullptr as input in that constructor
C++
State::State(StData* Stdata)
{
	this->Stdata = Stdata;
	this->window = Stdata->Window;//access memory at zero is totally wrong
}
In your code you ALWAYS NEED some valid pointer.

You need think about nullptr as special case: Makes it sense to create a State object?

If YES than check for nullptr like that
C++
if( pState != nullptr ) {//changed your problematic var
  this->window = pState->Window;
} else {
  this->window = nullptr;
}
BTW: it is bad style to write a variable with the same writing as a class
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900