Search code examples
cocos2d-iphonecontrolsmulti-touchuitouch

MultiTouch control of a sprites movement - cocos2d


I've been dealing with this problem for quite some time. What I am trying to do is have a CCSprite's right/left movement controlled by touches on either the left side of the screen or the right.

Doing this is no problem if you lift your finger after each touch. But what I want is best described by an example: The player touches the left side of the screen and the sprite moves to the left. Now the player (while still touching the left side) touches the right side...the sprite should now move right. Now the player has one finger on the left and one on the right side, if he now lifts the touch off the right side the sprite should again move to the left.

This is what I have now:

-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSSet *allTouches = [event allTouches];
    UITouch * touch = [[allTouches allObjects] objectAtIndex:0];
    CGPoint location = [touch locationInView: [touch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];

    if (location.x < 240) {
        [player walk:kkMoveLeft];
    } else if (location.x > 240) {
        [player walk:kkMoveRight];
    }

    //Swipe Detection Part 1
    firstTouch = location;
}

-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    NSSet *allTouches = [event allTouches];
    UITouch * touch = [[allTouches allObjects] objectAtIndex:0];
    CGPoint location = [touch locationInView: [touch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];

    //Swipe Detection Part 2
    lastTouch = location;

    float swipeLength = ccpDistance(firstTouch, lastTouch);

    if (firstTouch.y < lastTouch.y && swipeLength > 60) {
        [player jump:kkJumpUp];
    } else if (firstTouch.y > lastTouch.y && swipeLength > 60){
        [player jump:kkJumpDown];
    }

    [player endWalk];

}

I'd appreciate it if someone could tell me how to go about this. Thank you .

UPDATE MY SOLUTION:

//1. Enable multitouch in the appDelegate
[glView setMultipleTouchEnabled:YES];

//2. Create an Array to keep track of active touches
touchArray = [[NSMutableArray alloc] init];

//3. Touch Methods
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    for (UITouch *touch in touches) {
        if (![touchArray containsObject:touch]) {
            [touchArray addObject:touch];
            CGPoint location = [touch locationInView:[touch view]];
            location = [[CCDirector sharedDirector] convertToGL:location];
            CCLOG(@"start: %f", location.x);
            if (location.x < 240) {
                [player walk:kkMoveLeft];
            } else if (location.x > 240) {
                [player walk:kkMoveRight];
            }
        }
    }

}

-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

    for (UITouch *touch in touches) {
        [touchArray removeObject:touch];
        CGPoint location = [touch locationInView:[touch view]];
        location = [[CCDirector sharedDirector] convertToGL:location];
        CCLOG(@"end: %f", location.x);
    }

    for (UITouch *touch in touchArray) {
        CGPoint location = [touch locationInView:[touch view]];
        location = [[CCDirector sharedDirector] convertToGL:location];
        CCLOG(@"still: %f", location.x);
        if (location.x < 240) {
            [player walk:kkMoveLeft];
        } else if (location.x > 240) {
            [player walk:kkMoveRight];
        }
    }


    if ([touchArray count] == 0) {
        [player endWalk];
    }

}

Solution

  • If I understand correctly your problem, what you should do is:

    1. in ccTouchesEnded, instead of simply calling endWalk, check to see is any touch is still present (to do so, you could iterate over allTouches);

    2. in the appropriate case (i.e., a touch is still activating the player), call startWalk.

    3. if no touch is present, call endWalk.

    The code would be similar to what you have in ccTouchesBegan, only you iterate (I am not sure what allTouches contains at index 0 in touchesEnded).

    OLD ANSWER:

    You are not saying anything about how you are handling touches right now. In any case, the way to go is defining ccTouches* methods (vs. ccTouch*), where * can be: Began, Moved, Ended.

    -(void)tccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [[event allTouches] anyObject];
    CGPoint location = [touch locationInView:[touch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];
        ...
    }
    -(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
      ...
    }
    -(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
      ...
    }
    

    Keep in mind that touchesBegan is fired at each new touch that is detected. So, if you want to know the status of all touches currently active, you have to use allTouches.

    Have also a look at this post from iphonesdk which I found insightful as to the semantics of touches in those methods.