0
\$\begingroup\$

I'm currently learning how to program a 2d game with SFML using a tutorial series by Suraj Sharma.This's his channel:

https://www.youtube.com/channel/UC2i39AOpDSlO1Mrn1jQ8Xkg

The tutorial series:

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

Recently i'm making an animation class that works with a player class. Everytime i push a button repeatedly the debug will tell me i have a 'write access violation:this was nullptr'.

Here's the code.

AnimCmp.h:

#ifndef ANIM_CMP_H
#define ANIM_CMP_H

#include "pch.h"

class AnimCmp
{
private:
class Anim {
public:
    //Vars
    sf::Sprite& Spr;
    sf::Texture& TexSheet;
    sf::IntRect StartRct;
    sf::IntRect CurrRect;
    sf::IntRect EndRct;

    bool Done;
    float Timer;
    float AnimTimer;
    int w;
    int h;

    Anim(sf::Sprite& Spr, sf::Texture& TexSheet, float AnimTimer, int stx, int sty, int frx, int fry, int w, int h)
        :Spr(Spr), TexSheet(TexSheet),AnimTimer(AnimTimer),Timer(0.f),Done(false),w(w),h(h){
        this->w = w;
        this->h = h;
        this->StartRct = sf::IntRect(stx * w, sty * h, w, h);
        this->CurrRect = this->StartRct;
        this->EndRct = sf::IntRect(frx * w, fry * h, w, h);

        this->Spr.setTexture(this->TexSheet, true);
        this->Spr.setTextureRect(this->StartRct);
    }
    //virtual~Anim();
    //Functions
    void Pause();
    void Reset() {
        this->Timer = this->AnimTimer;
        this->CurrRect = this->StartRct;
    }

    const bool& Play(const float& dt) {
        //Update Timer
        this->Done = false;
        this->Timer += 100.f * dt;
        if (this->Timer >= this->AnimTimer) {
            //Reset Timer
            this->Timer = 0.f;
            //Animate
            if (this->CurrRect != this->EndRct) {
                this->CurrRect.left += this->w;
            }
            else {//Reset
                this->CurrRect.left = this->StartRct.left;
                this->Done = true;
            }
            this->Spr.setTextureRect(this->CurrRect);
        }
        return this->Done;
    }

    const bool& Play(const float& dt, float modprcnt) {
        //Update Timer
        if (modprcnt < 0.5f)
            modprcnt = 0.5f;

        this->Done = false;//access violation occurs here
        this->Timer += modprcnt * 100.f * dt;
        if (this->Timer >= this->AnimTimer) {
            //Reset Timer
            this->Timer = 0.f;
            //Animate
            if (this->CurrRect != this->EndRct) {
                this->CurrRect.left += this->w;
            } 
            else {//Reset
                this->CurrRect.left = this->StartRct.left;
                this->Done = true;
            }
            this->Spr.setTextureRect(this->CurrRect);
        }
        return this->Done;
    }
    //Access
    const bool& isDone()const {
        return this->Done;
    }

};

sf::Sprite& Spr;
sf::Texture& TexSheet;
std::map<std::string, Anim*> Anims;
Anim* LastAnim;
Anim* Priority;
public:
AnimCmp(sf::Sprite& Spr,sf::Texture& TexSheet);
virtual~AnimCmp();
//Access
const bool& isDone(const std::string key);
//Functions
void AddAnim(const std::string key,float AnimTimer, int stx, int sty, int frx, int fry, int w, int h);

void Start(const std::string Anim);
void Pause(const std::string Anim);
void Reset(const std::string Anim);
const bool& Play(const std::string key, const float& dt, const bool priority = false);
const bool& Play(const std::string key, const float& dt, const float& mod, const float& modmax, const bool priority = false);
};

#endif // !ANIM_CMP_H

AnimCmp.cpp:

#include "AnimCmp.h"

