Cocos won't detect a touch in the sprite

Cocos won't detect a touch in the sprite
0

In a layer, I have made multiple sprites like so:

void Layer::ScatterSprites()
{


	for (int i = 0;i<7;i++)
	{
		Counters = Sprite::create("Image.png"); 
		Counters ->setPosition(P[i]);
		Counters ->setScale(S[i]);
		this->addChild(Counters);
	}
}

and elsewhere in the same layer, I have made the listeners like so:

bool Layer::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event)

{

	
	return true; // true if the function wants to swallow the touch
}

// called when the user moves their finger

void Layer::onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *event)

{



}

// called when the user lifts their finger

void Layer::onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *event)
{   
	//cocos2d::experimental::AudioEngine::play2d("audio.mp3");
       //^^This works when not commented out, so I am sure a touch is detected

	Point touchPoint = touch->getLocation();

	if (Counters ->getBoundingBox().containsPoint(touchPoint))
	{
		cocos2d::experimental::AudioEngine::play2d("audio.mp3");
	}
	
}

but I can’t hear the sound when I click Counters. I set it to swallow touches.

you aren’t adding the touch events to the Sprites you are creating…

I might also use a different class name than Layer

I’ll look into it, a rapid response too.

Just keeping some values private, this isn’t the actual name

Sure, however, replacing with the name of an Engine object leads to us having to think harder because we don’t know if you have a misunderstanding or something else.

I quite agree, I do avoid doing so to keywords, but in this case, it’s just a mode.

[gamemodename]Layer

This is what I do:

if (sprite && sprite->initWithSpriteFrameName(_kernelFileNames.at(0)))
    {
        sprite->retain();
        sprite->initOptions(_tKernelFileName, _tPopcornFileName);
        sprite->addEvents();
        sprite->scheduleOnce(schedule_selector(CornSprite::delayTimer), 
            sprite->getTimeUntilPop() + 1);
        sprite->scheduleOnce(schedule_selector(CornSprite::changeTexture), 
            sprite->getTimeUntilPop() - 2);
        sprite->scheduleOnce(schedule_selector(CornSprite::addMore), 
            sprite->getTimeUntilPop() - 2);
        
        return sprite;
    }
    
    CC_SAFE_DELETE(sprite);
    return nullptr;

and then the events piece:

void CornSprite::addEvents()
{
    // physics event
    auto contactListener = cocos2d::EventListenerPhysicsContact::create();
    contactListener->onContactBegin = std::bind(&CornSprite::onContactBegin, this, 
        std::placeholders::_1);
    cocos2d::Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);

    // touch events.
    auto listener = cocos2d::EventListenerTouchOneByOne::create();
    listener->setSwallowTouches(true);
    
    listener->onTouchBegan = [&](cocos2d::Touch* touch, cocos2d::Event* event)
    {
        if (!_gameObject->Instance()->getGameIsPaused())
        {
            cocos2d::Vec2 p = touch->getLocation();
            cocos2d::Rect rect = this->getBoundingBox();
            
            if(rect.containsPoint(p))
            {
                CornSprite::touchEvent(touch);
                return true;
            }
        }
        
        return false;
    };
    
    listener->onTouchEnded = [=](cocos2d::Touch* touch, cocos2d::Event* event)
    {
    };
    
    cocos2d::Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
}

void CornSprite::touchEvent(cocos2d::Touch* touch)
{
    //std::cout << "touched " << this->getTag() << std::endl;
    
    cocos2d::Vec2 p = touch->getLocation();
    cocos2d::Rect rect = this->getBoundingBox();
    
    if(rect.containsPoint(p))
    {
        //std::cout << "touched corn sprite" << std::endl;
        
        CocosDenshion::SimpleAudioEngine::getInstance()->playEffect("reward.mp3");
        
        GAMEOBJECTINSTANCE->incrementCurrentScore();
        
        //GAMEOBJECTINSTANCE-> setScoreLabel(GAMEOBJECTINSTANCE->getCurrentScore());
        
        GAMEOBJECTINSTANCE->decrementCornCount();
        
        addMoreSprites(1);
        
        for (int i=0; i < GAMEOBJECTINSTANCE->getCornVector().size(); i++)
        {
            CornSprite* c = GAMEOBJECTINSTANCE->getCornVector().at(i);
            
            if (this->getTag() == c->getTag())
            {
                GAMEOBJECTINSTANCE->getCornVector().erase(GAMEOBJECTINSTANCE->getCornVector().begin()+i);
                
                break;
            }
        }
        
        removeFromParentAndCleanup(true);

        //std::cout << "current score: " << GAMEOBJECTINSTANCE->getCurrentScore() << std::endl;
        //std::cout << "high score: " << GAMEOBJECTINSTANCE->getCurrentScore() << std::endl;
    }
}

bool CornSprite::onContactBegin(cocos2d::PhysicsContact& contact)
{
    return true;
}

There is stuff here that you don’t need or won’t be able to make sense of due to some #defines you don’t see, but in general the concepts should apply just fine.

Happy Sunday!

I’d say then post more complete code…omitting code makes it hard for us to see a complete picture, thus my suggestions.

As you wish. think of what’s below as seperate to all the code I have posted above, to avoid confusion
Context: In Xlayer want to make 7 sprites, and I want each of those 7 sprites to individually detect touches.
In the header:

#ifndef XLayer_H
#define XLayer_H

#include <stdio.h>
#include "cocos2d.h"

