In cocos2d game development, CGRectContainsPoint method often used to detect if touch on a CCSprite.
I use code fllow to get a sprite's (which in a CCNode) rect property
- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
CCLOG(#"ccTouchEnded");
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CCLOG(#"location.x:%f, y:%f", location.x, location.y);
CGRect rect;
rect = CGRectMake(self.firstCard.face.position.x-(self.firstCard.face.contentSize.width/2), self.firstCard.face.position.y-(self.firstCard.face.contentSize.height/2),
self.firstCard.face.contentSize.width, self.firstCard.face.contentSize.height);
if (CGRectContainsPoint(rect, location)) {
CCLOG(#"first card touched");
[firstCard open];
}
rect = CGRectMake(self.secondCard.face.position.x-(self.secondCard.face.contentSize.width/2), self.secondCard.face.position.y-(self.secondCard.face.contentSize.height/2),
self.secondCard.face.contentSize.width, self.secondCard.face.contentSize.height);
if (CGRectContainsPoint(rect, location)) {
CCLOG(#"second card touched");
[secondCard open];
}
}
I want to know if there is a convenient way to get a CCSprite 's rect straightforward?
Please use boundingBox i think it will be a great option to use.
Like this:
- ( void ) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
locationTouchBegan = [touch locationInView: [touch view]];
//location is The Point Where The User Touched
locationTouchBegan = [[CCDirector sharedDirector] convertToGL:locationTouchBegan];
//Detect the Touch On sprite
if(CGRectContainsPoint([sprite boundingBox], locationTouchBegan))
{
isSpriteTouched=YES;
}
}
Kobold2D has a convenience method containsPoint as a CCNode extension (Objective-C category) which you can replicate in your project:
-(BOOL) containsPoint:(CGPoint)point
{
CGRect bbox = CGRectMake(0, 0, contentSize_.width, contentSize_.height);
CGPoint locationInNodeSpace = [self convertToNodeSpace:point];
return CGRectContainsPoint(bbox, locationInNodeSpace);
}
Your code then be simplified to this and it will work with rotated and/or scaled sprites as well (the boundingBox method fails to test rotated and scaled sprites correctly).
if ([firstCard.face containsPoint:location]) {
CCLOG(#"first card touched");
}
Related
I have an NSDictionary (allSprites) with a lot of Sprites (spriteX) and in my Touch Method I want to check whether the sprite was touched.
My problem is that it doesn't react to the boundingBox. I don't see my error! Is it a problem with NSDictionary? I get no error or anything... But it doesn't work.
Is there another way to check the boundingBox in an NSDictionary? Can somebody help me?
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in [event allTouches]) {
for (NSValue* value in allSprites) {
CGPoint location = [touch locationInView:touch.view];
location = [[CCDirector sharedDirector] convertToGL:location];
if(CGRectContainsPoint([spriteX boundingBox], location)){
NSLog(#"sprite was touched");
}
}
}
}
you dont seem to refer to spriteX at all in your loop other than in the test for bounding box, it is probably not initialized. maybe you meant to do :
for (CCSprite* spriteX in [allSprites allValues]) {
CGPoint location = [touch locationInView:touch.view];
location = [[CCDirector sharedDirector] convertToGL:location];
if(CGRectContainsPoint([spriteX boundingBox], location)){
NSLog(#"sprite was touched");
}
}
if you need the key of the sprite :
for (NSString*key in [allSprites allKeys]) {
spriteX = [allSprites objectForKey:key];
CGPoint location = [touch locationInView:touch.view];
location = [[CCDirector sharedDirector] convertToGL:location];
if(CGRectContainsPoint([spriteX boundingBox], location)){
NSLog(#"sprite with key %# was touched",key);
}
}
i've 6 uiimageviews, say img1 - img6. when i touch and drag img1, it moves. but as i drag the img1 and when it comes near to other uiimageviews, the img1 stops moving and the img which comes near to it, starts moving. this happens when i drag the image very fast and not when i drag the image slowly. And also the dragging is not so smooth...... :(
Here's what i've done so far...
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
if (CGRectContainsPoint([self.firstImg frame], [touch locationInView:nil]))
{
[self.view bringSubviewToFront:self.firstImg];
self.firstImg.center = [touch locationInView:nil];
}
else if (CGRectContainsPoint([self.secondImg frame], [touch locationInView:nil]))
{
[self.view bringSubviewToFront:self.secondImg];
self.secondImg.center = [touch locationInView:nil];
}
else if (CGRectContainsPoint([self.thirdImg frame], [touch locationInView:nil]))
{
[self.view bringSubviewToFront:self.thirdImg];
self.thirdImg.center = [touch locationInView:nil];
}
else if (CGRectContainsPoint([self.fourthImg frame], [touch locationInView:nil]))
{
[self.view bringSubviewToFront:self.fourthImg];
self.fourthImg.center = [touch locationInView:nil];
}
else if (CGRectContainsPoint([self.fifthImg frame], [touch locationInView:nil]))
{
[self.view bringSubviewToFront:self.fifthImg];
self.fifthImg.center = [touch locationInView:nil];
}
else if (CGRectContainsPoint([self.sixthImg frame], [touch locationInView:nil]))
{
[self.view bringSubviewToFront:self.sixthImg];
self.sixthImg.center = [touch locationInView:nil];
}
}
There are a number of problems with your implementation:
You're passing nil as the view to locationInView:, which means that if you move the superview or support interface rotation, you will get incorrect coordinates.
You're setting the image view's center to the touch location. Because of this, when the user first touches a view, if the touch isn't exactly centered in the view, the view will jump to be centered at the touch location. This is not the behavior users expect.
You're always checking the views in a fixed order, instead of checking the views from front to back. This is why “when it comes near to other uiimageviews, the img1 stops moving and the img which comes near to it, starts moving.” Your code will always move firstImg if the touch is over firstImg, even if the user was dragging secondImg, because you always check firstImg before checking secondImg.
You're repeating yourself a lot. If you have to write the same thing twice, you should think about factoring it out into a separate function or method. If you have to write the same thing three times (or more), you should almost certainly factor it out.
The simplest answer to all of these problems is to stop using touchesMoved:withEvent: and related methods. Instead, add a UIPanGestureRecognizer to each image view:
- (void)makeImageViewDraggable:(UIImageView *)imageView {
imageView.userInteractionEnabled = YES;
UIPanGestureRecognizer *panner = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(imageViewPannerDidFire:)];
[imageView addGestureRecognizer:panner];
}
- (void)imageViewPannerDidFire:(UIPanGestureRecognizer *)panner {
UIView *view = panner.view;
[view.superview bringSubviewToFront:view];
CGPoint translation = [panner locationInView:view];
CGPoint center = view.center;
center.x += translation.x;
center.y += translation.y;
view.center = center;
[panner setTranslation:CGPointZero inView:view];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self makeImageViewDraggable:self.firstImg];
[self makeImageViewDraggable:self.secondImg];
[self makeImageViewDraggable:self.thirdImg];
[self makeImageViewDraggable:self.fourthImg];
[self makeImageViewDraggable:self.fifthImg];
[self makeImageViewDraggable:self.sixthImg];
}
I am creating a zoomable and pan-able map for my game (using CCPanZoomController) . Within this map I would like to have a tappable sprite, and when it is tapped, "do something"…
I can get the two things to work perfectly in separate projects, however when I try to combine them, nothing happens when I tap my sprite.
I have included an image to demonstrate further:
//in my init section
self.isTouchEnabled = YES;
mapBase = [CCSprite spriteWithFile:#"MapBase.png"];
mapBase.anchorPoint = ccp(0, 0);
[self addChild:mapBase z:-10];
gym = [CCSprite spriteWithFile:#"Gym.png"];
gym.scale = 0.3;
gym.position = ccp(1620, 250);
[self addChild:gym z:1];
CGRect boundingRect = CGRectMake(0, 0, 2499, 1753);
_controller = [[CCPanZoomController controllerWithNode:self] retain];
_controller.boundingRect = boundingRect;
_controller.zoomOutLimit = _controller.optimalZoomOutLimit;
_controller.zoomInLimit = 2.0f;
[_controller enableWithTouchPriority:1 swallowsTouches:YES];
//end of init
-(void) registerWithTouchDispatcher
{
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self
priority:0 swallowsTouches:NO];
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
CGPoint touchPoint1 = [touch locationInView:[touch view]];
if (CGRectContainsPoint(gym.boundingBox, touchPoint1)) return YES;
return NO;
}
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event{
CGPoint touchPoint2 = [touch locationInView:[touch view]];
if (CGRectContainsPoint(gym.boundingBox, touchPoint2)){
CCLOG(#"SPRITE HAS BEEN TAPPED");
}
}
I want to beable to zoom in/out and pan the wholemap (including the ‘Gym’ sprite).
And if the sprite 'Gym' is tapped by the user, then i would like to “do something”.
If anyone can figure this out, I would be extremely grateful!
Thanks.
I have a pong game, and I use finger to move paddle.
It all goes smooth and well when there is one finger. But when I want to control two players, two paddles, one paddle moves fine but another paddle moves very laggy, if at all. When second paddle starts moving my first paddle freezes. How do I make both movements feel smooth and responsive?
I have multitouch enabled in my Director.
Here is my code for touches:
- (void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CGRect leftTouchZone = CGRectMake(0, 0, 50, 320);
CGRect rightTouchZone = CGRectMake(430, 0, 50, 320);
if (CGRectContainsPoint(leftTouchZone, location))
{
CGPoint tempLoc = location;
tempLoc.x = paddle1.position.x;
paddle1.position = tempLoc;
}
if (CGRectContainsPoint(rightTouchZone, location))
{
CGPoint tempLoc = location;
tempLoc.x = paddle2.position.x;
paddle2.position = tempLoc;
}
Shouldnt you look through all your touches objects instead of just grabbing any object? If you are moving 2 touches at the same time, only one will get the touches moved event.
- (void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch* myTouch in touches)
{
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CGRect leftTouchZone = CGRectMake(0, 0, 50, 320);
CGRect rightTouchZone = CGRectMake(430, 0, 50, 320);
if (CGRectContainsPoint(leftTouchZone, location))
{
CGPoint tempLoc = location;
tempLoc.x = paddle1.position.x;
paddle1.position = tempLoc;
}
if (CGRectContainsPoint(rightTouchZone, location))
{
CGPoint tempLoc = location;
tempLoc.x = paddle2.position.x;
paddle2.position = tempLoc;
}
}
I have a spaceship. I want the spaceship to move to the area that the player has touched. So far I have this code:
- (void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// initialize touch
UITouch *touch = [touches anyObject];
// point out location of touch
CGPoint location = [touch locationInView:[touch view]];
// move to location
[player runAction:[CCMoveTo actionWithDuration:0.5 position:location]];
// log action
CCLOG(#"player moved");
}
However, this has a quirk: When I touch in certain places the shuttle will move slow, up instead of down, and other weird movements. Is there any way to correct this code?
After the line :
CGPoint location = [touch locationInView:[touch view]];
Add this line:
location = [[CCDirector sharedDirector] convertToGL: location];
Then try. :)