custom CCNode runAction cannot execute in Cocos2d-x? - c++

I have a class that inherits from CCNode. HcharacterDrawnode contains a group of StrokeDrawnode which is another custom CCNode. Now I add (m_HDrawnode)HcharacterDrawnode to a layer and runAction.
CCAction* place = CCMoveTo::create(2.0,ccp(0,0));
m_HDrawnode->runAction(place);
But nothing happened. I have checked some webpage. Someone said it may related to m_bRunning , however I cannot find a place to set this variable.
HcharacterDrawnode.h
class HcharacterDrawnode : public CCNode
{
public:
HcharacterDrawnode();
~HcharacterDrawnode();
CREATE_FUNC(HcharacterDrawnode);
virtual bool init();
virtual void onEnter();
virtual void onExit();
virtual void draw();
void addPoint(CCPoint point);
void addStroke(Stroke s);
void removeLastStroke();
CC_SYNTHESIZE_RETAIN(CCArray*,strokeDrawlist,StrokeDrawnodeList);
private:
};
HcharacterDrawnode.cpp
#include "HcharacterDrawnode.h"
HcharacterDrawnode::HcharacterDrawnode():strokeDrawlist(NULL)
{
}
HcharacterDrawnode::~HcharacterDrawnode()
{
CC_SAFE_RELEASE(strokeDrawlist);
}
void HcharacterDrawnode::onEnter(){
CCNode::onEnter();
}
void HcharacterDrawnode::onExit(){
CCNode::onExit();
}
bool HcharacterDrawnode::init(){
this->setStrokeDrawnodeList(CCArray::create());
return true;
}
void HcharacterDrawnode::draw(){
CCObject* ob;
CCARRAY_FOREACH(strokeDrawlist,ob){
((StrokeDrawnode*)(ob))->draw();
}
}
void HcharacterDrawnode::addPoint(CCPoint point){
StrokeDrawnode* t = (StrokeDrawnode*)(strokeDrawlist->objectAtIndex(strokeDrawlist->count()-1));
t->addPoint(point);
}
void HcharacterDrawnode::addStroke(Stroke s){
strokeDrawlist->addObject(StrokeDrawnode::create(s));
}
void HcharacterDrawnode::removeLastStroke(){
strokeDrawlist->removeLastObject();
}
StrokeDrawnode.h
class StrokeDrawnode : public CCNode
{
public:
StrokeDrawnode();
StrokeDrawnode(Stroke stro);
~StrokeDrawnode();
static StrokeDrawnode* create(Stroke stro);
Stroke stroke;
ccColor4B mcolor;
virtual void onEnter();
virtual void onExit();
virtual void draw();
int visibleIndex;
void addPoint(CCPoint point);
private:
};
StrokeDrawnode.cpp
#include "StrokeDrawnode.h"
StrokeDrawnode::StrokeDrawnode()
{
}
StrokeDrawnode::StrokeDrawnode(Stroke stro){
this->stroke = stro;
}
void StrokeDrawnode::onEnter(){
CCNode::onEnter();
}
void StrokeDrawnode::onExit(){
CCNode::onExit();
}
StrokeDrawnode* StrokeDrawnode::create(Stroke stro){
StrokeDrawnode* pRet = new StrokeDrawnode(stro);
if (pRet && pRet->init())
{
pRet->autorelease();
return pRet;
}else{
delete pRet;
pRet = NULL;
return NULL;
}
}
StrokeDrawnode::~StrokeDrawnode()
{
}
void StrokeDrawnode::draw(){
//CCLog("StrokeDrawnode::draw");
glLineWidth(6.0f);
ccDrawColor4F(0,0,0,1);
// glEnable(GL_LINE_SMOOTH);
CCPoint pre = stroke.pointList[0];
for (int i = 1; i< stroke.pointCount; i++)
{
ccDrawLine(pre,stroke.pointList[i]);
pre = stroke.pointList[i];
}
// glDisable(GL_LINE_SMOOTH);
}
void StrokeDrawnode::addPoint(CCPoint point){
this->stroke.addPoint(point);
}

You draw your StrokeNodes but you forgot to call the CCNode::draw() function for HcharacterDrawnode:
void HcharacterDrawnode::draw(){
CCNode::draw();
CCObject* ob;
CCARRAY_FOREACH(strokeDrawlist,ob){
((StrokeDrawnode*)(ob))->draw();
}
}
Also if you overwrite init() in your class you should call init of your parent:
bool HcharacterDrawnode::init(){
if(!CCNode::init())
return false;
this->setStrokeDrawnodeList(CCArray::create());
return true;
}

