Segmentation Fault?

This lecture was a beast. As others have mentioned the material went fast and a lot more was covered than I was ready to absorb. At 4:14 he talks about changing direction to velocity in the Character::Tick() but quietly deletes an entire line. This slipped by me glancing back over at my own code on the other screen and I fell into the same problem that @Mark_Burke had.

As to @sleepykraken 's question I think we zero out velocity because by this point we’ve already used it to move the character and we need it to be ready to use so the change doesn’t accumulate.

After that, I was working fine again and able to slog my way to the end only to come up with this. I still don’t quite understand this one so if you can offer any clues it’d be much appreciated.

BaseCharacter.h
#ifndef BASE_CHARACTER_H
#define BASE_CHARACTER_H
#include "raylib.h"

class BaseCharacter
{
public:
    BaseCharacter();
    Vector2 GetWorldPos() { return WorldPos; }
    void UndoMovement();
    Rectangle GetCollisionRec();
    virtual void Tick(float DeltaTime);
    virtual Vector2 GetScreenPos() = 0;

protected:
    Vector2 ScreenPos{};
    Vector2 WorldPos{};
    Vector2 WorldPosLastFrame{};
    Texture2D Texture{LoadTexture("characters/knight_idle_spritesheet.png")};
    Texture2D Idle{LoadTexture("characters/knight_idle_spritesheet.png")};
    Texture2D Run{LoadTexture("characters/knight_run_spritesheet.png")};
    // 1: facing right, -1 : facing left
    float RightLeft{1.f};
    // animation variables
    float RunningTime{};
    int Frame{};
    int MaxFrames{6};
    float UpdateTime{1.f / 12.f};
    float Speed{4.f};
    float Width{};
    float Height{};
    float Scale{4.0f};
    bool IsRunning{};
    Vector2 Velocity{};

private:

};

#endif
BaseCharacter.cpp
#include "BaseCharacter.h"
#include "raymath.h"

BaseCharacter::BaseCharacter()
{

};

void BaseCharacter::Tick(float DeltaTime)
{
    WorldPosLastFrame = WorldPos;

    // Update Animation
    RunningTime += DeltaTime;
    if (RunningTime >= UpdateTime)
    {
        Frame++;
        RunningTime = 0.f;
        if (Frame >= MaxFrames)
            Frame = 0;
    }

    // Swap Sprite w/direction & idle/run Sheet w/movement
    if (Vector2Length(Velocity) != 0.0)
    {
        // Take Normalized Velocity, scale it to speed and add it to my world position to move the character
        WorldPos = Vector2Add(WorldPos, Vector2Scale(Vector2Normalize(Velocity), Speed));
        // Direction.x <= 0.f ? RightLeft = -1 : RightLeft = 1.f;
        if (Velocity.x < 0.f)
            RightLeft = -1;
        else if (Velocity.x > 0.f)
            RightLeft = 1;
        Texture = Run;
    }
    else
    {
        Texture = Idle;
    }
    Velocity = {};  // Zero out Velocity after movement

    // Draw Character
    Rectangle Source{Frame * Width, 0.f, RightLeft * Width, Height};
    Rectangle Dest{GetScreenPos().x, GetScreenPos().y, Scale * Width, Scale * Height};
    DrawTexturePro(Texture, Source, Dest, Vector2{}, 0.f, WHITE);
}

void BaseCharacter::UndoMovement()
{
    WorldPos = WorldPosLastFrame;
}

Rectangle BaseCharacter::GetCollisionRec()
{
    return Rectangle
    {        
        GetScreenPos().x,
        GetScreenPos().y,
        Width * Scale,
        Height * Scale        
    };
}
Character.h
#ifndef CHARACTER_H
#define CHARACTER_H

#include "raylib.h"
#include "BaseCharacter.h"

class Character : public BaseCharacter
{
public:
    Character(int WinWidth, int WinHeight);
    virtual void Tick(float DeltaTime) override;
    virtual Vector2 GetScreenPos() override;

private:
    int WindowWidth{};
    int WindowHeight{};    
};

#endif
Character.cpp

#include "Character.h"
#include "raymath.h"

Character::Character(int WinWidth, int WinHeight) : WindowWidth(WinWidth),
                                                    WindowHeight(WinHeight)
{
    Width = Texture.width / MaxFrames;
    Height = Texture.height;
}

Vector2 Character::GetScreenPos()
{
    return Vector2{
        static_cast<float>(WindowWidth) / 2.0f - Scale * (0.5f * Width),
        static_cast<float>(WindowHeight) / 2.0f - Scale * (0.5f * Height)};
}

