I am making a game where player moves with two figures at a time. Each one has its own half of the screen and moves just within in. Unfortunately I found out that when I swipe with both thumbs at a time nothing happens. Not even one of my recognizers are being triggered.
Maybe there is one way. I made another two views on the top of the GameViewController and added separate gestures. But I cant reffer to them in my gamescene.m to create actions.
Is there anyway to recognize swipes declared in GameViewController, in GameScene and add to them any actions?
I've already tried to make my own recognizers according to touch began and ended but when two fingers are being released at a time it got messy and usually forgot to react twice, I mean for each release separately.
-(void)setUpGestActions{
_swipeGestureLeft = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeLeft:)];
[self.swipeGestureLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
self.swipeGestureLeft.cancelsTouchesInView = NO;
self.swipeGestureLeft.delegate = self;
[self.view addGestureRecognizer: self.swipeGestureLeft];
_swipeGestureRight = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeRight:)];
[self.swipeGestureRight setDirection:UISwipeGestureRecognizerDirectionRight];
self.swipeGestureRight.cancelsTouchesInView = NO;
self.swipeGestureRight.delegate = self;
[self.view addGestureRecognizer: self.swipeGestureRight];
_swipeGestureUp = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeUp:)];
[self.swipeGestureUp setDirection:UISwipeGestureRecognizerDirectionUp];
self.swipeGestureUp.cancelsTouchesInView = NO;
self.swipeGestureUp.delegate = self;
[self.view addGestureRecognizer: self.swipeGestureUp];
_swipeGestureDown = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeDown:)];
[self.swipeGestureDown setDirection:UISwipeGestureRecognizerDirectionDown];
self.swipeGestureDown.cancelsTouchesInView = NO;
self.swipeGestureDown.delegate = self;
[self.view addGestureRecognizer: self.swipeGestureDown];
_moveLeft = [SKAction moveByX:-self.frame.size.width/6 y:0 duration:self.velocity];
_moveRight = [SKAction moveByX:self.frame.size.width/6 y:0 duration:self.velocity];
_moveUp = [SKAction moveByX:0 y:self.frame.size.width/6 duration:self.velocity];
_moveDown = [SKAction moveByX:0 y:-self.frame.size.width/6 duration:self.velocity];
_downMovement = [SKAction moveByX:0 y:-1 duration:self.downMovementVelocity];
}
-(void)swipeLeft:(UISwipeGestureRecognizer*) recognizer{
_sideDisting = [recognizer locationInView:self.view];
if(self.sideDisting.x <= self.frame.size.width/2){
[_boy runAction:self.moveLeft];
}
else{
[_girl runAction:self.moveLeft];
}
}
-(void)swipeRight:(UISwipeGestureRecognizer*) recognizer{
_sideDisting = [recognizer locationInView:self.view];
if(self.sideDisting.x <= self.frame.size.width/2){
[_boy runAction:self.moveRight];
}
else{
[_girl runAction:self.moveRight];
}
}
-(void)swipeUp:(UISwipeGestureRecognizer*) recognizer{
_sideDisting = [recognizer locationInView:self.view];
if(self.sideDisting.x <= self.frame.size.width/2){
[_boy runAction:self.moveUp];
}
else{
[_girl runAction:self.moveUp];
}
}
-(void)swipeDown:(UISwipeGestureRecognizer*) recognizer{
_sideDisting = [recognizer locationInView:self.view];
if(self.sideDisting.x <= self.frame.size.width/2){
[_boy runAction:self.moveDown];
}
else{
[_girl runAction:self.moveDown];
}
}
To recognise multiple gestures at the same time, set a delegate on each gesture recogniser. The delegate can be the same object for each gesture.
In the delegate, implement this:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
I think you can look at this example.
It might help you.
UIScreenEdgePanGestureRecognizer *myScreenEdgePanGestureRecognizer;
...
myScreenEdgePanGestureRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:#selector(handleScreenEdgePan:)];
myScreenEdgePanGestureRecognizer.delegate = self;
// Configure the gesture recognizer and attach it to the view.
...
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
BOOL result = NO;
if ((gestureRecognizer == myScreenEdgePanGestureRecognizer) && [[otherGestureRecognizer view] isDescendantOfView:[gestureRecognizer view]]) {
result = YES;
}
return result;
}
Go through this link, you will find more information.
https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/GestureRecognizer_basics/GestureRecognizer_basics.html
The simplest solution is to divide screen into two minor views and attach separate gesture recognizers to each one.
I am trying to make a game that involves clicking and dragging tiles to create a path, similar to the popular game Flow Free.
I want to be able to select a tile and slide my finger all in one swipe, however I am having some issues.
I have tried using SwipeGestures, in that
// listen for swipes to the left
UISwipeGestureRecognizer * swipeLeft= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeLeft)];
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
[[[CCDirector sharedDirector] view] addGestureRecognizer:swipeLeft];
// listen for swipes to the right
UISwipeGestureRecognizer * swipeRight= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeRight)];
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
[[[CCDirector sharedDirector] view] addGestureRecognizer:swipeRight];
// listen for swipes up
UISwipeGestureRecognizer * swipeUp= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeUp)];
swipeUp.direction = UISwipeGestureRecognizerDirectionUp;
[[[CCDirector sharedDirector] view] addGestureRecognizer:swipeUp];
// listen for swipes down
UISwipeGestureRecognizer * swipeDown= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeDown)];
swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
[[[CCDirector sharedDirector] view] addGestureRecognizer:swipeDown];
My problem is that SwipeGestures only recognize one swipe per screen press -- If I change directions, mid swipe, it does not register.
Assuming that I will need to use UIGestureRecognizers, is it possible for me to use a PanGestureRecognizer along with a SwipeGestureRecognizer to continually check for changes in directions of swipes?
Any help would be appreciated. Thanks in advance!
You are correct in your assessment: UISwipeGestureRecognizer is not really useful for this because it only recognizes once the swipe has finished.
What you want is to track the item while the swipe is occurring, you'd use a UIPanGestureRecognizer and track each movement.
To track which direction, you can do something similar to this:
- (void)onPan:(UIPanGestureRecognizer *pan) {
CGPoint translation = [pan translationInView:[pan view]];
if (translation.x > 0) {
// moving right...
}
// important to "eat" the translation if you've handled the
// UI changes, otherwise the translation will keep accumulating
// across multiple calls to this method
[pan setTranslation:CGPointZero inView:[pan view]];
}
Hope this helps.
I have been attempting to figure out how I can associate one UISwipeGestureRecognizer with the right half of the screen and another UISwipeGesture recognizer with the other half of the screen, however, I have been unsuccessful in coding this mechanic properly. Below is my current code. I have no idea on how I can associate one of the swipe recognizers with one half of the screen. Any help would be much appreciated
-(void)didMoveToView:(SKView *)view {
UISwipeGestureRecognizer *leftSwipe1 = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(leftSwiped1)];
[leftSwipe1 setDirection:UISwipeGestureRecognizerDirectionLeft];
[leftSwipe1 setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:leftSwipe1];
UISwipeGestureRecognizer *rightSwipe1 = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(rightSwiped1)];
[rightSwipe1 setDirection:UISwipeGestureRecognizerDirectionRight];
[rightSwipe1 setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:rightSwipe1];
self.physicsWorld.gravity = CGVectorMake(0, -9.8);
self.physicsWorld.contactDelegate = self;
}
-(void)rightSwiped1 {
SKNode *person1 = [self childNodeWithName:#"person1"];
SKAction *moveRight = [SKAction moveTo:CGPointMake(CGRectGetMidX(self.frame) - 80, CGRectGetMidY(self.frame) + 200) duration:0.2f];
[person1 runAction:moveRight];
}
-(void)leftSwiped1 {
SKNode *person1 = [self childNodeWithName:#"person1"];
SKAction *moveLeft = [SKAction moveTo:CGPointMake(CGRectGetMidX(self.frame) - 400, CGRectGetMidY(self.frame) + 200) duration:0.2f];
[person1 runAction:moveLeft];
}
In a nutshell; You will have to do the filtering yourself.
In the documentation for UISwipeGestureRecognizer it states:
You may determine the location where a swipe began by calling the
UIGestureRecognizer methods locationInView: and
locationOfTouch:inView:. The former method gives you the centroid if
more than one touch was involved in the gesture; the latter gives the
location of a particular touch.
For example: For the left swipe gesture you will do something like
First change your initWithTarget action selector to take an argument like this
UISwipeGestureRecognizer *leftSwipe1 = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(leftSwiped1:)];
Then in your handler do something like this:
-(void)leftSwiped1:(UIGestureRecognizer *)gestureRecognizer {
CGPoint pt = [gestureRecognizer locationInView:self.view];
if(pt.x < (self.view.bounds.size.width/2))
{
SKNode *person1 = [self childNodeWithName:#"person1"];
SKAction *moveLeft = [SKAction moveTo:CGPointMake(CGRectGetMidX(self.frame) - 400, CGRectGetMidY(self.frame) + 200) duration:0.2f];
[person1 runAction:moveLeft];
}
}
I have MPMoviePlayerController which has some UIGestureRecognizers. It works well in normal view but when the player entered to fullscreen it doesn't fire the events even the events are binded.
Here is how I bind my events:
UISwipeGestureRecognizer * nextChannelRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(gotoNextChannel)];
[nextChannelRecognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[[player.view.subviews objectAtIndex:0] setUserInteractionEnabled:YES];
[[player.view.subviews objectAtIndex:0] addGestureRecognizer:nextChannelRecognizer];
UISwipeGestureRecognizer * previousChannelRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(gotoPreviousChannel)];
[previousChannelRecognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[[player.view.subviews objectAtIndex:0] addGestureRecognizer:previousChannelRecognizer];
for (UIGestureRecognizer *g in ((UIView *)[player.view.subviews objectAtIndex:0]).gestureRecognizers) {
NSLog(#"g %#", g.class);
}
In normal view and fullscreen the code in the loop outputs these
MPTapGestureRecognizer
MPSwipeGestureRecognizer
UIPinchGestureRecognizer
MPActivityGestureRecognizer
UITapGestureRecognizer
UITapGestureRecognizer
UIPinchGestureRecognizer
UISwipeGestureRecognizer
UISwipeGestureRecognizer
I tried add another temp view with view bounds of the player's view and bind the same events to it but result was same.
Can you tell me why it doesn't work? What is wrong?
I want to add simple swipe gesture recognition to my view based iPhone project. Gestures in all directions (right, down, left, up) should be recognized.
It is stated in the docs for UISwipeGestureRecognizer:
You may specify multiple directions by specifying multiple UISwipeGestureRecognizerDirection constants using bitwise-OR operands. The default direction is UISwipeGestureRecognizerDirectionRight.
However for me it doesn't work. When all four directions are OR'ed only left and right swipes are recognized.
- (void)viewDidLoad {
UISwipeGestureRecognizer *recognizer;
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionUp)];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];
[super viewDidLoad];
}
-(void)handleSwipeFrom:(UISwipeGestureRecognizer *)recognizer {
NSLog(#"Swipe received.");
}
I fixed this with adding four recognizers to the view but I'm curious to know why didn't it work as advertised in docs?
- (void)viewDidLoad {
UISwipeGestureRecognizer *recognizer;
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionUp)];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionDown)];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];
[super viewDidLoad];
}
-(void)handleSwipeFrom:(UISwipeGestureRecognizer *)recognizer {
NSLog(#"Swipe received.");
}
Seems like there is a bug. You can specify the allowed direction(s) as you did. But when you try to access the actual direction that triggered the swipe in the action selector method you still get the bit mask you originally set (for the allowed directions).
This means that checks for the actual direction will always fail when more than 1 direction is allowed.
You can see it for yourself quite easily when you output the value of 'direction' in the selector method (ie -(void)scrollViewSwiped:(UISwipeGestureRecognizer *)recognizer).
Filed a bug report (#8276386) to Apple.
[Update] I got an answer from Apple saying that the behavior works as was intended.
So for example in a table view you can swipe left or right in a table view cell to trigger 'delete' (this would have directions of the swipe gesture set to left and right)
This means that the original workaround is the way it's supposed to be used. The direction property can only be used to get the gestures recognized correctly, but not in the method performed on a successful recognition to compare for the actual direction that triggered the recognition.
I noticed that left/right and up/down gestures work together in pairs, so you only need to specify two gesture recognizers. And the docs do seem to be wrong.
Well that sucks, I solved the problem by adding 2 gestures like Lars mentioned and that worked perfectly...
1) Left/Right
2) Up/Down
UISwipeGestureRecognizer *swipeLeftRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
[swipeLeftRight setDirection:(UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionLeft )];
[self.view addGestureRecognizer:swipeLeftRight];
UISwipeGestureRecognizer *swipeUpDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
[swipeUpDown setDirection:(UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown )];
[self.view addGestureRecognizer:swipeUpDown];
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(didSwipe:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[self.view addGestureRecognizer:recognizer];
[recognizer release];
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(didSwipe:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[self.view addGestureRecognizer:recognizer];
[recognizer release];
Now this is the didSwipe function
- (void) didSwipe:(UISwipeGestureRecognizer *)recognizer{
if([recognizer direction] == UISwipeGestureRecognizerDirectionLeft){
//Swipe from right to left
//Do your functions here
}else{
//Swipe from left to right
//Do your functions here
}
}
If your using Xcode 4.2 you can add Gesture Recognizers # the storyboard and then link the GUI Gesture Recognizers to IBActions.
You can find the Gesture Recognizers in the Object Library of the Utility Pane (The bottom of the Right pane).
Then its just a matter of Control-dragging to the appropriate action.
If you want it to detect all four directions, you'll need to create four instances, as you did in your work-around.
Here's Why:
The same instance of UISwipeGestureRecognizer that you create is the instance that gets passed to the selector as sender. So if you set it to recognize all four directions, it will return true for sgr.direction == xxx where xxx is any one of the four directions.
Here's an alternative work-around that involves less code (assumes ARC use):
for(int d = UISwipeGestureRecognizerDirectionRight; d <= UISwipeGestureRecognizerDirectionDown; d = d*2) {
UISwipeGestureRecognizer *sgr = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
sgr.direction = d;
[self.view addGestureRecognizer:sgr];
}
Swift 2.1
I had to use the following
for var x in [
UISwipeGestureRecognizerDirection.Left,
UISwipeGestureRecognizerDirection.Right,
UISwipeGestureRecognizerDirection.Up,
UISwipeGestureRecognizerDirection.Down
] {
let r = UISwipeGestureRecognizer(target: self, action: "swipe:")
r.direction = x
self.view.addGestureRecognizer(r)
}
Here is a code sample for UISwipeGestureRecognizer usage. Note comments.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//add gesture recognizer. The 'direction' property of UISwipeGestureRecognizer only sets the allowable directions. It does not return to the user the direction that was actaully swiped. Must set up separate gesture recognizers to handle the specific directions for which I want an outcome.
UISwipeGestureRecognizer *gestureRight;
UISwipeGestureRecognizer *gestureLeft;
gestureRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeRight:)];//direction is set by default.
gestureLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeLeft:)];//need to set direction.
[gestureLeft setDirection:(UISwipeGestureRecognizerDirectionLeft)];
//[gesture setNumberOfTouchesRequired:1];//default is 1
[[self view] addGestureRecognizer:gestureRight];//this gets things rolling.
[[self view] addGestureRecognizer:gestureLeft];//this gets things rolling.
}
swipeRight and swipeLeft are methods that you use to perform specific activities based on left or right swiping. For example:
- (void)swipeRight:(UISwipeGestureRecognizer *)gesture
{
NSLog(#"Right Swipe received.");//Lets you know this method was called by gesture recognizer.
NSLog(#"Direction is: %i", gesture.direction);//Lets you know the numeric value of the gesture direction for confirmation (1=right).
//only interested in gesture if gesture state == changed or ended (From Paul Hegarty # standford U
if ((gesture.state == UIGestureRecognizerStateChanged) ||
(gesture.state == UIGestureRecognizerStateEnded)) {
//do something for a right swipe gesture.
}
}
UISwipeGestureRecognizer *Updown=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(handleGestureNext:)];
Updown.delegate=self;
[Updown setDirection:UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionUp];
[overLayView addGestureRecognizer:Updown];
UISwipeGestureRecognizer *LeftRight=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(handleGestureNext:)];
LeftRight.delegate=self;
[LeftRight setDirection:UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight];
[overLayView addGestureRecognizer:LeftRight];
overLayView.userInteractionEnabled=NO;
-(void)handleGestureNext:(UISwipeGestureRecognizer *)recognizer
{
NSLog(#"Swipe Recevied");
//Left
//Right
//Top
//Bottom
}
hmm, strange, it works perfect for me, I do exactly same thing
think you should try look at
UIGestureRecognizerDelegate method
- (BOOL)gestureRecognizerShouldBegin:(UISwipeGestureRecognizer *)gestureRecognizer {
// also try to look what's wrong with gesture
NSLog(#"should began gesture %#", gestureRecognizer);
return YES;
}
in logs you must see something like:
should began gesture ; target= <(action=actionForUpDownSwipeGestureRecognizer:, target=)>; direction = up,down,left,right>
use this, it should be the bit operation
gesture.direction & UISwipeGestureRecognizerDirectionUp ||
gesture.direction & UISwipeGestureRecognizerDirectionDown
This was driving me crazy. I finally figured out a reliable way to have multiple swipeGestureRecognizers.
It appears there is a bug in iOS if the name of your "action" selector is the same across multiple swipeGestureRecognizers. If you just name them differently, e.g. handleLeftSwipeFrom and handleRightSwipeFrom, everything works.
UISwipeGestureRecognizer *recognizer;
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleLeftSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleRightSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];