Related

How can I use a QMap to store and look at my data?

I am new to QT started to try out some things with QMap as it seems like a useful tool. I already read some other forum threads but I wasnt able to answer my question. The user is supposed to add and edit different shapes via the GUI. For the shapes I first wrote an abstract base class:
#ifndef BASE_H
#define BASE_H
#include <QListWidget>
#include <QMap>
class Base
{
protected:
QVariantMap m_properties;
QString m_key;
void setKey(const QString& key){
this->m_key=key;
}
public:
Base(){}
virtual ~Base(){}
QString key(){
return m_key;
}
void setProperty(QString key, QVariant variant){
m_properties[key]=variant;
}
virtual void toRTC()=0;
};
#endif // BASE_H
one example of a subclass is an ellipse with the following cpp file:
#include "ellipse.h"
Ellipse::Ellipse(int Start_x, int Start_y, int Rad_x, int Rad_y): rad_x(Rad_x), rad_y(Rad_y), start_x(Start_x), start_y(Start_y)
{
this->setKey("ellipse");
this->setProperty("radX", rad_x);
this->setProperty("radY", rad_y);
this->setProperty("startX", start_x);
this->setProperty("startY", start_y);
}
void Ellipse::set_rad_x(int rad_x)
{
Base::setProperty("radX", rad_x);
}
void Ellipse::set_rad_y(int rad_y)
{
Base::setProperty("radY", rad_y);
}
void Ellipse::set_start_x(int start_x)
{
Base::setProperty("startX", start_x);
}
void Ellipse::set_start_y(int start_y)
{
Base::setProperty("startY", start_y);
}
int Ellipse::get_rad_x()
{
return m_properties["radX"].toInt();
}
int Ellipse::get_rad_y()
{
return m_properties["radY"].toInt();
}
int Ellipse::get_start_x()
{
return m_properties["startX"].toInt();
}
int Ellipse::get_start_y()
{
return m_properties["startY"].toInt();
}
First off, is this a correct approach for the cpp file? I feel my approach is vary laborious.
In my main window file I thought about storing my data in a simple Vector QVector<Base *> data_storage;
Ellipse *e_values = new Ellipse(ui->Ellipse_Value_start_x->value(),ui->Ellipse_Value_start_y->value(), ui->Ellipse_Value_rad_x->value(),ui->Ellipse_Value_rad_y->value());
data_storage.append(e_values);
To load the data, I thought it would be a good idea to use the key to check which object of data_storage I want to load, but I don't really know how I can access the data which is connected to my key.
if(data_storage[t]->key()=="ellipse"){
ui->Ellipse_Value_rad_x->setValue(data_storage[t]->) //how can I access the correct data?
}
I feel like I messed up the entire approach, like how to properly use keys, so how would I do that?
You need to declare all the behaviours you need in the base class. I don't see the need to have Base hold the data.
E.g. if you need to be able to read and write the UI, there should be methods to do that.
class Base
{
public:
virtual ~Base() = default;
virtual void toRTC() = 0;
virtual QVariantMap properties() const = 0;
virtual void writeUI(form_t * ui) const = 0;
virtual void readUI(const form_t * ui) = 0;
};
class Ellipse : public Base
{
int start_x;
int start_y;
int rad_x;
int rad_y;
public:
void toRTC() final { /* ??? */ }
QVariantMap properties() const final {
return { { "radX", rad_x }, { "radY", rad_y },
{ "startX", start_x }, { "startY", start_y } };
}
void writeUI(form_t * ui) const final {
ui->Ellipse_Value_rad_x->setValue(rad_x);
ui->Ellipse_Value_rad_y->setValue(rad_y);
ui->Ellipse_Value_start_x->setValue(start_x);
ui->Ellipse_Value_start_y->setValue(start_y);
}
void readUI(const form_t * ui) final {
rad_x = ui->Ellipse_Value_rad_x->value().toInt();
rad_y = ui->Ellipse_Value_rad_y->value().toInt();
start_x = ui->Ellipse_Value_start_x->value().toInt();
start_y = ui->Ellipse_Value_start_y->value().toInt();
}
};
If you don't want to tie your shapes to the UI, you could define a visitor interface, with a visit method for each shape type.
class ShapeVisitor
{
virtual void accept(Ellipse * ellipse) = 0;
/* virtual void accept(Rectangle * rectangle) = 0; // etc.. */
};
class Base
{
public:
virtual ~Base() = default;
virtual void toRTC() = 0;
virtual QVariantMap properties() const = 0;
virtual void visit(ShapeVisitor & visitor) = 0;
};
class Ellipse : public Base
{
public:
int start_x;
int start_y;
int rad_x;
int rad_y;
void toRTC() final { /* ??? */ }
QVariantMap properties() const final {
return { { "radX", rad_x }, { "radY", rad_y },
{ "startX", start_x }, { "startY", start_y } };
}
void visit(ShapeVisitor & visitor) final {
visitor.accept(this); // calls visitor::accept(Ellipse *)
}
};
class UIReadVisitor : public ShapeVisitor
{
form_t * ui
void accept(Ellipse * ellipse) final {
ellipse->rad_x = ui->Ellipse_Value_rad_x->value().toInt();
ellipse->rad_y = ui->Ellipse_Value_rad_y->value().toInt();
ellipse->start_x = ui->Ellipse_Value_start_x->value().toInt();
ellipse->start_y = ui->Ellipse_Value_start_y->value().toInt();
}
}
class UIWriteVisitor : public ShapeVisitor
{
form_t * ui;
void accept(Ellipse * ellipse) final {
ui->Ellipse_Value_rad_x->setValue(ellipse->rad_x);
ui->Ellipse_Value_rad_y->setValue(ellipse->rad_y);
ui->Ellipse_Value_start_x->setValue(ellipse->start_x);
ui->Ellipse_Value_start_y->setValue(ellipse->start_y);
}
}

