0

I am making a small game using SFML. I want to load all my resources in one go when the game launches, so every time a new entity is created new resources don't need to be loaded to memory slowing down the game.

I have made a header file with a namespace for each kind of resource I need:

#pragma once

#include <SFML/Graphics.hpp>

#include <iostream>

#include "spritesheet.h"

namespace PlayerSprite {
    extern Spritesheet playerSpritesheet;
    extern sf::Sprite sp1, sp2, sp3, sp4, sp5, sp6;
    extern int width = 16;
    extern int height = 16;
}

namespace ButtonSprite {
    extern Spritesheet buttonSpritesheet;
    extern sf::Sprite button;
    extern int width = 32;
    extern int height = 16;
}

class Resources {
    public:
        Resources() = default;
        void loadResources();
};

Now I don't know much about namespaces only very basic stuff, this is the first reason to use one.

Now in the cpp file:

#include <iostream>

#include "../headers/resources.h"

void Resources::loadResources() {
    // PLAYER
    PlayerSprite::playerSpritesheet.setSprite("./res/img/tiles.png");
    PlayerSprite::sp1 = PlayerSprite::playerSpritesheet.getSprite(0, 0, PlayerSprite::width, 
    PlayerSprite::height);
    PlayerSprite::sp2 = PlayerSprite::playerSpritesheet.getSprite(32, 0, PlayerSprite::width, 
    PlayerSprite::height);
    PlayerSprite::sp3 = PlayerSprite::playerSpritesheet.getSprite(48, 0, PlayerSprite::width, 
    PlayerSprite::height);
    PlayerSprite::sp4 = PlayerSprite::playerSpritesheet.getSprite(64, 0, PlayerSprite::width, 
    PlayerSprite::height);
    PlayerSprite::sp5 = PlayerSprite::playerSpritesheet.getSprite(80, 0, PlayerSprite::width, 
    PlayerSprite::height);
    PlayerSprite::sp6 = PlayerSprite::playerSpritesheet.getSprite(0, 16, PlayerSprite::width, 
    PlayerSprite::height);
    // PLAYER

    // BUTTONS
    ButtonSprite::buttonSpritesheet.setSprite("./res/img/tiles.png");
    ButtonSprite::button = ButtonSprite::buttonSpritesheet.getSprite(48, 16, 32, 16);
    // BUTTONS
}

I then call this function in the main game file, but when I run I get this error in the player class:

undefined reference to 'PlayerSprite:sp1'

I don't know if this is because of the namespace declaration, or me coding the system wrong.


After looking at some comments on this question I have added this:

void Resources::allocateStorage() {
    sf::Sprite PlayerSprite::spritesheet;
    sf::Sprite PlayerSprite::sp1;
}

In the cpp file, but I am now getting this error:

unqualified-id in declaration before ';' token on the 1st line after the implementation of the function.

tygzy
  • 698
  • 1
  • 6
  • 23
  • 1
    I think `PlayerSprite` and `ButtonSprite` really want to become classes. Maybe with common base. – Lukas-T Apr 08 '20 at 15:46
  • You still need to tell the compiler to allocate space for them somewhere. Before your `loadResources()` function, you would need to do: `sf::Sprite PlayerSpriter::sp1;` (for each variable) – ChrisMM Apr 08 '20 at 15:46
  • @Brian, yes, but judging by the error, and the fact they're all marked `extern`, it seems like they aren't ever allocated any space. So when trying to initialize, they don't actually exist in memory. – ChrisMM Apr 08 '20 at 15:51
  • @ChrisMM I see what you meant now. I'll delete my previous comment. – Brian61354270 Apr 08 '20 at 15:52
  • @ChrisMM The reason i used `extern` is because when I was looking into namespaces I saw about using `extern` when declaring a variable in a namespace. – tygzy Apr 08 '20 at 15:52
  • @TylerHarrison, there's no program with using `extern`, but they still need to allocate space. – ChrisMM Apr 08 '20 at 15:54
  • @ChrisMM I have tried your comment, and have updated the question ^ – tygzy Apr 08 '20 at 15:57
  • 1
    You may find [this related question](https://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files) helpful. `extern` essentially tells the compiler that the symbol you're declaring is going to be _defined somewhere else_, which will need to be located at link time. Since you never define the symbols you declared as `extern`, the linker is complaining that it cannot find suitable definitions. – Brian61354270 Apr 08 '20 at 15:58
  • @ChrisMM Arrgh! Yes, my bad – Brian61354270 Apr 08 '20 at 15:59
  • @TylerHarrison, not inside a function ;) – ChrisMM Apr 08 '20 at 15:59
  • @ChrisMM I tried putting it in a constructor and got the same error – tygzy Apr 08 '20 at 16:01
  • @TylerHarrison **outside** of any function/constructor/destructor/etc. – ChrisMM Apr 08 '20 at 16:02

1 Answers1

4

The problem seems to be that the variables are not actually defined anywhere, just declared. When using extern, the compiler will assume that this variable exists, so the compiler can continue on assuming that the variable exists. The linker will then come in, and see where that variable exists. If it does not, you get an undefined reference error. To fix this, you need to define the variables somewhere.

For example, in say resources.cpp, you would have:

#include "../headers/resources.h"

sf::Sprite PlayerSpriter::sp1;
sf::Sprite PlayerSpriter::sp2;
sf::Sprite PlayerSpriter::sp3;
// etc...


void Resources::loadResources() { 
    // …
}

This is in addition to what you already have in your header.

NOTE: From your edit, this would occur outside any function.

ChrisMM
  • 8,448
  • 13
  • 29
  • 48