void Character::Tick(float DeltaTime)
{

    // Handle Movement
    if (IsKeyDown(KEY_A))
        Velocity.x -= 1.0;
    if (IsKeyDown(KEY_D))
        Velocity.x += 1.0;
    if (IsKeyDown(KEY_W))
        Velocity.y -= 1.0;
    if (IsKeyDown(KEY_S))
        Velocity.y += 1.0;

    BaseCharacter::Tick(DeltaTime);
}

Enemy.h
#include "raylib.h"
#include "BaseCharacter.h"
#include "Character.h"

class Enemy : public BaseCharacter
{
public:
    Enemy(Vector2 Pos, Texture2D idle_texture, Texture2D run_texture);
    virtual void Tick(float DeltaTime) override;
    void SetTarget(Character* Character) {Target = Character;}
    virtual Vector2 GetScreenPos() override;
    
private:
    Character* Target;

};
Enemy.cpp
#include "Enemy.h"
// #include "Character.h"
#include "raymath.h"

Enemy::Enemy(Vector2 Pos, Texture2D idle_texture, Texture2D run_texture) 
{
    WorldPos = Pos;
    Texture = idle_texture;
    Idle = idle_texture;
    Run = run_texture;
    Speed = 3.5f;

    Width = Texture.width / MaxFrames;
    Height = Texture.height;
}

void Enemy::Tick(float DeltaTime)
{
    
    // Get "ToTarget"
    Velocity = Vector2Subtract(Target->GetScreenPos(), GetScreenPos());
    BaseCharacter::Tick(DeltaTime);
}

Vector2 Enemy::GetScreenPos()
{
    return Vector2Subtract(WorldPos, Target->GetWorldPos());
}
Main.cpp
#include "raylib.h"
#include "raymath.h"
#include "Character.h"
#include "Prop.h"
#include "Enemy.h"

const int WindowDimensions[]{384, 384};
bool GameStarted{};
bool WinGame{};
double GameTimer{};

// This displays the button prompt and returns false until it is pressed
bool PromptSpace()
{
    DrawText("Press Space", (WindowDimensions[0] * .4), (WindowDimensions[1] * .65), 15, WHITE);
    DrawText("Esc to Quit", (WindowDimensions[0] * .70), (WindowDimensions[1] * .95), 15, BLACK);
    if (IsKeyDown(KEY_SPACE))
    {
        return true;
    }
    return false;
}

//  Displays a large text layered with a highlight and shadow
void ShadowAndOutline(const char *text, float PercentWindowPosX, float PercentWindowPosY)
{
    int TrimX = -2;
    int TrimY = -1;
    int ShadowX = -3;
    int ShadowY = -2;
    int FontSize = 60;
    DrawText(text, PercentWindowPosX * WindowDimensions[0] - TrimY, PercentWindowPosY * WindowDimensions[1] - TrimY, FontSize, DARKPURPLE);
    DrawText(text, PercentWindowPosX * WindowDimensions[0], PercentWindowPosY * WindowDimensions[1], FontSize, PURPLE);
    DrawText(text, PercentWindowPosX * WindowDimensions[0] + TrimX, PercentWindowPosY * WindowDimensions[1] + TrimY, FontSize, {0, 255, 255, 255});
    DrawText(text, PercentWindowPosX * WindowDimensions[0] + ShadowX, PercentWindowPosY * WindowDimensions[1] + ShadowY, FontSize, WHITE);
}

void DisplayTitleWaitForInput()
{
    ShadowAndOutline("Untitled", .20, .20);
    ShadowAndOutline("Game", .32, .40);
    // DrawText("Risk & Reward   Race & Record \n\n\n\n       The Quest to 100", WindowDimensions[0]*.3,  WindowDimensions[1]*.37, 14, BLACK);
    // DisplayTwistyText("Keep Jumping!    Don't Stop Ever!", .1, .06, 80, 20, MAROON);
    // DisplayTwistyText("More Jumps Means More Points!", .6, .9, -55, 20, MAROON);
    if (PromptSpace())
    {
        GameStarted = true;
        GameTimer = 0;
    }
}

