Drawing a UIImageView at position of user tap - iphone

This is the 2nd time I have asked this. How do I draw an image at the location of the user's tap every time the user taps the screen?
Could you please leave a sample project or code because I am new to iPhone programming and have a hard time understanding certain methods etc.
Thanks,
Tate

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
UIImageView * anImageView = [[UIImageView alloc] initWithImage:anImage];
[anImageView setCenter:[touch locationInView:self.view]];
[self.view addSubview:anImageView];
[anImageView release];
}
In the future, read the documentation or use Google.

Related

Velocity of touches

I'm making a simple physics game in cocos2d and want to launch a particle on swipe a the speed of the swipe. To get the velocity I need to take two touches and determine the (difference in position)/(difference in timestamp). My problem is that I can't get two touches. I tried a few methods but none of them are working out.
I tried storing the first touch
#property (nonatomic, strong) UITouch *firstTouch;
...
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
[self setFirstTouch:touch];
NSLog(#"first touch time 1: %f", self.firstTouch.timestamp);
}
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
NSLog(#"touch ended");
NSLog(#"first touch time 2: %f", self.firstTouch.timestamp);
NSLog(#"end of touch time: %f", touch.timestamp);
}
but this gives me a difference in timestamps of 0 every time. It seems to replace the firstTouch with the most recent touch
Am I doing something wrong with pointers that this is replaced?
Perhaps I can take the last two touches from ccTouchesMoved?
A far easier way of doing what you are trying to do is adding a UIPanGestureRecognizer to your [CCDirector sharedDirector].openGLView and then use the velocityInView property of the gesture recognizer.
UIPanGestureRecognizer* gestureRecognizer = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)] autorelease];
[[CCDirector sharedDirector].openGLView addGestureRecognizer:gestureRecognizer];
and then:
- (void)handleSwipe:(UIPanGestureRecognizer*)recognizer {
... recognizer.velocity...
}
If you want do follow your approach based on ccTouches..., it seems to me that possibly there is a misunderstanding about a swipe gesture, in that it is not made of 2 touches: it is just one touch that has a begin, some moves, and an end. So you need to track the movement of your finger in ccTouchesMoved:; then in touchesEnded determine whether it is a horizontal or vertical swipe, the direction, and send out the bullet.
Hope either of these suggestions may help.

Lower the CPU usage of an app

