How does c++ keep things in scope? - c++

To be more specific, I have a class that looks like this:
class Ball {
public:
unsigned collider_size;
scionofbytes::MovementComponent movement;
scionofbytes::GraphicComponent graphic;
Ball(u_int init_collider_size, std::string texture_path) {
collider_size = init_collider_size;
movement = scionofbytes::MovementComponent();
graphic = scionofbytes::GraphicComponent(
(u_int) collider_size/2,
(u_int) collider_size/2,
texture_path
);
}
};
I'm accepting the texture_path and passing it on to the graphic component, which looks like this:
class GraphicComponent {
unsigned height;
unsigned width;
public:
sf::Texture texture;
sf::Sprite sprite;
GraphicComponent() {}
GraphicComponent(unsigned init_height, unsigned init_width, std::string texture_path) {
width = init_width;
height = init_height;
texture.loadFromFile(texture_path);
sprite.setTexture(texture);
}
};
When I instantiate a ball object by passing in the texture_path, I'm creating a texture as a member of the graphic component and then assigning that texture to the graphic component's sprite member.
When using this sprite member to draw to the screen, I'm facing SFML's known white box problem.
Now from my understanding, of the ball objects stays alive, the graphic component member also stays alive as does the texture member of the graphic component.
So my question is, why does this not work? When using the sprite to draw on screen, I still get a white box. Why is the texture getting destroyed?

In your Ball class constructor you are making a copy of your GraphicComponent. IIRC sf::Sprite only holds a reference to the sf::Texture so your copy may end up with the sf::Sptite pointing to the deleted sf::Texture from the object it got copied from.
Try constructing your Ball without making a copy of your GraphicComponent:
class Ball {
public:
unsigned collider_size;
scionofbytes::MovementComponent movement;
scionofbytes::GraphicComponent graphic;
// Use initializer-list
Ball(u_int init_collider_size, std::string texture_path)
: collider_size(init_collider_size)
, movement()
, graphic((u_int) collider_size/2, (u_int) collider_size/2, texture_path)
{
// don't assign stuff here if you can avoid it
}
};
In addition to that you may also want to create a copy constructor for your GraphicComponent class to prevent corruption elsewhere:
class GraphicComponent
{
unsigned height;
unsigned width;
public:
sf::Texture texture;
sf::Sprite sprite;
GraphicComponent()
{
}
GraphicComponent(unsigned init_height, unsigned init_width,
std::string texture_path)
{
width = init_width;
height = init_height;
texture.loadFromFile(texture_path);
sprite.setTexture(texture);
}
// Give it a copy constructor
GraphicComponent(GraphicComponent const& other)
: height(other.height)
, width(other.width)
, texture(other.texture)
, sprite(texture) // make it point to the new Texture not the other one
{
}
};

Related

(SFML) Issues with inheritance (C++)

