How to perform drag and drop operation on sprite fetched from array and present on screen ? - cocos2d-x

I want to perform drag and drop operation on these image.
How can i make it possible with the following code.
void storeLocation::changescene()
{
this->removeAllChildren();
//CCDirector::sharedDirector()->replaceScene(storeLocation::scene());
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
//CCScene* scene=CCScene::create();
storeLocation *layer = storeLocation::create();
CCSprite *k=CCSprite::create("background.png");
this->addChild(k,0);
k->setPosition(ccp(visibleSize.width/2+ origin.x, visibleSize.height/2 + origin.y));
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(storeLocation::menuCloseCallback));
pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width ,
origin.y + pCloseItem->getContentSize().height/2));
pCloseItem->setScale(1.5);
// create menu, it's an autorelease object
CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
this->addChild(pMenu, 1);
this->addChild(pMenu, 1);
this->setTouchEnabled(true);
int l=5;
int posx=0,posy=0;
int count=0,r,j=-1,i=0,flag=0;
int x=20;
int b[30],a[30];
while(count<=5)
{
srand(time(0));
r=rand()%x+1;
flag=checktag(b,r,j);
if(flag==1)
{
b[i]=r;
i++;
count++;
j++;
}
}
int t;
CCObject* jt=NULL;
CCARRAY_FOREACH(images, jt)
{
// CCSize winSize = CCDirector::sharedDirector()->getWinSize();
//float i=winSize.width;
CCSprite *image = dynamic_cast<CCSprite*>(jt);
t=image->getTag();
for(i=0;i<l;i++)
{
if(t==b[i])
{
this->addChild(image);
image->setPosition(ccp(100+posx,100));
posx=posx+120;
}}}

To drag and drop images from one point to another on screen you have to use touch delegate methods
bool ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
void ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
void ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
Detect image on user touch in ccTouchBegan method, for this you can store all image objects in a array and check if touch is in rect of any image by using for loop.
To move the image with user touch change position of touched image(save touched image object in a global object) in ccTouchMoved.
And in ccTouchEnded method do whatever you want to do on droping image.

the easiest way to catch drag and drop events is by implementing the onTouchBegan and onTouchMoved and onTouchEnded methods like this:
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, sprite);
bool HelloWorld::onTouchBegan(Touch* touch, cocos2d::Event* event){
// this method is not needed but in order to implement the onTouchMoved you have to first implement onTouchBegan then the onTouchMoved
return true;
}
void HelloWorld::onTouchMoved(Touch* touch, cocos2d::Event* event){
if (sprite->getBoundingBox().containsPoint(touch->getLocation()))
{
sprite->setPosition(sprite->getPosition() + touch->getDelta());
}
}
void HelloWorld::onTouchEnded(Touch* touch, cocos2d::Event* event){
if (sprite->getBoundingBox().containsPoint(touch->getLocation()))
{
log("Sprite Drop Event");
}
}

Related

how to drag a jpanel with graphics across the jframe

I have the following code for a constructor:
public Building(Graphics g, int xb, int yb, int wb, int lb,boolean chklocb, Point nwlocb) {
x=xb;
y=yb;
w=wb;
l=lb;
chkloc=chklocb;
nwloc=nwlocb;
if(chkloc){
x = (int)nwloc.getX();
y = (int)nwloc.getY();
//System.out.print(i);
}
else{
System.out.print("mhffffff");
}
g.setColor(Color.BLACK);
g.drawRect(x,y,w,l);
g.fillRect(x,y,w,l);
}
And I have tried using setLocation() to move it.
This only made it disappear.
This is how I tried to move it:
public void mouseDragged(MouseEvent e){
//pset=MouseInfo.getPointerInfo().getLocation();
//panel.setVisible(false);
if(panel.contains(MouseInfo.getPointerInfo().getLocation())){
contains=true;
}
if(contains){
//panel=new Building(getGraphics(),(int)ptrck.x,(int)ptrck.y,100,100,contains,pset);
//panel.Nwloc(pset);
// remove(panel);
// constraints.gridx=(int)pset.getX();
// constraints.gridy=(int)pset.getY();
// add(panel);
e.translatePoint(e.getComponent().getLocation().x-x, e.getComponent().getLocation().y-y);
panel.setLocation(e.getX(), e.getY());
z.prnt("testcontain");
}
}
How can I drag it?

Disabling a TextButton

