Multi-touch detecting & differentiating - Cocos2d for iPhone

烈酒焚心 提交于 2019-12-03 10:04:01

Suppose you have two touches. You get a touch down event for the two, say at (1,1) and (2,2). Let's say the user the sides both fingers, you then get another event, but this time maybe at (3,3) and (4,4).

The question is, did (1,1) move to (3,3) and (2,2) move to (4,4) - or did the opposite happen - where (1,1) moved to (4,4) and (2,2) moved to (3,3).

This is what the "Hash Code" is used for - to give each touch a "name" - so you can tell what happens to that particular touch as subsequent events are generated for it.

So for your case, you would get the touch events - look at the coordinates and determine which key is pressed for each. You then keep track of the hash for each touch, to determine when they touch (i.e. the particular piano key) is released.

You can't use the coordinates for this, because to coordinates can change as fingers are slid.

Here is how I implemented this in case anyone else is trying to do this (I have limited it to 2-button combos but I could easily extend the logic to 3 & 4-button combos as well). I chose to handle each touch individually using the ccTouchBegan/Ended/Moved instead of using the ccTouchesBegan/Ended/Moved because I just couldn't get it to work with the hash code. Any alternative ideas would be welcome.

spuButton.h (a CCSprite Subclass)

#import <Foundation/Foundation.h>
#import "cocos2d.h"

typedef enum tagButtonState {
    kButtonStatePressed,
    kButtonStateNotPressed
} ButtonState;

typedef enum tagButtonStatus {
    kButtonStatusEnabled,
    kButtonStatusDisabled
} ButtonStatus;

@interface spuButton : CCSprite <CCTargetedTouchDelegate> {
@private
    ButtonState buttonState;
    CCTexture2D *buttonNormal;
    CCTexture2D *buttonLit;
    ButtonStatus buttonStatus;  
}

@property(nonatomic, readonly) CGRect rect;

+ (id)spuButtonWithTexture:(CCTexture2D *)normalTexture;

- (void)setNormalTexture:(CCTexture2D *)normalTexture;
- (void)setLitTexture:(CCTexture2D *)litTexture;
- (BOOL)isPressed;
- (BOOL)isNotPressed;
- (void)makeDisabled;
- (void)makeEnabled;
- (BOOL)isEnabled;
- (BOOL)isDisabled;
- (void)makeLit;
- (void)makeNormal;
- (void)dealloc;

@end

spuButton.m

#import "spuButton.h"
#import "cocos2d.h"

@implementation spuButton

- (CGRect)rect {
    CGSize s = [self.texture contentSize];
    return CGRectMake(-s.width / 2, -s.height / 2, s.width, s.height);
}

+ (id)spuButtonWithTexture:(CCTexture2D *)normalTexture {
    return [[[self alloc] initWithTexture:normalTexture] autorelease];
}

- (void)setNormalTexture:(CCTexture2D *)normalTexture {
    buttonNormal = normalTexture;
}
- (void)setLitTexture:(CCTexture2D *)litTexture {
    buttonLit = litTexture;
}

- (BOOL)isPressed {
    if (buttonState== kButtonStateNotPressed) return NO;
    if (buttonState== kButtonStatePressed) return YES;
    return NO;
}

- (BOOL)isNotPressed {
    if (buttonState== kButtonStateNotPressed) return YES;
    if (buttonState== kButtonStatePressed) return NO;
    return YES;
}

- (void)makeDisabled {
    buttonStatus = kButtonStatusDisabled;
    buttonState= kButtonStateNotPressed;
    [self makeNormal];
}
- (void)makeEnabled {
    buttonStatus = kButtonStatusEnabled;
    buttonState= kButtonStateNotPressed;
    [self makeNormal];
}

- (BOOL)isEnabled {
    if (buttonStatus== kButtonStatusDisabled) return NO;
    if (buttonStatus== kButtonStatusEnabled) return YES;
    return NO;
}

- (BOOL)isDisabled {
    if (buttonStatus== kButtonStatusEnabled) return NO;
    if (buttonStatus== kButtonStatusDisabled) return YES;
    return YES;
}

- (void)makeLit {
    [self setTexture:buttonLit];
}

