SMFL - Only 1 of 2 object gets drawn - c++

I'm having trouble drawing a custom sf::Drawable derived object.
//Textbox.h
#pragma once
#include "Header.h"
#ifndef TEXTBOX_H
#define TEXTBOX_H
class Textbox : public Drawable {
public:
Textbox(int max_chars, bool numeric);
Textbox(int max_chars);
Textbox(bool numeric);
Textbox();
void setTextColor(Color color);
void setPosition(float x, float y);
Vector2f getPosition() {
return m_gshape.getPosition();
}
Vector2f getSize();
String getString();
void setFocus(bool value);
bool isFocused();
void input(Uint32 text_char);
void clear();
private:
virtual void Textbox::draw(sf::RenderTarget& target, sf::RenderStates states) const {
target.draw(m_gshape, states);
target.draw(m_textbox, states);
}
unsigned int max_length;
int min_ascii = 32;
int max_ascii = 127;
bool focus;
string content;
Text m_textbox;
RectangleShape m_gshape;
};
#endif // !TEXTBOX_H
And
//Textbox.cpp
#pragma once
#include "Textbox.h"
Textbox::Textbox(int max_chars, bool numeric) {
max_length = max_chars;
m_gshape.setSize(Vector2f(6 + 15 * max_length, 30));
m_gshape.setFillColor(Color::White);
m_gshape.setOutlineThickness(2);
m_gshape.setOutlineColor(Color(60, 60, 60));
m_gshape.setPosition(0, 0);
m_textbox.setFont(default_font);
m_textbox.setCharacterSize(25);
m_textbox.setFillColor(Color::White);
if (max_chars > 1)
m_textbox.setString(to_string((int)pow(10, max_chars - 1)));
else
m_textbox.setString("0");
if (numeric) {
min_ascii = 47;
max_ascii = 58;
}
}
Textbox::Textbox(int max_chars) : Textbox(max_chars, false) {}
Textbox::Textbox(bool numeric) : Textbox(2, numeric) {}
Textbox::Textbox() : Textbox(2, false) {}
void Textbox::setTextColor(Color color) {
m_textbox.setFillColor(color);
}
void Textbox::setPosition(float x, float y) {
FloatRect textbox_bounds = m_textbox.getGlobalBounds();
m_gshape.setPosition(x, y);
m_textbox.setPosition(m_gshape.getPosition().x + (m_gshape.getSize().x - textbox_bounds.width) / 2 - textbox_bounds.left,
m_gshape.getPosition().y + (m_gshape.getSize().y - textbox_bounds.height) / 2 - textbox_bounds.top);
}
Vector2f Textbox::getSize() {
return m_gshape.getSize();
}
String Textbox::getString() {
return m_textbox.getString();
}
void Textbox::setFocus(bool value) {
focus = true;
}
bool Textbox::isFocused() {
return focus;
}
void Textbox::input(Uint32 text_char) {
content = m_textbox.getString().toAnsiString();
if (text_char == 13) {
focus = false;
return;
}
if (m_textbox.getString().getSize() < max_length) {
if (text_char > min_ascii && text_char < max_ascii) {
m_textbox.setString(m_textbox.getString() + text_char);
}
}
if (text_char == 8 && m_textbox.getString().getSize() > 0) {
content.resize(m_textbox.getString().getSize() - 1);
m_textbox.setString(content);
}
}
void Textbox::clear() {
m_textbox.setString("");
}
Everything works except for the drawing part: while g_shape gets drawn and rendered m_textbox doesn't. I'm sure of this because I can still edit the text, however it's not displayed.
I must admit I didn't fully understand the sf::Drawable inheritance and consequently I'm not sure I overrid draw() correctly.

Thanks to #AlexMeuer I found the solution.
In my header file I had my global font set as extern sf::Font default_font however in my main.cpp I never declared it.

Related

SFML performance issue in space invader like game

