iOS4.2: TouchBegan does not draw more than one circle per sensed touch - cocoa-touch

quick question (which might be a no-brainer for most here) :)
My code below should draw a circle for every time touch that is recognised but although more than ones touches are sensed only one circle will drawn up at a time.
Can anyone see any obvious issues?
This method sits in the XYZViewControler.m class.
TouchPoint.m is the class that defines the circle.
Thanks a bundle for your help and redirects.
Chris
- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *)event {
NSSet * allTouches = [event allTouches]; // get all events
for (UITouch * touch in touches) {
TouchPoint * touchPoint = [[TouchPoint alloc] initWithFrame:CGRectMake(0, 0, circleWidth, circleWidth)];
touchPoint.center = [touch locationInView:[self view]];
touchPoint.color = [UIColor redColor];
touchPoint.backgroundColor = [UIColor whiteColor];
[[self view] addSubview: touchPoint];
[touchPoint release];
CFDictionarySetValue(touchMap, touch , touchPoint);
}
[[self view] setNeedsDisplay];
}

code if fine! One has to enable multitouch for the view in order to make it work!
#property(nonatomic, getter=isMultipleTouchEnabled) BOOL multipleTouchEnabled

Related

Draw stuff on touch objective c

hy,
How can i make something that changes color when i touch it in objective c, i want the whole screen to be touchable and want to draw stuff on it with finger.
Everywhere i touch it should change the color.
Whats the best way to do it? I already have touchesMoved implemented to get the coordinates of the touch.
UITouch * touch = [touches anyObject];
CGPoint pos = [touch locationInView: [UIApplication sharedApplication].keyWindow];
Any example code would be nice thanks.
thank you in advance,
i have the following code but it doesnt print anything where i touch
-(void)setPaths:(NSMutableArray *)paths
{
self.paths =[[NSMutableArray alloc]init];
}
-(void)setAPath:(UIBezierPath *)aPath
{
self.aPath=[UIBezierPath bezierPath];
}
-(void) drawRect:(CGRect)rect{
[super drawRect:rect];
[[UIColor blackColor] set];
for (UIBezierPath *path in paths) {
[path stroke];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.paths addObject:self.aPath];
//self.aPath=[UIBezierPath bezierPath];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch = [touches anyObject];
CGPoint pos = [touch locationInView: [UIApplication sharedApplication].keyWindow];
[self.aPath addLineToPoint:[touch locationInView:self]];
// [self.aPath addLineToPoint:[touch locationInView:touch]];
NSLog(#"Position of touch: %.3f, %.3f", pos.x, pos.y);
}
#end
When your touch starts, create a UIBezierPath:
self.myPath = [UIBezierPath bezierPath];
Then, every time the touches moves, add a point to the path:
[self.myPath addLineToPoint:[touch locationInView:self]];
Once your touch has ended, in your drawRect just draw the path:
-(void) drawRect:(CGRect)rect{
[super drawRect:rect];
[[UIColor blueColor] set];
for (UIBezierPath *path in paths) {
[path stroke];
}
}
Find all the doc here:
UIBezierPath Class Reference
Maybe you're going to change your drawRect: method. insert these 2 lines:
[[UIColor blackColor] setStroke];
[path stroke];
and you should add [self setNeedsDisplay]; after you've added a line inside touchesMoved:
I just passed following tutorial, it should solve your problem. It also explains how you can improve your code so it won't get too lazy if you're drawing longer lines:
http://mobile.tutsplus.com/tutorials/iphone/ios-sdk_freehand-drawing/

SK Scene transition background

I've just started to learn how to program with xCode and more specifically with the new SpriteKit. So bare in mind I'm kind of new to this.
I've managed to move to a different scene by pressing on a label, but somehow the background of my scene has gone all wrong. the background should be like the first scene, but it gave me a background with two horizontal bars. I don't think I've done anything wrong since I've just copied the code needed to set the background to the second scene.
1st scene:
http://imageshack.us/photo/my-images/23/kyud.png/
2nd scene:
http://imageshack.us/photo/my-images/198/472h.png/
my code used to set up both backgrounds:
SKSpriteNode *background = [SKSpriteNode spriteNodeWithImageNamed:#"background_start"];
background.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
background.xScale = 0.7;
background.yScale = 0.7;
[self addChild:background];
transition is done with:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if([node.name isEqualToString:#"startgame"]){
Options_Scene *gs = [[Options_Scene alloc] initWithSize:self.size];
SKTransition *doors = [SKTransition doorsOpenVerticalWithDuration:0.5];
[self.view presentScene:gs transition:doors];
}
}
PS: I find it odd why I have to scale it to 0.7 when the background actually has the dimensions 480x320.
As you are using landscape I would swap the
viewWillAppear
With
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
SKView * skView = (SKView *)self.view;
if (!skView.scene) {
//skView.showsFPS = YES;
//skView.showsNodeCount = YES;
// Create and configure the scene.
SKScene * scene = [PMyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
}

Disable other UIImageViews when one UIImageView is touched

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];
}

CCPanZoomController + Tappable Sprites

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.

QuartzCore performance on clear UIView

I have a UIView where I set the background color to clear in the init method. I then draw a blue line between 2 points in drawRect. The first point is the very first touch on the view, and the second point is changed when touchesMoved is called.
So that one end of the line is fixed, and the other end moves with the users finger. However when the backgroundcolor is clear the line has quite a big of delay and skips (is not smooth).
If I change the background color to black (just uncommenting the setbackgroundcolor line) then the movement is much smoother and it looks great, apart from you can't see the views behind it.
How can I solve this issue? (on the iPad, I only have the simulator, and haven't currently got access to a device) So that the performance is smooth, but the background is clear so you can see the background views.
-(id) initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
//self.backgroundColor = [UIColor clearColor];
}
return self;
}
-(void) drawRect:(CGRect)rect {
if (!CGPointEqualToPoint(touchPoint, CGPointZero)) {
if (touchEnded) {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
} else {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
CGContextSetLineWidth(context, 3.0f);
CGFloat blue[4] = {0.0f, 0.659f, 1.0f, 1.0f};
CGContextSetAllowsAntialiasing(context, YES);
CGContextSetStrokeColor(context, blue);
CGContextMoveToPoint(context, startPoint.x, startPoint.y);
CGContextAddLineToPoint(context, touchPoint.x, touchPoint.y);
CGContextStrokePath(context);
CGContextSetFillColor(context, blue);
CGContextFillEllipseInRect(context, CGRectMakeForSizeAroundCenter(CGSizeMake(10, 10), touchPoint));
CGContextFillEllipseInRect(context, CGRectMakeForSizeAroundCenter(CGSizeMake(10, 10), startPoint));
}
}
}
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.touchEnded = NO;
if ([[touches allObjects] count] > 0)
startPoint = [[[touches allObjects] objectAtIndex:0] locationInView:self];
touchPoint = [[[touches allObjects] objectAtIndex:0] locationInView:self];
[self setNeedsDisplay];
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
self.touchEnded = NO;
if ([[touches allObjects] count] > 0)
touchPoint = [[[touches allObjects] objectAtIndex:0] locationInView:self];
[self setNeedsDisplay];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
self.touchEnded = YES;
[self setNeedsDisplay];
[self removeFromSuperview];
}
- (void)dealloc {
[super dealloc];
}
First of all, you should test performance on a device, rather than in Simulator. Most of graphics-related stuff works very differently in Simulator, some being much faster and some, surprisingly, much slower.
That said, if a transparent background does prove to be a performance problem on a device, it's most likely because you fill too many pixels with CGContextClearRect(). I can think of two solutions off the top of my head:
In touchesBegan:withEvent: you can make a snapshot of the underlying view(s) using CALayer's renderInContext: method and draw the snapshot as the background instead of clearing it. That way you can leave the view opaque and thus save time on compositing the view with views underneath it.
You can create a one-point-tall CALayer representing a line and transform it in touchesMoved:withEvent: so that its ends are in correct positions. Same goes for dots representing the line ends (CAShapeLayer is great for that). There will be some ugly trigonometry involved, but the performance is going to be excellent.