'Read access violation' exception in an SFML/C++ project:

I'm recently learning to make a 2d game in SFML using a tutorial series on youtube by Suraj Sharma(Video 57):
https://www.youtube.com/watch?v=kwd_AVCkvXE&list=PL6xSOsbVA1ebkU66okpi-KViAO8_9DJKg&index=57
His Source Code:
https://github.com/Headturna/SFML_RPG
Right now he's teaching me to symplify the game's menu system by making a mini class 'StateData' in the parent class 'State' so any inherited class can access 'State' parameters via 'StateData'(Ex:MainMenu(StData* Stdata){}).
After debugging the game seems to runs fine.But everytime i click on something on the menu(start,settings,etc...) a 'Read access violation:Stdata was nullptr' occurs in the 'State' class constructor.
Here's the code:
State.h:
#pragma once
#ifndef STATE_H
#define STATE_H
#include "Player.h"
#include "GrphSettings.h"
class Player;
class GrphSettings;
class State;
class StData {
public:
StData(){}
//Vars
float GridSize;
sf::RenderWindow* Window;
GrphSettings* GSettings;
std::map<std::string, int>* SupportedKeys;
std::stack<State*>* states;
};
class State
{
private:
protected:
StData* Stdata;
std::stack<State*>* states;
sf::RenderWindow* window;
std::map<std::string, int>* SupportedKeys ;
std::map<std::string, int> Keybinds;
bool quit;
bool pause;
float keyTime;
float keyTimeMax;
float GridSize;
sf::Vector2i MousePosScr;
sf::Vector2i MousePosWind;
sf::Vector2f MousePosView;
//Resources
std::map<std::string,sf::Texture> texture;
//Funcs
virtual void InitKeybinds() = 0;
public:
State(StData* Stdata);
virtual~State();
//Access
const bool getKeytime();
const bool& getquit()const;
//Funcs
void Endstate();
void PauseSt();
void UnPauseSt();
virtual void UpdateInput(const float& dt) = 0;
virtual void UpdateMousePos();
virtual void UpdateKeyTime(const float& dt);
virtual void Update(const float& dt) = 0;
virtual void Render(sf::RenderTarget* target = nullptr) = 0;
};
#endif // !1
State.cpp:
#include "pch.h"
#include "State.h"
State::State(StData* Stdata)
{
this->Stdata = Stdata;
this->window = Stdata->Window;
this->SupportedKeys = Stdata->SupportedKeys;
this->states = Stdata->states;
this->quit = false;
this->pause = false;
this->keyTime = 0.f;
this->keyTimeMax = 10.f;
this->GridSize = Stdata->GridSize;
}
State::~State()
{
}
//Access
const bool State::getKeytime()
{
if (this->keyTime >= this->keyTimeMax) {
this->keyTime = 0.f;
return true;
}
return false;
}
const bool& State::getquit() const
{
// TODO: insert return statement here
return this->quit;
}
//Funcs
void State::Endstate()
{
this->quit = true;
}
void State::PauseSt()
{
this->pause = true;
}
void State::UnPauseSt()
{
this->pause = false;
}
void State::UpdateMousePos()
{
this->MousePosScr = sf::Mouse::getPosition();
this->MousePosWind = sf::Mouse::getPosition(*this->window);
this->MousePosView = this->window->mapPixelToCoords(sf::Mouse::getPosition(*this->window));
}
void State::UpdateKeyTime(const float& dt)
{
if (this->keyTime < this->keyTimeMax)
this->keyTime += 100.f * dt;
}
Every button one the menu(start,exit...)is an inherited state from 'State' class.This is,for example,the 'Edit' state.
Edit.h:
#pragma once
#ifndef EDIT_H
#define EDIT_H
#include "State.h"
#include "Gui.h"
#include "PauseMenu.h"
#include "TileMap.h"
class State;
class Gui;
class PauseMenu;
class TileMap;
class Edit:public State
{
private:
//Vars
sf::Font Fnt;
PauseMenu* PMenu;
std::map<std::string, gui::Button*> buttons;
TileMap Map;
//Functions
void InitVars();
void InitBackGrnd();
void InitFonts();
void InitKeybinds();
void InitPauseMenu();
void InitBtn();
public:
Edit(StData* Stdata);
virtual~Edit();
//Functions
void UpdateInput(const float& dt);
void Update(const float& dt);
void UpdatePButtons();
void UpdateBtn();
void Endstate();
void RenderBtn(sf::RenderTarget& target);
void Render(sf::RenderTarget* target = nullptr);
};
#endif // ! EDIT_H
Edit.cpp:
#include "pch.h"
#include "Edit.h"
void Edit::InitVars()
{
}
void Edit::InitBackGrnd()
{
}
void Edit::InitFonts()
{
if (!this->Fnt.loadFromFile("Fonts/SPACEMAN.ttf")) {
throw("Error::Edit::Couldn't load font");
}
}
void Edit::InitKeybinds()
{
std::ifstream ifs("Config/EditKeys.ini");
if (ifs.is_open()) {
std::string key = "";
std::string key2 = "";
int keyval = 0;
while (ifs >> key >> key2)
{
this->Keybinds[key] = this->SupportedKeys->at(key2);
}
}
ifs.close();
this->Keybinds["Close"] = this->SupportedKeys->at("ESC");
this->Keybinds["Left"] = this->SupportedKeys->at("A");
this->Keybinds["Right"] = this->SupportedKeys->at("D");
this->Keybinds["Up"] = this->SupportedKeys->at("W");
this->Keybinds["Down"] = this->SupportedKeys->at("S");
}
void Edit::InitPauseMenu()
{
this->PMenu = new PauseMenu(*this->window, this->Fnt);
this->PMenu->addButtons("Quit", 800.f, "Quit");
}
void Edit::InitBtn()
{
}
Edit::Edit(StData* Stdata)
:State(Stdata)
{
this->InitVars();
this->InitBackGrnd();
this->InitFonts();
this->InitKeybinds();
this->InitPauseMenu();
this->InitBtn();
}
Edit::~Edit()
{
auto it = this->buttons.begin();
for (it = this->buttons.begin(); it != this->buttons.end(); ++it) {
delete it->second;
}
delete this->PMenu;
}
//Funcs
void Edit::UpdateInput(const float& dt)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key(this->Keybinds.at("Close")))
&& this->getKeytime()) {
if (!this->pause)
this->PauseSt();
else this->UnPauseSt();
}
}
void Edit::Update(const float& dt)
{
this->UpdateMousePos();
this->UpdateKeyTime(dt);
this->UpdateInput(dt);
if (!this->pause) {//Unpaused
this->UpdateBtn();
}
else {//Paused
this->PMenu->Update(this->MousePosView);
this->UpdatePButtons();
}
this->UpdateBtn();
std::cout << this->MousePosView.x << " " << this->MousePosView.y << "\r";
}
void Edit::UpdatePButtons()
{
if (this->PMenu->isPressed("Quit"))
this->Endstate();
}
void Edit::UpdateBtn()
{ //Update buttons and handle their functions
for (auto& it : this->buttons) {
it.second->Update(MousePosView);
}
}
void Edit::Endstate()
{
std::cout << "Ending State" << "\n";
}
void Edit::RenderBtn(sf::RenderTarget& target)
{
for (auto& it : this->buttons) {
it.second->Render(target);
}
}
void Edit::Render(sf::RenderTarget* target)
{
if (!target)
target = this->window;
this->RenderBtn(*target);
this->Map.Render(*target);
if (this->pause) {//Pause Menu
this->PMenu->Render(*target);
}
sf::Text MText;
MText.setPosition(this->MousePosView);
MText.setFont(this->Fnt);
MText.setCharacterSize(12);
std::stringstream ss;
ss << this->MousePosView.x << ' ' << this->MousePosView.y;
MText.setString(ss.str());
target->draw(MText);
}
Can anyone help me ?

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

