Detect Touch on image Texture in OpenGl - iphone

I am trying to develop a game using openGL where i have used GLTextureLoader class to load images and these sprites are moving from left to right with some calculated velocity , i need to detect touch on these images.

Since your purpose is very simple, all you have to do is draw whatever object you have twice, the visible one and another one with just color on an invisible buffer. then you check for the location where the user pressed in the invisible buffer, see what color it is and there you have your object.
http://www.lighthouse3d.com/opengl/picking/index.php3?color1
That is the basic theory.

OpenGL is a rendering API. It only draws stuff.
Techniques like lighthouse3d do work, but glReadPixels is slow.
You should check this on the CPU; that is, for each drawn sprite, test if the touch position is inside.

I found out how to do it ,as per my requirement , As i said i am not the expert in openGL but managed to do it some way around.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[touches allObjects] objectAtIndex:0];
CGPoint touchLocation = [touch locationInView:self.view];
touchLocation = touchLocation = CGPointMake(touchLocation.x, 320 - touchLocation.y);
//self.player.moveVelocity = GLKVector2Make(50, 50);
//NSLog(#"Location in view %#", NSStringFromCGPoint(touchLocation));
//NSLog(#"bounding box is %#",NSStringFromCGRect([self.player boundingBox]));
GameSprite *temp;
for (GameSprite *tempSprite in self.children) {
if (CGRectContainsPoint([tempSprite boundingBox], touchLocation)) {
NSLog(#"touched the player");
temp =tempSprite;
}
}
[self.children removeObject:temp];
}
- (CGRect)boundingBox {
CGRect rect = CGRectMake(self.position.x, self.position.y, self.contentSize.width, self.contentSize.height);
return rect;
}

Related

cocos2d for iPhone - Touch no longer works correctly after scale

