user3482617
user3482617

Reputation: 307

Spritekit - Using gestures to draw multiple lines with multiple fingers simultaneously

Using the below code, I can draw a line using the pan gesture using 1 finger. However what I am attempting to do is for 1 finger to draw 1 line and another finger to draw the second simultaneously. I've read somewhere about using a dictionary to store the touches but don't know how to write it in code. Can any one help?

-(void)didMoveToView:(SKView *)view {

    UIPanGestureRecognizer *gestureRecognizerPan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanFrom:)];
    [[self view] addGestureRecognizer:gestureRecognizerPan];

}

- (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer
{
    if (recognizer.state == UIGestureRecognizerStateBegan) {

        CGPoint touchLocation = [recognizer locationInView:recognizer.view];
        touchLocation = [self convertPointFromView:touchLocation];

        pathToDraw = CGPathCreateMutable();
        CGPathMoveToPoint(pathToDraw, NULL, touchLocation.x, touchLocation.y);
        lineNode = [[SKShapeNode alloc] init];
        lineNode.path = pathToDraw;
        lineNode.name = lineNodeCategoryName;
        [_gameLineNode addChild:lineNode];

    } else if (recognizer.state == UIGestureRecognizerStateChanged) {

        CGPoint touchLocation = [recognizer locationInView:recognizer.view];
        touchLocation = [self convertPointFromView:touchLocation];

        CGPathAddLineToPoint(pathToDraw, NULL, touchLocation.x, touchLocation.y);
        lineNode.path = pathToDraw;
        lineNode.name = lineNodeCategoryName;
        lineNode.physicsBody = [SKPhysicsBody bodyWithEdgeChainFromPath:pathToDraw];
        lineNode.physicsBody.dynamic = YES;
        lineNode.strokeColor = [SKColor blackColor];
        lineNode.glowWidth = 3.0;

    } else if (recognizer.state == UIGestureRecognizerStateEnded) {

        CGPathRelease(pathToDraw);

    }
}

Upvotes: 1

Views: 308

Answers (1)

0x141E
0x141E

Reputation: 12773

Drawing multiple lines simultaneously is fairly straightforward. The key is to track each touch event independently. One way to do that is to maintain a dictionary that uses the touch event as the key and the shape node (used to draw the line) as the value.

@implementation GameScene {
    NSMutableDictionary *lines;
}

-(void)didMoveToView:(SKView *)view {
    self.scaleMode = SKSceneScaleModeResizeFill;
    // Create a mutable dictionary
    lines = [NSMutableDictionary dictionaryWithCapacity:10];
}

// Add each line node to the dictionary with the touch event as the key
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    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
        SKShapeNode *lineNode = [SKShapeNode shapeNodeWithPath:path.CGPath];
        lineNode.strokeColor = [SKColor blackColor];
        [self 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];
    }
}

// Update the lines as needed
-(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];
        SKShapeNode *lineNode = [lines objectForKey:key];
        if (lineNode != NULL) {
            // Create and initialize a mutable path with the lineNode's current path
            UIBezierPath *path = [UIBezierPath bezierPathWithCGPath:lineNode.path];
            // Add a line to the current touch point
            [path addLineToPoint:location];
            // Update lineNode
            lineNode.path = path.CGPath;
        }
    }
}

// Remove the line nodes from the dictionary when the touch ends
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    for (UITouch *touch in touches) {
        NSValue *key = [NSValue valueWithPointer:(void *)touch];
        [lines removeObjectForKey:key];
    }
}

@end

Upvotes: 2

Related Questions