int main()
{
    // bool Collision{}; // initialize collision Game State as false
    InitWindow(WindowDimensions[0], WindowDimensions[1], "Top Down Game");

    // texture variables
    Texture2D Map = LoadTexture("nature_tileset/WorldMap.png");
    Vector2 MapPos = {0.0, 0.0};
    const float MapScale{4.0};
    //int NumberOfProps{2};

    Character Knight{WindowDimensions[0], WindowDimensions[1]};

    Enemy Goblin{
        Vector2{}, 
        LoadTexture("characters/goblin_idle_spritesheet.png"), 
        LoadTexture("characters/goblin_run_spritesheet.png")
    };

    Prop Props[2]{
        Prop{Vector2 {250.f, 250.f}, LoadTexture("nature_tileset/Rock.png")},
        Prop{Vector2 {400.f, 500.f}, LoadTexture("nature_tileset/Log.png") }       
    };

    SetTargetFPS(60);
    while (!WindowShouldClose())
    {
        BeginDrawing();
        ClearBackground(SKYBLUE);

        // if game has not started
        if (!GameStarted)
        {
            DisplayTitleWaitForInput(); // display title and keys and wait for input
        }
        // if the game is afoot
        else if (GameStarted)
        {
            MapPos = Vector2Scale(Knight.GetWorldPos(), -1.f);

            // Draw Map
            DrawTextureEx(Map, MapPos, 0, MapScale, WHITE);
            
            // Draw Props
            for (auto Prop : Props)
            {
                Prop.Render(Knight.GetWorldPos());
            }

            Knight.Tick(GetFrameTime());
            
            // check map bounds
            if ((Knight.GetWorldPos().x < 0.f) ||
                (Knight.GetWorldPos().y < 0.f) ||
                (Knight.GetWorldPos().x + WindowDimensions[0] > Map.width * MapScale) ||
                (Knight.GetWorldPos().y + WindowDimensions[1] > Map.height * MapScale))
            {
                Knight.UndoMovement();
            }

            // loop through props for Collisions
            for (auto Prop : Props)
            {
                if (CheckCollisionRecs(Prop.GetCollisionRec(Knight.GetWorldPos()), Knight.GetCollisionRec()))
                {
                    Knight.UndoMovement();
                }
            }

            Goblin.Tick(GetFrameTime());
            Goblin.SetTarget(&Knight);
        }
        // if my player has won
        else if (WinGame)
        {
            // CheckForCheatingDisplayVictory();
            // DelayPromptAndResetGame(dT);
            // Checkpoint = CheckpointDistance;
        }
        EndDrawing();
    }
    // UnloadTexture(Texture);
    // UnloadTexture(Idle);
    // UnloadTexture(Run);
    UnloadTexture(Map);
}
Prop.h
#include "raylib.h"


class Prop
{
public:
    Prop(Vector2 Pos, Texture2D Tex);
    void Render(Vector2 KnightPos);
    Rectangle GetCollisionRec(Vector2 KnightPos);

private:
    Vector2 WorldPos{};
    Texture2D Texture{};
    Vector2 ScreenPos{};
    float Scale{4.f};

};
Prop.cpp
#include "Prop.h"
#include "raymath.h"

Prop::Prop(Vector2 Pos, Texture2D Tex) : WorldPos(Pos),
                                         Texture(Tex)
{
    
}

void Prop::Render(Vector2 KnightPos)
{
    Vector2 ScreenPos{Vector2Subtract(WorldPos, KnightPos) };
    DrawTextureEx(Texture, ScreenPos, 0.f, Scale, WHITE);
}

Rectangle Prop::GetCollisionRec(Vector2 KnightPos)
{
    Vector2 ScreenPos{Vector2Subtract(WorldPos, KnightPos) };
    return Rectangle{
        ScreenPos.x,
        ScreenPos.y,
        Texture.width * Scale,
        Texture.height * Scale
    };    
}

The really unusual part is that the game actually runs. There are no problems listed. It’s not until you press space to leave my title screen then you get this.

After offering everything I had and stepping aside for a week and a half in frustration I came back and rewatched. I caught this discrepancy and repaired it.

While this changed where the Segmentation Fault occurs it still doesn’t get my code working.

Again, this builds fine and only crashes once I run it.
The google results of “access violation” don’t clear this up to me.

Can someone more familiar with this please offer a suggestion or insight?

You won’t want to put LoadTexture calls in your header, as I suspect they’re being called before InitWindow does.

(Access Violation means you’re trying to access data where there is none allocated for you or simply does not exist)

But it’s here! So please elaborate.


Yes, mine got jumbled a bit but that’s only a couple of lines of difference over in Stephen’s repo. So is he doing it wrong too?

That Exception I’m getting now is happening in the goblin’s enemy class tick which, after using the new screenPos function calls the BaseCharacter tick…

Wait, why does the character get his texture in such a different way from the props and enemies? Should we really have the knight’s texture in the parent class that propagates down to the enemies too? This better not be one of those things I get hung up on that that gets solved in the very next lecture…

You caught me there, I put my foot in my mouth by not checking the code before answering! In my defense I was trying to tackle this on my phone.

A quick check, are you calling InitWindow before creating any of the characters or props?

