Swipe gesture on SKSpriteNode - ios

I have a spriteNode where I need to have swipe detection on a SKSpriteNode, but it seems that swipe gesture can only do on view. Is there a way to do this?
SKSpriteNode *rabbit = [SKSpriteNode spriteNodeWithImageNamed:#"rabbit_img"];
UISwipeGestureRecognizer * swipeleft=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(handleSwipeGesture:)];
swipeleft.direction=UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:swipeleft];

You can get the starting coordinates of the swipe via the state property.
- (void)swipe:(UISwipeGestureRecognizer *)recognizer
{
CGPoint point = [recognizer locationInView:[recognizer view]];
if (recognizer.state == UIGestureRecognizerStateBegan)
NSLog(#"start coordinates: %#", NSStringFromCGPoint(point));
}
You can then compare those coordinates against your desired nodes using the SKNode method containsPoint: to see if the swipe originated from a node.

Related

Gesture recognizer with Voice Over active

I developed an application which allows to the user to draw his finger signature in a canvas.
This feature is implemented using UIPanGestureRecognizer with a specific target action to draw a line in a UIView, but when the “Voice Over” is active the gesture recognizer action is not triggered anymore.
Gesture initialize code
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(pan:)];
pan.maximumNumberOfTouches = pan.minimumNumberOfTouches = 1;
[self addGestureRecognizer:pan];
Gesture action code
- (void)pan:(UIPanGestureRecognizer *)pan {
CGPoint currentPoint = [pan locationInView:self];
CGPoint midPoint = midpoint(previousPoint, currentPoint);
if (pan.state == UIGestureRecognizerStateBegan)
{
[path moveToPoint:currentPoint];
}
else if (pan.state == UIGestureRecognizerStateChanged)
{
[path addQuadCurveToPoint:midPoint controlPoint:previousPoint];
}
previousPoint = currentPoint;
[self setNeedsDisplay];
}
Is there any way to draw a line in a view using gesture with “Voice Over” active?
Thanks and regards!
I resolved my problem setting both isAccessibilityElement and accessibilityTraits properties for UIView canvas:
canvasView.isAccessibilityElement = YES;
canvasView.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction;

Dragging coordinates with CGPoint

I want to get the coordinates from the user's finger while dragging. I tried this code, but it says the coordinates are always {0, 0},
What's wrong?
- (IBAction)Drag{
UIPanGestureRecognizer *Recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(dragged)];
[self.view addGestureRecognizer:Recognizer];
}
-(void) dragged{
UITouch *touch ;
CGPoint location = [touch locationInView:touch.view];
NSLog(#"%#", NSStringFromCGPoint (location));
}
I also tried NSLog(#"%.2f %.2f" location.x, location.y); and got the same.
Thanks
It's quite normal, you're using touch without having ever assigned a value to it.
The action for a gesture recognizer takes a parameter, which is the recognizer itself, which in turn has a locationInView: method, so you should use that. Also, you need to check the state of the recognizer. Finally, you probably don't want to add the gesture recognizer when you need it, just add it from the start.
// probably in your viewDidLoad
UIPanGestureRecognizer *Recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:#selector(panGestureRecognizerAction:)];
[self.view addGestureRecognizer:Recognizer];
- (void)panGestureRecognizerAction:(UIPanGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateBegan ||
recognizer.state == UIGestureRecognizerStateChanged)
{
CGPoint location = [recognizer.state locationInView:touch.view];
NSLog(#"%#", NSStringFromCGPoint (location));
}
}

Using gestures with SpriteKit to Drag, rotate and scale multiple sprite separately at the same time

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

UITapGestureRecognizer and UIPanGestureRecognizer

I want to create and see a uiimageview when i tap the screen.
Before i lift the finger, i want to move the uiimageview around the screen and the image set only when i take the finger off. Heres what i did:
- (IBAction)tap:(UITapGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:self.view];
UIImageView *circle = [[UIImageView alloc] initWithFrame:CGRectMake(location.x, location.y, 50, 50)];
circle.userInteractionEnabled = YES;
[circle setImage:[UIImage imageNamed:#"monkey_1.png"]];
[self.view addSubview:circle];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:circle action:nil];
[recognizer requireGestureRecognizerToFail:pan];
CGPoint translation = [pan translationInView:circle];
pan.view.center = CGPointMake(pan.view.center.x + translation.x, pan.view.center.y + translation.y);
[pan setTranslation:CGPointMake(0, 0) inView:self.view];
}
You can do this with just an UIPanGestureRecognizer or an UILongPressGestureRecognizer. In the gesture handling method, check the state property of the recognizer, and show your image when it's UIGestureRecognizerStateEnded (i.e. when the user lifts the finger from the screen). E.g.:
- (void)handleGesture:(UILongPressGestureRecognizer *)recognizer {
if(recognizer.state == UIGestureRecognizerStateEnded) {
// gesture ended: show the image
}
else if(recognizerState == UIGestureRecognizerStateBegan) {
// this code runs when the gesture is started.
}
else if(recognizerState == UIGestureRecognizerStateChanged) {
// gesture is in progress
}
}

How to detect or define the orientation of a pinch gesture with UIPinchGestureRecognizer?

I'm using UIPinchGestureRecognizer to detect pinch gestures, something like:
- (void) initPinchRecon {
UIPinchGestureRecognizer *pinchRecognizer = [[[UIPinchGestureRecognizer alloc]
initWithTarget:self
action:#selector(Perform_Pinch:)] autorelease];
[self addGestureRecognizer:pinchRecognizer];
[pinchRecognizer setScale:20.0f];
}
- (void) Perform_Pinch:(UIPinchGestureRecognizer*)sender{
NSLog(#"PINCH");
}
And it works well to detect a simple pinch gesture: It's possible to determine (or define myself) the angle or orientation of the pinch gesture ?, for example, to differentiate between an horizontal and an vertical pinch gesture ?
A very simple solution is to implement the gesture handler like this:
-(void)handlePinchGesture:(UIPinchGestureRecognizer *)recognizer {
if (recognizer.state != UIGestureRecognizerStateCancelled) {
if (recognizer.numberOfTouches == 2) {
CGPoint firstPoint = [recognizer locationOfTouch:0 inView:recognizer.view];
CGPoint secondPoint = [recognizer locationOfTouch:1 inView:recognizer.view];
CGFloat angle = atan2(secondPoint.y - firstPoint.y, secondPoint.x - firstPoint.x);
// handle the gesture based on the angle (in radians)
}
}

Resources