I am having an issue with CPU usage. When I starts my app its animation starts at good speed and all of sudden animation speed gets lower down and then app gets crashed. But when I checked the app with Activity Monitor(Instrument) my app use CPU near about 80%-90%. I am unable reduce the CPU usage.
CODE:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint location;
UITouch *touch = [[event allTouches] anyObject];
location = [touch locationInView:self.view];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint location;
UITouch *touch = [[event allTouches] anyObject];
location = [touch locationInView:self.view];
touchMovedX = location.x;
touchMovedY = location.y;
[self merge];
}
// -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
//{
// [self merge];
// }
-(void)merge
{
CGSize size = CGSizeMake(320, 480);
UIGraphicsBeginImageContext(size);
CGPoint point1 = CGPointMake(0,0);
CGPoint point2 = CGPointMake(touchMovedX,touchMovedY);
UIImage *imageOne = [UIImage imageNamed:#"iphone.png"];
[imageOne drawAtPoint:point1];
UIImage *imageTwo = [UIImage imageNamed:#"Cloud.png"];
[imageTwo drawAtPoint:point2];
imageB.image=imageTwo;
UIImage *imageC = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
imageview = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,320,480)];
imageview.image=imageC;
[self.view addSubview:imageview];
}
-(IBAction)save:(id)sender {
UIImage* imageToSave = imageview.image;
UIImageWriteToSavedPhotosAlbum(imageToSave, nil, nil, nil);
[imageToSave release];
}
Any help would be appreciable.
Thanks
Don't call touchesMoved in your touchesBegan code. touchesMoved is called by iOS in response to touches being moved
Likewise with touchesEnded - this gets called when the user removes the finger from the screen
In addition - your code for merge is adding more and more subviews to your view - at the end of every call to merge you are callin [self.view addSubview:imageview] which is going increase your CPU usage in handling all the subviews. Everytime you move your finger in touches moved then this will be adding a new subview and never removing them.
-(void)viewDidAppear:(BOOL)animated{
UIPanGestureRecognizer *pgr1 = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(image1Moved:)];
[iv1 addGestureRecognizer:pgr1];
}
-(void)image1Moved:(UIPanGestureRecognizer *)pgr{
NSLog(#"Came here");
[iv1 setCenter:[pgr locationInView:self.view]];
}
Do some thing like the above. Where you can move the imageview.
Also, call the merge using another button, where you move the image at will, but when it is time to merge, click a button. That way, you will call Merge only once and it will not be any load on the CPU.
Looks like you are a beginner and I would highly recommend that you follow some tutorials and learn some more about
Instance Variables
Properties
gesture recognizers etc
It is not touchesMoved or touchesBegan which is causing the CPU usage. It is definitely [self merge]. I am assuming that you are doing some CPU intensive job in [self merge] and that is being done so many times.
You have to do any CPU intensive job on another thread for the app to be responsive. Also if you are doing stuff at every move, then it may become too slow.
Please post the code for what you are doing in merge method.
There are three things which you can do
Improve the merge method to make it efficient.
Use Grand Central dispatch
Read up about dispatch_async(dispatch_get_global_queue, ^{ }); etc. This will be under Grand Central Dispatch section.
Another way is to do [self performSelector:#(merge) afterDelay:0.5s];
This method will call merge, only once every 0.5 seconds.
and then if you do not want the same method to be called so many times, or it is not necessary for every move, just before that call
[NSObject cancelPreviousPerformRequestsWithTarget:<#(id)#> selector:<#(SEL)#> object:<#(id)#>
The cancel method will cancel previous invocations and call the method again.
But again, it all depends on what you are trying to do.

How to make two specific images, when a user places one on top of the other, create a third specified image (all of them pre-created images)

I would like the user to be able to press and drag one image (ex: image1.png) and place it over another (ex: image2.png). When the user releases, a third image (ex: image3.png) is added to the screen. How could I go about doing that in xcode?
It's not so easy to do what you want, you have to start to see this touches tutorial from Apple Developer program
here is a code sample for the image moving:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self.view];
if (CGRectContainsPoint([image1 frame], location)) {
images.center = location;
if (CGRectContainsPoint([image1 frame], [image2 frame]) {
//place your code when image1 = images2
[self.view addSubview:image3];
}
}
}
i think something like this could work

How can I get touch co-ordinates in cocos2d?

What I want is that wherever user touches on iPhone screen, where I will display a pic at that place.
Can anyone help me how to get co-ordinates of the area everytime when user touches the screen?
You don't say you are using cocos2d, but you tagged your question as such. I will assume this is the case.
You need to put code in your ccTouchesEnded function. This is basically what it looks like:
-(BOOL)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView: [touch view]];
CCSprite *myImage = [CCSprite spriteWihFile: #"myImage.png"];
[myImage setPosition: location];
[self addChild: myImage];
return YES;
}
It sounds like you might need more help than that. If so, you should go to the cocos2d iphone page and look through the setup and tutorials.

UIScrollView touches vs subview touches

Please can someone help sort a noob out? I've posted this problem on various forums and received no answers, while many searches for other answers have turned up stackOverflow, so I'm hoping this is the place.
I've got a BeachView.h (subclass of UIScrollView, picture of a sandy beach) covered with a random number of Stone.h (subclass of UIImageView, a random PNG of a stone, userInteractionEnabled = YES to accept touches).
If the user touches and moves on the beach, it should scroll.
If the user taps a stone, it should call method "touchedStone".
If the user taps the beach where there is no stone, it should call method "touchedBeach".
Now, I realize this sounds dead simple. Everyone and everything tells me that if there's something on a UIScrollView that accepts touches that it should pass control on to it. So when I touch and drag, it should scroll; but if I tap, and it's on a stone, it should ignore beach taps and accept stone taps, yes?
However, it seems that both views are accepting the tap and calling both touchedStone AND touchedBeach. Furthermore, the beach tap occurs first, so I can't even put in a "if touchedStone then don't run touchedBeach" type flag.
Here's some code.
On BeachView.m
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.decelerating) { didScroll = YES; }
else { didScroll = NO; }
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:touch.view];
NSLog(#"touched beach = %#", [touch view]);
lastTouch = touchLocation;
[super touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
didScroll = YES;
[super touchesMoved:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (didScroll == NO && isPaused == NO) {
[self touchedBeach:YES location:lastTouch];
}
[super touchesEnded:touches withEvent:event];
}
On Stone.m
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[parent stoneWasTouched]; // parent = ivar pointing from stone to beachview
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:touch.view];
NSLog(#"touched stone = %#", [touch view]);
[parent touchedStone:YES location:touchLocation];
}
After a stone tap, My NSLog looks like this:
Touched beach = <BeachView: 0x1276a0>
ran touchedBeach
Touched Stone = <Stone: 0x1480c0>
ran touchedStone
So it's actually running both. What's even stranger is if I take the touchesBegan and touchesEnded out of Stone.m but leave userInteractionEnabled = YES, the beachView registers both touches itself, but returns the Stone as the view it touched (the second time).
Touched beach = <BeachView: 0x1276a0>
ran touchedBeach
Touched beach = <Stone: 0x1480c0>
ran touchedBeach
So PLEASE, I've been trying to sort this for days. How do I make it so a tapped stone calls only touchedStone and a tapped beach calls only touchedBeach? Where am I going wrong?
Is true, iPhone SDK 3.0 and up, don't pass touches to -touchesBegan: and -touchesEnded: **UIScrollview**subclass methods anymore. You can use the touchesShouldBegin and touchesShouldCancelInContentView methods that is not the same.
If you really want to get this touches, have one hack that allow this.
In your subclass of UIScrollView override the hitTest method like this:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *result = nil;
for (UIView *child in self.subviews)
if ([child pointInside:point withEvent:event])
if ((result = [child hitTest:point withEvent:event]) != nil)
break;
return result;
}
This will pass to you subclass this touches, however you can't cancel the touches to UIScrollView super class.
Prior to iPhone OS 3.0, the UIScrollView's hitTest:withEvent: method always returns self so that it receives the UIEvent directly, only forwarding it to the appropriate subview if and when it determines it's not related to scrolling or zooming.
I couldn't really comment on iPhone OS 3.0 as it's under NDA, but check your "iPhone SDK Release notes for iPhone OS 3.0 beta 5" :)
If you need to target pre-3.0, you could override hitTest:withEvent: in BeachView and set a flag to ignore the next beach touch if the CGPoint is actually in a stone.
But have you tried simply moving your calls to [super touches*:withEvent:] from the end of your overridden methods to the start? This might cause the stone tap to occur first.
I had a similar problem with a simpleView and it is added to a scrollView , and whenever I touched the simpleView , the scrollView used to get the touch and instead of the simpleView , the scrollView moved . To avoid this , I disabled the srcolling of the scrollView when the user touched the simpleView and otherwise the scrolling is enabled .
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *result = [super hitTest:point withEvent:event] ;
if (result == simpleView)
{
scrollView.scrollEnabled = NO ;
}
else
{
scrollView.scrollEnabled = YES ;
}
return result ;
}
This could be related to a bug in iOS7 please review my issue (bug report submitted)
UIScrollView subclass has changed behavior in iOS7