SpriteKit键盘观察者

3

我目前正在使用委托和SKView自定义类来监控我的OS X SpriteKit游戏中的按键。我需要为我的键盘监视类使用多个代理,但我知道这是不可能的,但可以通过使用观察者实现。如何完成这个任务?这是使用委托模式的代码:

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

为什么你认为多个委托不可能?没有任何东西阻止你创建一个委托数组。 - Ben Kane
这只是我从许多其他帖子中读到的。好的,那么按照数组的想法,我需要在CustomSKView类中创建一个数组,然后在它们各自的类中将每个场景或任何其他对象添加到其中,对吗?从那里开始,在CustomSKView类中,我会运行一个循环通知所有代理,对吗? - 02fentym
是的,你会有一个委托数组,每当有东西想成为委托时,你就将其添加到数组中。然后,当你想调用委托方法时,你可以使用for循环并在所有委托上调用它。我并不是说这是可取的,我只是想指出这是可能的 :) - Ben Kane
哈哈...嗯,好的。如果不建议这样做,那么什么是首选方法呢?不过那样做很有道理 :) - 02fentym
可能是NSNotificationCenter,这是你想要使用的。有很多好的教程可以参考。基本上,您将发布一个带有名称的通知,任何观察该名称通知的类都将调用一个方法并执行其操作。 - Ben Kane
是的,我看过一些教程,但我并不清楚所有细节。我总体上理解这个概念,但就像我说的那样,还不足以在我的项目中实现代码。 - 02fentym
1个回答

3
您需要使用NSNotificationCenter。要将一个对象添加为观察者,请使用以下代码:
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyPressed:)
                                             name:@"KeyPressedNotificationKey"
                                           object:nil];

这会导致该对象观察名为@"KeyPressedNotificationKey"的通知。要发布一个带有该名称并附加按下的键的keyCode的通知,请调用以下内容:

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

当您发布通知时,任何观察者都将调用与观察者相关联的方法。您可以从您在发布通知时附加的userInfo字典中获取keyCode。在这种情况下,将调用具有此签名的方法:

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

这里有一个需要注意的地方。一旦对象完成观察,你需要立即将其作为观察者移除。如果你在未移除观察者的情况下释放了该对象,并且发布了通知,则仍会尝试在不存在的对象上调用方法并导致崩溃。使用以下代码将对象作为观察者移除:

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

在我添加观察者的第一部分中,由于它只有一个选择器,我是否应该为键入的每个键添加一个观察者?如果您查看我上面的代码,每个键都调用委托的单独方法。 - 02fentym
不,使用一个通知,并将键代码作为 NSNumber 传递给通知的对象属性。 - Ben Kane
@02fentym 我编辑了答案,使其更符合您的情况。希望这有所帮助。 - Ben Kane
太棒了,它起作用了。因此,我将拥有一个超级大的开关块来处理每个情况。与每个类使用keyUp和/或keyDown方法相比,这样做的好处是什么? - 02fentym
我猜如果你想为每个可按下的键创建一个可选的委托方法,然后让你的委托实现只需要它们所需的内容,那么这可能是可以接受的。但是然后你将不得不为每个键码调用特定的委托方法,而不是只调用一个简单的委托方法并传递键码。真的取决于你想要做什么设计选择。我认为没有任何性能差异,只是更标准的说法是“我按下了一个键,在这里”,而不是每个方法都说“我按下了这个特定的键”。 - Ben Kane
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接