02fentym
02fentym

Reputation: 1792

SpriteKit Keyboard Observer

I have currently been using delegation and an SKView custom class to monitor key presses in my OS X SpriteKit game. I need to employ multiple delegates for my keyboard monitoring class, which I know is not possible, but it is possible through using observers. How can this be accomplished? Here's my code using the delegation pattern:

CustomSKView.h

#import <SpriteKit/SpriteKit.h>

@protocol KeyPressedDelegate;

@interface CustomSKView : SKView

@property (weak) id <KeyPressedDelegate> delegate;

@end

@protocol KeyPressedDelegate

- (void) upArrowPressed;
- (void) downArrowPressed;

@end

CustomSKView.m

#import "CustomSKView.h"

@implementation CustomSKView:SKView {
    // Add instance variables here

}

- (id) initWithCoder:(NSCoder *)coder {
    self = [super initWithCoder:coder];
    if (self) {
        // Allocate and initialize your instance variables here

    }
    return self;
}

- (void) keyDown:(NSEvent *)theEvent {
    // Add code to handle a key down event here
    if (self.delegate) {
        switch (theEvent.keyCode) {
            case 126: {
                NSLog(@"delegate = %@", [self delegate]);
                [self.delegate upArrowPressed];
                break;
            }
            case 125:
                [self.delegate downArrowPressed];
                break;
            default:
                break;
        }
    }
}

@end

GameScene.h

#import <SpriteKit/SpriteKit.h>
#import "CustomSKView.h"

@interface GameScene : SKScene <KeyPressedDelegate>

@end

GameScene.m

#import "GameScene.h"

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
    ((CustomSKView *)view).delegate = self;
}

- (void) upArrowPressed {
    NSLog(@"Up Arrow Pressed");
}
- (void) downArrowPressed {
    NSLog(@"Down Arrow Pressed");
}

@end

Upvotes: 3

Views: 302

Answers (1)

Ben Kane
Ben Kane

Reputation: 10060

You are looking for NSNotificationCenter. To add an object as an observer, use the following:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyPressed:)
                                             name:@"KeyPressedNotificationKey"
                                           object:nil];

This causes that object to observe notifications with the name @"KeyPressedNotificationKey". To post a notification with that name and attach the keyCode for the key that was pressed, call this:

[[NSNotificationCenter defaultCenter] postNotificationName:@"KeyPressedNotificationKey"
                                                    object:nil
                                                  userInfo:@{@"keyCode" : @(event.keyCode)];

When you post the notification, any observers will call the method associated with the observer. You can get the keyCode from the userInfo dictionary you attached when you posted the notification. In this case, the method with this signature will be called:

- (void)keyPressed:(NSNotification *)notification
{
    NSNumber *keyCodeObject = notification.userInfo[@"keyCode"];
    NSInteger keyCode = keyCodeObject.integerValue;
    // Do your thing
}

There is one catch to this. You need to remove the object as an observer as soon as it is done observing. If you deallocate an object without removing the observer, then post the notification, it'll still try to call the method on your non-existent object and crash. Use the following code to remove the object as an observer:

[[NSNotificationCenter defaultCenter] removeObserver:self
                                                name:@"NotificationNameKey"
                                              object:nil];

Upvotes: 3

Related Questions