UIBezierPath Draw line while touchesMoved with two fingers - ios

How can I draw a line in touchesMoved using UIBezierPath? When I am trying to draw a line using two touches/fingers, it is being drawn but it draws multiple lines. I tried removing lastObjectIndex and also tried removeAllObjects but still the same result. I would just like to draw a single line from finger 1 to finger 2 and when the user releases his/her finger then the line will be drawn on a UIImageView. Here is my code:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([drawMode isEqualToString:#"stroke"]) {
UITouch *touch=[[touches allObjects] objectAtIndex:0];
[myPath addLineToPoint:[touch locationInView:self]];
}
else if ([drawMode isEqualToString:#"line"]) {
NSArray *allTouches = [touches allObjects];
if ([touches count] == 2) {
UITouch *touch1 = [allTouches objectAtIndex:0];
UITouch *touch2 = [allTouches objectAtIndex:1];
CGPoint touchLoc1 = [touch1 locationInView:self];
CGPoint touchLoc2 = [touch2 locationInView:self];
[myPath moveToPoint:touchLoc1];
[myPath addLineToPoint:touchLoc2];
[shapeArray removeAllObjects];
[shapeArray addObject:myPath];
}
}
[self setNeedsDisplay];
}

Related

Spritekit - calculate distance the finger has travelled between two events to increment your a NSUInteger

I use the following code to draw a line from point Touch point A to Touch point B.
The code also allows me to draw multiple lines simultaneously.
My first attempt was to create a NSUInteger and increase it by 1 per pixel moved in touchesMoved. However the increment is not consistent. It appears that moving your finger fast will increase the number slowly whereas moving your finger slowly will increase the number fast.
I think I need to calculate the distance moved between two events and then increment the number. I don't know how to do this, can anyone help?
//Create a line at first point of touch
(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
SKLabelNode *touchedNode = (SKLabelNode *)[self nodeAtPoint:positionInScene];
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
// Create a mutable path
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:location];
// Create a shape node using the path
lineNode = [SKShapeNode shapeNodeWithPath:path.CGPath];
lineNode.strokeColor = [SKColor blackColor];
lineNode.glowWidth = 3.0;
[_gameLineNode addChild:lineNode];
// Use touch pointer as the dictionary key. Since the dictionary key must conform to
// NSCopying, box the touch pointer in an NSValue
NSValue *key = [NSValue valueWithPointer:(void *)touch];
[lines setObject:lineNode forKey:key];
}
}
// Draw the line to last touch point dynamically
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
// Retrieve the shape node that corresponds to touch
NSValue *key = [NSValue valueWithPointer:(void *)touch];
lineNode = [lines objectForKey:key];
if (lineNode != NULL) {
// Create and initial a mutable path with the lineNode's path
UIBezierPath *path = [UIBezierPath bezierPathWithCGPath:lineNode.path];
// Add a line to the current touch point
[path addLineToPoint:location];
// Update lineNode
lineNode.path = path.CGPath;
lineNode.physicsBody = [SKPhysicsBody bodyWithEdgeChainFromPath:path.CGPath];
lineNode.physicsBody.categoryBitMask = lineNodeCategory;
lineNode.physicsBody.contactTestBitMask = bubble1Category | bubble2Category| bubble3Category | bubble4Category | bubble5Category | bubble6Category;
lineNode.physicsBody.collisionBitMask = ballCategory | ballHalf1Category | ballHalf2Category;
lineNode.physicsBody.dynamic = YES;
lineNode.name = lineNodeCategoryName;
//ATTEMPT 1 - NSUINTEGER that increases per pixal moved
testNumber ++;
testLabel.text = [NSString stringWithFormat:#"%lu",(unsigned long)testNumber];
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
inkLockOrUnlock = [[NSUserDefaults standardUserDefaults] boolForKey:#"inkLockOrUnlock"];
if (inkLockOrUnlock == NO) {
SKAction *block0 = [SKAction runBlock:^{
for (UITouch *touch in touches) {
NSValue *key = [NSValue valueWithPointer:(void *)touch];
[lines removeObjectForKey:key];
}
[_gameLineNode removeAllChildren];
}];
SKAction *inkAnimation = [SKAction sequence:#[block0,]];
[self runAction:[SKAction repeatAction:inkAnimation count:1]];
} else {}
}
If I understand you, I think you might be misunderstanding a lot here. Every time touchMoved gets called, it gives you an xy coord for current position of that touch. That function can only be called max once per frame.
It sounds like you are thinking the function is called for every pixel the touch gets moved, which is not the case.
So store the initial point from touchBegan, then use math to determine distance between initial point and the current point inside touchMoved.
But also keep in mind that points don't necessarily equal pixels.

How to get all the coordinate points (X and Y) in ios

I am writing an app which allows the user to draw what ever they want in the view. While they drawing I am sending the coordinate values simultaneously to web using Json and draw the same diagram in web. When I draw slowly I am getting all the coordinates values like this.
{"XY":["92,240","94,240","96,240","97,240","98,240","99,240","100,240","102,240","103,240","104,240","104,240","105,240","106,240","107,240","108,240","108,240","110,240","110,240","112,240","112,240","114,240","115,240","116,240","117,240","118,240","120,240","120,240","120,240","122,240","122,240","124,240","124,240","126,240"]}
But when I draw quickly I am getting the desired drawing but missing lots of coordinate values.
{"XY":["96,320","117,302","170,262","252,208"]}
The following code that I used to implement this.
#implementation PJRSignatureView
{
UIBezierPath *beizerPath;
UIImage *incrImage;
CGPoint points[10];
uint control;
}
- (void)drawRect:(CGRect)rect
{
[incrImage drawInRect:rect];
[beizerPath stroke];
// Set initial color for drawing
UIColor *fillColor = INITIAL_COLOR;
[fillColor setFill];
UIColor *strokeColor = INITIAL_COLOR;
[strokeColor setStroke];
[beizerPath stroke];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([lblSignature superview]){
[lblSignature removeFromSuperview];
}
rectArray = [[NSMutableArray alloc] init];
control = 0;
UITouch *touch = [touches anyObject];
points[0] = [touch locationInView:self];
CGPoint startPoint = points[0];
CGPoint endPoint = CGPointMake(startPoint.x + 1.5, startPoint.y
+ 2);
[beizerPath moveToPoint:startPoint];
NSLog(#"myPoint = %#", [NSValue valueWithCGPoint:endPoint]);
NSLog(#"beizerPath :%#",beizerPath);
[beizerPath addLineToPoint:endPoint];
NSLog(#"beizerPath end:%#",beizerPath);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
control++;
points[control] = touchPoint;
if (control == 4)
{
points[3] = CGPointMake((points[2].x + points[4].x)/2.0, (points[2].y + points[4].y)/2.0);
[beizerPath moveToPoint:points[0]];
[beizerPath addCurveToPoint:points[3] controlPoint1:points[1] controlPoint2:points[2]];
[self setNeedsDisplay];
points[0] = points[3];
points[1] = points[4];
control = 1;
}
NSLog(#"beizerPathmove:%#",beizerPath);
NSString *rect_xy = [NSString stringWithFormat:#"%.f,%.f",touchPoint.x,touchPoint.y];
[rectArray addObject:rect_xy];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self drawBitmapImage];
[self setNeedsDisplay];
[beizerPath removeAllPoints];
NSMutableDictionary *rectDict = [[NSMutableDictionary alloc]init];
[rectDict setValue:rectArray forKey:#"XY"];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:rectDict options:0 error:nil];
// Checking the format
NSLog(#"%#",[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]);
control = 0;
}
How to find all the coordinate values even when I draw quickly?
The Apple products sends the touch events at a certain intervals. So, If you draw/write anything slowly its possible to get all of the coordinate values, if you draw/write fast you will less some of them. And apply the same kind of function in the web that you have used. Hope this will be fixed now.
The system sends touch events at a certain interval. If you move slow you get more, but going fast you get less of them. You can't get more if you move fast. But you also don't need more probably. You just have to draw the line between points, no matter if the distance between them is small or bigger.

touchesMoved on a specific moving object

Im using Spritekit to create a game for iOS 7. The game has circles moving across the screen using this code
_enemy = [SKSpriteNode spriteNodeWithImageNamed:#"greeny"];
_enemy.position = CGPointMake(CGRectGetMidX(self.frame)+300,
CGRectGetMidY(self.frame));
_enemy.size = CGSizeMake(70, 70);
_enemy.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:35];
_enemy.physicsBody.mass = 0;
_enemy.physicsBody.categoryBitMask = Collisiongreen;
[_enemies addObject:_enemy];
NSLog(#"Enemies%lu",(unsigned long)_enemies.count);
[self addChild:_enemy];
[_enemy runAction:[SKAction moveByX:-900 y:0 duration:4]];
[self runAction:[SKAction playSoundFileNamed:#"Spawn.wav" waitForCompletion:NO]];
[self runAction:[SKAction sequence:#[
[SKAction waitForDuration:1.4],
[SKAction performSelector:#selector(move)
onTarget:self],
]]];
I would like to have it that when the user touches one of the objects moving across the screen that they can move it with their finger either up or down (thats why I'm using touches moved)
The code i have set up right now is
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if(_dead)
return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if(CGRectContainsPoint(_enemy.frame, location)){
[_enemy runAction:[SKAction moveTo:[[touches anyObject] locationInNode:self] duration:0.01]];
}
My problem is that if i touch it the object will move a few pixels but will stop right after. How can I get it to move with my finger and if i let go it will continue moving left like programed before? Thanks!!
So the trick here is that in the touchesMoved method, you want the enemy's postion set to the location of your touch. Use the touchesEnded method to execute a method that makes the enemy continue in the direction of your last touch. This is a rough non-tested example.
You need to store the difference of the current location with the previous location.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if(_dead)
return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if(CGRectContainsPoint(_enemy.frame, location)){
someBool = False;
[_enemy setPosition:location];
changeInX = location.x - lastX;
changeInY = location.y - lastY;
lastX = location.x;
lastY = location.y;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
someBool = True;
}
- (void)update:(NSTimeInterval)currentTime
{
...
if (someBool) {
enemy.position = CGPointMake((enemy.position.x + changeInX), (enemy.position.y + changeInY));
}
...
}

Two views with multitouch

I should manage two different views inside my main view; I want detect the exact number of finger inside my views, that is if I have four fingers inside "first view" I want a var that say me a value = 4, and if I have 3 fingers in "second view" I want another var that say me a value = 3. I show you my code that don't work fine.
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
NSLog(#"cgpoint:%f,%f", touchLocation.x, touchLocation.y);
if (CGRectContainsPoint(view1.frame, touchLocation)){
NSLog(#"TOUCH VIEW 1");
totalTouch1 = [[event allTouches]count];
NSLog(#"TOTAL TOUCH 1:%d", totalTouch1);
}
else if (CGRectContainsPoint(view2.frame, touchLocation)){
NSLog(#"TOUCH VIEW 2");
totalTouch2 = [[event allTouches]count];
NSLog(#"TOTAL TOUCH 2:%d", totalTouch2);
}
}
With my code if I begin to lay my finger in "first view", it's all ok, but for example if I lay my fourth finger inside second view my code enter in first "if" and say that my finger is yet in first view. I don't understand the problem.
[[event allTouches] anyObject]; is fetching you only one of the touches.
you need to iterate over all the touches like so:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
int touch1 = 0;
int touch2 = 0;
NSArray *touches = [[event allTouches] allObjects];
for( UITouch *touch in touches ) {
CGPoint touchLocation = [touch locationInView:self.view];
NSLog(#"cgpoint:%f,%f", touchLocation.x, touchLocation.y);
if (CGRectContainsPoint(view1.frame, touchLocation)){
NSLog(#"TOUCH VIEW 1");
touch1 += 1;
NSLog(#"TOTAL TOUCH 1:%d", totalTouch1);
}
else if (CGRectContainsPoint(view2.frame, touchLocation)){
NSLog(#"TOUCH VIEW 2");
touch2 += 1;
NSLog(#"TOTAL TOUCH 2:%d", totalTouch2);
}
}
NSLog(#"Total touches on view 1: %d", touch1);
NSLog(#"Total touches on view 2: %d", touch2);
}

Drag UIVIew relative to finger

I have a little problem.
I have some UIView and I'm able to drag them with methods touchesBegan and touchesMoved.
My problem is my UIView's coordinates (0,0) is coming under my finger. I would like to avoid that.
Do you know how to do that. I try some things but with no success :(
Thanks a lot !
It will depend on the size of the view but you can probably set the center property to your touch's location.
Animating the center to your tap location
[UIView animateWithDuration:0.25f
delay:0.0f
options:(UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseInOut)
animations:^{
theView.center = tapLocation;
}
completion:NULL]
Instead of just moving the location or translating it, you can animate the view to your current touch in all touches* methods.
when you press down your finger save the point
then measure the speed of the drag, and apply the speed to the position of your view (I translate my view with origin in my exemple)
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSUInteger touchCount = [touches count];
NSUInteger tapCount = [[touches anyObject] tapCount];
NSLog(#"touchesBegan");
NSLog(#"%d touches", touchCount);
NSLog(#"%d taps", tapCount);
UITouch *touch = [touches anyObject];
pNow = [touch locationInView:self];
pLast = [touch locationInView:self];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSUInteger touchCount = [touches count];
NSUInteger tapCount = [[touches anyObject] tapCount];
NSLog(#"touchesMoved");
NSLog(#"%d touches", touchCount);
NSLog(#"%d taps", tapCount);
UITouch *touch = [touches anyObject];
pNow = [touch locationInView:self];
mouseSpeed.x = pNow.x - pLast.x;
mouseSpeed.y = pNow.y - pLast.y;
NSLog(#"mouseSpeed : %f, %f", mouseSpeed.x, mouseSpeed.y);
origin.x += mouseSpeed.x;
origin.y += mouseSpeed.y;
NSLog(#"origin : %f, %f", origin.x, origin.y);
//copy point for the next update
pLast = pNow;
}

Resources