AnimCmp::AnimCmp(sf::Sprite& Spr, sf::Texture&    TexSheet)
:Spr(Spr), TexSheet(TexSheet), LastAnim(NULL),   Priority(NULL)
{
}

AnimCmp::~AnimCmp()
{
for (auto& i : this->Anims) {
    delete i.second;
}
}

const bool& AnimCmp::isDone(const std::string key)
{
return this->Anims[key]->isDone();
}

void AnimCmp::AddAnim(const std::string key,float AnimTimer, int stx, int sty, int frx, int fry, int w, int h)
{
this->Anims[key] = new Anim(this->Spr, this->TexSheet, AnimTimer, stx, sty, frx, fry, w, h);
}
//Functions
void AnimCmp::Start(const std::string Anim)
{
}

void AnimCmp::Pause(const std::string Anim)
{
}

void AnimCmp::Reset(const std::string Anim)
{
}

const bool& AnimCmp::Play(const std::string key, const float& dt, const bool priority)
{   
if (this->Priority) {//If priority present
    if (this->Priority == this->Anims[key]) {
        if (this->LastAnim != this->Anims[key])
        {
            if (this->LastAnim == NULL)
                this->LastAnim = this->Anims[key];
            else {
                this->LastAnim->Reset();
                this->LastAnim = this->Anims[key];
            }
        }
        //Priority done,remove
        if (this->Anims[key]->Play(dt)) {
            this->Priority = NULL;
        }
    }
}else{//Play animation
    if (priority) {
        this->Priority = this->Anims[key];
    }
    if (this->LastAnim != this->Anims[key])
    {
        if (this->LastAnim == NULL)
            this->LastAnim = this->Anims[key];
        else {
            this->LastAnim->Reset();
            this->LastAnim = this->Anims[key];
        }
    }
    this->Anims[key]->Play(dt);
}
return this->Anims[key]->isDone();
}

const bool& AnimCmp::Play(const std::string key, const float& dt, const float& mod, const float& modmax, const bool priority)
{
if (this->Priority) {//If priority present
    if (this->Priority == this->Anims[key]) {
        if (this->LastAnim != this->Anims[key])
        {
            if (this->LastAnim == NULL)
                this->LastAnim = this->Anims[key];
            else {
                this->LastAnim->Reset();
                this->LastAnim = this->Anims[key];
            }
        }
        if (this->Anims[key]->Play(dt, abs(mod / modmax))) {
            this->Priority = NULL;
        }
    }
}
else {//Play animation
    if (priority) {//If is priority,set it
        this->Priority = this->Anims[key];
    }
    if (this->LastAnim != this->Anims[key])
    {
        if (this->LastAnim == NULL)
            this->LastAnim = this->Anims[key];
        else {
            this->LastAnim->Reset();
            this->LastAnim = this->Anims[key];
        }
    }
    this->Anims[key]->Play(dt, abs(mod / modmax));
}
return this->Anims[key]->isDone();
}

Player.h:

#pragma once
#ifndef PLAYER_H
#define PLAYER_H

#include "Entity.h"
class Player :
    public Entity
{
private:
    //Vars
    bool atking;
    //Init Funcs
    void InitVars();
    void InitComp();
public:
    Player(float x, float y, sf::Texture& TexSheet);
    virtual ~Player();
    //Funcs
    void UpdateAtk();
    void UpdateAnim(const float& dt);
    virtual void Update(const float& dt);
};

#endif // !PLAYER_H

Player.cpp:

    #include "Player.h"

//Init Funcs
void Player::InitVars()
{
    this->atking = false;
}

void Player::InitComp()
{
}