As for character setup, it really should be like the goblin, slime, and props instead of how it is but doesn’t truly harm anything by being there. This is not something that gets changed in a later lecture so you don’t need to worry there.

Dude, no worries, I’m only glad you were answering. There is no “perfect” way, right? If it works it’s a solution by definition. I’m just too happy to know that this is actually getting through my thick skull. I’m impatient to get it, but it seems like I’m getting there.
:mountain_biking_man:

Here’s the first 25 lines of

Main()
int main()
{
    // bool Collision{}; // initialize collision Game State as false
    InitWindow(WindowDimensions[0], WindowDimensions[1], "Top Down Game");

    // texture variables
    Texture2D Map = LoadTexture("nature_tileset/WorldMap.png");
    Vector2 MapPos = {0.0, 0.0};
    const float MapScale{4.0};
    //int NumberOfProps{2};

    Character Knight{WindowDimensions[0], WindowDimensions[1]};

    Enemy Goblin{
        Vector2{}, 
        LoadTexture("characters/goblin_idle_spritesheet.png"), 
        LoadTexture("characters/goblin_run_spritesheet.png")
    };

    Prop Props[2]{
        Prop{Vector2 {250.f, 250.f}, LoadTexture("nature_tileset/Rock.png")},
        Prop{Vector2 {400.f, 500.f}, LoadTexture("nature_tileset/Log.png") }       
    };

    SetTargetFPS(60);
    while (!WindowShouldClose())

Maybe my SetTargetFPS() has to be declared up there too? Nope, that doesn’t help.
Then later down Main()

We get to here and I hit my exception...
           // Draw Props
            for (auto Prop : Props)
            {
                Prop.Render(Knight.GetWorldPos());
            }

            Knight.Tick(GetFrameTime());
            
            // check map bounds
            if ((Knight.GetWorldPos().x < 0.f) ||
                (Knight.GetWorldPos().y < 0.f) ||
                (Knight.GetWorldPos().x + WindowDimensions[0] > Map.width * MapScale) ||
                (Knight.GetWorldPos().y + WindowDimensions[1] > Map.height * MapScale))
            {
                Knight.UndoMovement();
            }

            // loop through props for Collisions
            for (auto Prop : Props)
            {
                if (CheckCollisionRecs(Prop.GetCollisionRec(Knight.GetWorldPos()), Knight.GetCollisionRec()))
                {
                    Knight.UndoMovement();
                }
            }

            Goblin.Tick(GetFrameTime());

Alright, in this case I will probably need to dig deeper. Seg Faults are tricky to debug without seeing the whole codebase.

Can put your project into a zip file and upload it here? (your cpp and header (.h) files are good enough)

That’ll give me an opportunity to do some debugging in real-time.

Wow, thank you so much!

I stripped out the images that I downloaded from the project resources and only included my .tmx in the art folder before I zipped. If you can, log the steps you use to discover this so I might follow your method next time.

Hi @Maverick1868,

I’m not sure what is causing your error but at present @Tuomo_T is not able to reply to this question.
I wonder if you have joined our discord server to see if anyone else there has experienced this issue?
Community Discord
You may find others have had a similar issue that can help in the meantime until Tuomo is able to reply and check the project files itself.

Have you tried downloading the project from the lecture resources and see if that works for you?
If the course works it may help to do a side by side comparison of the code used to see if you can spot the difference.

Let us know how you get on

Oh No! I hope he’s okay. Send my regards, I’m totally patient.

I’ve been on the community discord before, it’s good for a faster answer. I might try that but I came to this course to get more comfortable with C++, am pleased with my progress, and have gone back to building in Unreal rather than frustrate myself. Many times when I return to a project I have newer insights or understanding I wouldn’t have had at the time. Maybe this is good.

1 Like

Hi Maverick,

I’m relatively alright, just dealing with a nasty viral infection I need to rest a good while for.

2 Likes

Heal up well, my friend.

Hi Maverick, thank you for your patience while I spent time to rest.

I found the problem! It’s a matter of order-of-operations. Let’s take a look at one of your example images. See what’s being called immediately after Goblin.Tick()?

But! Look at what information we’re trying to use inside of Enemy::Tick()

We’re trying to get information about our target before we know we have a target. So the system panics and gives as Seg Fault, which is really just an Access Violation.

1 Like

YES!

So I need to set the target before I tick because tick uses target. Of COURSE!! ugh.

So I reversed those two lines and now I have running code. Thank you, Tuomo. After scrutinizing the database it looks like his version of main() (that doesn’t even get edited in this video) calls the setTarget() way up before the while loop right after the goblin texture gets loaded. I don’t even know how I got myself this screwed up. Thank you again.

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.

Privacy & Terms