So, I'm using SFML and I'm trying to setup an entity class and a player sub-class that inherits from it, but this is my first time working with inheritance and I'm having issues:
First, I have an AssetManager class that I cobbled together from different sources, since I don't quite understand how they work yet:
AssetManager.h:
class AssetManager {
public:
AssetManager();
static sf::Texture& LoadTexture(std::string const& path);
static sf::SoundBuffer& LoadSoundBuffer(std::string const& path);
static sf::Font& LoadFont(std::string const& path);
private:
std::map<std::string, sf::Texture> m_Textures;
std::map<std::string, sf::SoundBuffer> m_SoundBuffers;
std::map<std::string, sf::Font> m_Fonts;
static AssetManager* sInstance;
};
But you can only need to see the part relating to textures, here is that part from AssetManager.cpp:
AssetManager* AssetManager::sInstance = nullptr;
AssetManager::AssetManager() {
assert(sInstance == nullptr);
sInstance = this;
}
sf::Texture& AssetManager::LoadTexture(std::string const& path) {
auto& texMap = sInstance->m_Textures;
auto pairFound = texMap.find(path);
if (pairFound != texMap.end()) {
return pairFound->second;
}
else {
auto& texture = texMap[path];
texture.loadFromFile(path);
return texture;
}
}
Then an object of that class is included inside a Sprite class, that facilitates declaring sprites for me.
Sprite.h:
class Sprite {
public:
AssetManager manager;
sf::Texture m_Texture;
sf::Sprite m_Sprite;
sf::Vector2f sprite_scale;
sf::Vector2u original_size;
sf::Vector2f texture_size;
Sprite(std::string path,sf::IntRect rect,sf::Vector2f size);
};
Sprite.cpp:
Sprite::Sprite(std::string path, sf::IntRect rect, sf::Vector2f size) {
m_Texture = sf::Texture(AssetManager::LoadTexture(path));
m_Sprite.setTextureRect(rect);
m_Sprite.setTexture(m_Texture);
original_size = m_Texture.getSize();
texture_size.x = static_cast<float>(original_size.x);
texture_size.y = static_cast<float>(original_size.y);
sprite_scale.x = size.x / texture_size.x;
sprite_scale.y = size.y / texture_size.y;
m_Sprite.setScale(sf::Vector2f(sprite_scale.x, sprite_scale.y));
m_Sprite.setOrigin(sf::Vector2f(original_size.x / 2, original_size.y / 2));
}
Then, an object of the Sprite class is itself included within an Entity class.
Entity.h:
class Entity {
public:
Sprite entity_sprite;
int health;
float speed;
bool collision = false;
bool entity_collision(sf::Sprite entity2_sprite);// Entity.cpp only contains the declaration of this function so far so no need to post it.
};
Now, for a reason I don't understand, I'm not able to directly assign any arguments to the entity_sprite object when declaring it, and I'm only able to declare it with no arguments, despite the class having not a default constructor.
However I am able to get around it using assignment:
Entity entity_sprite = Entity("res/wildcard.png", { 0,0,36,63 }, { 36,63 });
But this isn't the main issue, and using the Entity class directly is not what I'm trying to do, I'm trying to write the Player sub-class and use that instead:
Player.h:
class Player:public Entity {
Player() {
entity_sprite = Sprite("res/wildcard.png", { 0,0,36,63 }, { 36,63 });
}
};
Now I'm once again not able to directly assign arguments to the object directly, because the call of an object of a class type without appropriate operator() or conversion function to pointer-to-function type (Interestingly enough if I go back to the Entity object and assign the arguments there and pretend the errors don't exist, the error produced by the Player class changes to Too many arguments' and 'Too many initializers
This is getting too confusing.
Nonetheless, I am once again able to get around it using assignment, exactly the same as before, except this time I get an error saying the default constructor "Entity" cannot be referenced -- its a deleted function., so I go back to the Entity class and add an empty constructor like this: Entity() { } but then this constructor gives me another error saying no default constructor exists for class "Sprite", even though the Entity class doesn't exactly inherit from the Sprite class, so I go back even further to the Sprite class and give that an empty constructor: Sprite(){}, and the errors seemingly disappear, that is until I declare a Player object in the main.cpp file and try to compile and get a debug error pointing to the following line in AssetManager.cpp: assert(sInstance == nullptr);
So many problems for such a seemingly simple task, how do I pull myself out of this?
Ok, after consulting the SFML Forums, I have refactored the code to the following:
Sprite.h:
#include "AssetManager.h"
class Sprite{
public:
sf::Sprite m_sprite;
sf::Vector2f sprite_scale;
sf::Vector2u original_size;
sf::Vector2f texture_size;
Sprite(){}
sf::Sprite set_sprite(sf::Texture& tx, sf::IntRect rect, sf::Vector2f size);
};
Sprite.cpp:
#include "Sprite.h"
sf::Sprite Sprite::set_sprite(sf::Texture& tx, sf::IntRect rect, sf::Vector2f size) {
sf::Sprite spr(tx);
spr.setTextureRect(rect);
original_size =tx.getSize();
texture_size.x = static_cast<float>(original_size.x);
texture_size.y = static_cast<float>(original_size.y);
sprite_scale.x = size.x / texture_size.x;
sprite_scale.y = size.y / texture_size.y;
spr.setScale(sf::Vector2f(sprite_scale.x, sprite_scale.y));
spr.setOrigin(sf::Vector2f(original_size.x / 2, original_size.y / 2));
return spr;
}
Entity.h:
#pragma once
#include "Sprite.h"
#include "collision.h"
#include "Timer.h"
class Entity {
public:
Sprite spr;
sf::Sprite entity_sprite;
int health;
float max_speed;
sf::Vector2f speed;
sf::Vector2f direction;
float acceleration;
bool collision = false;
timer t;
float acc_time;
};
Player.h:
#pragma once
#include "Entity.h"
class Player:public Entity {
public:
Player();
float acc_time = t.accumulate_time();
void keyboard_controls();
void mouse_controls(sf::Vector2f cursor);
};
Player.cpp:
#include "Player.h"
#include <math.h>
Player::Player() {
speed = { 0,0 };
acceleration = 2;
max_speed = 500 + acceleration;
entity_sprite = spr.set_sprite(AssetManager::LoadTexture("res/wildcard.png"), { 0,0,60,63 }, { 60,63 });
}
In short, the Sprite class' constructor is replaced with a method that has the same exact role, that way I can simply declare a Sprite object with no parameters inside the Entity class, and I won't have any issues with the derived Player class since I won't be asked to create default constructors for both the Sprite and Entity classes.