I am rather new to using Cocos2d for iPhone and I am having an issue with touch locations. At the moment I am simply trying to touch and move a sprite on the screen, this works fine when the layer is unmoved as well as when I translate the layer (changing self.position in X direction in my case) however, when I scale my layer (example: self.scale = .5) the touch no longer moves the sprite. I have done a lot of forum searching/google searching and I think my issue has to do with my coordinate transforms (node space/world space etc.) But I am not 100% sure. I did notice that when I scale, if I click the location where the sprite would be without the scale, then I could move the sprite. This leads me to believe that my transforms are not taking the scale into account.
Here is the coordinate transform code I am currently using to get touch locations:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [self convertToNodeSpace:location];
location = [[CCDirector sharedDirector] convertToGL:location];
}
Here is the code that is checking if the location (same location variable as above) is touching a sprite, although I feel much more confident that this code is correct, who knows!
for (CCSprite *sprite in movableSprites) {
if (CGRectContainsPoint(sprite.boundingBox, touchLocation)) {
NSLog(#"Woohoo, you touched a sprite!");
break;
}
}
Let me know if you need anymore information and thanks for reading!
I think you should double the bounding box with the scale
for (CCSprite *sprite in movableSprites) {
if (CGRectContainsPoint(sprite.boundingBox*sprite.scale, touchLocation)) {
//touch sprite action
}
}
About converting the point, if I need an absolut screen point I always use:
convertToWorldSpace:CGPointZero.
I'm not really sure why you need this on your touch location, I would usually do this on sprites when I need to disregard their position in a parent node.
Other then that, If your game is not real multi-touch game you better use ccTouchBegan and not ccTouchesBegan.
Use this function to get sprite rect.
-(CGRect)getSpriteRect:(CCNode *)inSprite
{
CGRect sprRect = CGRectMake(
inSprite.position.x - inSprite.contentSize.width*inSprite.anchorPoint.x,
inSprite.position.y - inSprite.contentSize.height*inSprite.anchorPoint.y,
inSprite.contentSize.width,
inSprite.contentSize.height
);
return sprRect;
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
for (CCSprite *sprite in movableSprites)
{
CGRect rect = [self getSpriteRect:sprite];
if (CGRectContainsPoint(rect, location))
{
NSLog(#"Woohoo, you touched a sprite!");
break;
}
}
}

Jittery movement when using CGAffineTransformMakeRotation

I'm having a problem with a jumping movement with using CGAffineTransformMakeRotation. It seems to work fine until I get to the top of quadrants 1 and 2. Below is the code I am using and youtube link that shows what happens. Any insight would be really appreciated.
My goal is to rotate a UIWebView with an svg inside. Since I can't easily detect touch on the UIWebView alone, I'm putting a blank UIImageView over it. This allows me to detect the touch and prevent the copy dialog from popping up.
http://www.youtube.com/watch?v=x_OmS0MPdEE&feature=youtu.be
- (void)touchesMoved: (NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
NSArray *allTouches = [touches allObjects];
CGPoint location = [[allTouches objectAtIndex:0] locationInView:self.view];
if(selected == 1) {
CGFloat rads = atan2f(location.y - (grid1.frame.size.height/2),location.x - (grid1.frame.size.width/2));
grid1.transform = grid1Btn.transform = CGAffineTransformMakeRotation(rads);
}
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
NSArray *allTouches = [touches allObjects];
CGPoint location = [[allTouches objectAtIndex:0] locationInView:self.view];
if(CGRectContainsPoint(grid1Btn.frame, location))
{
selected = 1;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
selected = -1;
}
You use some frame.size.* in your computations. Note, that those values (unlike bounds.size.*) are affected by transform. Use grid1.center instead. It is also more logical (you rotate around center).
The next thing you need to fix is that it should not jump to new position when touches start :)
The jerkiness is caused by the inherent inaccuracy of touch event locations.
Touch events that are located sufficiently close to the center of the frame have a high likelihood of straying to the diagonally opposite quadrant of the frame whilst a circle is being traced about the center of the frame.
This will result in a sudden jump of 90 degrees as observed in your video.
One way to avoid the problem is to introduce a dead zone about the center of the frame. Any touch that is located within a given radius of the center of the frame would not trigger the rotation to be recalculated.
Hope this helps.

iOS - Drag and drop collision detection How to detect when your selected item drags over another subview?

We are adding drag and drop functionality to what is to become a sports field with positions for players.
The positions are mapped out using Interface Builder with each being a separate UIImageView.
We want to be able to drag player images from bench positions from the side of the screen onto positions on the field.
How best can we detect when the selected player which is being moved around collides with an existing gamePosition imageView?
We are looking for a way to detect if there is a view or ImageView under the current location.
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
tile1.center = location;
if gamePositionExistsAtCurrentLocation(location) { //want something like this
[tile1 setBackgroundColor:[UIColor blueColor]];
} else {
[tile1 setBackgroundColor:[UIColor yellowColor]];
}
}
check if the frame of the item you are moving intersects with the frame from on of your subviews
for (UIView *anotherView in self.subviews) {
if (movingView == anotherView)
continue;
if (CGRectIntersectsRect(movingView.frame, anotherView.frame)) {
// Do something
}
}
If I were you, I would add all game relevant items to an NSArray and for-loop through this. So you don't detect collisions with subviews that have nothing to do with your game like labels and so on.
Also might want to consider view.center with CGRectContainsPoint()

Smoothly drag a Sprite in cocos2d - iPhone

I have implemented a drag on a sprite object as follows..
-(BOOL)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
CGPoint location = [[Director sharedDirector] convertCoordinate: [touch locationInView:touch.view]];
[diskSprite setPosition:ccp(location.x , location.y )];
return kEventHandled;
}
but this dragging is not smooth.....
when i drag fast with my thumb the object left from the path.
Thanks
Probably a little bit late but I was searching for a similar thing.
I found this great Tutorial which explained everything:
http://www.raywenderlich.com/2343/how-to-drag-and-drop-sprites-with-cocos2d
- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
CGPoint oldTouchLocation = [touch previousLocationInView:touch.view];
oldTouchLocation = [[CCDirector sharedDirector] convertToGL:oldTouchLocation];
oldTouchLocation = [self convertToNodeSpace:oldTouchLocation];
CGPoint translation = ccpSub(touchLocation, oldTouchLocation);
CGPoint newPos = ccpAdd(mySpriteToMove.position, translation);
mySpriteToMove.position = newPos;
}
I had this same issue with my game. Dragging operations appeared jerky. I believe the reason is that touch events aren't generated fast enough to give a smooth appearance.
To solve the problem I smoothed the motion out by running an action on the sprite toward the desired location, instead of setting the position immediately.
I'm not exactly sure what you mean by "the object left from the path". I suppose what you mean is that if you drag your finger over the screen in an arc or circle, that the sprite will "jump" from point to point, instead of follow your finger precisely. Is this correct?
If you want your sprite to follow an exact path, you will have to create a path and then set the sprite to follow it. What you do now is simply set the sprite's position to the touch position, but a "dragged" touch will not create an event for every pixel it touches.
It is fairly easy to create a path for touches received, and code samples can be found here and there. However, if the sprite's speed (in pixels per frame) is too high, you will always see it "jump", even if you use a smooth path.
Example:
You can animate a sprite over a circular path. If you animate this to complete the path in 1 second, you will likely see smooth animation. But if it runs at a high speed, like a full circle in 4 frames, you will just see your sprite at 4 places, not in a smooth circle.
If you wish to 'correct' that, you will need to look into blending, or determine what the maximum speed is for acceptable motion, and slow your sprite down when it's too fast.
I hope that answers your question. If it's not clear, feel free to edit your question, or add a comment to my answer.
look here, what I suggest you to try in such case:
-(void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
if (_binCaptured) {
CGPoint location = [self convertTouchToNodeSpace:touch];
[_sprite stopAllActions];
id move = [CCEaseIn actionWithAction:[CCMoveTo actionWithDuration:0.1 position:ccp(location.x, _sprite.position.y)]];
[_sprite runAction:move];
}
}
And it really work smoothly.
I enjoyed this easy way.

