Reputation: 61
I have created an iOS app in which I need to be able to move, rotate and scale a sprite ( I am using Apple's Sprite Kit) at the same time. For the most part I have this working. I currently can touch with 1 finger and move the sprite, and if I use two fingers I can scale and rotate the sprite. To do this I am using UIPanGestureRecognizer, UIPinchGestureRecognizer and UIRotateGestureRecognizer. That works fine. What I would like is, while I am dragging, rotating and scaling a one sprite with my right hand, I can take my left hand and drag rotate and scale a different sprite independently of the other sprite.
Currently I am using iOS gestures to move, rotate and scale the sprites. I used code very close to what I found on Ray Wenderlich's website in his Drag and Drop Sprites tutorial for Sprite Kit. http://www.raywenderlich.com/44270/sprite-kit-tutorial-how-to-drag-and-drop-sprites. The part I am using is near the bottom when he start to use UIPanGestureRecognizers instead of just the touch method.
Like I said the Gestures work fine on one sprite at a time. How do I make it work on more than one sprite?
For instance for the UIPanGesturRecognizer I add the code below:
- (void)didMoveToView:(SKView *)view {
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanFrom:)];
[[self view] addGestureRecognizer:gestureRecognizer];
}
Then I have a method for that called gestureRecognizer below:
- (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
CGPoint touchLocation = [recognizer locationInView:recognizer.view];
touchLocation = [self convertPointFromView:touchLocation];
[self selectNodeForTouch:touchLocation]; // This just returns the node that has been touched
} else if (recognizer.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [recognizer translationInView:recognizer.view];
translation = CGPointMake(translation.x, -translation.y);
[self panForTranslation:translation];
[recognizer setTranslation:CGPointZero inView:recognizer.view];
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
[_selectedNode removeAllActions];
}
}
Finally there is the method that moves the sprite:
- (void)panForTranslation:(CGPoint)translation {
if([[_selectedNode name] isEqualToString:kAnimalNodeName]) {
CGPoint position = [_selectedNode position];
// Set variable for the point to move selected node
CGPoint movePoint = CGPointMake(position.x + translation.x, position.y + translation.y);
[_selectedNode setPosition:newPos];
}
}
Now the example code is showing only the methods for the UIPanGestureRecognizer but I also have similar methods for the rotate and pinch gestures. All of this code is in my scene class.
Thank you for the help.
Upvotes: 3
Views: 3626
Reputation: 36
I'm also using that tutorial to do something similar. The sample code relies on an instance variable, selectedNode
, that represents the one node that is selected.
To make this work for multiple nodes, I would recommend using an NSMutableArray
of selectedNodes, or subclassing SKSpriteNode
to store whether or not it is currently "selected". Good luck!
Upvotes: 0
Reputation: 1070
Well, the tutorial you posted pretty much shows how to do it...
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
[self selectNodeForTouch:positionInScene];
}
- (void)selectNodeForTouch:(CGPoint)touchLocation {
//The below statement assigns touchedNode from a sprite that contains touchLocation
SKSpriteNode *touchedNode = (SKSpriteNode *)[self nodeAtPoint:touchLocation];
//2
if(![_selectedNode isEqual:touchedNode]) {
[_selectedNode removeAllActions];
[_selectedNode runAction:[SKAction rotateToAngle:0.0f duration:0.1]];
_selectedNode = touchedNode;
//the below if statement determines what SKNode is to be given a SKAction
if([[touchedNode name] isEqualToString:kAnimalNodeName]) {
SKAction *sequence = [SKAction sequence:@[[SKAction rotateByAngle:degToRad(-4.0f) duration:0.1],
[SKAction rotateByAngle:0.0 duration:0.1],
[SKAction rotateByAngle:degToRad(4.0f) duration:0.1]]];
[_selectedNode runAction:[SKAction repeatActionForever:sequence]];
}
}
}
So if you want to apply the action to multiple nodes, simply give them the same name. I suggest naming your nodes, put them in an array, and then iterate through them checking if they have the same name. If you have any further questions please comment.
UPDATE: 1
- (void)panForTranslation:(CGPoint)translation {
//Once again you would do the same thing. Just give the nodes the same name.
if([[_selectedNode name] isEqualToString:kAnimalNodeName]) {
CGPoint position = [_selectedNode position];
// Set variable for the point to move selected nodes
CGPoint movePoint = CGPointMake(position.x + translation.x, position.y + translation.y);
[_selectedNode setPosition:newPos];
}
Upvotes: 1