I am trying to disable a TextButton that I've coded as follows:
// Setup new game button
final TextButton newGameButton = new TextButton("New Game", style);
newGameButton.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
Tyr.getInstance().setScreen(new GameScreen());
AudioHelper.stopMusic();
return true;
}
});
table.add(newGameButton).spaceBottom(BUTTON_SPACE);
table.row();
However, the "setDisabled(true)" function doesn't seem to be working. Is there some other way that I can accomplish this task?
Found a solution: "newGameButton.setTouchable(Touchable.disabled);"

Using ccTouchBegan and ccTouchesEnded at the same time in Cocos2dx

Can I use ccTouchBegan and ccTouchesEnded at the same time?
When I'm trying to add actions in ccTouchBegan, I recognize that ccTouchesEnded isn't called. Can anyone explain for me how to use touch events?
Some of my code
bool GameplayScene::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){
CCActionInterval* actionBy = CCRotateBy::create(1, 180);
weapon->runAction(CCSequence::create(actionBy, NULL, NULL));
location = pTouch->getLocation();
shootBullet();
this->schedule(schedule_selector(GameplayScene::shootBullet), 1.0);
return true;
}
void GameplayScene::ccTouchesEnded(cocos2d::CCSet* touches, cocos2d::CCEvent* event){
this->unschedule(schedule_selector(GameplayScene::shootBullet));
}
void GameplayScene::registerWithTouchDispatcher(void) {
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, INT_MIN + 1, true);
}
First you are using ccTouchBegan and ccTouchesEnded, you could use ccTouchesBegan.
To use ccTouchesBegan and ccTouchesEnded, you need to set:
layer->setTouchEnabled(true);
where layer is the main layer of your Gameplay scene.

A cocos2d-x code that cause crash on Android but not on iOS

While porting an cocos2d-x project from iOS to Android, I found a problem that will cause crashing on Android but not on iOS, to show this problem, I made a small modification to the HelloWorld sample. To reproduce this problem, just press the close button on the bottom-right corner, on Android it will crash but not on iOS.
The code that cause the crashing is:
void TestNode::test()
{
// This will cause crash on Android, but OK on iOS
CCCallFunc *selector = CCCallFunc::create(this, callfunc_selector(TestNode::destroy));
this->runAction(selector);
// This is ok on both Android and iOS
// CCCallFunc *selector = CCCallFunc::create(scene_, callfunc_selector(HelloWorld::destroyNode));
// scene_->runAction(selector);
// This is ok on both Android and iOS
// destroy();
}
The complete code as the following:
HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class TestNode : public cocos2d::CCNode {
public:
TestNode(cocos2d::CCLayer *scene);
~TestNode();
void test();
void destroy();
cocos2d::CCLayer *scene_;
cocos2d::CCSprite *sprite_;
};
class HelloWorld : public cocos2d::CCLayer
{
private:
TestNode *node_;
public:
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::CCScene* scene();
// a selector callback
void menuCloseCallback(CCObject* pSender);
// implement the "static node()" method manually
CREATE_FUNC(HelloWorld);
void destroyNode();
};
#endif // __HELLOWORLD_SCENE_H__
HelloWorldScene.cpp:
#include "HelloWorldScene.h"
#include "AppMacros.h"
USING_NS_CC;
TestNode::TestNode(cocos2d::CCLayer *scene):
scene_(scene)
{
sprite_ = CCSprite::create("CloseNormal.png");
sprite_->setPosition(ccp(200, 200));
scene_->addChild(sprite_, 255);
}
TestNode::~TestNode()
{
scene_->removeChild(sprite_, true);
scene_->removeChild(this, true);
CCLog("+++ ~TestNode");
}
void TestNode::test()
{
// This will cause crash on Android, but OK on iOS
CCCallFunc *selector = CCCallFunc::create(this, callfunc_selector(TestNode::destroy));
this->runAction(selector);
// This is ok on both Android and iOS
// CCCallFunc *selector = CCCallFunc::create(scene_, callfunc_selector(HelloWorld::destroyNode));
// scene_->runAction(selector);
// This is ok on both Android and iOS
// destroy();
}
void TestNode::destroy()
{
CCLog("+++ destroy");
delete this;
}
CCScene* HelloWorld::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
HelloWorld *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()
{
//////////////////////////////
// 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);
/////////////////////////////
// 3. add your codes below...
// add a label shows "Hello World"
// create and initialize a label
CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", TITLE_FONT_SIZE);
// position the label on the center of the screen
pLabel->setPosition(ccp(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - pLabel->getContentSize().height));
// add the label as a child to this layer
this->addChild(pLabel, 1);
// add "HelloWorld" splash screen"
CCSprite* pSprite = CCSprite::create("HelloWorld.png");
// position the sprite on the center of the screen
pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
// add the sprite as a child to this layer
this->addChild(pSprite, 0);
node_ = new TestNode(this);
this->addChild(node_);
return true;
}
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
// CCDirector::sharedDirector()->end();
if (node_) {
node_->test();
node_ = NULL;
}
//#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
// exit(0);
//#endif
}
void HelloWorld::destroyNode()
{
node_->destroy();
}
I don't know why this works on iOS but you should not do this anyway. When you run the code
CCCallFunc *selector = CCCallFunc::create(this, callfunc_selector(TestNode::destroy));
this->runAction(selector);
which calls the function
void TestNode::destroy()
{
CCLog("+++ destroy");
delete this;
}
you are destroying an object that the CCCallFunc action still keeps a pointer to. Then when the CCCallFunc object is destroyed, it runs the CC_SAFE_RELEASE macro which will call release on your TestNode object. However, by now that TestNode object is already deallocated and that is most likely the reason for your crash.