How can I detect touch in cocos2d?

I am developing a 2d game for iPhone by using cocos2d.
I use many small sprite (image) in my game. I want to touch two similar types of sprite(image) and then both sprite(image) will be hidden.
How can I detect touch in a specific sprite(image) ?
A better way to do this is to actually use the bounding box on the sprite itself (which is a CGRect). In this sample code, I put all my sprites in a NSMutableArray and I simple check if the sprite touch is in the bounding box. Make sure you turn on touch detection in the init. If you notice I also accept/reject touches on the layer by returning YES(if I use the touch) or NO(if I don't)
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint location = [self convertTouchToNodeSpace: touch];
for (CCSprite *station in _objectList)
{
if (CGRectContainsPoint(station.boundingBox, location))
{
DLog(#"Found sprite");
return YES;
}
}
return NO;
}
Following Jonas's instructions, and adding onto it a bit more ...
- (void)ccTouchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch* touch = [touches anyObject];
CGPoint location = [[[Director sharedDirector] convertCoordinate: touch.location];
CGRect particularSpriteRect = CGMakeRect(particularSprite.position.x, particularSprite.position.y, particularSprite.contentSize.width, particularSprite.contentSize.height);
if(CGRectContainsPoint(particularSpriteRect, location)) {
// particularSprite touched
return kEventHandled;
}
}
You may need to adjust the x/y a little to account for the 'centered positioning' in Cocos
In your layer that contains your sprite, you need to say:
self.isTouchEnabled = YES;
then you can use the same events that you would use in a UIView, but they're named a little differently:
- (void)ccTouchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch* touch = [touches anyObject];
//in your touchesEnded event, you would want to see if you touched
//down and then up inside the same place, and do your logic there.
}
#david, your code has some typos for cocos 0.7.3 and 2.2.1, specifically CGRectMake instead of CGMakeRect and [touch location] is now [touch locationInView:touch.view].
here's what I did:
- (BOOL)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
CGPoint location = [[Director sharedDirector] convertCoordinate: [touch locationInView:touch.view]];
CGRect myRect = CGRectMake(sprite.position.x, sprite.position.y, sprite.contentSize.width, sprite.contentSize.height);
if(CGRectContainsPoint(myRect, location)) {
// particularSprite touched
return kEventHandled;
}
}
#Genericrich: CGRectContainsPoint works in CocosLand because of the call 2 lines above:
[[Director sharedDirector] convertCoordinate:]
The Cocos2D objects will be using the OpenGL coordinate system, where 0,0 is the lower left, and UIKit coordinates (like where the touch happened) have 0,0 is upper left. convertCoordinate: is making the flip from UIKit to OpenGL for you.
Here's how it worked for me...
Where spriteSize is obviously the sprite's size... :P
- (BOOL)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
CGPoint location = [[Director sharedDirector] convertCoordinate: [touch locationInView:touch.view]];
CGRect myRect = CGRectMake(sprite.position.x-spriteSize/2, sprite.position.y-spriteSize/2, spriteSize, spriteSize);
if(CGRectContainsPoint(myRect, location)) {
// particularSprite touched
return kEventHandled;
}
}
this is a good tutorial explaining the basic touch system
http://ganbarugames.com/2010/12/detecting-touch-events-in-cocos2d-iphone/
first, write
self.isTouchEnabled = YES;
then, you need to implement the functions ccTouchesEnded, ccTouchesBegan, etc
from what I understood, you want to be able to 'match' two sprites that can be on different coordinates on the screen.
a method for doing this.. : (im sure theres many other methods)
consider having 2 global variables.
so everytime a touch touches a sprite, you use the CGRectContainsPoint function that is mentioned several times to find which sprite has been touched. then, you can save the 'tag' of that sprite in one of the global variables.
You do the same for the second touch, and then you compare the 2 global variables.
you should be able to figure out the rest but comment if you have problems.