SFML drawing elements of vector of pointers

here is the structure of my program:
class Game
{
public:
unsigned int progressFlags;
sf::RenderWindow appWindow;
Screen* currentScreen;
Game(const unsigned int& width, const unsigned int& height,
const unsigned int& bitsPerPixel, const std::string& windowName);
~Game();
void drawScreen();
};
Game contains a Screen which is defined as:
class Screen
{
public:
std::vector<sf::Drawable*> sceneElements;
sf::Sprite backgroundSprite;
Screen();
virtual ~Screen();
protected:
sf::Texture backgroundTexture;
};
Elements of std::vector sceneElements are collected from screens like this:
sceneElements.push_back(&backgroundSprite);
At last, I am trying to draw all my graphic objects using a simple method:
void Game::drawScreen()
{
for (unsigned int i = 0; i < currentScreen->sceneElements.size(); i++)
appWindow.draw(*currentScreen->sceneElements(i));
}
But appWindow.draw() fails. I think it is something about dereferencing pointers (some basic c++ knowledge I cant just remember), but I don't know how to fix it. I would appreciate any help.
I'd just derive your custom classes from sf::Drawable (and potentially sf::Transformable). This way drawing hierarchically is very easy and basically done by SFML. The following snippets are written from memory; there might be typos. :)
You'll just have to subclass your Screen class:
class Screen : public sf::Drawable
{
public:
std::vector<sf::Drawable*> sceneElements;
sf::Sprite backgroundSprite;
Screen();
virtual ~Screen();
virtual void draw(sf::RenderTarget &rt, sf::RenderStates states) const;
protected:
sf::Texture backgroundTexture;
};
Inside draw() you'd just iterate over all your elements (similar to the way you do already):
void draw(sf::RenderTarget &rt, sf::RenderStates states) const
{
for (const auto &e : sceneElements)
rt.draw(*e, states);
}
Here we're dereferencing once to get from a pointer back to the object, which is then passed by reference (where inheritance does the rest).
Game::drawScreen() becomes more simple as well:
void Game::drawScreen()
{
appWindow.draw(*currentScreen);
}
Once again, derefrencing once to go from the pointer to the actual object (passed by reference).
Also note that your original design violates encapuslation, by Game having to know how to work with stuff that's inside your Scene. So if you change things inside Scene, you'll have to adjust Game accordingly. Using inheritance, you're avoiding this issue.

How to create Resource Manager for Game

I am trying to make an "resource manager" for my 2D game with c++.
The initial idea is anything like this:
class resource_manager
{
private:
static std::unordered_map<std::string, std::shared_ptr<texture> > all_textures;
public:
static std::shared_ptr<texture> texture_load(std::string path)
{
// if path no exist in map all_textures:
// load texture, store in map, return the pointer.
// else: only return the pointer.
}
protected
resource_manager() {}
~resource_manager() {}
};
class texture
{
private:
unsigned id; // opengl texture id
unsigned width;
unsigned height;
public:
texture(unsigned _id, unsigned _width, unsigned _height)
: id(_id), width(_width), height(_height) {}
~texture() {}
// getters and setters
};
But, i have a problem. When the shared_ptr counter come to < 0, the pointer of texture will be destroyed, ok, but my texture still continues in VGA memory. So, when the pointer destruct herself, i need call glDeleteTextures() to unload the texture in memory.
C++ is not my speciality, for that, is hard to me do it.
Sorry for my poor english. Any help is welcome.

Embedded C++ Class interaction

