Cocos2d: Detect touch on rotated sprite?

时光总嘲笑我的痴心妄想 提交于 2019-12-21 19:11:29

问题


How would one detect a touch on a rotated CCSprite?

I am familiar with the general technique of using ccTouchesBegan and contentSize, anchorPoint etc. to have a sprite detect if a touch was within its bounds ... but I am not sure how to proceed once the sprite has been rotated by some angle.

I want the sprite itself to detect the touch (encapsulation) and report the event via a delegate to another object.

If anyone has some code to share ... would be great.


回答1:


Try using the CCNode convertTouchToNodeSpaceAR: method to convert the point to the rotated coordinates and then you can do the compare of the sprite bounds.

I made this a category on CCNode so it's available to any CCNode or subclass.

@interface CCNode (gndUtils)

// Lets a node test to see if a touch is in it.
// Takes into account the scaling/rotation/transforms of all 
// the parents in the parent chain.
// Note that rotation of a rectangle doesn't produce a rectangle 
// (and we are using a simple rectangle test)
//   so this is testing the smallest rectangle that encloses the rotated node.
// This does the converstion to view and then world coordinates
// so if you are testing lots of nodes, do that converstion manually
//
//  CGPoint touchLoc = [touch locationInView: [touch view]];  // convert to "View"
//  touchLoc = [[CCDirector sharedDirector] convertToGL: touchLoc]; // move to "World"
// and then use worldPointInNode: method instead for efficiency.

- (BOOL) touchInNode: (UITouch *) touch;

// allows a node to test if a world point is in it.
- (BOOL) worldPointInNode: (CGPoint) worldPoint;

@end

and the implementation:

@implementation CCNode (gndUtils)

- (BOOL) touchInNode: (UITouch *) touch
{
    CGPoint touchLoc = [touch locationInView: [touch view]];            // convert to "View coordinates" from "window" presumably
    touchLoc = [[CCDirector sharedDirector] convertToGL: touchLoc];     // move to "cocos2d World coordinates"

    return [self worldPointInNode: touchLoc];
}

- (BOOL) worldPointInNode: (CGPoint) worldPoint
{
    // scale the bounding rect of the node to world coordinates so we can see if the worldPoint is in the node.
    CGRect bbox = CGRectMake( 0.0f, 0.0f, self.contentSize.width, self.contentSize.height );    // get bounding box in local 
    bbox = CGRectApplyAffineTransform(bbox, [self nodeToWorldTransform] );      // convert box to world coordinates, scaling etc.
    return CGRectContainsPoint( bbox, worldPoint );
}
@end



回答2:


@Dad's code transforms the node's bbox into world. For a rotated node, this expands the bbox and can return true for touches that are outside the actual node but inside the world bbox. To avoid this, transform the world point into the node's coordinate space, and test the local point there.




回答3:


As Absinthe said - code of poundev23 really checking only BB around the rotated sprite. I have written correct code (but on Cocos2dx - c++) - hope it helps somebody:

CCSize size = this->getContentSize();
CCRect rect = CCRect(0, 0, size.width, size.height);
CCPoint pt = touch->locationInView();
pt = CCDirector::sharedDirector()->convertToGL(pt);
pt = CCPointApplyAffineTransform(pt, this->worldToNodeTransform());
bool b = CCRect::CCRectContainsPoint(rect, pt);

have a nice code !

Edit: Nice solution! I converted it to Objective C.

- (BOOL) containsTouchLocation:(UITouch *) touch
{
    CGSize size = self.contentSize;
    CGRect rect = CGRectMake(0, 0, size.width, size.height);
    CGPoint touchLocation = [touch locationInView: [touch view]];
    touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
    touchLocation = CGPointApplyAffineTransform(touchLocation, self.worldToNodeTransform);
    bool containsPoint = CGRectContainsPoint(rect, touchLocation);

    return containsPoint;
}


来源:https://stackoverflow.com/questions/3273945/cocos2d-detect-touch-on-rotated-sprite

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!