I'm trying to learn C++, and I'm making this little space-invader-like game to get better at it.
Currently everything works just fine but for some reason the performance of the game is kind of terrible considering how simple the graphics are (the game runs smoothly for a while and then stops for like half a second, constantly).
I'm pretty sure the lag is due to the amount of bullets I'm removing and creating from the vector containing them (I'm removing the bullets that go outside the screen because there's no point in updating them or rendering them). So how could I fix this?
I checked the game loop and the problem isn't there.
Code below
player.h:
#pragma once
#include <vector>
#include <iostream>
#include "entity.h"
#include "SFML/Graphics.hpp"
#include "vector.h"
class Player : public Entity {
private:
int f_lastshot = 0;
const double shoot_delay = 0.5;
const float bullet_speed = 1, speed = 0.75;
std::vector<Entity> bullets;
sf::Clock *c;
sf::Sprite bullet_sprite;
public:
Player(Vector &pos, int w, int h, sf::Sprite &spr);
~Player();
void init();
void update();
void render(Window &win);
void shoot();
};
player.cpp:
#include "player.h"
Player::Player(Vector &pos, int w, int h, sf::Sprite &spr) : Entity() {
this->pos = pos;
this->sprite = spr;
this->width = w;
this->height = h;
float scale_x = (float)w / (float)spr.getTexture()->getSize().x;
float scale_y = (float)h / (float)spr.getTexture()->getSize().y;
sprite.setScale(scale_x, scale_y);
}
void Player::update() {
if (sf::Mouse::isButtonPressed(sf::Mouse::Left) || sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
if ((double)(f_lastshot / 60) > shoot_delay) // shoot only if enough time has passed
shoot();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) dir.setX(-speed); // move left
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) dir.setX(speed); // move right
else dir.setX(0); // stop if no button is being pressed
f_lastshot++;
pos = pos + dir; // add the direction to the position
for (Entity &e : bullets) {
e.update(); // update each bullet
if (e.getPos().getY() < 0) // if the bullet is outside the screen delete it
bullets.erase(bullets.begin());
}
}
void Player::render(Window &win) {
sprite.setPosition(pos.getX(), pos.getY()); // update the position of the sprite
win.render(sprite);
for (Entity &bullet : bullets)
bullet.render(win);
}
void Player::shoot() {
f_lastshot = 0;
bullets.push_back(Entity::Entity(Vector::Vector(pos.getX() + width / 2 - 8, pos.getY()), 16, 32, bullet_sprite, Vector::Vector(0,-bullet_speed)));
}
void Player::init() {
if (c == nullptr) c = new sf::Clock();
else c->restart();
dir.setX(0); dir.setY(0);
sf::Texture *bullet_texture = new sf::Texture();
if (!bullet_texture->loadFromFile("bullet.png"))
std::cerr << "Could not load bullet image" << std::endl;
bullet_sprite.setTexture(*bullet_texture);
}
Player::~Player() {
delete bullet_sprite.getTexture();
delete c;
}
entity.h:
#pragma once
#include <SFML/Graphics.hpp>
#include <iostream>
#include "vector.h"
#include "window.h"
class Entity {
protected:
Vector pos;
sf::Sprite sprite;
int width, height;
Vector dir; // the direction
public:
Entity();
Entity(Vector &pos, int w, int h, sf::Sprite &spr);
Entity(Vector pos, int w, int h, sf::Sprite &spr);
Entity(Vector pos, int w, int h, sf::Sprite &spr, Vector dir);
void update();
void render(Window &win);
bool collides(Entity &other) const;
public:
Vector getPos() const;
Vector getDirection() const;
sf::Sprite getSprite() const;
int getWidth() const;
int getHeight() const;
void setPos(Vector &pos);
void setWidth(int width);
void setHeight(int height);
void setSize(int width, int height);
void setSprite(sf::Sprite &sprite);
void setDirection(Vector dir);
};
entity.cpp:
#include "entity.h"
Entity::Entity() {}
Entity::Entity(Vector &pos, int w, int h, sf::Sprite &spr)
: pos(pos), width(w), height(h) {
this->sprite = spr;
float scale_x = (float)w/(float)spr.getTexture()->getSize().x;
float scale_y = (float)h/(float)spr.getTexture()->getSize().y;
sprite.setPosition(pos.getX(), pos.getY());
sprite.setScale(scale_x, scale_y);
}
Entity::Entity(Vector pos, int w, int h, sf::Sprite &spr)
: pos(pos), width(w), height(h) {
this->sprite = spr;
float scale_x = (float)w / (float)spr.getTexture()->getSize().x;
float scale_y = (float)h / (float)spr.getTexture()->getSize().y;
sprite.setPosition(pos.getX(), pos.getY());
}
Entity::Entity(Vector pos, int w, int h, sf::Sprite &spr, Vector dir)
: pos(pos), width(w), height(h) {
this->sprite = spr;
this->dir = dir;
float scale_x = (float)w / (float)spr.getTexture()->getSize().x;
float scale_y = (float)h / (float)spr.getTexture()->getSize().y;
sprite.setPosition(pos.getX(), pos.getY());
}
bool Entity::collides(Entity &other) const {
bool x_coll = (pos.getX() + width> other.getPos().getX() && pos.getX()< other.getPos().getX())||(pos.getX() < other.getPos().getX() + other.getWidth() && pos.getX() > other.getPos().getX());
bool y_coll = (pos.getY() + height > other.getPos().getY() && pos.getY() < other.getPos().getY()||(pos.getY() < other.getPos().getY() + other.getHeight() && pos.getY() > other.getPos().getY()));
return (x_coll && y_coll);
}
void Entity::render(Window &win) {
sprite.setPosition(pos.getX(), pos.getY());
win.render(sprite);
}
void Entity::update() {
pos = pos + dir;
}
Vector Entity::getPos() const { return pos; }
int Entity::getWidth() const { return width; }
int Entity::getHeight() const { return height; }
sf::Sprite Entity::getSprite() const { return sprite; }
Vector Entity::getDirection() const { return dir; }
void Entity::setPos(Vector &pos) { this->pos = pos; }
void Entity::setWidth(int width) { this->width = width; }
void Entity::setHeight(int height) { this->height = height; }
void Entity::setSprite(sf::Sprite &sprite) { this->sprite = sprite; }
void Entity::setDirection(Vector dir) { this->dir = dir; }
void Entity::setSize(int width, int height) {
this->width = width;
this->height = height;
}
To identify bottlenecks and other performance issues you should use a profiler. Only by looking the code it's hard if not impossible to find the correct places that need optimisation. But one problem is indeed the way you remove bullets:
for (Entity &e : bullets) {
e.update(); // update each bullet
if (e.getPos().getY() < 0) // if the bullet is outside the screen delete it
bullets.erase(bullets.begin());
}
There is a logic error. You check if the current bullet e is outside the screen, but then delete the first one anyway. This can't be right.
It's extremely inefficient to delete the first element of a std::vector, because all the following elements will have to be moved one place left. This happens for every bullet you remove!
It may cause undefined behavior. The reference says that erase
Invalidates iterators and references at or after the point of the erase, including the end() iterator.
Changing the size of a vector while iterating over it is usually a bad idea.
To overcome those issues you could use the Erase-Remove-Idiom like this:
// Update as usual
for (Entity &e : bullets) {
e.update();
}
// Erase-Remove bullets that are out of screen
bullets.erase(std::remove_if(bullets.begin(), bullets.end(),
[](const Entity &e){ return e.getY() < 0;}), bullets.end());