Player::Player(float x, float y, sf::Texture& TexSheet)
{
    this->InitVars();
    this->setPos(x, y);

    this->CreateHboxCmp(this->Spr, 20.f, 0.f, 80.f, 128.f);
    this->CreateMovCmp(200.f, 10.f, 4.f);
    this->CreateAnimCmp(TexSheet);

    this->animCmp->AddAnim("Idl", 10.f, 2, 0, 2, 0, 128, 128);
    this->animCmp->AddAnim("Walk", 10.f, 0, 6, 5, 6, 128, 128);
    this->animCmp->AddAnim("PShoot", 30.f, 3, 0, 5, 0, 128, 128);
}

Player::~Player()
{
}
//Funcs
void Player::UpdateAtk()
{
    if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
        this->atking = true;
    }
}

void Player::UpdateAnim(const float& dt)
{
    if (this->atking) {
        //Chk for anim end and animate
        if (this->animCmp->Play("PShoot", dt, true)) {
            this->atking = false;
        }
    }
    if (this->movCmp->GetSt(IDL)) {
        this->animCmp->Play("Idl", dt);
    }
    else if (this->movCmp->GetSt(LFT)) {
        if (this->Spr.getScale().x < 0.f) {
            this->Spr.setOrigin(115.f, 0.f);
            this->Spr.setScale(-1.f, 1.f);
        }
        this->animCmp->Play("Walk", dt, this->movCmp->getVel().x, this->movCmp->getMaxVel());
    }
    else if (this->movCmp->GetSt(RGT)) {
        if (this->Spr.getScale().x > 0.f) {
            this->Spr.setOrigin(0.f, 0.f);
            this->Spr.setScale(1.f, 1.f);
        }
        this->animCmp->Play("Walk", dt, this->movCmp->getVel().x, this->movCmp->getMaxVel());
    }
    else if (this->movCmp->GetSt(UP)) {
        this->animCmp->Play("Walk_up", dt, this->movCmp->getVel().x, this->movCmp->getMaxVel());
    }
    else if (this->movCmp->GetSt(DN)) {
        this->animCmp->Play("Walk_dn", dt, this->movCmp->getVel().x, this->movCmp->getMaxVel());
    }

}

void Player::Update(const float& dt)
{
    this->movCmp->Update(dt);
    this->UpdateAtk();
    this->UpdateAnim(dt);
    this->hbCmp->Update();
}

The Exception occurs right after the 'bool Done' variable was declared.

Here's the video where that happened:

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

I've also checked the 'this' pointer in debug mode.It said that it wasn't able to get the value of the following variables:

TexSheet

Spr

StartRect,CurrRect and EndRect

I hope this is enough information.Can anyone help me ?

\$\endgroup\$
1
\$\begingroup\$

'this' was nullptr

and

It said that it wasn't able to get the value of the following variables [...]

You're trying to modify an object that does not exists. This could have worked in the older days, and you would have had a really hard time to figure out what was going on. Today, the systems are smarter and it's really harder to shoot yourself in the foot: they detect such issues and crash right away.

One of the ways to answer questions such as: What is the nullptr' object? Who's calling the function? What are the values that would help me pin-point the issue? is by using the callstack debug window. This will tell you who's calling it, and you can click on all those steps to get more info; the Visual Studio debugger will also reveal information such as the values of the variables that were involved.

Or, if you don't have such tools, like here, spend more time understanding your code and what goes on.

Here, I suspect you try to call an animation that does not exists: from the looks of it, it appears that you try to access animation Walk_up or Walk_dn, but I don't see it initialized in the Player constructor.

\$\endgroup\$
  • 2
    \$\begingroup\$ I've just commented out those uninitialized animations.It seems that the game works fine now,i forgot the game will loop and check for everything.Thanks for the help. \$\endgroup\$ – TankRocket Oct 27 at 0:35
  • \$\begingroup\$ @TankRocket if this answer helped you, please consider clicking the checkmark icon to mark it "Accepted." Or you can post your own route to a solution as a separate answer, and accept that after a short delay. This helps highlight working solutions for other users trying to find them. \$\endgroup\$ – DMGregory Nov 26 at 1:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.