Returning a polymorphic class

i'm creating a little xbox application and for the beginning it should detect what game is currently running and then bypass and/or launch a program. Since i recently learned polymorphism i thought i could implement it here to gain efficiency. Below is my code (not as efficient as i thought it would be):
DWORD(__cdecl *XamGetCurrentTitleID)() = (DWORD(__cdecl *)())ResolveFunction("xam.xex", 0x1CF); // Resolves current Game ID
typedef enum _XBOX_GAMES : DWORD // Enum that holds Game IDs
{
BOOT_UP = 0x00000000,
DASHBOARD = 0xFFFE07D1,
FREESTYLEDASH = 0xF5D20000,
COD_WORLD_AT_WAR = 0x4156081C,
COD_MODERN_WARFARE = 0x415607E6,
COD_MODERN_WARFARE_2 = 0x41560817,
COD_BLACK_OPS_1 = 0x41560855,
COD_MODERN_WARFARE_3 = 0x415608CB,
COD_BLACK_OPS_2 = 0x415608C3,
COD_GHOSTS = 0x415608fC,
COD_ADVANCED_WARFARE = 0x41560914,
COD_BLACK_OPS_3 = 0x4156091D,
DESTINY = 0x415608F8,
GTAV = 0x545408A7
} XBOX_GAMES;
DWORD GameChecker()
{
DWORD lastID = NULL;
Game *game;
AW aw; BO1 bo1; BO2 bo2; BO3 bo3; Ghosts ghosts; MW2 mw2; MW3 mw3; Dashboard dashboard;
for (;;)
{
if (XamGetCurrentTitleID() != lastID)
{
switch (XamGetCurrentTitleID())
{
case BOOT_UP:
// nothing
break;
case DASHBOARD:
game = &dashboard;
game->Launch();
break;
case COD_MODERN_WARFARE_2:
game = &mw2;
game->Launch();
break;
case COD_MODERN_WARFARE_3:
game = &mw3;
game->Launch();
break;
case COD_GHOSTS:
game = &ghosts;
game->Bypass();
game->Launch();
break;
case COD_BLACK_OPS_1:
game = &bo1;
game->Launch();
break;
case COD_BLACK_OPS_2:
game = &bo2;
game->Bypass();
break;
case COD_BLACK_OPS_3:
game = &bo3;
game->Bypass();
break;
case COD_ADVANCED_WARFARE:
game = &aw;
game->Bypass();
game->Launch();
break;
}
lastID = XamGetCurrentTitleID();
}
}
return 0;
}
As you can see i could've moved the game->Launch() and game->Bypass() outside of the switch statement to have less code and only call it once, but i didn't knew how i could determine when a game needs a bypass and/or launch. This is my GameClass:
class Game
{
public:
virtual void Bypass() { }
virtual void Launch() { }
};
And this is the class of an example game:
// needs bypass and launch called
class AW : public Game
{
public:
void Bypass()
{
// bypass
}
void Launch()
{
Sleep(500);
XNotifyUI(L"AW - Loaded!");
}
};
I would like to know if there is a way to do something like this:
DWORD GameChecker()
{
DWORD lastID = NULL;
Game *game;
for (;;)
{
if (XamGetCurrentTitleID() != lastID)
{
switch (XamGetCurrentTitleID())
{
case BOOT_UP:
// nothing
break;
default:
game = &functionThatReturnsClassBasedOnGame(XamGetCurrentTitleID()); // I don't know how to code such an function
break;
}
if (game->needsBypass)
game->Bypass();
if (game->needsLaunch)
game->Launch();
lastID = XamGetCurrentTitleID();
}
}
return 0;
}
Any help is greatly appreciated! Thanks for your time.
A simple way to accomplish your example is like this:
const int NEEDS_BYPASS = 1;
const int NEEDS_LAUNCH = 2;
class Game
{
public:
virtual ~Game() { }
virtual int getFeatures() const { return 0; }
virtual void Bypass() { }
virtual void Launch() { }
};
class Game_Dashboard : public Game
{
public:
int getFeatures() const { return NEEDS_LAUNCH; }
void Launch() {
Sleep(500);
XNotifyUI(L"Dashboard - Loaded!");
}
};
class Game_ModernWarfare2 : public Game
{
public:
int getFeatures() const { return NEEDS_LAUNCH; }
void Launch() {
Sleep(500);
XNotifyUI(L"MW2 - Loaded!");
}
};
class Game_ModernWarfare3 : public Game
{
public:
int getFeatures() const { return NEEDS_LAUNCH; }
void Launch() {
Sleep(500);
XNotifyUI(L"MW3 - Loaded!");
}
};
class Game_Ghosts : public Game
{
public:
int getFeatures() const { return NEEDS_BYPASS | NEEDS_LAUNCH; }
void Bypass() {
// bypass...
}
void Launch() {
Sleep(500);
XNotifyUI(L"Ghosts - Loaded!");
}
};
class Game_BlackOpts1 : public Game
{
public:
int getFeatures() const { return NEEDS_LAUNCH; }
void Launch() {
Sleep(500);
XNotifyUI(L"BO1 - Loaded!");
}
};
class Game_BlackOpts2 : public Game
{
public:
int getFeatures() const { return NEEDS_BYPASS; }
void Bypass() {
// bypass...
}
};
class Game_BlackOpts3 : public Game
{
public:
int getFeatures() const { return NEEDS_BYPASS; }
void Bypass() {
// bypass...
}
};
class Game_AdvancedWarfare : public Game
{
public:
int getFeatures() const { return NEEDS_BYPASS | NEEDS_LAUNCH; }
void Bypass() {
// bypass
}
void Launch() {
Sleep(500);
XNotifyUI(L"AW - Loaded!");
}
};
Game* getGame(DWORD ID)
{
switch (ID)
{
case DASHBOARD:
return new Game_Dashboard;
case COD_MODERN_WARFARE_2:
return new Game_ModernWarfare2;
case COD_MODERN_WARFARE_3:
return new Game_ModernWarfare3;
case COD_GHOSTS:
return new Game_Ghosts;
case COD_BLACK_OPS_1:
return new Game_BlackOpts1;
case COD_BLACK_OPS_2:
return new Game_BlackOpts2;
case COD_BLACK_OPS_3:
return new Game_BlackOpts3;
case COD_ADVANCED_WARFARE:
return new Game_AdvancedWarfare;
}
return NULL;
}
DWORD GameChecker()
{
DWORD currentID, lastID = 0;
Game *game;
do
{
currentID = XamGetCurrentTitleID();
if (currentID != lastID)
{
lastID = currentID;
game = getGame(currentID);
if (game)
{
if (game->getFeatures() & NEEDS_BYPASS)
game->Bypass();
if (game->getFeatures() & NEEDS_LAUNCH)
game->Launch();
delete game;
}
}
}
while (true);
return 0;
}
However, a better use of polymorphism would to be more like this instead:
class Game
{
public:
virtual ~Game() { }
};
class CanBypass
{
public:
virtual void Bypass() = 0;
};
class CanLaunch
{
public:
virtual void Launch() = 0;
};
class Game_Dashboard : public Game, public CanLaunch
{
public:
void Launch() {
Sleep(500);
XNotifyUI(L"Dashboard - Loaded!");
}
};
class Game_ModernWarfare2 : public Game, public CanLaunch
{
public:
void Launch() {
Sleep(500);
XNotifyUI(L"MW2 - Loaded!");
}
};
class Game_ModernWarfare3 : public Game, public CanLaunch
{
public:
void Launch() {
Sleep(500);
XNotifyUI(L"MW3 - Loaded!");
}
};
class Game_Ghosts : public Game, public CanBypass, public CanLaunch
{
public:
void Bypass() {
// bypass...
}
void Launch() {
Sleep(500);
XNotifyUI(L"Ghosts - Loaded!");
}
};
class Game_BlackOpts1 : public Game, public CanLaunch
{
public:
void Launch() {
Sleep(500);
XNotifyUI(L"BO1 - Loaded!");
}
};
class Game_BlackOpts2 : public Game, public CanBypass
{
public:
void Bypass() {
// bypass...
}
};
class Game_BlackOpts3 : public Game, public CanBypass
{
public:
void Bypass() {
// bypass...
}
};
class Game_AdvancedWarfare : public Game, public CanBypass, public CanLaunch
{
public:
void Bypass() {
// bypass
}
void Launch() {
Sleep(500);
XNotifyUI(L"AW - Loaded!");
}
};
Game* getGame(DWORD ID)
{
switch (ID)
{
case DASHBOARD:
return new Game_Dashboard;
case COD_MODERN_WARFARE_2:
return new Game_ModernWarfare2;
case COD_MODERN_WARFARE_3:
return new Game_ModernWarfare3;
case COD_GHOSTS:
return new Game_Ghosts;
case COD_BLACK_OPS_1:
return new Game_BlackOpts1;
case COD_BLACK_OPS_2:
return new Game_BlackOpts2;
case COD_BLACK_OPS_3:
return new Game_BlackOpts3;
case COD_ADVANCED_WARFARE:
return new Game_AdvancedWarfare;
}
return NULL;
}
DWORD GameChecker()
{
DWORD currentID, lastID = 0;
Game *game;
CanBypass *bypasser;
CanLaunch *launcher;
do
{
currentID = XamGetCurrentTitleID();
if (currentID != lastID)
{
lastID = currentID;
game = getGame(currentID);
if (game)
{
bypasser = dynamic_cast<CanBypass*>(game);
if (bypasser)
bypasser->Bypass();
launcher = dynamic_cast<CanLaunch*>(game);
if (launcher)
launcher->Launch();
delete game;
}
}
}
while (true);
return 0;
}