CCScrollView with CCControlButton. How to control the touch area?

I have CCScrollView with container with CCControlButtons, when the buttons scroll out of the visible CCScrollView area, They are also can be touched too. How can I control the area ?
Inspired by Tomasz's answer, I created an alternative solution, also inheriting from CCControlButton:
bool ScrollableButton::isTouchInside(CCTouch *touch) {
return !dragging && CCControlButton::isTouchInside(touch);
}
bool ScrollableButton::ccTouchBegan(CCTouch *touch, CCEvent *event) {
dragging = false;
return CCControlButton::ccTouchBegan(touch, event);
}
void ScrollableButton::ccTouchMoved(CCTouch *touch, CCEvent *event) {
if (!dragging && ccpDistance(touch->getLocation(), touch->getStartLocation()) > 25) {
dragging = true;
}
CCControlButton::ccTouchMoved(touch, event);
}
void ScrollableButton::ccTouchEnded(CCTouch *touch, CCEvent *event) {
CCControlButton::ccTouchEnded(touch, event);
dragging = false;
}
void ScrollableButton::ccTouchCancelled(CCTouch *touch, CCEvent *event) {
CCControlButton::ccTouchCancelled(touch, event);
dragging = false;
}
The secret sauce is the override of the isTouchInside function, which will return false even if the touch is inside, but was moved. This way, the button will also release its "zoomed" state as soon as you start scrolling.
It also adds a small tolerance factor, so if the touch moves just a little, it's still considered a "click". This factor is hardcoded at 25 in the example above.
My problems:
There is a scrollView with many buttons (items). Above it there are 2 function buttons (return, start).
When I scroll down item buttons overlie function buttons. When I swallow all touches above my scrollview I will lose my function buttons. So I have to find another solution.
When I start draging scroll view a item button is pressed. When I ended the button action will be execute. This is very annoying.
But there is the solution. I have created new CCControlButton. It checks whether was clicked outside scrollview or was dragged. The button is used for items buttons.
bool ControlButtonForScrolling::checkIfTouchIsInsideScrollView(CCTouch *pTouch)
{
CCPoint touchLocation = pTouch->getLocation(); // Get the touch position
touchLocation = _scrollView->getParent()->convertToNodeSpace(touchLocation);
CCRect bBox=_scrollView->boundingBox();
bool result = bBox.containsPoint(touchLocation);
return result;
}
bool ControlButtonForScrolling::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
bool isInside = this->checkIfTouchIsInsideScrollView(pTouch);
if (isInside) {
return CCControlButton::ccTouchBegan(pTouch, pEvent);
}
else
{
return false;
}
}
void ControlButtonForScrolling::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
CCControlButton::ccTouchMoved(pTouch, pEvent);
_scrollWasDragged = true; // information about dragging is stored to prevent sending action
}
void ControlButtonForScrolling::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
// this method is a copy of CCControlButton::ccTouchEnded except lines with _scrollWasDragged
m_eState = CCControlStateNormal;
m_isPushed = false;
setHighlighted(false);
if (!_scrollWasDragged)
{
if (isTouchInside(pTouch))
{
sendActionsForControlEvents(CCControlEventTouchUpInside);
}
else
{
sendActionsForControlEvents(CCControlEventTouchUpOutside);
}
}
_scrollWasDragged = false;
}