- (void)makeNormal {
    [self setTexture:buttonNormal];
}

- (id)initWithTexture:(CCTexture2D *)aTexture {
    if ((self = [super initWithTexture:aTexture]) ) {       
        buttonState = kButtonStateNotPressed;
        buttonStatus = kButtonStatusEnabled;
    }
    return self;
}

- (void)onEnter {
    if (buttonStatus == kButtonStatusDisabled) return;
    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:NO];
    [super onEnter];
}

- (void)onExit {
    if (buttonStatus == kButtonStatusDisabled) return;
    [[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
    [super onExit];
}   

- (BOOL)containsTouchLocation:(UITouch *)touch {
    return CGRectContainsPoint(self.rect, [self convertTouchToNodeSpaceAR:touch]);
}

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    if (buttonStatus == kButtonStatusDisabled) return NO;
    if (buttonState== kButtonStatePressed) return NO;
    if ( ![self containsTouchLocation:touch] ) return NO;

    buttonState= kButtonStatePressed;
    [self makeLit];

    return YES;
}

- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
    // If it weren't for the TouchDispatcher, you would need to keep a reference
    // to the touch from touchBegan and check that the current touch is the same
    // as that one.
    // Actually, it would be even more complicated since in the Cocos dispatcher
    // you get NSSets instead of 1 UITouch, so you'd need to loop through the set
    // in each touchXXX method.

    if (buttonStatus == kButtonStatusDisabled) return;
    if ([self containsTouchLocation:touch]) return;

    buttonState= kButtonStateNotPressed;
    [self makeNormal];
}

- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
    if (buttonStatus == kButtonStatusDisabled) return;

    buttonState= kButtonStateNotPressed;
    [self makeNormal];
}

- (void)dealloc {
    [buttonNormal release];
    [buttonLit release];
    [super dealloc];
}

@end

HelloWorldScene.m (Just my tick: method to keep my other functions from confusing the example)