Inheritance container of Parent type cannot hold children?

I have a parent Menu class and children MainMenu, SettingsMenu, PauseMenu, etc.
I want to be able to hold them all in a vector...
I can do
std::vector<Menu*> myVector;
and then typecast each one when I push_back in the vector
pMainMenu = new MainMenu;
myVector.push_back((Menu*)pMainMenu);
and it compiles but something's not working right down the road...
It doesn't have to be a vector but I want to be able to iterate through them.
I'm always trying to implement the Observer pattern and I'm having difficulties with inheritance as well in that area!
For the Observer pattern I have an Observer class and Game inherits Observer. I have a Subject class inherited by InputComponent. Subject has a vector of Observer* called vObserver and a function called addObserver(Observer* observer) and adds the passed pointer in vObserver. I also have a function called Notify(event e), which iterates through vObserver and calls their onNotify functions.
So in Game, I have an InputComponent instance called inputComp. I do inputComp.addObserver(this) and inputComp.vObserver.size() is 1. Good. I have a call to Notify in InputComponent which does get triggered, but when it executes, the vObserver.size inside Subject is 0... idk what I'm doing wrong
EDIT:
class Menu
{
public:
virtual void draw() = 0;
virtual void onMouseMove(int x, int y) = 0;
virtual void onMouseButton(int button, bool is_down) = 0;
friend class InputComponent;
friend class MainMenuInputComponent;
protected:
SDL_Renderer* _renderer;
std::vector<Button> vButton;
std::vector<SDL_Texture *> vTexture;
};
class MainMenu : public Menu
{
public:
MainMenu(SDL_Renderer* renderer);
virtual void draw();
virtual void onMouseMove(int x, int y);
virtual void onMouseButton(int button, bool is_down);
friend class MainMenuInputComponent;
};
class InputComponent: public Subject
{
public:
virtual void processInput()
{}
static bool isMouseWithin(int mouseX, int mouseY, SDL_Rect rect)
{
if (mouseX >= rect.x && mouseX <= rect.x + rect.w && mouseY >= rect.y && mouseY <= rect.y + rect.h)
return true;
else
return false;
}
};
class MainMenuInputComponent : public InputComponent
{
public:
MainMenuInputComponent(MainMenu* owner)
:_owner(owner){}
virtual void processInput();
virtual void onBtnClick(std::string btnName);
MainMenu* _owner;
};
class Game : public Observer
{
public:
Game();
void initSDL();
void initGame();
void processGameInput();
void renderGame();
void update();
virtual void onNotify(Events e);
SDL_Window* myWindow;
SDL_Renderer* myRenderer;
std::vector<MainMenuInputComponent> vInputComponent;
std::stack<MainMenu*> menuStack;
};
Game::Game()
{
initSDL();
initGame();
}
void Game::initGame()
{
//Create the Main Menu
MainMenu* pMainMenu = new MainMenu(myRenderer);
//Add menu to the stack
menuStack.push((pMainMenu));
//Add it's components to respective arrays
MainMenuInputComponent inputComp = MainMenuInputComponent(pMainMenu);
vInputComponent.push_back(inputComp);
//Add Observer/Subject relationship.
inputComp.addObserver((Observer*)this);
int bob = (int)inputComp.vObserver.size(); //to see if size went up
}
void Game::processGameInput()
{
if (!menuStack.empty())
{
for (int i = 0; i < (int)vInputComponent.size(); i++)
{
//Menu* compOwner = (Menu*)(vInputComponent[i]._owner);
//std::unique_ptr<Menu, std::default_delete<Menu>> a = menuStack.top();
if ((vInputComponent[i]._owner) == menuStack.top())
{
vInputComponent[i].processInput();
}
//vInputComponent[i].processInput();
}
}
else
for (int i = 0; i < (int)vInputComponent.size(); i++)
{
vInputComponent[i].processInput();
}
}
void Game::renderGame()
{
SDL_RenderClear(myRenderer);
MainMenu* bob = menuStack.top();
if (!menuStack.empty())
(menuStack.top())->draw();
SDL_RenderPresent(myRenderer);
}
void Game::onNotify(Events event)
{
switch (event)
{
case POP_MENU:
menuStack.pop();
break;
case GOTO_SETTINGS:
//Menu* pSettingsMenu =(Menu*)(new SettingsMenu(myRenderer));
//menuStack.push(std::unique_ptr<Menu>(pSettingsMenu));
break;
// Handle other events, and update heroIsOnBridge_...
}
}
class Subject
{
public:
void addObserver(Observer* observer)
{
vObserver.push_back(observer);
}
void removeObserver(Observer* observer)
{
//vObserver.erase(std::find(vObserver.begin(), vObserver.end(), 8));
}
std::vector<Observer*> vObserver;
protected:
void notify(Events e)
{
for (int i = 0; i < (int)vObserver.size(); i++)
{
vObserver[i]->onNotify(e);
}
}
};
class Observer
{
public:
virtual ~Observer() {}
virtual void onNotify(Events e) = 0;
};
If MainMenu publically inherits from Menu, then you shouldn't even need to type cast the pointer to MainMenu to Menu at all. That is, this should work:
class Menu {};
class MainMenu : public Menu {};
std::vector<Menu*> myVector;
MainMenu* pMainMenu = // ...
myVector.push_back(pMainMenu);
However, what you really should be doing is using something like shared_ptr or unique_ptr. Here's a more complete example, using shared_ptr:
#include <vector>
#include <memory>
#include <iostream>
class Menu
{
public:
virtual void on_event() = 0;
// virtual destructor needed for polymorphic base classes
virtual ~Menu() {}
};
class MainMenu : public Menu
{
public:
virtual void on_event()
{
std::cout << "Hello world! from MainMenu" << std::endl;
}
};
class PauseMenu : public Menu
{
public:
virtual void on_event()
{
std::cout << "Hello world! from PauseMenu" << std::endl;
}
};
class SettingsMenu : public Menu
{
public:
virtual void on_event()
{
std::cout << "Hello world! from SettingsMenu" << std::endl;
}
};
int main()
{
std::vector<std::shared_ptr<Menu>> myVector;
myVector.push_back(std::make_shared<MainMenu>());
myVector.push_back(std::make_shared<PauseMenu>());
myVector.push_back(std::make_shared<SettingsMenu>());
for(auto& menu : myVector) {
menu->on_event();
}
return 0;
}
Expected output:
Hello world! from MainMenu
Hello world! from PauseMenu
Hello world! from SettingsMenu
This should also work and gives you the bonus feature of taking care of memory management for you.