UPDATE i changed to more simpler example
Ok , now i really puzzled i simplified the class as as i was reading on the net the suggestion was to extend CCNode better then CCSprite
and keep it as member of the CCNode
so here is the very simpleminded example based on the Hello cpp.
the problem remine the same , when touching any of the Gem instances i get printed the last Gem added , why ??
i expect that each Touchwill give me the correct instance that have bean touched ( i print id and name )
Im using cocos2d-2.1rc0-x-2.1.3 c++ , and i have something strange i created 10 CCSprites.
i have class that extend CCSprite and CCTargetedTouchDelegate like this :
Gem.cpp
#include "Gem.h"
Gem::Gem()
{
;
}
Gem::~Gem()
{
;
}
void Gem::onEnter()
{
CCDirector* pDirector = CCDirector::sharedDirector();
pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, true);
CCNode::onEnter();
}
void Gem::onExit()
{
CCDirector* pDirector = CCDirector::sharedDirector();
pDirector->getTouchDispatcher()->removeDelegate(this);
CCNode::onExit();
}
bool Gem::ccTouchBegan(CCTouch* touch, CCEvent* event)
{
CCPoint touchPoint = touch->getLocation();
CCLOG("Gem Touched! ImageName:%s |GemId:%s x:%f ,y:%f myspriteX:%f, myspriteY:%f nodePosX:%f nodePosY:%f",this->getImageName().c_str(),this->getGemId().c_str(),touchPoint.x,touchPoint.y,getGemSprite()->getPositionX(),getGemSprite()->getPositionY(),this->getPositionX(),this->getPositionY());
return true;
}
void Gem::ccTouchMoved(CCTouch* touch, CCEvent* event)
{
CCPoint touchPoint = touch->getLocation();
}
void Gem::ccTouchEnded(CCTouch* touch, CCEvent* event)
{
}
Gem.h
class Gem :public CCNode , public CCTargetedTouchDelegate
{
public:
Gem();
virtual ~Gem();
CC_SYNTHESIZE(std::string,imageName,ImageName)
CC_SYNTHESIZE(std::string,gemId,GemId)
CC_SYNTHESIZE(CCPoint,gemPos,GemPos)
CC_SYNTHESIZE(CCSprite*,gemSprite,GemSprite)
virtual void onEnter();
virtual void onExit();
virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);
virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);
virtual void ccTouchEnded(CCTouch* touch, CCEvent* event);
};
The helloWorldScene.cpp init() method
bool HelloWorld::init()
{
bool bRet = false;
//////////////////////////////////////////////////////////////////////////
// super init first
//////////////////////////////////////////////////////////////////////////
if(!CCLayer::init())
return false;
CCSize m_winSize;
CCSize visibleSize;
CCPoint origin;
m_winSize = CCDirector::sharedDirector()->getWinSize();
visibleSize = CCDirector::sharedDirector()->getVisibleSize();
origin = CCDirector::sharedDirector()->getVisibleOrigin();
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("sprites.plist","sprites.png");
CCSpriteBatchNode* gameBatchNode = CCSpriteBatchNode::create("sprites.png"/*,200*/);
CCSprite *bg= CCSprite::create("grideFinal.png");
//bg->setAnchorPoint(ccp(0,0));
bg->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
this->addChild(bg,1);
Gem* gem1 = new Gem();
gem1->retain();
gem1->setGemId("gem1");
gem1->setImageName("img_1");
gem1->setGemSprite(CCSprite::createWithSpriteFrameName("gem1.png"));
Gem* gem2 = new Gem();
gem2->retain();
gem2->setGemId("gem2");
gem2->setImageName("img_2");
gem2->setGemSprite(CCSprite::createWithSpriteFrameName("gem2.png"));
gem1->setAnchorPoint(ccp(0,0));
gem2->setAnchorPoint(ccp(0,0));
gem1->setPosition(ccp(0,0));
gem2->setPosition(ccp(gem1->getGemSprite()->getContentSize().width,40));
gem1->getGemSprite()->setAnchorPoint(ccp(0,0));
gem2->getGemSprite()->setAnchorPoint(ccp(0,0));
gem1->getGemSprite()->setPosition(ccp(0,0));
gem2->getGemSprite()->setPosition(ccp(gem1->getGemSprite()->getContentSize().width,40));
//gameBatchNode->addChild(gem1->getGemSprite(),4,44);
//gameBatchNode->addChild(gem2->getGemSprite(),4,45);
this->addChild(gameBatchNode);
bg->addChild(gem1->getGemSprite(),50);
bg->addChild(gem2->getGemSprite(),50);
bg->addChild(gem1,50);
bg->addChild(gem2,50);
bRet = true;
return bRet;
}
Every thing is woring fine except when i touch the screen and trigger Gem::ccTouchBegan method. its always gives me the last CCSprite ( and i have like 50 on the screen
why is that ? what im missing here ?
Because every Gem instance extend CCTargetedTouchDelegate and register touch dispatcher, only the highest or latest added will be triggered.
So what the correct way is implement CCTargetedTouchDelegate in HelloWorld class, and when touch occur, check which Gem is touched by touch point.
Here is a method used for checking if touch is in some node:
bool Gem::isTouchInside(CCTouch* pTouch)
{
CCPoint touchLocation = pTouch->getLocation();
CCRect rect =
CCRectApplyAffineTransform(CCRectMake(0 ,
0 ,
this->getContentSize().width,
this->getContentSize().height),
this->nodeToWorldTransform());
return rect.containsPoint(touchLocation);
}
Related
I have written a program in c++ using wxwidgets.I am placing a rectangle on the image and want to select the part of image covered by rectangle for which the rectangle should be draggable. But the problem is when I click the mouse the image vanishes and the only rectangle (which can be dragged) remains and it happens vice-versa.
`
class BasicDrawPane : public wxPanel
{
public:
BasicDrawPane();
BasicDrawPane(wxFrame* parent);
void paintEvent(wxPaintEvent & evt);
void render(wxDC& dc);
void mouseMoved(wxMouseEvent& event);
void mouseDown(wxMouseEvent& event);
void mouseWheelMoved(wxMouseEvent& event);
void mouseReleased(wxMouseEvent& event);
void rightClick(wxMouseEvent& event);
void mouseLeftWindow(wxMouseEvent& event);
DECLARE_EVENT_TABLE()
};
class MyFrame: public wxFrame{
public:
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
wxString path;
BasicDrawPane panel;
private:
void OnHello(wxCommandEvent& event);
void OnExit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
void OnOpen(wxCommandEvent& event);
void OnPaint(wxCommandEvent& event);
void OnRect(wxCommandEvent& event);
void OnSave(wxCommandEvent& event);
DECLARE_EVENT_TABLE();
wxBitmap bmp;
wxMemoryDC memDC;
};
enum
{
ID_Hello = 1, ID_PAINT = 2, ID_RECT = 3, ID_SAVE = 4
};
BEGIN_EVENT_TABLE( MyFrame, wxFrame )
EVT_MENU(ID_Hello,MyFrame::OnHello)
EVT_MENU(wxID_EXIT,MyFrame::OnExit)
EVT_MENU(wxID_ABOUT,MyFrame::OnAbout)
EVT_MENU(wxID_OPEN,MyFrame::OnOpen)
EVT_MENU(ID_PAINT,MyFrame::OnPaint)
EVT_MENU(ID_RECT,MyFrame::OnRect)
EVT_MENU(ID_SAVE,MyFrame::OnSave)
END_EVENT_TABLE()
void MyFrame::OnPaint(wxCommandEvent& event)
{
//wxPaintDC dc( this );
//dc.DrawBitmap( m_bitmap, 0, 0, true /* use mask */ );
//wxStaticBitmap *b1 = new wxStaticBitmap(this, -1, wxBitmap(wxImage(path)));
bmp.LoadFile((path),wxBITMAP_TYPE_ANY);
// bmp.LoadFile((path),wxBITMAP_TYPE_PNG);
memDC.SelectObject( bmp );
//memDC.SetBackground(*wxWHITE_BRUSH);
//memDC.Clear();
/* memDC.SetPen(*wxGREEN_PEN);
memDC.SetBrush(*wxTRANSPARENT_BRUSH);
memDC.DrawRectangle( m_x, m_y, WIDTH, HEIGHT );*/
//Check();
memDC.SelectObject(wxNullBitmap);
// wxSize sz(512,384);
// wxSize sz(900,600);
wxStaticBitmap *b1 = new wxStaticBitmap(/* dynamic_cast<wxFrame*>*/this, -1, bmp, wxDefaultPosition);
Refresh();
}
class MyApp: public wxApp
{
public:
virtual bool OnInit();
//MyFrame *frame;
BasicDrawPane * drawPane;
};
IMPLEMENT_APP(MyApp)
bool MyApp::OnInit()
{
// wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
//frame = new MyFrame((wxFrame *)NULL, -1, wxT("Hello wxDC"), wxPoint(50,50), wxSize(800,600));
MyFrame *frame = new MyFrame( _T("Hello World"), wxPoint(50, 50), wxSize(600, 600) );
// drawPane = new BasicDrawPane( (wxFrame*) frame );
// sizer->Add(drawPane, 1, wxEXPAND);
//frame->SetSizer(sizer);
// /* dynamic_cast<wxFrame*>(this)*/ frame-> SetAutoLayout(true);
/* dynamic_cast<wxFrame*>(this)*/frame -> Show();
return true;
}
BEGIN_EVENT_TABLE(BasicDrawPane, wxPanel)
EVT_MOTION(BasicDrawPane::mouseMoved)
EVT_LEFT_DOWN(BasicDrawPane::mouseDown)
EVT_LEFT_UP(BasicDrawPane::mouseReleased)
EVT_RIGHT_DOWN(BasicDrawPane::rightClick)
EVT_LEAVE_WINDOW(BasicDrawPane::mouseLeftWindow)
EVT_MOUSEWHEEL(BasicDrawPane::mouseWheelMoved)
EVT_PAINT(BasicDrawPane::paintEvent)
// catch paint events
END_EVENT_TABLE()
void BasicDrawPane::mouseDown(wxMouseEvent& event)
{
/* if (event.GetPosition().x >= m_x && event.GetPosition().x <= m_x + WIDTH &&
event.GetPosition().y >= m_y && event.GetPosition().y <= m_y + HEIGHT)
{
m_dragging = true;
m_previous_mouse_x = event.GetPosition().x;
m_previous_mouse_y = event.GetPosition().y;
}*/
}
void BasicDrawPane::mouseWheelMoved(wxMouseEvent& event) {}
void BasicDrawPane::mouseReleased(wxMouseEvent& event)
{
m_dragging = true;
}
void BasicDrawPane::mouseMoved(wxMouseEvent& event)
{
if (m_dragging && event.Dragging())
{
int delta_x = event.GetPosition().x - m_previous_mouse_x;
int delta_y = event.GetPosition().y - m_previous_mouse_y;
m_x += delta_x;
m_y += delta_y;
m_previous_mouse_x = event.GetPosition().x;
m_previous_mouse_y = event.GetPosition().y;
// trigger paint event
Refresh();
}
}
void BasicDrawPane::mouseLeftWindow(wxMouseEvent& event)
{
m_dragging = true;
}
void BasicDrawPane::rightClick(wxMouseEvent& event) {}
BasicDrawPane::BasicDrawPane(wxFrame* parent) :
wxPanel(parent)
{
// m_dragging = true;
// m_x = 100;
// m_y = 100;
}
/*
* Called by the system of by wxWidgets when the panel needs
* to be redrawn. You can also trigger this call by
* calling Refresh()/Update().
*/
void BasicDrawPane::paintEvent(wxPaintEvent & evt)
{
//wxCommandEvent w1(wxEVT_NULL, ID_PAINT);
//OnPaint(w1);
wxPaintDC dc(this);
render(dc);
}
void BasicDrawPane::render(wxDC& dc)
{
dc.SetPen(*wxGREEN_PEN);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle( m_x, m_y, WIDTH, HEIGHT );
}
`
There are several things to explain in order to answer this question, so I will take them one at a time. I think your basic idea is okay, so I won't go into a lot of detail on how the actual selection should take place etc.
Firstly, I would recommend to use either Connect() or Bind() instead of an event table. This allows you to connect child window events back to the parent window and handle them all in one place.
For example, if your main frame class is called MainFrame and you have a wxPanel member called m_DrawPanel, in the MainFrame ctor you could have:
MainFrame::MainFrame(wxWindow* parent)
{
// Connect mouse event handlers.
m_DrawPanel->Connect(wxEVT_LEFT_DOWN,
wxMouseEventHandler(MainFrame::OnPanelLDown), NULL, this);
m_DrawPanel->Connect(wxEVT_LEFT_UP,
wxMouseEventHandler(MainFrame::OnPanelLUp), NULL, this);
m_DrawPanel->Connect(wxEVT_MOTION,
wxMouseEventHandler(MainFrame::OnPanelMotion), NULL, this);
// Connect paint and erase handlers.
m_DrawPanel->Connect(wxEVT_PAINT,
wxPaintEventHandler(MainFrame::OnPanelPaint), NULL, this);
m_DrawPanel->Connect(wxEVT_ERASE_BACKGROUND,
wxEraseEventHandler(MainFrame::OnPanelErase), NULL, this);
// Load the bitmap and set the mode to 'not currently selecting'.
m_Picture.LoadFile ("wxwidgets.png", wxBITMAP_TYPE_PNG);
m_SelectionMode = false;
}
Note: I included a wxEVT_ERASE_BACKGROUND event override because otherwise panels tend to be cleared which leads to flicker (this is one simple approach).
The 3 mouse event handlers can implement your selection logic (I think this is basically what you are intending already):
void MainFrame::OnPanelLDown(wxMouseEvent& event)
{
m_SelectionMode = true;
m_SelectionRect = wxRect(event.GetPosition(), wxSize(0, 0));
}
void MainFrame::OnPanelLUp(wxMouseEvent& event)
{
m_SelectionMode = false;
// ... handle what to do with the selection here
// (selected area is defined by m_SelectionRect).
// ...
// Zero the selection rectangle for neatness (not really required).
m_SelectionRect = wxRect ();
}
void MainFrame::OnPanelMotion(wxMouseEvent& event)
{
m_SelectionRect = wxRect(m_SelectionRect.GetTopLeft(), event.GetPosition());
// Call Refresh() to trigger a paint event.
m_mainPanel->Refresh();
}
As mentioned earlier, override the panel's wxEVT_ERASE_BACKGROUND event to do nothing:
void MainFrame::OnPanelErase(wxEraseEvent& event)
{
}
Finally, I think this is the bit that you really are asking in your question (I included the others to help you build a working program):
void MainFrame::OnPanelPaint(wxPaintEvent& event)
{
// Obtain a wxPaintDC.
wxPaintDC pdc (m_mainPanel);
// Draw our image.
pdc.DrawBitmap(m_Picture, wxPoint(0, 0));
// If the user is currently selecting (left mouse button is down)
// then draw the selection rectangle.
if (m_SelectionMode)
{
pdc.SetPen(*wxRED_PEN);
pdc.SetBrush(*wxTRANSPARENT_BRUSH);
pdc.DrawRectangle(m_SelectionRect);
}
}
This is a paint event handler, so first we need to create a wxPaintDC context. Next, we paint the bitmap, this ensures it is refreshed every time and not damaged by mouse movements, resizing or other windows being dragged etc. Finally, if the user is currently moving the mouse with the left button pressed, then draw the selection rectangle.
There are many other ways of achieving the same thing. Some of them are possibly better, or more efficient, however this is a simple working way until you become more familiar with wxWidgets.
Briefly, I have two sprites, one of which is a child of another.
With each sprite related the event listener, as described there.
If both sprites are child nodes of the layer, then everything works great.
Now I need to second sprite is a child node of the first sprite.
But in this case, the second sprite does not respond to events in general.
I'm in a panic and have no idea what's wrong and how to fix it. Please help.
Here's a simplified example:
.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class HelloWorld : public cocos2d::Layer
{
public:
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::Scene* createScene();
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// a selector callback
void menuCloseCallback(cocos2d::Ref* pSender);
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld);
};
class PlaySprite : public cocos2d::Sprite
{
public:
virtual bool init();
CREATE_FUNC(PlaySprite);
void addEvent();
bool touchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
};
class InPlaySprite : public cocos2d::Sprite
{
public:
virtual bool init();
CREATE_FUNC(InPlaySprite);
void addEvent();
bool touchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
};
#endif // __HELLOWORLD_SCENE_H__
.cpp
#include "HelloWorldScene.h"
USING_NS_CC;
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
// add a "close" icon to exit the progress. it's an autorelease object
auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
origin.y + closeItem->getContentSize().height/2));
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 1);
/////////////////////////////
// 3. add your codes below...
auto sprite1 = PlaySprite::create();
this->addChild(sprite1);
auto sprite2 = InPlaySprite::create();
// !!!
sprite1->addChild(sprite2);
return true;
}
void HelloWorld::menuCloseCallback(Ref* pSender)
{
Director::getInstance()->end();
}
bool PlaySprite::init()
{
if(!Sprite::init())
return false;
// to do
Size visibleSize = Director::getInstance()->getVisibleSize();
this->setTexture("1.png");
this->setPosition(visibleSize.width / 2, visibleSize.height / 2);
this->addEvent();
return true;
}
void PlaySprite::addEvent()
{
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = [=](Touch* touch, Event* event)
{
return this->touchBegan(touch, event);
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
bool PlaySprite::touchBegan(Touch* touch, Event* event)
{
auto target = (Sprite* ) event->getCurrentTarget();
auto rect = this->getBoundingBox();
if(rect.containsPoint(touch->getLocation()))
{
this->setTexture("1d.png");
return true;
}
return false;
}
bool InPlaySprite::init()
{
if(!Sprite::init())
return false;
// to do
Size visibleSize = Director::getInstance()->getVisibleSize();
this->setTexture("2.png");
this->setPosition(150.0f, 150.0f);
this->addEvent();
return true;
}
void InPlaySprite::addEvent()
{
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = [=](Touch* touch, Event* event)
{
return this->touchBegan(touch, event);
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
bool InPlaySprite::touchBegan(Touch* touch, Event* event)
{
// auto target = (Sprite* ) event->getCurrentTarget();
auto rect = this->getBoundingBox();
if(rect.containsPoint(touch->getLocation()))
{
this->setTexture("2d.png");
return true;
}
return false;
}
Classes PlaySprite and InPlaySprite are are very similar because this is a very simplified example.
I think your problem is that you are swallowing touch events in the parent sprite when you call
listener->setSwallowTouches(true);
If you make that call inside of PlaySprite::addEvent() with false instead, I suspect things will work out for you.
i try to follow the cocose2d-x 2.2 Test file :
cocos2d-x-2.2\samples\Cpp\TestCpp\Classes\SchedulerTest\SchedulerTest.h
i implemented the slider control and i see it and the :
virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);
virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);
virtual void ccTouchEnded(CCTouch* touch, CCEvent* event);
function are triggerd just right when i try to slide
but its not sliding at all this is what i have :
the default close menu is working find :
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
/////////////////////////////
// 2. add a menu item with "X" image, which is clicked to quit the program
// you may modify it.
// add a "close" icon to exit the progress. it's an autorelease object
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(HelloWorld::menuCloseCallback));
pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,
origin.y + pCloseItem->getContentSize().height/2));
// create menu, it's an autorelease object
CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
this->addChild(pMenu, 1);
bSliderCtlTouched = false;
this->setTouchEnabled(true);
this->schedule(schedule_selector(HelloWorld::tick));
return true;
}
void HelloWorld::tick(float dt)
{
;
}
void HelloWorld::onEnter()
{
CCLayer::onEnter();
CCSize s = CCDirector::sharedDirector()->getWinSize();
m_pSliderCtl = sliderCtl();
m_pSliderCtl->retain();
m_pSliderCtl->setPosition(ccp(s.width / 2.0f, s.height - (m_pSliderCtl->getContentSize().height*2)));
this->addChild(m_pSliderCtl,1);
}
CCControlSlider* HelloWorld::sliderCtl()
{
CCControlSlider * slider = CCControlSlider::create("extensions/sliderTrack2.png","extensions/sliderProgress2.png" ,"extensions/sliderThumb.png");
slider->addTargetWithActionForControlEvents(this, cccontrol_selector(HelloWorld::sliderAction), CCControlEventValueChanged);
slider->setMinimumValue(-3.0f);
slider->setMaximumValue(3.0f);
slider->setValue(1.0f);
return slider;
}
void HelloWorld::sliderAction(CCObject* pSender, CCControlEvent controlEvent)
{
bSliderCtlTouched =true;
CCControlSlider* pSliderCtl = (CCControlSlider*)pSender;
float scale;
scale = pSliderCtl->getValue();
}
void HelloWorld::registerWithTouchDispatcher()
{
// higher priority than dragging
CCDirector* pDirector = CCDirector::sharedDirector();
pDirector->getTouchDispatcher()->addTargetedDelegate(this,0, true);
}
bool HelloWorld::ccTouchBegan(CCTouch* touch, CCEvent* event)
{
if(bSliderCtlTouched)
CCLOGWARN("bSliderCtlTouched is true");
CCPoint touchLocation = touch->getLocation();
CCPoint location = convertToNodeSpace( touchLocation );
CCSize screenSize = CCDirector::sharedDirector()->getWinSize();
float screenSizeW = screenSize.width;
//CCLOGWARN("pos: %f,%f -> %f,%f", touchLocation.x, touchLocation.y, location .x, location .y);
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
float halfScreen = screenSize.width/2;
if(location.x <= halfScreen)
{
left = true;
right = false;
}
else
{
left = false;
right = true;
}
#ifdef MOUSEJOINT
return isNodeTouched(locationWorld);
#else
return true;
#endif
}
void HelloWorld::ccTouchMoved(CCTouch* touch, CCEvent* event)
{
if (!bSliderCtlTouched)
{
return;
}
CCPoint touchLocation = touch->getLocation();
CCPoint location = convertToNodeSpace( touchLocation );
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
}
void HelloWorld::ccTouchEnded(CCTouch* touch, CCEvent* event)
{
if(bSliderCtlTouched)
{
bSliderCtlTouched = false;
}
CCPoint touchLocation = touch->getLocation();
CCPoint nodePosition = convertToNodeSpace( touchLocation );
}
As far as your question was unanswered about 7 months, I will answer your question for the new version of cocos2d-x. This code works for cocos2d-x 3.0:
cocos2d::extension::ControlSlider* slider = cocos2d::extension::ControlSlider::create(
"images/buttons/container.png", "images/buttons/progress.png", "images/buttons/knob.png");
slider->setPosition(200, 200);
slider->setMinimumValue(0);
slider->setMaximumValue(10);
slider->setValue(3);
slider->addTargetWithActionForControlEvents(this, cccontrol_selector(IntroView::valueChangedCallback), cocos2d::extension::Control::EventType::VALUE_CHANGED);
addChild(slider);
void IntroView::valueChangedCallback(Ref* sender, cocos2d::extension::Control::EventType evnt)
{
float value = static_cast<cocos2d::extension::ControlSlider*>(sender)->getValue();
CCLOG(std::to_string(value).c_str());
}
Don't forget to #include "GUI/CCControlExtension/CCControlExtensions.h" and use libExtensions in your project.
So I'm trying to create a simple app using cocos2d-x newest build and for some reason can't get my touch wired up. Here are my classes:
class GameLayer : public cocos2d::Layer
{
public:
static cocos2d::Layer* createLayer();
void update(float dt);
virtual bool init();
CREATE_FUNC(GameLayer);
private:
bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
void onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event);
void onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event);
};
cocos2d::Layer* GameLayer::createLayer()
{
GameLayer *layer = GameLayer::create();
return layer;
}
bool GameLayer::init()
{
if (!cocos2d::Layer::init())
{
return false;
}
this->schedule(schedule_selector(GameLayer::update));
this->setTouchEnabled(true);
return true;
}
void GameLayer::update(float dt)
{
}
bool GameLayer::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event)
{
cocos2d::log("You touched %f, %f", touch->getLocationInView().x, touch->getLocationInView().y);
return true;
}
void GameLayer::onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event)
{
}
void GameLayer::onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event)
{
}
I noticed when I call into the setTouchEnabled call that an internal flag called _running is set to false so it doesn't actually register my touch events. However I can't seem to figure out why that is the case. Am I calling things incorrectly or in the wrong order?
Currently, cocos2dx is going through a major overhauling of the library and many things have changed including Touch registration and propagation. Here is how it works now:
GameLayer.h
class GameLayer : public cocos2d::Layer
{
public:
static cocos2d::Layer* createLayer();
void update(float dt);
virtual bool init();
CREATE_FUNC(GameLayer);
private:
virtual void onEnter();
virtual void onExit();
bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
void onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event);
void onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event);
};
GameLayer.cpp
cocos2d::Layer* GameLayer::createLayer()
{
GameLayer *layer = GameLayer::create();
return layer;
}
bool GameLayer::init()
{
if (!cocos2d::Layer::init())
{
return false;
}
this->schedule(schedule_selector(GameLayer::update));
return true;
}
void GameLayer::onEnter()
{
Layer::onEnter();
// Register Touch Event
auto dispatcher = Director::getInstance()->getEventDispatcher();
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(GameLayer::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(GameLayer::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(GameLayer::onTouchEnded, this);
dispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
void GameLayer::onExit()
{
// You don't need to unregister listeners here as new API
// removes all linked listeners automatically in CCNode's destructor
// which is the base class for all cocos2d DRAWING classes
Layer::onExit();
}
void GameLayer::update(float dt)
{
}
bool GameLayer::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event)
{
cocos2d::log("You touched %f, %f", touch->getLocationInView().x, touch->getLocationInView().y);
return true;
}
void GameLayer::onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event)
{
}
void GameLayer::onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event)
{
}
Hope it helps!
This question already has answers here:
cocos2d subclassing sprite to handle touch?
(4 answers)
Closed 7 years ago.
I have my sprites on screen and I have a vector that stores each sprite.
Can a CCSprite* handle a touch event? Or just the CCLayer*?
What is the best way to decide what sprite was touched? Should I store the coordinates of where the sprite is (in the sprite class) and when I get the event, see if where the user touched is where the sprite is by looking through the vector and getting each sprites current coordinates?
UPDATE: I subclass CCSprite:
class Field : public cocos2d::CCSprite, public cocos2d::CCTargetedTouchDelegate
and I implement functions:
cocos2d::CCRect rect();
virtual void onEnter();
virtual void onExit();
bool containsTouchLocation(cocos2d::CCTouch* touch);
virtual bool ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event);
virtual void ccTouchMoved(cocos2d::CCTouch* touch, cocos2d::CCEvent* event);
virtual void ccTouchEnded(cocos2d::CCTouch* touch, cocos2d::CCEvent* event);
virtual void touchDelegateRetain();
virtual void touchDelegateRelease();
I put CCLOG statements in each one and I dont hit them!
When I touch the CCLayer this sprite is on though I do hit those in the class that implements the Layer and puts these sprites on the layer.
UPDATE: The code I have been trying:
Field* Field::createWithLocation(cocos2d::CCPoint p)
{
Field* f = new Field();
f->autorelease();
f->initWithLocation(p);
return f;
}
void Field::initWithLocation(cocos2d::CCPoint p)
{
setFieldCenterPoint(p);
setFieldGraphicName(FIELD::fieldIconFileName);
setFieldSprite(cocos2d::CCSprite::create(getFieldGraphicName().c_str()));
getFieldSprite()->setPosition(ccp(getFieldCenterPoint().x, getFieldCenterPoint().y));
setFieldSize(getFieldSprite()->getContentSize());
}
cocos2d::CCRect Field::rect()
{
cocos2d::CCSize s = getFieldSprite()->getTexture()->getContentSize();
return cocos2d::CCRectMake(-s.width / 2, -s.height / 2, s.width, s.height);
}
void Field::onEnter()
{
CCLOG("In onEnter");
cocos2d::CCDirector* pDirector = cocos2d::CCDirector::sharedDirector();
pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, true);
//_dir->Instance()->getDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);
cocos2d::CCSprite::onEnter();
}
void Field::onExit()
{
CCLOG("In onExit");
cocos2d::CCDirector* pDirector = cocos2d::CCDirector::sharedDirector();
pDirector->getTouchDispatcher()->removeDelegate(this);
//_dir->Instance()->getDirector()->getTouchDispatcher()->removeDelegate(this);
cocos2d::CCSprite::onExit();
}
bool Field::containsTouchLocation(cocos2d::CCTouch* touch)
{
return rect().containsPoint(convertTouchToNodeSpaceAR(touch));
}
bool Field::ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event)
{
CCLOG("In ccTouchBegan");
return true;
}
void Field::ccTouchMoved(cocos2d::CCTouch* touch, cocos2d::CCEvent* event)
{
CCLOG("In ccTouchMoved");
}
void Field::ccTouchEnded(cocos2d::CCTouch* touch, cocos2d::CCEvent* event)
{
CCLOG("In ccTouchEnded");
}
void Field::touchDelegateRetain()
{
this->retain();
}
void Field::touchDelegateRelease()
{
this->release();
}
I have answered this before.
Please go to cocos2d subclassing sprite to handle touch? to find the details.