So I have this scene graph for a visual studio project where me and a group of people are working on a game concept. I'm fairly new to this so any suggestions is greatly appreciated.
here is the header file for the scene graph:
#include "Category.hpp" //4
#include <SFML/System/NonCopyable.hpp> //5
#include <SFML/Graphics/Transformable.hpp> //6
#include <SFML/Graphics/Drawable.hpp> //7
#include <vector> //8
#include <set> //9
#include <memory> //10
#include <utility> //11
struct Command; //17
class CommandQueue; /18
class SceneNode : public sf::Transformable, public sf::Drawable, private sf::NonCopyable //20
{
public: //22
typedef std::unique_ptr<SceneNode> Ptr; //23
typedef std::pair<SceneNode*, SceneNode*> Pair; //24
public: //27
explicit SceneNode(Category::Type category = Category::None); //28
void attachChild(Ptr child); //30
Ptr detachChild(const SceneNode& node); //31
void update(sf::Time dt, CommandQueue& commands); //33
sf::Vector2f getWorldPosition() const; //35
sf::Transform getWorldTransform() const; //36
void onCommand(const Command& command, sf::Time dt); //38
virtual unsigned int getCategory() const; //39
void checkSceneCollision(SceneNode& sceneGraph, std::set<Pair>& collisionPairs); //41
void checkNodeCollision(SceneNode& node, std::set<Pair>& collisionPairs); //42
void removeWrecks(); //43
virtual sf::FloatRect getBoundingRect() const; //44
virtual bool isMarkedForRemoval() const; //45
virtual bool isDestroyed() const; //46
private: //49
virtual void updateCurrent(sf::Time dt, CommandQueue& commands); //50
void updateChildren(sf::Time dt, CommandQueue& commands); //51
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; //53
virtual void drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const; //54
void drawChildren(sf::RenderTarget& target, sf::RenderStates states) const; //55
void drawBoundingRect(sf::RenderTarget& target, sf::RenderStates states) const; //56
private: //59
std::vector<Ptr> mChildren; //60
SceneNode* mParent; //61
Category::Type mDefaultCategory; //62
};
bool collision(const SceneNode& lhs, const SceneNode& rhs); //65
float distance(const SceneNode& lhs, const SceneNode& rhs); //66
////.cpp file
#include "Scene Graph.h" //1
#include <SFML/Graphics/RectangleShape.hpp> //2
#include <SFML/Graphics/RenderTarget.hpp> //3
#include <algorithm> //6
#include <cassert> //7
#include <cmath> //8
SceneNode::SceneNode(Category::Type category) //11
: mChildren() //12
, mParent(nullptr) //13
, mDefaultCategory(category) //14
{ //15
} //17
void SceneNode::attachChild(Ptr child) //19
{
child->mParent = this; //21
mChildren.push_back(std::move(child)); //22
}
SceneNode::Ptr SceneNode::detachChild(const SceneNode& node) //25
{
auto found = std::find_if(mChildren.begin(), mChildren.end(), [&](Ptr& p) { return p.get() == &node; }); //27
assert(found != mChildren.end()); //28
Ptr result = std::move(*found); //30
result->mParent = nullptr; //31
mChildren.erase(found); //32
return result; //33
}
void SceneNode::updateCurrent(sf::Time dt, CommandQueue& commands) //36
{
updateCurrent(dt, commands); //38
updateChildren(dt, commands); //39
}
void SceneNode::updateCurrent(sf::Time, CommandQueue&) //42
{
//do nothing by default //44
}
void SceneNode::updateChildren(sf::Time dt, CommandQueue& commands) //47
{
for(Ptr& child : mChildren) //50
child->update(dt, commands); //51
}
void SceneNode::draw(sf::RenderTarget& target, sf::RenderStates states) const //54
{
//apply transform of current node //56
states.transform *= getTransform(); /57
//Draw node and children with changed transform //59
drawCurrent(target, states); //60
drawChildren(target, states); //61
}
void SceneNode::drawCurrent(sf::RenderTarget&, sf::RenderStates) const //66
{
//do nothing by default //68
}
void SceneNode::drawChildren(sf::RenderTarget& target, sf::RenderStates states) const //71
{
for(const Ptr& child : mChildren) //73
child->draw(target, states); //74
}
void SceneNode::drawBoundingRect(sf::RenderTarget& target, sf::RenderStates) const //77
{
sf::FloatRect rect = getBoundingRect(); //79
sf::RectangleShape shape; //80
shape.setPosition(sf::Vector2f(rect.left, rect.top)); //81
shape.setSize(sf::Vector2f(rect.width, rect.height)); //82
shape.setFillColor(sf::Color::Transparent); //83
shape.setOutlineColor(sf::Color::Green); //84
shape.setOutlineThickness(1.f); //85
target.draw(shape); //86
}
sf::Vector2f SceneNode::getWorldPosition() const //89
{
return getWorldTransform() * sf::Vector2f(); //91
}
sf::Transform SceneNode::getWorldTransform() const //94
{
sf::Transform transform = sf::Transform::Identity; //96
for (const SceneNode* node = this; node != nullptr; node = node->mParent) //98
transform = node->getTransform() * transform; //99
return transform; //101
}
void SceneNode::onCommand(const Command& command, sf::Time dt) //104
{
//command current node, if category matches //106
if (command.category & getCategory()) //107
command.action(*this, dt); //108
//command children //110
for(Ptr& child : mChildren) //111
child->onCommand(command, dt); //112
}
unsigned int SceneNode::getCategory() const //115
{
return mDefaultCategory; //117
}
void SceneNode::checkSceneCollision(SceneNode& sceneGraph, std::set<Pair>& collisionPairs) //120
{
checkNodeCollision(sceneGraph, collisionPairs); //122
for(Ptr& child : sceneGraph.mChildren) //124
checkSceneCollision(*child, collisionPairs); //125
}
void SceneNode::checkNodeCollision(SceneNode& node, std::set<Pair>& collisionPairs) //128
{
if (this != &node && collision(*this, node) && !isDestroyed() && !node.isDestroyed()) //130
collisionPairs.insert(std::minmax(this, &node)); //131
for(Ptr& child : mChildren) //133
child->checkNodeCollision(node, collisionPairs); //134
}
void SceneNode::removeWrecks() //137
{
// Remove all children which request so //139
auto wreckfieldBegin = std::remove_if(mChildren.begin(), mChildren.end(), std::mem_fn(&SceneNode::isMarkedForRemoval)); //140
mChildren.erase(wreckfieldBegin, mChildren.end()); //141
// Call function recursively for all remaining children //143
std::for_each(mChildren.begin(), mChildren.end(), std::mem_fn(&SceneNode::removeWrecks)); //144
}
sf::FloatRect SceneNode::getBoundingRect() const //147
{
return sf::FloatRect(); //149
}
bool SceneNode::isMarkedForRemoval() const //152
{
// By default, remove node if entity is destroyed //154
return isDestroyed(); //155
}
bool SceneNode::isDestroyed() const //158
{
// By default, scene node needn't be removed //160
return false; //161
}
bool collision(const SceneNode& lhs, const SceneNode& rhs) //164
{
return lhs.getBoundingRect().intersects(rhs.getBoundingRect()); //166
}
float distance(const SceneNode& lhs, const SceneNode& rhs) //169
{
return length(lhs.getWorldPosition() - rhs.getWorldPosition()); //171
}
The errors I'm getting are listed as the following:
1)Incomplete type is not allowed .cpp line 107, 108
2) namespace std has no member "mem_fn" .cpp line 140, 144
3)Identifier "length" not found .cpp line 171
4) use of undefined type "Command" .cpp line 108, 109
It looks like you don't have the <functional> header included for definition of std::mem_fn and although I see a forward declaration of Command in your scene graph header file there does not seem to be an include directive for the header file that defines Command.
Related
I am having 12 errors looping from:
Unexpected token(s) preceding ';'
missing type specifier - int assumed, Note: C++ does not support default - int
syntax error: missing ';' before '*
at Line 11 of Player.h
Here is the player.h code:
#pragma once
#include "GameObjects.h"
using namespace sf;
class Player : GameObject2D
{
public:
// Classes
GameSprite* playerSprite = new GameSprite("Textures/player.png", Vector2f(32.f, 32.f), IntRect(0, 0, 64, 64));
PlayerAnimationPlayer* anim = new PlayerAnimationPlayer(this, "idle", 0.5f, 0, 2, "", true);
// Sprite and animation variables
IntRect spriteFrames[3] = {
IntRect(0, 0, 64, 64),
IntRect(64, 0, 64, 64),
IntRect(128, 0, 64, 64),
};
// Movement variables
sf::Vector2f direction;
sf::Vector2f velocity;
const float speed = 300.f;
// Player functions
void inputDirection();
// Game Object functions
void update(float deltaTime) override;
void inputEvent(Event ev) override;
void draw(RenderWindow& target) override;
void free() override;
// 2D Functions
void setPos(float x, float y) override;
Vector2f moveObj(Vector2f direction, float speed, float deltaTime);
};
class PlayerAnimationPlayer : AnimationPlayer
{
public:
Player* parent;
PlayerAnimationPlayer(Player* newParent, std::string startAnimation,
float newSpeed, int startIndex, int newMaxIndex, bool isOneShot, bool autoStart);
void animation(int index) override;
};
Here is the game object code (INCLUDING THE ANIMATION PLAYER):
#pragma once
#include <SFML\Graphics.hpp>
#include <map>
#include <iostream>
// BASE OBJECT OF ALL GAME OBJECTS
class GameObject
{
public:
virtual void update(float deltaTime) {}
virtual void inputEvent(sf::Event ev) {}
virtual void draw(sf::RenderWindow& target) {} // This draws all drawable objects
virtual void free() {} // This frees all pointer variables including the class itself
};
// GAMEOBJECT USED FOR 2D AND MOVEMENT
class GameObject2D : GameObject
{
public:
sf::Vector2f position;
sf::Vector2f getPos(); // Returns the position
virtual void setPos(float x, float y); // This moves all child classes including the class itself
virtual sf::Vector2f moveObj(sf::Vector2f direction, float speed, float deltaTime); // Moves all child classes by direction
};
// Class for sprites
class GameSprite
{
public:
sf::Sprite sprite;
sf::Texture texture;
GameSprite(std::string texturePath, sf::Vector2f offset, sf::IntRect visibleFrame);
void setSprite(std::string newTexturePath, sf::Vector2f offset = sf::Vector2f(0.f, 0.f), sf::IntRect visibleFrame = sf::IntRect(0, 0, -1, -1));
};
// THIS ANIMATES THE OBJECTS
class AnimationPlayer
{
public:
int maxIndex = 10;
sf::Clock clock;
std::string activeAnimation;
void updateTime(); // Updates the time
public:
bool isActive;
bool oneShot;
float speed = 1.f;
int index = 0;
AnimationPlayer(std::string startAnimation, float newSpeed, int startIndex, int newMaxIndex, bool isOneShot = false, bool autoStart = false);
void start(std::string animation, int startIndex = 0); // Starts the animation player
void stop(); // Stops the animation player
virtual void animation(int index) {}
};
Here is the cpp file for animation player
#include "GameObjects.h"
// CONSTRUCTOR AND MAIN LOGIC
AnimationPlayer::AnimationPlayer(std::string startAnimation, float newSpeed, int startIndex, int newMaxIndex, bool isOneShot, bool autoStart)
{
activeAnimation = startAnimation;
speed = newSpeed;
index = startIndex;
maxIndex = newMaxIndex;
oneShot = isOneShot;
isActive = autoStart;
std::cout << "Constructor called" << std::endl;
if (oneShot)
start(startAnimation, startIndex);
}
// Updates the time
void AnimationPlayer::updateTime()
{
if (clock.getElapsedTime().asSeconds() > speed)
{
if (!isActive)
return;
if (index > maxIndex)
{
if (oneShot)
isActive = false;
else
index = 0;
}
else
{
index += 1;
}
animation(index);
}
}
/// STARTS AND STOP THE ANIMATION PLAYER
// Starts the animation player
void AnimationPlayer::start(std::string animation, int startIndex)
{
isActive = true;
index = startIndex;
}
// Stops the animation player
void AnimationPlayer::stop()
{
isActive = false;
}
Here is the code for the player animation player cpp
#include "Player.h"
PlayerAnimationPlayer::PlayerAnimationPlayer(Player* newParent, std::string startAnimation, float newSpeed, int startIndex, int newMaxIndex, bool isOneShot, bool autoStart) :
AnimationPlayer(startAnimation, newSpeed, startIndex, newMaxIndex, isOneShot, autoStart)
{
parent = newParent;
}
void PlayerAnimationPlayer::animation(int index)
{
parent->playerSprite->sprite.setTextureRect(parent->spriteFrames[index]);
}
Ty!
I'm trying to implement a graph using adjacency list, but in the A_List class function called ,,AddGraphEdge" , there's a problem ,,Exception thrown: read access violation.this was 0x20." It occurs in the list.cpp function ,,AddEdge" when I do if(head==nullptr). I just simply check if head is null. When i delete this statement in place when I assign head=new_edge it tells me the same problem. It works fine if I'm using only normal list, and i create an list object in main and call AddEdge function. I don't know why calling this function in another causes problems.
Graph.h
class Graph
{
protected:
int _Vertices;
int _Edges;
int _Density;
public:
Graph() : _Vertices(0), _Edges(0), _Density(0) {};
Graph(const int& Vertices,const int& Edges, const int& Density) : _Vertices(Vertices), _Density(Density), _Edges(Edges) {};
void set_Vertices(const int& Vertices) { _Vertices=Vertices; };
int get_Vertices() { return _Vertices; };
void set_Edges(const int& Edges) { _Edges=Edges; };
int get_Edges() { return _Edges; };
virtual void DisplayGraph() = 0;
virtual void Get_Random_Graph() = 0;
};
Edge.h
class Edge
{
private:
int _StartVertice;
int _EndVertice;
int _weight;
Edge* _NextEdge;
public:
Edge():_StartVertice(0), _EndVertice(0), _weight(0), _NextEdge(nullptr) {};
Edge(const int& StartVertice, const int& EndVertice, const int& weight) : _StartVertice(StartVertice), _EndVertice(EndVertice), _weight(weight), _NextEdge(nullptr) {};
const int& get_StartVertice() const { return _StartVertice; };
const int& get_EndVertice() const { return _EndVertice; };
const int& get_Weight() const { return _weight; };
Edge* get_NextEdge() { return _NextEdge; };
void set_NextEdge(Edge* NextEdge) { _NextEdge = new Edge; _NextEdge = NextEdge; };
void set_EdgeValues(const int& StartVertice, const int& EndVertice, const int& weight)
{
_StartVertice = StartVertice;
_EndVertice = EndVertice;
_weight = weight;
};
};
List.h
#include "Edge.h"
class List
{
private:
int ListSize;
Edge* head;
public:
~List() {};
List() : ListSize(0), head(nullptr) {};
const Edge* get_head() { return head; };
const int get_ListSize() { return ListSize; };
void AddEdge(const int& StartVertice, const int& EndVertice, const int& weigth);
void DisplayList();
};
Adjacency_List.h
#include "List.h"
#include "Graph.h"
class A_List: public Graph
{
private:
List* _Adj_List;
public:
A_List() : Graph() { _Adj_List = nullptr; };
A_List(const int& Vertices, const int& Edges, const int& Density) : Graph(Vertices, Edges, Density) { _Adj_List = new List[Vertices]; };
virtual void DisplayGraph() override;
virtual void Get_Random_Graph() override;
void AddGraphEdge(const int& StartVertice, const int& EndVertice, const int& weigth);
};
List.cpp
#include "List.h"
#include <iostream>
void List::AddEdge(const int& StartVertice, const int& EndVertice, const int& weigth)
{
Edge* new_edge = new Edge;
new_edge->set_EdgeValues(StartVertice, EndVertice, weigth);
if (head == nullptr)
{
head = new_edge;
}
else
{
Edge* tmp = head;
head = new_edge;
new_edge->set_NextEdge(tmp);
}
ListSize++;
}
void List::DisplayList()
{
Edge* tmp = head;
while (head->get_NextEdge() != nullptr)
{
std::cout << tmp->get_StartVertice() << tmp->get_Weight() << tmp->get_EndVertice() << std::endl;
tmp = tmp->get_NextEdge();
}
std::cout << tmp->get_StartVertice() << tmp->get_Weight() << tmp->get_EndVertice() << std::endl;
}
Adjacency_List.cpp
#include "Adjacency_List.h"
void A_List::AddGraphEdge(const int& StartVertice, const int& EndVertice, const int& weigth)
{
_Adj_List[StartVertice].AddEdge(StartVertice, EndVertice, weigth);
}
void A_List::DisplayGraph()
{int Vertices = A_List::get_Edges();
for (int i = 0; i < Vertices; i++)
{
_Adj_List[i].DisplayList();
}
}
void A_List::Get_Random_Graph()
{
}
main.cpp
#include <iostream>
#include "Adjacency_List"
int main()
{
A_List Graph_list;
Graph_list.AddGraphEdge(4,3,2);
Graph_list.DisplayGraph();
return 0;
}
The constructor sets _Adj_List to nullptr:
A_List() : Graph() { _Adj_List = nullptr; };
And now it gets dereferenced and used (it's still nullptr):
void A_List::AddGraphEdge(const int& StartVertice, const int& EndVertice, const int& weigth)
{
_Adj_List[StartVertice].AddEdge(StartVertice, EndVertice, weigth);
}
But it might not be the only bug, as it's quite messy code
In a pawn class that inherits from the cocos2d Sprite class, I used this->getBoundingBox() in it's update function. This caused an "Access violation at reading location" error. Then, I swapped "this" with "GAME::PLAYER", a variable in a namespace that references the player and it worked. Why does this->getBoundingBox() cause an error when GAME::PLAYER->getBoundingBox() works perfectly fine? Aren't they supposed to be the same thing? Just to note, "this->" works with any other function but getBoundingBox. Is it something I'm doing wrong? I'm not THAT good with C++
Here's pawn.h
#include <cocos2d.h>
#ifndef PLAYER_CONTROLLER
#define PLAYER_CONTROLLER GAME::PLAYER
class pawn : public cocos2d::Sprite {
public:
pawn();
~pawn();
static pawn* create();
static pawn* create(bool default_moving);
bool moving;
bool right;
int speed;
cocos2d::Rect getBounds();
void step();
void initOptions();
void update(float dt) override;
void move(cocos2d::Vec2 vec);
void moveX(int x);
void moveY(int y);
virtual bool touchBegan(cocos2d::Touch*, cocos2d::Event*);
virtual void touchEnded(cocos2d::Touch*, cocos2d::Event*);
};
namespace GAME {
static pawn* PLAYER;
};
#endif
Here's pawn.cpp
#include "player.h"
#include <cocos2d.h>
pawn::pawn() {
}
pawn::~pawn() {
}
bool pawn::touchBegan(cocos2d::Touch* touch, cocos2d::Event* event) {
this->move(cocos2d::Vec2(5, 0));
this->moving = false;
return true;
}
void pawn::touchEnded(cocos2d::Touch* touch, cocos2d::Event* event) {
this->moving = true;
}
void pawn::step() {
if (this->moving) {
if (this->right) {
this->move(cocos2d::Vec2(this->speed, 0));
}
else {
this->move(cocos2d::Vec2(-this->speed, 0));
}
if (this->getPositionX() < 0) {
this->right = true;
CCLOG("Going right V4");
}
else {
if (this->getPositionX() + this->getContentSize().width > cocos2d::Director::getInstance()->getWinSizeInPixels().width + cocos2d::Director::getInstance()->getVisibleOrigin().x){
this->right = false;
CCLOG("Going left V4");
}
}
}
}
void pawn::move(cocos2d::Vec2 vec) {
PLAYER_CONTROLLER->setPosition(cocos2d::Vec2(PLAYER_CONTROLLER->getPositionX() + vec.x, PLAYER_CONTROLLER->getPositionY() + vec.y));
}
void pawn::moveX(int x) {
}
void pawn::moveY(int y) {
}
void pawn::update(float dt) {
//cocos2d::Rect act = this->getBoundingBox();
this->getPosition();
this->step();
}
cocos2d::Rect pawn::getBounds() {
if (!PLAYER_CONTROLLER) {
CCLOG("Is this the problem?");
}
return PLAYER_CONTROLLER->getBoundingBox();
}
pawn* pawn::create() {
auto character = new pawn();
character->moving = true;
character->right = false;
character->speed = 5;
character->setPositionY(50);
if (PLAYER_CONTROLLER == NULL) {
CCLOG("There is no player, yet.");
CCLOG("Adding player");
PLAYER_CONTROLLER = character;
}
else {
CCLOG("There's already a player");
return NULL;
}
//character->setPositionX(40);
if (character->initWithFile("Base.jpg")){
return character;
}
CC_SAFE_DELETE(character);
return NULL;
}
pawn* pawn::create(bool default_moving) {
pawn* character = new pawn();
character->moving = default_moving;
character->setPositionX(40);
if (character->initWithFile("Base.jpg")){
return character;
}
CC_SAFE_DELETE(character);
return NULL;
}
Is it maybe because I call a pawn method from another class? I use a Collider class to call functions in pawn
Collider.cpp
#include "Collider.h"
#include "player.h"
Collider::Collider() : CollideMode(OVERLAP) {
}
Collider::~Collider() {
}
Collider* Collider::create() {
Collider* col = new Collider;
if (col->initWithFile("Base.jpg")){
col->setAnchorPoint(cocos2d::Vec2(0, 0));
col->setContentSize(cocos2d::Size(100, 100));
return col;
}
CC_SAFE_DELETE(col);
return NULL;
}
void Collider::collision(cocos2d::Vec2 intersect) {
CCLOG("IT IS COLLIDING");
if (intersect.x < intersect.y) {
PLAYER_CONTROLLER->move(cocos2d::Vec2(-intersect.x, 0));
CCLOG("X");
}
else if (intersect.x > intersect.y) {
PLAYER_CONTROLLER->move(cocos2d::Vec2(0, -intersect.y));
CCLOG("Y");
}
}
void Collider::update(float dt) {
//cocos2d::Rect col = this->getBoundingBox();
auto act = PLAYER_CONTROLLER->getBounds();
if (PLAYER_CONTROLLER) {
if (!PLAYER_CONTROLLER) {
CCLOG("There is no player?");
}
}
else {
CCLOG("Not colliding");
}
}
I don't seems any problem with this->getBoundingBox() inside update(float dt) function.
I've created small test :
declaration inside .h file
class MySprite: public Sprite {
public:
bool init() override;
void update(float) override;
CREATE_FUNC(MySprite);
};
Now method definition inside .cpp file
bool MySprite::init(){
if(!Sprite::init())
return false;
scheduleUpdate();
return true;
}
void MySprite::update(float dt){
auto rect=this->getBoundingBox();
CCLOG("Inside Update method of MySprite Bounding rect Width %f & Height %f",rect.size.width,rect.size.height);
}
Then I created an autoreleased object of MySprite and add to parent.
auto mysprite=MySprite::create();
mysprite->setContentSize(Size(10,10));
addChild(mysprite);
Run, Expected result on output console.
I see my mistake. It was the fact that I redefined the namespace "GAME" and it's variable, "GAME::PLAYER" every time I included pawn.h, the other source files that I called the pawn functions from didn't know what GAME::PLAYER or PLAYER_CONTROLLER ( just a macro for GAME::PLAYER ) was, as I had only defined PLAYER_CONTROLLER in pawn.cpp. That's why when you called PLAYER_CONTROLLER->method() in another file, it passed in NULL as "this", and also why PLAYER_CONTROLLER was referring to a different PLAYER_CONTROLLER than the one passed in as "this".
I solved it by using the extern keyword that makes the variables global between all files, which was my original intention.
pawn.h
#include <cocos2d.h>
#ifndef PLAYER_CONTROLLER
#define PLAYER_CONTROLLER GAME::PLAYER
#define INITIALIZE_PLAYER pawn* GAME::PLAYER = NULL
class pawn : public cocos2d::Sprite {
public:
pawn();
~pawn();
static pawn* create();
static pawn* getController();
static pawn* create(bool default_moving);
bool moving;
bool right;
int speed;
cocos2d::Rect getBounds();
void step();
void initOptions();
void update(float dt) override;
void move(cocos2d::Vec2 vec);
void moveX(int x);
void moveY(int y);
virtual bool touchBegan(cocos2d::Touch*, cocos2d::Event*);
virtual void touchEnded(cocos2d::Touch*, cocos2d::Event*);
};
namespace GAME {
extern pawn* PLAYER;
};
#endif
This is why I said I wasn't that good at C++.
I was trying to follow the SFML Blueprint book. I managed to remove all the errors but one error remains in the code.
I have tried to find about the debug-assertion-failed.
I think this issue is arising due to the lists one of them is getting emptied.
My code for the world.cpp
#include "World.h"
#include "Entity.h"
World::World(int x, int y) : _x(x), _y(y) {}
World::~World() { clear(); }
void World::add(Entity* entity){
_entities_tmp.push_back(entity);
}
void World::clear()
{
for (Entity* entity : _entities)
delete entity;
_entities.clear();
for (Entity* entity : _entities_tmp)
delete entity;
_entities_tmp.clear();
_sounds.clear();
}
void World::add(Configuration::Sounds sound_id){
std::unique_ptr<sf::Sound> sound(new sf::Sound(Configuration::sounds.get(sound_id)));
sound->setAttenuation(0);
sound->play();
_sounds.emplace_back(std::move(sound));
}
bool World::isCollide(const Entity& other)
{
for (Entity* entity_ptr : _entities)
if (other.isCollide(*entity_ptr))
return true;
return false;
}
int World::size() {
return _entities.size() + _entities_tmp.size();
}
int World::getX() const{
return _x;
}
int World::getY() const{
return _y;
}
const std::list<Entity*> World::getEntities() const {
return _entities;
}
void World::update(sf::Time deltaTime)
{
if (_entities_tmp.size() > 0)
_entities.merge(_entities_tmp);
for (Entity* entity_ptr : _entities)
{
Entity& entity = *entity_ptr;
entity.update(deltaTime);
sf::Vector2f pos = entity.getPosition();
if (pos.x < 0)
{
pos.x = _x;
pos.y = _y - pos.y;
}
else if (pos.x > _x)
{
pos.x = 0;
pos.y = _y - pos.y;
}
if (pos.y < 0)
pos.y = _y;
else if (pos.y > _y)
pos.y = 0;
entity.setPosition(pos);
}
const auto end = _entities.end();
for (auto it_i = _entities.begin(); it_i != end; ++it_i)
{
Entity& entity_i = **it_i;
auto it_j = it_i;
it_j++;
for (; it_j != end; ++it_j)
{
Entity& entity_j = **it_j;
if (entity_i.isAlive() && entity_i.isCollide(entity_j))
entity_i.onDestroy();
if (entity_j.isAlive() && entity_j.isCollide(entity_i))
entity_j.onDestroy();
}
}
for (auto it = _entities.begin(); it != _entities.end();)
{
if (!(*it)->isAlive()){
delete *it;
it = _entities.erase(it);
}
else ++it;
}
_sounds.remove_if([](const std::unique_ptr<sf::Sound>& sound)->
bool {
return sound->getStatus() != sf::SoundSource::Status::Playing;
});
}
void World::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
for (Entity* entity : _entities)
target.draw(*entity, states);
}
Code for world.hpp
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <list>
#include <memory>
#include "Configuration.h"
class Entity;
class World : public sf :: Drawable
{
public:
World(const World&) = delete;
World& operator=(const World&) = delete;
World(int x, int y);
~World();
void add(Entity* entity);
void clear();
bool isCollide(const Entity& other);
int size();
void add(Configuration::Sounds sound_id);
const std::list<Entity*> getEntities() const;
int getX() const;
int getY() const;
void update(sf::Time deltaTime);
private:
std::list<Entity*> _entities;
std::list<Entity*> _entities_tmp;
std::list<std::unique_ptr<sf::Sound>> _sounds;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
const int _x;
const int _y;
};
code for Entity.h
class World;
class Entity : public sf::Drawable
{
public:
//Constructors
Entity(const Entity&) = delete;
Entity& operator= (const Entity&) = delete;
Entity(Configuration::Textures tex_id, World& world);
virtual ~Entity();
//Helpers
virtual bool isAlive() const;
const sf::Vector2f& getPosition() const;
template<typename ... Args>
void setPosition(Args&& ... args);
virtual bool isCollide(const Entity& other) const = 0;
//Updates
virtual void update(sf::Time deltaTime) = 0;
virtual void onDestroy();
protected:
friend class Meteor;
friend class Player;
friend class Saucer;
friend class ShootPlayer;
friend class ShootSaucer;
sf::Sprite _sprite;
sf::Vector2f _impulse;
World& _world;
bool _alive;
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
};
if (_entities_tmp.size() > 0)
_entities.merge(_entities_tmp);
This does not work. merge works with two sorted ranges. And your vector is not sorted. This is why you get an assertion.
If not sorting them is on purpose and you just want to concatenate the two vectors, you can do:
_entities.reserve( _entities.size() + _entities_tmp.size() );
_entities.insert( _entities.end(), _entities_tmp.begin(), _entities_tmp.end() );
I'm working on compiling the code for Acellerated c++ chapter 15. I more or less copied the code straight out of the book, except in some places they defined things like constructors in the class body in the header file, and I separated them out to avoid link errors.
Below is the code; I attempted to compile it in Visual Studio 2010, but unfortunately it fails. It tells me it cannot create instances of the "String_Pic" and the other derived classes (Frame_Pic, HCat_Pic, and VCat_Pic) because it says they are still abstract classes. It says the culprit is the "display" function, which it says is undefined. However, I clearly define it for each derived class, as you can see below.
What's going on here?
Header:
#ifndef _GUARD_PIC_BASE_H
#define _GUARD_PIC_BASE_H
#include "Ptr.h"
#include <iostream>
#include <string>
#include <vector>
class Picture;
class Pic_base {
friend std::ostream& operator<<(std::ostream&, const Picture&);
friend class Frame_Pic;
friend class HCat_Pic;
friend class VCat_Pic;
friend class String_Pic;
typedef std::vector<std::string>::size_type ht_sz;
typedef std::string::size_type wd_sz;
virtual wd_sz width() const = 0;
virtual ht_sz height() const = 0;
virtual void display(std::ostream, ht_sz, bool) const = 0;
public:
virtual ~Pic_base(){ }
protected:
static void pad(std::ostream&, wd_sz, wd_sz);
};
// public interface class and operations
class Picture {
friend std::ostream& operator<<(std::ostream&, const Picture&);
friend Picture frame(const Picture&);
friend Picture hcat(const Picture&, const Picture&);
friend Picture vcat(const Picture&, const Picture&);
public:
Picture(const std::vector<std::string>& =
std::vector<std::string>());
private:
Picture(Pic_base* ptr); //here's one difference
Ptr<Pic_base> p;
};
Picture frame(const Picture&);
Picture hcat(const Picture&, const Picture&);
Picture vcat(const Picture&, const Picture&);
std::ostream& operator<<(std::ostream&, const Picture&);
class String_Pic: public Pic_base {
friend class Picture;
std::vector<std::string> data;
String_Pic(const std::vector<std::string>&);
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};
class VCat_Pic: public Pic_base {
friend Picture vcat(const Picture&, const Picture&);
Ptr<Pic_base> top, bottom;
VCat_Pic(const Ptr<Pic_base>&, const Ptr<Pic_base>&);
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};
class HCat_Pic: public Pic_base {
friend Picture hcat(const Picture&, const Picture&);
Ptr<Pic_base> left, right;
HCat_Pic(const Ptr<Pic_base>&, const Ptr<Pic_base>&);
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};
class Frame_Pic: public Pic_base {
friend Picture frame(const Picture&);
Ptr<Pic_base> p;
Frame_Pic(const Ptr<Pic_base>& pic);
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};
#endif
.cpp/implementation file:
#include "Ptr.h"
#include "Pic_Base.h"
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
//Picture-Specific Functions:
Picture::Picture(Pic_base* ptr):p(ptr) {}
Picture::Picture(const vector<string>& v): p(new String_Pic(v)) { }
//Frame-Specific Functions:
Frame_Pic::Frame_Pic(const Ptr<Pic_base>& pic): p(pic) {}
Pic_base::wd_sz Frame_Pic::width() const { return p->width() + 4; }
Pic_base::ht_sz Frame_Pic::height() const { return p->height() + 4; }
void Frame_Pic::display(ostream& os, ht_sz row, bool do_pad) const{
if (row >= height()) {
// out of range
if (do_pad)
pad(os, 0, width());
} else {
if (row == 0 || row == height() - 1) {
// top or bottom row
os << string(width(), '*');
} else if (row == 1 || row == height() - 2) {
// second from fop or bottom row
os << "*";
pad(os, 1, width() - 1);
os << "*";
} else {
// interior row
os << "* ";
p->display(os, row - 2, true);
os << " *";
}
}
}
Picture frame(const Picture& pic){
return new Frame_Pic(pic.p);
}
//HCat-Specific Functions:
HCat_Pic::HCat_Pic(const Ptr<Pic_base>& l, const Ptr<Pic_base>& r): left(l), right(r) { }
HCat_Pic::HCat_Pic(const Ptr<Pic_base>& l, const Ptr<Pic_base>&r):
left(l), right(r) { }
Pic_base::wd_sz width() const { return left->width() + right->width(); }
Pic_base::ht_sz height() const { return max(left->height(), right->heigth()); }
void HCat_Pic::display(ostream& os, ht_sz row, bool do_pad) const{
left->display(os, row, do_pad || row < right->height());
right->display(os, row, do_pad);
}
Picture hcat(const Picture& l, const Picture& r){
return new HCat_Pic(l.p, r.p);
}
//VCat-Specific Functions:
VCat_Pic::VCat_Pic(const Ptr<Pic_base>& t, const Ptr<Pic_base>& b): top(t), bottom(b) { }
Picture vcat(const Picture& t, const Picture& b){
return new VCat_Pic(t.p, b.p);
}
Pic_base::wd_sz VCat_Pic::width() const {
return max(top->width(), bottom->width());
}
Pic_base::ht_sz VCat_Pic::height() const{
return top->height() + bottom->height();
}
void VCat_Pic::display(ostream& os, ht_sz row, bool do_pad) const{
wd_sz w = 0;
if (row < top->height()) {
// we are in the top subpicture
top->display(os, row, do_pad);
w = top->width();
} else if (row < height()) {
// we are in the bottom subpicture
bottom->display(os, row - top->height(), do_pad);
w = bottom->width();
}
if (do_pad)
pad(os, w, width());
}
//String_Pic-Specific Functions:
String_Pic::String_Pic(const std::vector<std::string>& v): data(v) { }
Pic_base::ht_sz String_Pic::height() const { return data.size(); }
Pic_base::wd_sz String_Pic::width() const{
Pic_base::wd_sz n = 0;
for (Pic_base::ht_sz i = 0; i != data.size(); ++i)
n = max(n, data[i].size());
return n;
}
void String_Pic::display(ostream& os, ht_sz row, bool do_pad) const{
wd_sz start = 0;
// write the row if we're still in range
if (row < height()) {
os << data[row];
start = data[row].size();
}
// pad the output if necessary
if (do_pad)
pad(os, start, width());
}
//Pic_base-Specific functions:
void Pic_base::pad(std::ostream& os, wd_sz beg, wd_sz end) {
while (beg != end) {
os << " ";
++beg;
}
}
//Non-Specific Functions:
ostream& operator<<(ostream& os, const Picture& picture){
const Pic_base::ht_sz ht = picture.p->height();
for (Pic_base::ht_sz i = 0; i != ht; ++i) {
picture.p->display(os, i, false);
os << endl;
}
return os;
}
You declare the pure virtual function as taking a ofstream object by value, while all your subclasses define it as taking a reference to one.
virtual void display(std::ostream, ht_sz, bool) const = 0;
vs
void display(std::ostream&, ht_sz, bool) const;
^
Pi_base declares display with this signature:
virtual void display(std::ostream, ht_sz, bool) const = 0;
But your derived classes declare it with this signature:
void display(std::ostream&, ht_sz, bool) const;
Compare them closely and you'll see that your base class takes a std::ostream while your derived classes take a std::ostream&.