SFML c++ How change Sprites per Primitives on Asteroid Game Code(Have Sprite Code Working)

I have some code that when compiled, runs an Asteroid Game. I want to make some changes. In place of sprites for the ship, I would like to use trianges. For a bullet, I'd like to use a small rectangle, and finally, a polygon for the asteroids. The code uses an Entity Master Class with a list. Can somebody please elaborate on how to make these changes?
#include <SFML/Graphics.hpp>
#include <time.h>
#include <list>
using namespace sf;
const int W = 1200;
const int H = 800;
float DEGTORAD = 0.017453f;
class Animation
{
public:
float Frame, speed;
Sprite sprite;
std::vector<IntRect> frames;
Animation(){}
Animation (Texture &t, int x, int y, int w, int h, int count, float Speed)
{
Frame = 0;
speed = Speed;
for (int i=0;i<count;i++)
frames.push_back( IntRect(x+i*w, y, w, h) );
sprite.setTexture(t);
sprite.setOrigin(w/2,h/2);
sprite.setTextureRect(frames[0]);
}
void update()
{
Frame += speed;
int n = frames.size();
if (Frame >= n) Frame -= n;
if (n>0) sprite.setTextureRect( frames[int(Frame)] );
}
bool isEnd()
{
return Frame+speed>=frames.size();
}
};
class Entity
{
public:
float x,y,dx,dy,R,angle;
bool life;
std::string name;
Animation anim;
Entity()
{
life=1;
}
void settings(Animation &a,int X,int Y,float Angle=0,int radius=1)
{
anim = a;
x=X; y=Y;
angle = Angle;
R = radius;
}
virtual void update(){};
void draw(RenderWindow &app)
{
anim.sprite.setPosition(x,y);
anim.sprite.setRotation(angle+90);
app.draw(anim.sprite);
CircleShape circle(R);
circle.setFillColor(Color(255,0,0,170));
circle.setPosition(x,y);
circle.setOrigin(R,R);
//app.draw(circle);
}
virtual ~Entity(){};
};
class asteroid: public Entity
{
public:
asteroid()
{
dx=rand()%8-4;
dy=rand()%8-4;
name="asteroid";
}
void update()
{
x+=dx;
y+=dy;
if (x>W) x=0; if (x<0) x=W;
if (y>H) y=0; if (y<0) y=H;
}
};
class bullet: public Entity
{
public:
bullet()
{
name="bullet";
}
void update()
{
dx=cos(angle*DEGTORAD)*6;
dy=sin(angle*DEGTORAD)*6;
// angle+=rand()%7-3; /*try this*/
x+=dx;
y+=dy;
if (x>W || x<0 || y>H || y<0) life=0;
}
};
class player: public Entity
{
public:
bool thrust;
player()
{
name="player";
}
void update()
{
if (thrust)
{ dx+=cos(angle*DEGTORAD)*0.2;
dy+=sin(angle*DEGTORAD)*0.2; }
else
{ dx*=0.99;
dy*=0.99; }
int maxSpeed=15;
float speed = sqrt(dx*dx+dy*dy);
if (speed>maxSpeed)
{ dx *= maxSpeed/speed;
dy *= maxSpeed/speed; }
x+=dx;
y+=dy;
if (x>W) x=0; if (x<0) x=W;
if (y>H) y=0; if (y<0) y=H;
}
};
bool isCollide(Entity *a,Entity *b)
{
return (b->x - a->x)*(b->x - a->x)+
(b->y - a->y)*(b->y - a->y)<
(a->R + b->R)*(a->R + b->R);
}
int main()
{
srand(time(0));
RenderWindow app(VideoMode(W, H), "Asteroids!");
app.setFramerateLimit(60);
Texture t1,t2,t3,t4,t5,t6,t7;
t1.loadFromFile("images/spaceship.png");
t2.loadFromFile("images/background.jpg");
t3.loadFromFile("images/explosions/type_C.png");
t4.loadFromFile("images/rock.png");
t5.loadFromFile("images/fire_blue.png");
t6.loadFromFile("images/rock_small.png");
t7.loadFromFile("images/explosions/type_B.png");
t1.setSmooth(true);
t2.setSmooth(true);
Sprite background(t2);
Animation sExplosion(t3, 0,0,256,256, 48, 0.5);
Animation sRock(t4, 0,0,64,64, 16, 0.2);
Animation sRock_small(t6, 0,0,64,64, 16, 0.2);
Animation sBullet(t5, 0,0,32,64, 16, 0.8);
Animation sPlayer(t1, 40,0,40,40, 1, 0);
Animation sPlayer_go(t1, 40,40,40,40, 1, 0);
Animation sExplosion_ship(t7, 0,0,192,192, 64, 0.5);
std::list<Entity*> entities;
for(int i=0;i<15;i++)
{
asteroid *a = new asteroid();
a->settings(sRock, rand()%W, rand()%H, rand()%360, 25);
entities.push_back(a);
}
player *p = new player();
p->settings(sPlayer,200,200,0,20);
entities.push_back(p);
/////main loop/////
while (app.isOpen())
{
Event event;
while (app.pollEvent(event))
{
if (event.type == Event::Closed)
app.close();
if (event.type == Event::KeyPressed)
if (event.key.code == Keyboard::Space)
{
bullet *b = new bullet();
b->settings(sBullet,p->x,p->y,p->angle,10);
entities.push_back(b);
}
}
if (Keyboard::isKeyPressed(Keyboard::Right)) p->angle+=3;
if (Keyboard::isKeyPressed(Keyboard::Left)) p->angle-=3;
if (Keyboard::isKeyPressed(Keyboard::Up)) p->thrust=true;
else p->thrust=false;
for(auto a:entities)
for(auto b:entities)
{
if (a->name=="asteroid" && b->name=="bullet")
if ( isCollide(a,b) )
{
a->life=false;
b->life=false;
Entity *e = new Entity();
e->settings(sExplosion,a->x,a->y);
e->name="explosion";
entities.push_back(e);
for(int i=0;i<2;i++)
{
if (a->R==15) continue;
Entity *e = new asteroid();
e->settings(sRock_small,a->x,a->y,rand()%360,15);
entities.push_back(e);
}
}
if (a->name=="player" && b->name=="asteroid")
if ( isCollide(a,b) )
{
b->life=false;
Entity *e = new Entity();
e->settings(sExplosion_ship,a->x,a->y);
e->name="explosion";
entities.push_back(e);
p->settings(sPlayer,W/2,H/2,0,20);
p->dx=0; p->dy=0;
}
}
if (p->thrust) p->anim = sPlayer_go;
else p->anim = sPlayer;
for(auto e:entities)
if (e->name=="explosion")
if (e->anim.isEnd()) e->life=0;
if (rand()%150==0)
{
asteroid *a = new asteroid();
a->settings(sRock, 0,rand()%H, rand()%360, 25);
entities.push_back(a);
}
for(auto i=entities.begin();i!=entities.end();)
{
Entity *e = *i;
e->update();
e->anim.update();
if (e->life==false) {i=entities.erase(i); delete e;}
else i++;
}
//////draw//////
app.draw(background);
for(auto i:entities) i->draw(app);
app.display();
}
return 0;
}
it is not really relevant question to be asked here,
but take a look at this part of code:
Texture t1,t2,t3,t4,t5,t6,t7;
t1.loadFromFile("images/spaceship.png");
t2.loadFromFile("images/background.jpg");
t3.loadFromFile("images/explosions/type_C.png");
t4.loadFromFile("images/rock.png");
t5.loadFromFile("images/fire_blue.png");
t6.loadFromFile("images/rock_small.png");
t7.loadFromFile("images/explosions/type_B.png");

