No way to detect touch on a sprite? I refer to detect touch and not touch if transparent part of the sprite as use png
use cocos2d 2.2.6
No way to detect touch on a sprite? I refer to detect touch and not touch if transparent part of the sprite as use png
use cocos2d 2.2.6
Do you want to know how to do it or if there is a built-in function?
I want to know how to do or suggestions, I was using the “menuitem” but me when you touch me also take the transparent part of the image
The simplest way is within onTouchBegan
or onTouchesBegan
:
// get the location of the touch on screen
var location = touch.getLocation();
// get the location of the touch relative to your button
var nodeSpaceLocation = node.getParent().convertToNodeSpace(location);
// check if touch is inside node's bounding box
if (cc.rectContainsPoint(node.getBoundingBox(), nodeSpaceLocation)) {
// node has been touched; add code here
}
Change node
to the variable for your sprite.
Cocos2d-x does not support pixel perfect touch as far as I know.
There are a few ways that spring to mind, you can render your scene using a unique shader to an render buffer as solid colours per object, you then sample the render buffer with the touch coord and map that back to the object.
Another is similar but more brute force: you could simply sample the texture of your sprite after transforming the touch position into the texel space.
And thirdly you might try and clip away the transparent pixels by creating a mesh based on the texture and test against that. cocos2d-x has recently added such a feature.
I have a v2.2.6 app that uses a RenderTexture
and glReadPixels
to test if the touched location is transparent or not. Works perfectly for me, and it’s relatively simple. Not sure if this one of @almax27’s methods or not.
How I do it:
begin
with your RenderTexture.glReadPixels
(probably gl.readPixels
in JavaScript) to get the bottom-left pixel of the screen.end
with your RenderTexture.color[3]
, if you called your array color
.I can provide source code, but maybe one of the other 3 methods might be easier or better, I’m not sure.
Yeah it’s similar to the second solution I suggested, quick to implement and simple but will get very expensive if you start testing lots of different images. glReadPixels can be pretty slow so you want to minimise how much you call it. First solution is probably the most performant but will take longer to implement.
Continuing the discussion from Detect touch in sprite:
Try the code you passed me but I pulled this error on the console:
Uncaught TypeError: cc.rectContainsPoint is not a function
you got an example? I would greatly appreciate it
Sorry, I have been busy for the last few days.
I am not sure why you are getting this error. It should be a built-in function of Cocos2d-x.
Here is some code that works for me. Not sure if it is perfect, but I have tested it and it seems to work.
// the onTouchesBegan function for your layer
onTouchesBegan:function(touches) {
// to check position, it needs to be in the node space of the node's parent
var pos = this.node.getParent().convertToNodeSpace(touches[0].getLocation());
// checking for transparency can be costly, so avoid it if you can. if the touch is outside of the node's
// bounding box, then there is no chance you have touched the node, so no need to check for transparency.
if (cc.rectContainsPoint(this.node.getBoundingBox(), pos)) {
// if the bounding box was touched, then you need to check for transparency
if (!isTransparent(this.node, pos)) {
// if the touched pixel was not transparent, you have touched the node
cc.log("Touched!");
return;
}
}
// either the touch was outside the bounding box or was a transparent pixel
cc.log("Not touched!");
}
// check if a position in the node space of a node's parent is a transparent pixel
function isTransparent(node, pos) {
// used to store the RGBA value for the pixel
var pixel = new Uint8Array(4);
// a RenderTexture is used to read the colour of the pixel
var renderTexture = cc.RenderTexture.create(5, 5);
// to be efficient, we create a small RenderTexture and move the node so that the touched point is at
// at position (0, 0), which is the bottom-left of the RenderTexture. because of this, we need to remember
// the location of the node so we can move it back afterwards.
var originalPosition = node.getPosition();
// move the node so that the touched point is at (0, 0)
node.setPosition(originalPosition.x - pos.x, originalPosition.y - pos.y);
// because we get get the colour of the pixel of the RenderTexture, we need to clear the RenderTexture to
// make sure we are only getting the colour of the node.
renderTexture.beginWithClear(0, 0, 0, 0);
// draw the node onto the RenderTexture
node.visit();
// get the colour of the pixel at (0, 0)
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
// finish drawing on the RenderTexture
renderTexture.end();
// put the node back in its original position
node.setPosition(originalPosition);
// pixel[3] is the alpha value of the pixel. if it has a value of 0, the pixel is completely transparent. sometimes
// the edges of nodes are partially transparent, so you should determine at which value you decide a pixel
// is not transparent.
return (pixel[3] < 50);
}
This seems very expensive doing all this checking just create a customs sprite object which inherits from ccSrpite then if you create one global touch eventlistener and inside this check the bounds of the touch against its parents bounds (Tells you if inside the sprite) then just add this touch listener to the custom sprite whenever you create one.
Global Listener
var onTouchBegan = function(touch,event)
{
var target = event.getCurrentTarget();
var location = target.convertToNodeSpace(touch.getLocation());
var targetSize = target.getContentSize();
var targetRectangle = cc.rect(0, 0, targetSize.width, targetSize.height);
//Check if pressed inside the object
if (cc.rectContainsPoint(targetRectangle, location))
{
target.setPressed(true);
}
return true;
};
this gets if the touch was inside the sprite then you just need to add it to your object here is a simple example
var ObjectTile = cc.Sprite.extend({
checkHit:false,
lightListener:null,
ctor:function()
{
this._super(res.Outline_png);
//Add touch listener for object
this.lightListener = cc.EventListener.create({
event: cc.EventListener.TOUCH_ONE_BY_ONE,
swallowTouches: false,
onTouchBegan: onTouchBegan,
onTouchEnded: onTouchEnded
});
cc.eventManager.addListener(this.lightListener, this);
},
removeListener:function()
{
cc.eventManager.removeListener(this.lightListener);
},
setPressed:function(on)
{
this.checkHit = on;
},
});
kelor wants to know how to determine if a touch is on a transparent or on an opaque pixel. Testing if the touch location is within the bounding box will tell you if you are touching the sprite, but not if the pixel you are touching is transparent or not.
Hey, you can now fix it, looking at google found a feature that detects if a sprite transparent or opaque and opaque if I put the function.
and it works on 2.2.6
Thank you very much to all
@keior please link what you found on google so others who have the same issue in the future can benefit,
Thank you