The following code works:
class Handler {
public:
Application* application;
bool handle(sf::Event&);
};
class TestApp {
public:
TestApp();
bool running;
void run();
void attach_handler(Handler*);
std::forward_list<std::unique_ptr<Handler>> handlerFList;
};
TestApp::TestApp() {
}
void Application::run() {
while (running) {
sf::Event event;
while (window->pollEvent(event)) {
for (auto& handler : handlerFList) {
if (handler->handle(event)) {
break;
}
}
}
}
}
void Application::attach_handler(Handler* handler) {
handlerFList.push_front(std::unique_ptr<Handler>(std::move(handler)));
handler->application = this;
}
int main() {
sqt::TestApp app;
sqe::HandlerClose hc;
app.attach_handler(&hc);
app.run();
return 0;
}
But this one does not:
class Handler {
public:
Application* application;
bool handle(sf::Event&);
};
class TestApp {
public:
TestApp();
bool running;
void run();
void attach_handler(Handler*);
std::forward_list<std::unique_ptr<Handler>> handlerFList;
};
TestApp::TestApp() {
sqe::HandlerClose hc;
attach_handler(&hc);
}
void TestApp::run() {
while (running) {
sf::Event event;
while (window->pollEvent(event)) {
for (auto& handler : handlerFList) {
if (handler->handle(event)) { // SEGFAULTS
break;
}
}
}
}
}
void TestApp::attach_handler(Handler* handler) {
handlerFList.push_front(std::unique_ptr<Handler>(std::move(handler)));
handler->application = this;
}
int main() {
sqt::TestApp app;
app.run();
return 0;
}
It segfaults where marked. I can't work out what I'm doing wrong. Isn't std::move supposed to move the base object? What it seems like is happening is that once TestApp's constructor finishes, the object is getting deleted. How can I fix this?
Related
I want a Timer class with reset method. When the reset method is called, std::function<void(void)> func execution will be postponed for next interval milliseconds. Here is my code (obtained from C++ 11: Calling a C++ function periodically) (the reset method doesn't work correctly):
// .h
class Timer
{
public:
Timer(const int interval, const std::function<void(void)>& func);
~Timer();
void stop();
void start();
bool is_running() const noexcept;
void reset();
private:
const int interval_;
const std::function<void(void)> func_;
std::atomic<bool> execute_;
std::thread thd_;
};
//////////////////////////////////////////////////////////////////////////////////
// .cpp
utl::Timer::Timer(const int interval, const std::function<void(void)>& func) :
func_{ func },
interval_{ interval },
execute_(false)
{
}
utl::Timer::~Timer()
{
if (execute_.load(std::memory_order_acquire)) {
stop();
};
}
void utl::Timer::stop()
{
execute_.store(false, std::memory_order_release);
if (thd_.joinable())
thd_.join();
}
void utl::Timer::start()
{
if (execute_.load(std::memory_order_acquire)) {
stop();
};
execute_.store(true, std::memory_order_release);
thd_ = std::thread([this]()
{
while (execute_.load(std::memory_order_acquire)) {
func_();
std::this_thread::sleep_for(
std::chrono::milliseconds(interval_));
}
});
}
bool utl::Timer::is_running() const noexcept {
return (execute_.load(std::memory_order_acquire) &&
thd_.joinable());
}
void utl::Timer::reset()
{
stop();
start();
}
//////////////////////////////////////////////////////////////////////////////////
// a main function for test
#include <iostream>
using namespace std;
using namespace utl;
int main()
{
Timer timer(5000, []() {
cout << "reached!" << endl;
});
timer.start();
while (true)
{
cout << "working ...";
this_thread::sleep_for(std::chrono::seconds(1));
timer.reset();
}
}
This output of the main function (it is expected that string "reached!" not showed in cmd):
working ... reached! working ... reached! working
... reached! . . .
My problems are:
after calling start the func object is called without any delay.
reset method does not work
I'm using Visual Studio 2017. I have a class defined thusly:
class Timer
{
friend class TimerFactory;
protected:
explicit Timer(std::function<void()>theCallback, uint theTimer, std::thread::id theThread, bool theImmediate, bool recurring) :
myCallback(theCallback), myTimer(theTimer), myThread(theThread), isImmediate(theImmediate), isRecurring(recurring), myWorkComplete(false)
{
}
Timer(const Timer& orig)
{
myCallback = orig.myCallback;
myTimer = orig.myTimer;
myThread = orig.myThread;
myWorkComplete = orig.myWorkComplete;
isImmediate = orig.isImmediate;
isRecurring = orig.isRecurring;
}
public:
~Timer()
{
}
void Start()
{
Run();
}
private:
std::function<void()>myCallback;
uint myTimer;
std::thread::id myThread;
bool myWorkComplete;
bool isImmediate;
bool isRecurring;
void Run();
};
void Timer::Run()
{
std::chrono::nanoseconds ms(myTimer);
begin: std::this_thread::sleep_for(ms);
if (!(myCallback == nullptr))
{
myCallback();
}
myWorkComplete = true;
if (isRecurring)
{
goto begin;
}
if (!isImmediate)
{
TimerFactory::GetInst()->TimerFired(myThread, this);
}
}
These guys are created like this:
std::function<void()> run_callback = std::bind(&Dispatcher::Run, this);
TimerFactory::GetInst()->CreateTimer(run_callback, MY_DISPATCHER_CLOCK_RATE, true, true);
And
void TimerFactory::CreateTimer(std::function<void()>theCallback, uint theInterval, bool theImmediate, bool recurring)
{
std::lock_guard<std::mutex> guard(myMutex);
if (myTerminated == true)
{
return;
}
thread* t = new thread(&TimerFactory::CreateTimerOnThread, theCallback, theInterval, theImmediate, recurring);
if (recurring)
{
t->detach();
}
else if (theImmediate)
{
t->join();
}
else
{
myThreads.push_back(t);
}
}
Followed by:
void TimerFactory::CreateTimerOnThread(std::function<void()>theCallback, uint theTimer, bool theImmediate, bool recurring)
{
if (theImmediate)
{
Timer p(theCallback, theTimer, std::this_thread::get_id(), theImmediate, recurring);
p.Start();
}
else
{
Timer* p = new (std::nothrow) Timer(theCallback, theTimer, std::this_thread::get_id(), theImmediate, recurring);
Dispatcher<Timer>::GetInst()->addElement(p);
}
}
The Timer objects that are !isImmediate are the ones that are causing the problem when I pop them off of a list:
template <typename T>
class Dispatcher
{
private:
static Dispatcher<T>* myInstance;
static std::once_flag myOnceFlag;
std::list<T*> myData;
std::mutex myMutex;
Dispatcher()
{
myInstance = this;
}
public:
static Dispatcher* GetInst()
{
std::call_once(Dispatcher::myOnceFlag, []() {new Dispatcher(); });
return Dispatcher::myInstance;
}
virtual void Initialize()
{
//std::lock_guard<std::mutex> guard(myMutex);
while (myData.size() > 0)
{
myData.pop_back();
}
std::function<void()> run_callback = std::bind(&Dispatcher::Run, this);
TimerFactory::GetInst()->CreateTimer(run_callback, MY_DISPATCHER_CLOCK_RATE, true, true);
}
/* Add an element to my list */
bool addElement(T* theElement)
{
std::lock_guard<std::mutex> guard(myMutex);
myData.push_back(theElement);
return true;
}
/* Clear my list */
void Reset()
{
std::lock_guard<std::mutex> guard(myMutex);
while (myData.size() > 0)
{
myData.pop_back();
T* temp = (*myData.begin());
myData.pop_front();
temp->Start();
delete temp; // This causes the exception.
}
}
virtual void Run()
{
std::lock_guard<std::mutex> guard(myMutex);
if (myData.size() > 0)
{
T* temp = (*myData.begin());
myData.pop_front();
temp->Start();
delete temp; // This is the line that leads to the exception.
}
}
};
I'm trying to wrap them in unique_ptrs but when the destructor gets called my application throws the exception:
Exception thrown at 0x0F695DCF (SudokuAPI.dll) in SudokuInterface.exe: 0xC0000005: Access violation reading location 0xDDDDDDDD. occurred
and the call stack is:
SudokuAPI.dll!std::_Func_class<void>::_Tidy() Line 470 C++ Symbols loaded.
SudokuAPI.dll!std::_Func_class<void>::~_Func_class<void>() Line 356 C++ Symbols loaded.
SudokuAPI.dll!std::function<void __cdecl(void)>::~function<void __cdecl(void)>() Line 53 C++ Symbols loaded.
SudokuAPI.dll!Timer::~Timer() Line 35 C++ Symbols loaded.
SudokuAPI.dll!Timer::`scalar deleting destructor'(unsigned int) C++ Non-user code. Symbols loaded.
This exception also occurs when not using unique_ptrs, so I'm stuck. Any thoughts would be greatly appreciated.
When a Timer starts with isRecurring = true, the thread it runs on never ends. Trying to destroy the Timer leads to undefined behaviour, as you have a running function where this is an invalid pointer
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;
}
In this program I have a class inheriting of QGraphicsObject. This object (mario) go forward, go back and jump. For this jobs I changed mario's coordinate. But I have a problem. I want it to stop when collide with bricks. While I don't use of QPropertyAnimation how to stop this item.
extern mario* _mario=new mario;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
size_of_plane_y=600;
size_of_plane_x=2000;
view=new QGraphicsView;
scene=new QGraphicsScene;
rec=new QGraphicsRectItem;
setCentralWidget(view);
view->setScene(scene);
scene->setSceneRect(0,0,size_of_plane_x,size_of_plane_y);
scene->addRect(scene->sceneRect());
x_scene=0;
y_scene=0;
int tmpb=8*30+120+10*30+120;
int tmpb2=10*30+120+8*30+120;
int firstb=100;
int firstb2=100+8*30+120;
for(int i=0;i<3;i++)
{
_brick=new brick(0,firstb,size_of_plane_y-180);
scene->addItem(_brick);
_brick2=new brick2(0,firstb2,size_of_plane_y-180);
scene->addItem(_brick2);
firstb+=tmpb;
firstb2+=tmpb2;
}
timer1=new QTimer(this);
timer1->setInterval(500);
connect(timer1,SIGNAL(timeout()),this,SLOT(up()));
};
void MainWindow::keyPressEvent(QKeyEvent *k)
{
switch (k->key())
{
case Qt::Key_J:
{
forward();
break;
}
case Qt::Key_Z:
{
timer1->start();
break;
}
case Qt::Key_F:
{
back();
break;
}
default:
break;
}
}
void MainWindow::forward()
{
if(ismovepossible(_mario->pos().x()+50,_mario->pos().y())==true)
{
_mario->setX(_mario->pos().x()+50);
scene->setSceneRect(x_scene+40,y_scene,size_of_plane_x,size_of_plane_y);
x_scene+=40;
}
}
void MainWindow::up()
{
static bool flag=0;
if(!flag)
{
if(ismovepossible(_mario->pos().x(),_mario->pos().y()-90)==true)
{
_mario->setY(_mario->pos().y()-90);
flag=1;
}
}
else
{
if(ismovepossible(_mario->pos().x(),_mario->pos().y()-90)==true)
{
_mario->setY(_mario->pos().y()+90);
timer1->stop();
flag=0;
}
}
}
void MainWindow::back()
{
if(ismovepossible(_mario->pos().x()-50,_mario->pos().y())==true)
{
_mario->setX(_mario->pos().x()-50);
scene->setSceneRect(x_scene-50,y_scene,size_of_plane_x,size_of_plane_y);
x_scene-=50;
}
}
////////////////edit
void MainWindow::projectile()//when user press Z and J simultaneity
{
static bool flag=0;
if(!flag)
{
if(ismovepossible(_mario->pos().x()+50,_mario->pos().y()-90)==true)
{
_mario->setY(_mario->pos().y()-90);
_mario->setX(_mario->pos().x()+50);
scene->setSceneRect(x_scene+50,y_scene,size_of_plane_x,size_of_plane_y);
x_scene-=50;
text->setPos(x_scene+200,10);
flag=1;
}
}
else
{
if(ismovepossible(_mario->pos().x(),_mario->pos().y()+90)==true)
{
_mario->setY(_mario->pos().y()+90);
timer2->stop();
flag=0;
}
}
}
/////////////////////add function
bool MainWindow::ismovepossible(int x, int y)
{
int dis_b=10*30+120+120;
int dis_b2=4*30+120+8*30+120;//8*30+120+120;
int firstb=100;
int endb=/*firstb*/100+8*30;
int firstb2=/*endb*/100+8*30+120;
int endb2=/*firstb2*/100+8*30+120+4*30;
int firstb3=/*endb2*/100+8*30+120+4*30+2*30;
int endb3=/*firstb3*/100+8*30+120+4*30+2*30+4*30;
int dis_b3=120+8*30+120+4*30+2*30;
if(y>size_of_plane_y-60 && y<=size_of_plane_y)
{
return false;
}
while(endb<size_of_plane_x)
{
if((y>size_of_plane_y-180 && y<size_of_plane_y-180+30)&&(x>firstb && x<endb))
{
return false;
}
else
{
firstb+=dis_b;
endb+=firstb;
}
}
while(endb2<size_of_plane_x)
{
if((y>size_of_plane_y-180 && y<size_of_plane_y-180+30)&&(x>firstb2 && x<endb2))
{
return false;
}
else
{
firstb2+=dis_b2;
endb2+=firstb2;
}
}
while(endb3<size_of_plane_x)
{
if((y>size_of_plane_y-180 && y<size_of_plane_y-180+30)&&(x>firstb3 && x<endb3))
{
return false;
}
else
{
firstb3+=dis_b3;
endb3+=firstb3;
}
}
return true;
}
class brick : public QGraphicsObject
{
Q_OBJECT
public:
explicit brick(QGraphicsItem *parent = 0,int x=100,int y=600-180);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QRectF boundingRect()const;
public slots:
void collision();
private:
int size_of_plane_y;
int start_x;
int start_y;
int size_brick;
};
brick::brick(QGraphicsItem *parent, int x, int y) : QGraphicsObject(parent)
{
size_of_plane_y=600;
start_x=x;
start_y=y;
size_brick=30;
connect(_mario,SIGNAL(xChanged()),this,SLOT(collision()));
connect(_mario,SIGNAL(yChanged()),this,SLOT(collision()));
}
void brick::collision()
{
if(this->collidesWithItem(_mario))
{
qDebug()<<"collision";
//what write here for stopping super mario?
}
}
I think you should modify your algorithm. The main problem here is you move mario before checking if there is a brick.
You move mario, you emit the signal xChanged() or yChanged(), check if you're on a brick or not ? Then you have to go back to the previous location ?
Since you know where you put your bricks, you can do something more like this:
void MainWindow::forward()
{
if(moveIsPossible(xDest, yDest))
{
_mario->setX(...);
[...]
}
In the moveIsPossible(xDest, yDest), you put the tuple (X,Y) of the future location, it returns true if you have no brick, no wall, no whatever you want, false otherwise.
Seeing your code, I just want to draw your attention on many thing:
Try to use const variable to put any configuration variable such as board size, brick size, etc ...
Try to create specific classes for specific function. forward(), back(), etc.. have not to be implemented in the mainwindow class.
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;
}