cocos2d this->getBoundingBox

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++.

Unable to solve the "error: candidate is:" in cocos2dx

I'm currently having a problem with the following error when I try to run my game. I tried to understand what the meaning of the following error but I find it hard to understand. I believe that there is more than one error but I have no clue where to look. I would love to have some help from you!
[armeabi] Compile++ thumb: MyGame_shared <= BallSprite.cpp
[armeabi] Compile++ thumb: MyGame_shared <= Character.cpp
[armeabi] StaticLibrary : libcocos2d.a
[armeabi] StaticLibrary : libcocostudio.a
[armeabi] StaticLibrary : libcocosbuilder.a
[armeabi] StaticLibrary : libcocos3d.a
jni/../../../Classes/Character.cpp:26:5: error: prototype for 'int Character::getTurnCount()' does not match any in class 'Character'
int Character::getTurnCount()
^
In file included from /Users/michael/Desktop/CocoFolder/Puzzle/cocos2d/cocos/3d/../base/CCAsyncTaskPool.h:28:0,
from /Users/michael/Desktop/CocoFolder/Puzzle/cocos2d/cocos/3d/../cocos2d.h:41,
from jni/../../../Classes/Character.h:4,
from jni/../../../Classes/Character.cpp:1:
/Users/michael/Desktop/CocoFolder/Puzzle/cocos2d/cocos/3d/../platform/CCPlatformMacros.h:153:25: error: candidate is: virtual int Character::getTurnCount() const
public: virtual varType get##funName(void) const;\
^
jni/../../../Classes/Character.h:26:5: note: in expansion of macro 'CC_PROPERTY'
CC_PROPERTY(int, _turnCount, TurnCount);
^
jni/../../../Classes/BallSprite.cpp:62:27: error: prototype for 'BallSprite::PositionIndex BallSprite::getPositionIndex()' does not match any in class 'BallSprite'
BallSprite::PositionIndex BallSprite::getPositionIndex()
^
In file included from /Users/michael/Desktop/CocoFolder/Puzzle/cocos2d/cocos/3d/../base/CCAsyncTaskPool.h:28:0,
from /Users/michael/Desktop/CocoFolder/Puzzle/cocos2d/cocos/3d/../cocos2d.h:41,
from jni/../../../Classes/BallSprite.h:4,
from jni/../../../Classes/BallSprite.cpp:1:
/Users/michael/Desktop/CocoFolder/Puzzle/cocos2d/cocos/3d/../platform/CCPlatformMacros.h:153:25: error: candidate is: virtual BallSprite::PositionIndex BallSprite::getPositionIndex() const
public: virtual varType get##funName(void) const;\
^
jni/../../../Classes/BallSprite.h:53:5: note: in expansion of macro 'CC_PROPERTY'
CC_PROPERTY(PositionIndex, _positionIndex, PositionIndex);
^
make: *** [obj/local/armeabi/objs-debug/MyGame_shared/__/__/__/Classes/BallSprite.o] Error 1
make: *** Waiting for unfinished jobs....
make: *** [obj/local/armeabi/objs-debug/MyGame_shared/__/__/__/Classes/Character.o] Error 1
make: Leaving directory `/Users/michael/Desktop/CocoFolder/Puzzle/proj.android-studio/app'
Error running command, return code: 2.
code for the character
#include "Character.h"
USING_NS_CC;
Character::Character()
: _hp(0)
, _maxHp(0)
, _attack(0)
, _element(Element::None)
, _turnCount(0)
, _remainingTurn(0)
{
}
Character* Character::create()
{
Character *pRet = new Character();
pRet->autorelease();
return pRet;
}
int Character::getTurnCount()
{
return _turnCount;
}
void Character::setTurnCount(int turnCount)
{
_turnCount = turnCount;
_remainingTurn = _turnCount;
}
float Character::getHpPercentage()
{
return _hp * 100.f / _maxHp;
}
bool Character::isAttackTurn()
{
_remainingTurn--;
if (_remainingTurn <= 0)
{
_remainingTurn = _turnCount;
return true;
}
return false;
}
int Character::getDamage(int ballCount, int chainCount, Character* attacker, Character* defender)
{
float baseDamage = ballCount / 3.0 * 100;
float chainBonus = powf(1.1, chainCount - 1);
float elementBonus = getElementBonus(attacker->getElement(), defender->getElement());
return baseDamage * chainBonus * elementBonus;
}
float Character::getElementBonus(Element attackElement, Element defenseElement)
{
switch (attackElement)
{
case Element::Fire:
{
switch (defenseElement)
{
case Element::Wind:return 2;
case Element::Water:return 0.5;
default:return 1;
}
break;
}
case Element::Water:
{
switch (defenseElement)
{
case Element::Fire:return 2;
case Element::Wind:return 0.5;
default:return 1;
}
break;
}
case Element::Wind:
{
switch (defenseElement)
{
case Element::Water:return 2;
case Element::Wind:return 0.5;
default:return 1;
}
break;
}
case Element::Holy:
{
switch (defenseElement)
{
case Element::Shadow:return 2;
default:return 1;
}
break;
}
case Element::Shadow:
{
switch (defenseElement)
{
case Element::Holy:return 2;
default:return 1;
}
break;
}
default:
{
return 1;
}
}
}
Characters header
class Character : public cocos2d::Ref
{
public:
enum class Element
{
Fire,
Water,
Wind,
Holy,
Shadow,
None,
};
protected:
int _remainingTurn;
CC_SYNTHESIZE(int, _hp, Hp);
CC_SYNTHESIZE(int, _maxHp, MaxHp);
CC_SYNTHESIZE(int, _attack, Attack);
CC_SYNTHESIZE(Element, _element, Element);
CC_PROPERTY(int, _turnCount, TurnCount);
public:
Character();
static Character* create();
float getHpPercentage();
bool isAttackTurn();
static int getDamage(int ballCount, int chainCount, Character* attacker, Character* defender);
protected:
static float getElementBonus(Element attackElement, Element defenseElement);
};
#endif
BallSprite.cpp
#include "BallSprite.h"
USING_NS_CC;
BallSprite::BallSprite()
: _removedNo(0)
, _checkedX(false)
, _checkedY(false)
, _fallCount(0)
, _positionIndex(0, 0)
{
}
BallSprite* BallSprite::create(BallType type, bool visible)
{
BallSprite *pRet = new BallSprite();
if (pRet && pRet->init(type, visible))
{
pRet->autorelease();
return pRet;
}
else
{
delete pRet;
pRet = nullptr;
return nullptr;
}
}
bool BallSprite::init(BallType type, bool visible)
{
if (!Sprite::initWithFile(getBallImageFilePath(type)))
return false;
_ballType = type;
setVisible(visible);
return true;
}
void BallSprite::resetParams()
{
_removedNo = 0;
_checkedX = false;
_checkedY = false;
_fallCount = 0;
}
void BallSprite::resetPosition()
{
setPosition(getPositionForPositionIndex(_positionIndex));
}
void BallSprite::getPositionIndex()
{
return _positionIndex;
}
void BallSprite::setPositionIndex(PositionIndex positionIndex)
{
_positionIndex = positionIndex;
setTag(generateTag(_positionIndex));
}
void BallSprite::setPositionIndexAndChangePosition(PositionIndex positionIndex)
{
setPositionIndex(positionIndex);
resetPosition();
}
void BallSprite::removingAndFallingAnimation(int maxRemovedNo)
{
removingAnimation(maxRemovedNo);
fallingAnimation(maxRemovedNo);
}
void BallSprite::removingAnimation(int maxRemovedNo)
{
if (_removedNo > 0)
{
auto delay1 = DelayTime::create(ONE_ACTION_TIME * (_removedNo - 1));
auto fade = FadeTo::create(ONE_ACTION_TIME, 0);
auto delay2 = DelayTime::create(ONE_ACTION_TIME * (maxRemovedNo - _removedNo));
auto removeSelf = RemoveSelf::create(false);
runAction(Sequence::create(delay1, fade, delay2, removeSelf, nullptr));
}
}
void BallSprite::fallingAnimation(int maxRemovedNo)
{
if (_fallCount > 0)
{
setPositionIndex(PositionIndex(_positionIndex.x, _positionIndex.y - _fallCount));
auto delay = DelayTime::create(ONE_ACTION_TIME * maxRemovedNo);
auto show = Show::create();
auto move = MoveTo::create(ONE_ACTION_TIME, getPositionForPositionIndex(getPositionIndex()));
runAction(Sequence::create(delay, show, move, nullptr));
}
}
std::string BallSprite::getBallImageFilePath(BallType type)
{
switch (type)
{
case BallType::Red: return "red.png";
case BallType::Blue: return "blue.png";
default: return "pink.png";
}
}
Point BallSprite::getPositionForPositionIndex(PositionIndex positionIndex)
{
return Point(BALL_SIZE * (positionIndex.x - 0.5) + 1,
BALL_SIZE * (positionIndex.y - 0.5) + 1);
}
int BallSprite::generateTag(PositionIndex positionIndex)
{
return positionIndex.x * 10 + positionIndex.y;
}
BallSprite header
#include "cocos2d.h"
#define BALL_SIZE 106
#define ONE_ACTION_TIME 0.2
class BallSprite : public cocos2d::Sprite
{
public:
enum class BallType
{
Blue,
Red,
Green,
Yellow,
Purple,
Pink,
};
struct PositionIndex
{
PositionIndex()
{
x = 0;
y = 0;
}
PositionIndex(int _x, int _y)
{
x = _x;
y = _y;
}
int x;
int y;
};
BallSprite();
static BallSprite* create(BallType type, bool visible);
virtual bool init(BallType type, bool visible);
CC_SYNTHESIZE(int, _removedNo, RemovedNo);
CC_SYNTHESIZE(bool, _checkedX, CheckedX);
CC_SYNTHESIZE(bool, _checkedY, CheckedY);
CC_SYNTHESIZE(int, _fallCount, FallCount);
CC_SYNTHESIZE_READONLY(BallType, _ballType, BallType);
CC_PROPERTY(PositionIndex, _positionIndex, PositionIndex);
void setPositionIndexAndChangePosition(PositionIndex positionIndex);
void resetParams();
void resetPosition();
void removingAndFallingAnimation(int maxRemovedNo);
static std::string getBallImageFilePath(BallType type);
static cocos2d::Point getPositionForPositionIndex(PositionIndex positionIndex);
static int generateTag(PositionIndex positionIndex);
protected:
void removingAnimation(int maxRemovedNo);
void fallingAnimation(int maxRemovedNo);
};
#endif
CC_PROPERTY(int, _turnCount, TurnCount);
virtual method definition should be like this because in declaration it is constant.
int Character::getTurnCount() const
{
return _turnCount;
}
And there is problem in return type of getter method, it should be like this.
CC_PROPERTY(PositionIndex, _positionIndex, PositionIndex);
PositionIndex BallSprite::getPositionIndex() const
{
return _positionIndex;
}
EDIT
You can't directly access PositionIndex, use it with BallSprite
BallSprite::PositionIndex BallSprite::getPositionIndex() const
{
return _positionIndex;
}

STL list push_back crashes when called from a pointer list

I have a problem that arised with another question I made. I am using a list of pointers of a custom class (class that I have implemented), and the program crashes when I call this method, however, if I do not use a pointer list, it works fine. This is the function where the program crashes:
void enemy_spawner()
{
Point2D enemy_pos = Point2D(rand() % (SCREEN_WIDTH - 20) + 20, -20);
Point2D enemy_vel = Point2D(0, rand() % 4 + 1);
Sprite* enemy = new Sprite(enemy_pos, enemy_vel, enemy_image, enemy_info);
//Kamikaze* enemy = new Kamikaze(enemy_pos, enemy_vel, 0, enemy_image, enemy_info);
if (enemy_group.size() < MAX_ENEMIES)
{
// Program crashes here
enemy_group.push_back(enemy);
}
}
The enemy_group is a global variable defined as follows:
std::list<Sprite*> enemy_group;
My Sprite class is as follows (I have read that I need to have properly defined copy constructors, etc)
class Sprite
{
private:
Point2D sp_pos;
Point2D sp_vel;
SDL_Surface* sp_img;
Point2D sp_center;
Point2D sp_size;
double sp_radius;
bool sp_animated;
int sp_frames;
int sp_cur_frame;
public:
Sprite() {}
Sprite(Point2D pos, Point2D vel, SDL_Surface *img, ImageInfo info, bool animated = false, int frames = 0);
virtual void draw(SDL_Surface* screen);
virtual void update();
void setInfo (ImageInfo info);
void setPos( Point2D pos ) { sp_pos = pos; }
void setVel( Point2D vel ) { sp_vel = vel; }
void setImg (SDL_Surface* img) { sp_img = img; }
void setNextFrame() { sp_cur_frame++; }
void setFrame( int frame ) { sp_cur_frame = frame; }
void setAnimated(bool animated) { sp_animated = animated; }
void changeVelX (int c) { sp_vel.setX(c);}
void changeVelY (int c) { sp_vel.setY(c);}
void changePosX (int c) { sp_pos.setX(c);}
void changePosY (int c) { sp_pos.setY(c);}
SDL_Surface* getImg() { return sp_img; }
Point2D getPos() { return sp_pos; }
Point2D getVel() { return sp_vel; }
Point2D getCenter() { return sp_center; }
Point2D getSize() { return sp_size; }
double getRadius() { return sp_radius; }
int getCurFrame() { return sp_cur_frame; }
int getFrames() { return sp_frames; }
bool collide(Sprite &another_sprite);
virtual ~Sprite() {}
Sprite& operator=(Sprite other) {
std::swap(sp_pos, other.sp_pos);
std::swap(sp_vel, other.sp_vel);
std::swap(sp_img, other.sp_img);
std::swap(sp_center, other.sp_center);
std::swap(sp_size, other.sp_size);
std::swap(sp_radius, other.sp_radius);
std::swap(sp_animated, other.sp_animated);
std::swap(sp_frames, other.sp_frames);
std::swap(sp_cur_frame, other.sp_cur_frame);
return *this;
}
Sprite(const Sprite &obj)
{
sp_pos = obj.sp_pos;
sp_vel = obj.sp_vel;
sp_img = new SDL_Surface;
*sp_img = *obj.sp_img;
sp_center = obj.sp_center;
sp_size = obj.sp_size;
sp_radius = obj.sp_radius;
sp_animated = obj.sp_animated;
sp_frames = obj.sp_frames;
sp_cur_frame = obj.sp_cur_frame;
}
};
If it matters, I am using gcc compiler (Actually my IDE is codeblocks). The question is, why does the program crash? How do I solve this issue?
Thanks in advance