-(void)tick:(ccTime)dt {
    if ([[_otherControlsArray objectAtIndex:0] wasPressed]) {
        [[_otherControlsArray objectAtIndex:0] setWasPressed:NO];
        [self removeChild:[_otherControlsArray objectAtIndex:0] cleanup:YES];
        [self addChild:[_otherControlsArray objectAtIndex:1]];
        NSLog(@"Play");

        _gameHasNotBeenPlayedYet = NO;
        Snarfle_s_PowerUPAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
        [delegate makeNotPaused];
        [self gameLogic];
    }

    if (_gameHasNotBeenPlayedYet) {
        return;
    }

    if (_buttonsPressedAndReleased > 0) {  //respond to button(s) released and reset
        NSLog(@"Buttons Pressed and Released-->%d",_buttonsPressedAndReleased);
        if ([self checkButtons:_buttonsPressedAndReleased]);
        _buttonsPressed = 0;
        _buttonsPressedAndReleased = 0;

        return;
    }
    if (_buttonsPressed <= 4) { // two buttons have not already been pressed
        for (spuButton *aButton in _fourButtonsArray) {
            if ([aButton isNotPressed]) continue; //this button is not pressed
            if (_buttonsPressed == 0) { //this button is pressed and no other buttons have been pressed
                _buttonsPressed = aButton.tag;
                continue;
            }
            //this button is pressed while another has been pressed
            //figure out which two buttons have been pressed
            if (_buttonsPressed == 1) {  //red plus another
                switch (aButton.tag) {
                    case 2:   //blue
                        _buttonsPressed = 5;
                        [[_fourButtonsArray objectAtIndex:2] makeDisabled];
                        [[_fourButtonsArray objectAtIndex:3] makeDisabled];
                        break;
                    case 3:  //green
                        _buttonsPressed = 6;
                        [[_fourButtonsArray objectAtIndex:1] makeDisabled];
                        [[_fourButtonsArray objectAtIndex:3] makeDisabled];
                        break;
                    case 4:  //yellow
                        _buttonsPressed = 7;
                        [[_fourButtonsArray objectAtIndex:1] makeDisabled];
                        [[_fourButtonsArray objectAtIndex:2] makeDisabled];
                        break;
                    default:
                        _buttonsPressed = 1;
                        break;
                }
            }
            if (_buttonsPressed == 2) {  //blue plus another
                switch (aButton.tag) {
                    case 1:   //red
                        _buttonsPressed = 5;
                        [[_fourButtonsArray objectAtIndex:2] makeDisabled];
                        [[_fourButtonsArray objectAtIndex:3] makeDisabled];
                        break;
                    case 3:  //green
                        _buttonsPressed = 8;
                        [[_fourButtonsArray objectAtIndex:0] makeDisabled];
                        [[_fourButtonsArray objectAtIndex:3] makeDisabled];
                        break;
                    case 4:  //yellow
                        _buttonsPressed = 9;
                        [[_fourButtonsArray objectAtIndex:0] makeDisabled];
                        [[_fourButtonsArray objectAtIndex:2] makeDisabled];
                        break;
                    default:
                        _buttonsPressed = 2;
                        break;
                }
            }
            if (_buttonsPressed == 3) {  //green plus another
                switch (aButton.tag) {
                    case 1:   //red
                        _buttonsPressed = 6;
                        [[_fourButtonsArray objectAtIndex:1] makeDisabled];
                        [[_fourButtonsArray objectAtIndex:3] makeDisabled];
                        break;
                    case 2:  //blue
                        _buttonsPressed = 8;
                        [[_fourButtonsArray objectAtIndex:0] makeDisabled];
                        [[_fourButtonsArray objectAtIndex:3] makeDisabled];
                        break;
                    case 4:  //yellow
                        _buttonsPressed = 10;
                        [[_fourButtonsArray objectAtIndex:0] makeDisabled];
                        [[_fourButtonsArray objectAtIndex:1] makeDisabled];
                        break;
                    default:
                        _buttonsPressed = 3;
                        break;
                }
            }
            if (_buttonsPressed == 4) {  //yellow plus another
                switch (aButton.tag) {
                    case 1:   //red
                        _buttonsPressed = 7;
                        [[_fourButtonsArray objectAtIndex:1] makeDisabled];
                        [[_fourButtonsArray objectAtIndex:2] makeDisabled];
                        break;
                    case 2:  //blue
                        _buttonsPressed = 9;
                        [[_fourButtonsArray objectAtIndex:0] makeDisabled];
                        [[_fourButtonsArray objectAtIndex:2] makeDisabled];
                        break;
                    case 3:  //green
                        _buttonsPressed = 10;
                        [[_fourButtonsArray objectAtIndex:0] makeDisabled];
                        [[_fourButtonsArray objectAtIndex:1] makeDisabled];
                        break;
                    default:
                        _buttonsPressed = 4;
                        break;
                }
            }
            if (_buttonsPressed > 4) break;  //more than one has been pressed and identified
        }
    }
    //now we know what buttons have been pressed now check to see if they have been released
    //if more than one has been pressed disable the other two
    //also if more than one has been pressed and one of them gets released disable the released one but keep it lit
    switch (_buttonsPressed) {
        case 1:  //red
            if ([[_fourButtonsArray objectAtIndex:0] isNotPressed]) _buttonsPressedAndReleased = 1;
            break;
        case 2:  //blue
            if ([[_fourButtonsArray objectAtIndex:1] isNotPressed]) _buttonsPressedAndReleased = 2;
            break;
        case 3:  //green
            if ([[_fourButtonsArray objectAtIndex:2] isNotPressed]) _buttonsPressedAndReleased = 3;
            break;
        case 4:  //yellow
            if ([[_fourButtonsArray objectAtIndex:3] isNotPressed]) _buttonsPressedAndReleased = 4;
            break;
        case 5:  //red & blue
            if (([[_fourButtonsArray objectAtIndex:0] isNotPressed]) && ([[_fourButtonsArray objectAtIndex:1] isNotPressed])) _buttonsPressedAndReleased = 5;
            else {
                if ([[_fourButtonsArray objectAtIndex:0] isNotPressed]) {
                    [[_fourButtonsArray objectAtIndex:0] makeDisabled];
                    [[_fourButtonsArray objectAtIndex:0] makeLit];
                }
                if ([[_fourButtonsArray objectAtIndex:1] isNotPressed]) {
                    [[_fourButtonsArray objectAtIndex:1] makeDisabled];
                    [[_fourButtonsArray objectAtIndex:1] makeLit];
                }
            }
            break;
        case 6:  //red & green
            if (([[_fourButtonsArray objectAtIndex:0] isNotPressed]) && ([[_fourButtonsArray objectAtIndex:2] isNotPressed])) _buttonsPressedAndReleased = 6;
            else {
                if ([[_fourButtonsArray objectAtIndex:0] isNotPressed]) {
                    [[_fourButtonsArray objectAtIndex:0] makeDisabled];
                    [[_fourButtonsArray objectAtIndex:0] makeLit];
                }
                if ([[_fourButtonsArray objectAtIndex:2] isNotPressed]) {
                    [[_fourButtonsArray objectAtIndex:2] makeDisabled];
                    [[_fourButtonsArray objectAtIndex:2] makeLit];
                }
            }
            break;
        case 7:  //red & yellow
            if (([[_fourButtonsArray objectAtIndex:0] isNotPressed]) && ([[_fourButtonsArray objectAtIndex:3] isNotPressed])) _buttonsPressedAndReleased = 7;
            else {
                if ([[_fourButtonsArray objectAtIndex:0] isNotPressed]) {
                    [[_fourButtonsArray objectAtIndex:0] makeDisabled];
                    [[_fourButtonsArray objectAtIndex:0] makeLit];
                }
                if ([[_fourButtonsArray objectAtIndex:3] isNotPressed]) {
                    [[_fourButtonsArray objectAtIndex:3] makeDisabled];
                    [[_fourButtonsArray objectAtIndex:3] makeLit];
                }
            }
            break;
        case 8:  //blue & green
            if (([[_fourButtonsArray objectAtIndex:1] isNotPressed]) && ([[_fourButtonsArray objectAtIndex:2] isNotPressed])) _buttonsPressedAndReleased = 8;
            else {
                if ([[_fourButtonsArray objectAtIndex:1] isNotPressed]) {
                    [[_fourButtonsArray objectAtIndex:1] makeDisabled];
                    [[_fourButtonsArray objectAtIndex:1] makeLit];
                }
                if ([[_fourButtonsArray objectAtIndex:2] isNotPressed]) {
                    [[_fourButtonsArray objectAtIndex:2] makeDisabled];
                    [[_fourButtonsArray objectAtIndex:2] makeLit];
                }
            }
            break;
        case 9:  //blue & yellow
            if (([[_fourButtonsArray objectAtIndex:1] isNotPressed]) && ([[_fourButtonsArray objectAtIndex:3] isNotPressed])) _buttonsPressedAndReleased = 9;
            else {
                if ([[_fourButtonsArray objectAtIndex:1] isNotPressed]) {
                    [[_fourButtonsArray objectAtIndex:1] makeDisabled];
                    [[_fourButtonsArray objectAtIndex:1] makeLit];
                }
                if ([[_fourButtonsArray objectAtIndex:3] isNotPressed]) {
                    [[_fourButtonsArray objectAtIndex:3] makeDisabled];
                    [[_fourButtonsArray objectAtIndex:3] makeLit];
                }
            }
            break;
        case 10:  //green & yellow
            if (([[_fourButtonsArray objectAtIndex:2] isNotPressed]) && ([[_fourButtonsArray objectAtIndex:3] isNotPressed])) _buttonsPressedAndReleased = 10;
            else {
                if ([[_fourButtonsArray objectAtIndex:2] isNotPressed]) {
                    [[_fourButtonsArray objectAtIndex:2] makeDisabled];
                    [[_fourButtonsArray objectAtIndex:2] makeLit];
                }
                if ([[_fourButtonsArray objectAtIndex:3] isNotPressed]) {
                    [[_fourButtonsArray objectAtIndex:3] makeDisabled];
                    [[_fourButtonsArray objectAtIndex:3] makeLit];
                }
            }
            break;
        default:
            _buttonsPressedAndReleased = 0;
            break;
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!