class XLayer : public cocos2d::Layer {
private:
	XLayer();
	~XLayer();

	bool onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event);

	// called when the user moves their finger

	void onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *event);

	// called when the user lifts their finger

	void onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *event);

	// called when the device goes to another application such as a phone call

	void onTouchCancelled(cocos2d::Touch *touch, cocos2d::Event *event);

	void DragCheck(cocos2d::Touch *touch);

public:
	cocos2d::Sprite *Counters;

      //declaration of other sprites and functions,irrelevant

In the .cpp
Sprite draw function and all listener based functions and code


void XLayer::PlayButton(cocos2d::Ref *pSender)
{
	
	auto addlisteners = [this]()
	{
		EventListenerTouchOneByOne *listener = EventListenerTouchOneByOne::create();

		listener->setSwallowTouches(true);



		listener->onTouchBegan = CC_CALLBACK_2(XLayer::onTouchBegan, this);

		listener->onTouchMoved = CC_CALLBACK_2(XLayer::onTouchMoved, this);

		listener->onTouchEnded = CC_CALLBACK_2(XLayer::onTouchEnded, this);

		listener->onTouchCancelled = CC_CALLBACK_2(XLayer::onTouchCancelled, this);



		Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
	};
	auto seq = Sequence::create(
		//open game actions
		CallFunc::create(addlisteners),
		nullptr);
	this->runAction(seq);

	ScatterSprites();
}
void XLayer::ScatterSprites(int counternum)
{
	
	std::vector<Vec2> X;
	
	X.push_back(Vec2(/*set position*/));
	//^^repeated numerous times...
	for (int i = 0;i<7;i++)
	{
		Counters= Sprite::create("Image.png"); 
		Counters->setPosition(X[i]);
		this->addChild(Counters);
	}
}

bool XLayer::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event)

{

	
	return true; // true if the function wants to swallow the touch
}

void XLayer::DragCheck(cocos2d::Touch *touch)
{
  Point touchPoint = touch->getLocation();

	if (Counters->getBoundingBox().containsPoint(touchPoint))
	{
		cocos2d::experimental::AudioEngine::play2d("sound.mp3");
	}  
}

// called when the user moves their finger

void XLayer::onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *event)

{



}

// called when the user lifts their finger

void XLayer::onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *event)
{   
	
	
	DragCheck(touch);
}




// called when the device goes to another application such as a phone call

void XLayer::onTouchCancelled(cocos2d::Touch *touch, cocos2d::Event *event)

{



}

I haven’t see this done before.

I would add the event listeners upon Sprite creation.

Ok, i have done so, but unfortunately to no avail. I based how I setup this touch system, to how I previously set up a touch system for an array of rects, if that helps

I’d suggest setting up the touch events like I demonstrated or look at cpp-tests.

Very well, Thanks for your time.

You are using getLocation() on the Touch object for the Point, and using getBoundingBox() for the Rect to try and check for containsPoint()

The first returns a Point in GL coordinates, and the second returns a Rect in screen coordinates.

Use getLocationInView() so your geometry is in the same reference frame and coordinates…

Thank you ever so much @tdebock This has made the click detectable in the right place, I would have to say it was the solution, it appears the box is there, the asset itself is absent. I am doing what I can with the anchoring and positioning of it to try resolve the issue.

Are you saying this method works?

I don’t add the listeners with that line specifically anymore, ever since your advice.
The code in general, I’m not sure if it would, in theory, work. I’ve updated my last post

Annotated image(sorry if the blue text is hard to read):

void XLayer::ActCheck(cocos2d::Touch *touch)
{   

	Point touchPoint = touch->getLocationInView();
    if (Counters->getBoundingBox().containsPoint(touchPoint))
	{
		cocos2d::experimental::AudioEngine::play2d("sound.mp3");
	}
	CCLOG("click: %f, %f", touchPoint.x, touchPoint.y);
	CCLOG("CounterPos: %f, %f", Counters->getPositionX(), NimCounters->getPositionY());
}


// called when the user lifts their finger

void XLayer::onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *event)
{   
	
	ActCheck(touch);

}

As you can see, I have made the Log say the click location, as well as the location of the sprite. When I click in the space you see in a green box, the following log is printed:

click: 509.000000, 80.000000
CounterPos: 468.292694, 80.000000
V/AudioPlayer (69): ~AudioPlayer() (0D4EC2F8), id=4
V/AudioPlayer (83): AudioPlayer::destroy begin, id=4
V/AudioPlayer (128): Before alSourceStop
V/AudioPlayer (130): Before alSourcei
V/AudioPlayer (136): AudioPlayer::destroy end, id=4
V/AudioPlayer (147): AudioPlayer::play2d, _alSource: 1, player id=5

But the sprite Counters is nowhere to be seen. I made counters like so:

	std::vector<Vec2> X;
	
	X.push_back(Vec2(visibleSize.width / 2.05 + origin.x, visibleSize.height / 8 + origin.y));
	Counters= Sprite::create("PaperclipG.png");
	Counters->setPosition(X[0]);
	Counters->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);//trying different anchor points to solve error
	this->addChild(Counters);

If I position it here: visibleSize.width / 3.9 + origin.x, visibleSize.height / -0.67 + origin.y
It IS in view, but the bounding box is no longer present. I imagine due to the negative value

Look into your node hierarchy and relative transformations. Collision Math is done in 1 reference frame, generally you bring all values into worldspace, unless they are on the same parent.