I used a solution from this question SpriteKit Objective-C: programming directional pad controls as well as a version of custom class buttons from here Correct way to create button in Sprite Kit? with omitted target-action methods to create virtual control buttons for my SpriteKit game. So here is the problem: what I am trying to implement is two separate sets of buttons unrelated to each other (for instance, D-pad on the left, and fire buttons on the right) and the ability to use them both at the same time with help of multi-touch, just like you would on a hardware controller with action buttons on the right and dirs on the left. So let's imagine the situation:
1) I start by holding a directional button and a fire button. Then I drag my left finger outside the directional button, which triggers the if(node.name)'s ELSE statement, that sets all buttons' "selected" bools to NO. This is not what I want because the fire button is still held, and it should retain it's "selected" state, while directional button — shouldn't.
2) Same situation, but if I drag my right finger outside the fire button instead, and keep holding directional button. Both buttons get "deselected", when fire button shouldn't do it.
So how do I implement it correctly with a way to detect, which button exactly got "deselected" to "deselect" just that particular set of buttons? Please push me in the right direction. Hope what I have requested is possible.
Current code (It's pretty messy, excuse the gorilla-style coding):
DirectionalButton.h
#import <SpriteKit/SpriteKit.h>
@interface DirectionalButton : SKSpriteNode
@property (nonatomic) BOOL isEnabled;
@property (nonatomic) BOOL isSelected;
@property (nonatomic, readonly, strong) SKLabelNode *title;
@property (nonatomic, readwrite, strong) SKTexture *normalTexture;
@property (nonatomic, readwrite, strong) SKTexture *selectedTexture;
@property (nonatomic, readwrite, strong) SKTexture *disabledTexture;
- (instancetype)initWithTextureNormal:(SKTexture *)normal selected:(SKTexture *)selected;
- (instancetype)initWithTextureNormal:(SKTexture *)normal selected:(SKTexture *)selected disabled:(SKTexture *)disabled;
- (instancetype)initWithImageNamedNormal:(NSString *)normal selected:(NSString *)selected;
- (instancetype)initWithImageNamedNormal:(NSString *)normal selected:(NSString *)selected disabled:(NSString *)disabled;
@end
DirectionalButton.m
#import "DirectionalButton.h"
@implementation DirectionalButton
#pragma mark Texture Initializer
- (instancetype)initWithTexture:(SKTexture *)texture color:(UIColor *)color size:(CGSize)size {
    return [self initWithTextureNormal:texture selected:nil disabled:nil];
}
- (instancetype)initWithTextureNormal:(SKTexture *)normal selected:(SKTexture *)selected {
    return [self initWithTextureNormal:normal selected:selected disabled:nil];
}
- (instancetype)initWithTextureNormal:(SKTexture *)normal selected:(SKTexture *)selected disabled:(SKTexture *)disabled {
    self = [super initWithTexture:normal color:[UIColor whiteColor] size:normal.size];
    if (self) {
        [self setNormalTexture:normal];
        [self setSelectedTexture:selected];
        [self setDisabledTexture:disabled];
        [self setIsEnabled:YES];
        [self setIsSelected:NO];
        _title = [SKLabelNode labelNodeWithFontNamed:@"Arial"];
        [_title setVerticalAlignmentMode:SKLabelVerticalAlignmentModeCenter];
        [_title setHorizontalAlignmentMode:SKLabelHorizontalAlignmentModeCenter];
        [self addChild:_title];
        [self setUserInteractionEnabled:YES];
    }
    return self;
}
#pragma mark Image Initializer
- (instancetype)initWithImageNamedNormal:(NSString *)normal selected:(NSString *)selected {
    return [self initWithImageNamedNormal:normal selected:selected disabled:nil];
}
- (instancetype)initWithImageNamedNormal:(NSString *)normal selected:(NSString *)selected disabled:(NSString *)disabled {
    SKTexture *textureNormal = nil;
    if (normal) {
        textureNormal = [SKTexture textureWithImageNamed:normal];
    }
    SKTexture *textureSelected = nil;
    if (selected) {
        textureSelected = [SKTexture textureWithImageNamed:selected];
    }
    SKTexture *textureDisabled = nil;
    if (disabled) {
        textureDisabled = [SKTexture textureWithImageNamed:disabled];
    }
    return [self initWithTextureNormal:textureNormal selected:textureSelected disabled:textureDisabled];
}
#pragma -
#pragma mark Setter overrides
- (void)setIsEnabled:(BOOL)isEnabled {
    _isEnabled = isEnabled;
    if ([self disabledTexture]) {
        if (!_isEnabled) {
            [self setTexture:_disabledTexture];
        } else {
            [self setTexture:self.normalTexture];
        }
    }
}
- (void)setIsSelected:(BOOL)isSelected {
    _isSelected = isSelected;
    if ([self selectedTexture] && [self isEnabled]) {
        if (_isSelected) {
            [self setTexture:_selectedTexture];
            [self runAction:[SKAction fadeAlphaTo:0.55 duration:0.12f]];
        } else {
            [self setTexture:self.normalTexture];
            [self runAction:[SKAction fadeAlphaTo:1 duration:0.12f]];
        }
    }
}
@end
GameScene.m
- (void)createHUD {
//Executed in didMoveToView
NSString *pathToImageForLeftButtonTexture = @"buttonDirectionalLeft";
NSString *pathToImageForRightButtonTexture = @"buttonDirectionalRight";
dirBtnLeft = [[DirectionalButton alloc]initWithImageNamedNormal:pathToImageForLeftButtonTexture selected:pathToImageForLeftButtonTexture];
/*
    Set size and position for left
*/
dirBtnLeft.name = @"directionalLeft";
dirBtnRight = [[DirectionalButton alloc]initWithImageNamedNormal:pathToImageForRightButtonTexture selected:pathToImageForRightButtonTexture];
/*
    Set size and position accordingly to left button for right
*/
dirBtnRight.name = @"directionalRight";
dirBtnLeftFrame = [SKSpriteNode spriteNodeWithColor:[SKColor clearColor] size:dirBtnLeft.size];
dirBtnLeftFrame.position = dirBtnLeft.position;
dirBtnRightFrame = [SKSpriteNode spriteNodeWithColor:[SKColor clearColor] size:dirBtnRight.size];
fireBtn = [[DirectionalButton alloc]initWithImageNamedNormal:@"default.jpg" selected:@"default.jpg"];
/*
    Set position and size for fire
*/
fireBtnFrame = [SKSpriteNode spriteNodeWithColor:[SKColor clearColor] size:fireBtn.size];
fireBtnFrame.position = fireBtn.position;
dirBtnRightFrame.position = dirBtnRight.position;
dirBtnLeftFrame.zPosition = 100;
dirBtnRightFrame.zPosition = 100;
fireBtnFrame.zPosition = 100;
dirBtnRight.zPosition = 99;
dirBtnLeft.zPosition = 99;
fireBtn.zPosition = 99;
dirBtnLeftFrame.name = @"directionalLeftFrame";
dirBtnRightFrame.name = @"directionalRightFrame";
fireBtnFrame.name = @"primaryFire";
[self addChild:dirBtnLeft];
[self addChild:dirBtnRight];
[self addChild:dirBtnLeftFrame];
[self addChild:dirBtnRightFrame];
[self addChild:fireBtn];
[self addChild:fireBtnFrame];    
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self touchesMoved:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for(UITouch *touch in [event allTouches]){
    CGPoint touchLocation = [touch locationInNode:self];
    SKNode *node = [self nodeAtPoint:touchLocation];
    if (node.name)
    {
        if ([node.name isEqualToString:@"directionalRightFrame"])
        {
            if(!dirBtnRight.isSelected){
            [dirBtnRight setIsSelected:YES];
                [dirBtnLeft setIsSelected:NO];}
        }
        else if ([node.name isEqualToString:@"directionalLeftFrame"])
        {
            if(!dirBtnLeft.isSelected){
            [dirBtnRight setIsSelected:NO];
                [dirBtnLeft setIsSelected:YES];}
        }
        else if ([node.name isEqualToString:@"primaryFire"]) {
            if (!fireBtn.isSelected) {
                [fireBtn setIsSelected:YES];
            }
        }
    }
    else
    {
        [dirBtnRight setIsSelected:NO];
        [dirBtnLeft setIsSelected:NO];
        [fireBtn setIsSelected:NO];
    }}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in [event allTouches]) {
    CGPoint touchPoint = [touch locationInNode:self];
    SKNode *node = [self nodeAtPoint:touchPoint];
    if(node.name){
    if ([node.name isEqualToString:@"directionalLeftFrame"]) {
dirBtnLeft.isSelected = NO;}
else if ([node.name isEqualToString:@"directionalRightFrame"])
{
    dirBtnRight.isSelected = NO;
}
else if([node.name isEqualToString:@"primaryFire"]){
    fireBtn.isSelected = NO;}
    }    else
    {
        dirBtnLeft.isSelected = NO;
        dirBtnRight.isSelected = NO;
        fireBtn.isSelected = NO;}}
}
-(void)update:(CFTimeInterval)currentTime {
    if(dirBtnLeft.isSelected){
        //Do something
    }
    else if(dirBtnRight.isSelected){
        //Do something else
    }
    else
    {
        //Stop doing anything
    }
}
 
    