I'm continuing with a game for an embedded microcontroller (Arduino), and I have a question on class interaction -- this question continues from my previous question here and I have based my code on the suggestion of sheddenizen (see response to the given link in 'here'):
I have three classes that inherit from a base class-
(i) class Sprite - (bass class) has a bitmap shape and (x,y) position on an LCD
(ii) class Missile : public Sprite - has a specific shape, (x,y) and also takes a obj
(iii) class Alien : public Sprite - has specific shape and (x,y)
(iv) class Player : public Sprite - ""
They all have different (virtual) method of moving and are shown on the LCD:
My streamlined code is below - specifically, I only want the missile to fire under certain conditions: when missile is created it takes an objects (x,y) value, how can I access a passed objects value within an inherited class?
// Bass class - has a form/shape, x and y position
// also has a method of moving, though its not defined what this is
class Sprite
{
public:
Sprite(unsigned char * const spacePtrIn, unsigned int xInit, unsigned int yInit);
virtual void Move() = 0;
void Render() { display.drawBitmap(x,y, spacePtr, 5, 6, BLACK); }
unsigned int X() const { return x; }
unsigned int Y() const { return y; }
protected:
unsigned char *spacePtr;
unsigned int x, y;
};
// Sprite constructor
Sprite::Sprite(unsigned char * const spacePtrIn, unsigned int xInit, unsigned int yInit)
{
x = xInit;
y = yInit;
spacePtr = spacePtrIn;
}
/*****************************************************************************************/
// Derived class "Missile", also a sprite and has a specific form/shape, and specific (x,y) derived from input sprite
// also has a simple way of moving
class Missile : public Sprite
{
public:
Missile(Sprite const &launchPoint): Sprite(&spaceMissile[0], launchPoint.X(), launchPoint.Y()) {}
virtual void Move();
};
void Missile::Move()
{
// Here - how to access launchPoint.X() and launchPoint.Y() to check for
// "fire conditions"
y++;
Render();
}
// create objects
Player HERO;
Alien MONSTER;
Missile FIRE(MONSTER);
// moving objects
HERO.Move();
MONSTER.Move();
FIRE.Move();
Since Missile is a subclass of Sprite you can access Sprite::x and Sprite::y as if they were members of Missile. That is by simply writing x (or this->x if you insist).
The launchpoint reference that you got in the constructor is gone by now, so your Missile::Move memfunction cannot access it any more.
If in the meantime the members x and y changed, but you want the original value, you can either save a reference to launchpoint (which might be dangerous, it is destroyed) or you have to keep a copy of the original coordinates.

Refactoring code for drawing game components

How can I refractor the following, to move my drawing functions from the h-file into a GraphicsManager class?
//drawingFunctions.h
void drawTexturedQuad( Texture texture, Vector2 pos, Vector2 dim) {
// bind texture...
glBegin(...); // draw
//...
glEnd(...);
}
//class file
#include "drawingFunctions.h"
class Player {
void drawPlayer(){ drawTexturedQuad( texture, pos, dim) }
};
class Enemy {
void drawEnemy(){ drawTexturedQuad( texture, pos, dim) }
};
class Item {
void drawItem(){ drawTexturedQuad( texture, pos, dim) }
};
// and so on for the other components
//gameloop file
// instantiate components objects
while (true) {
// input, logic
Player.drawPlayer();
Enemy.drawEnemy();
Item.drawItem();
// and so on
}
(The code is obviously simplified, I am just asking about the drawing here)
Should I...
pass a pointer to the GraphicsManager to every call of drawPlayer, drawEnemy etc from within the gameloop
have Player, Enemy etc have a pointer to GraphicsManger as a data member
have Player, Enemy etc extend a drawableGameComponent class that has a pointer to GraphicsManager as a data member
something else?
That sounds like a perfect use case for inheritance:
class Drawable
{
public:
void draw()
{
// gl stuff
}
protected:
Texture _texture;
Vector2 _pos;
Vector2 _dim;
};
class Player : Drawable
{
public:
// should modify _texture _pos and _dim somewhere.
};
// same thing for the other objects.
I would pass a renderer to the model, and ask it to draw itself.
class Player
{
public:
void draw(Renderer& renderer);
};
class Enemy
{
public:
void draw(Renderer& renderer);
};
Note you don't have to name the function drawPlayer or drawEnemy, because you already know that it's a Player or an Enemy by the class type. This uniform calling convention is perfect for extracting into a common interface:
class Model
{
public:
virtual void draw(Renderer& renderer) = 0;
virtual ~Model() {}
};
Then you can have each of your models inherit from Model, and each implement draw.
As I mentioned in a comment on #J.N.'s answer you can also have Renderer be an abstract class. For example I worked on a project which used OpenGL, GDI+, and also needed to create printouts of schematics.
class Renderer
{
public:
virtual render(const Triangle& triangle, const Texture& texture) = 0;
virtual ~Renderer() {}
};
I would go for the first possibility: passing the pointer to the GraphicsManager in the call. Eventhough it seems a bit overkill, the knowledge of which GraphicsManager is used is maintained on higher level and can be modified easier later on.
Having said this, I would still inherit from a Drawable interface and put the items that need to be drawn in a container, so you can just iterate through it to display the items via a virtual drawItem() function.
Like so (C++03, not tested):
std::vector<Drawable*> Items;
Items.push_back(&player);
Items.push_back(&enemy);
...
for (std::vector<Drawable*>::iterator it = Items.begin(); it != Items.end(): ++it)
{
(*it)->drawItem(&graphMgr);
}