自定义按钮类设置userinteractionenabled

时间:2014-10-05 01:57:50

标签: objective-c button sprite-kit

注意:这适用于OS X应用,而非iOS应用。

我正在创建一个自定义按钮类,它是SKSpriteNode的子类。我希望这个类能够处理按钮按下,所以我发现我必须将setuserinteractionenabled设置为YES。当我在自定义按钮类中执行此操作以便mouseDown事件接收消息时,创建按钮的SKScene在单击按钮时不再接收消息。有没有办法解决这个问题?我甚至尝试在SKScene中启用setuserinteractionenabled,但无济于事。我找不到任何有关此问题的问题。

Button.h

#import <SpriteKit/SpriteKit.h>

typedef enum ButtonState {
    UNPRESSED,
    PRESSED
} ButtonState;

@interface Button : SKSpriteNode

@property ButtonState state;

-(id)initButtonWithImage:(NSString*)unselectedImage selectedImage:(NSString*)selectedImage;
-(void)setButtonState:(NSString*)event;

@end

Button.m(自定义按钮类)

#import "Button.h"

@interface Button()

@property SKSpriteNode *image;
@property SKSpriteNode *unselectedImage;
@property SKSpriteNode *selectedImage;

@end

@implementation Button

@synthesize state = _state;
@synthesize image = _image;
@synthesize unselectedImage = _unselectedImage;
@synthesize selectedImage = _selectedImage;

-(id)initButtonWithImage:(NSString*)unselectedImage selectedImage:(NSString*)selectedImage {
    if (self = [super init]) {
        _unselectedImage = [[SKSpriteNode alloc] initWithImageNamed:unselectedImage];
        _selectedImage = [[SKSpriteNode alloc] initWithImageNamed:selectedImage];

        _image = _unselectedImage;
        _image.name = @"image";

        [self addChild:_image];
        self.userInteractionEnabled = YES;

    }
    return self;
}

-(void)setButtonState:(NSString*)event {
    [self removeAllChildren];
    if ([event isEqualToString:@"mousedown"])
        _image = _selectedImage;
    else if ([event isEqualToString:@"mouseup"])
        _image = _unselectedImage;

    [self addChild:_image];
}

-(void)mouseDown:(NSEvent *)theEvent {
    [self setButtonState:@"mousedown"];
}

-(void)mouseUp:(NSEvent *)theEvent {
    [self setButtonState:@"mouseup"];
}

@end

GameMenu.m(SKScene)

#import "GameMenu.h"
#import "NoteBlasterMenu.h"
#import "ChordAttackMenu.h"
#import "Button.h"

@implementation GameMenu

-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */
        self.userInteractionEnabled = YES; //allows scene to register clicks

        [self initBackground];
        [self initButtons];
        [self setUserInteractionEnabled:YES];
    }
    return self;
}

-(void) initBackground {
    SKSpriteNode *bg = [SKSpriteNode spriteNodeWithImageNamed:@"menubg"];
    bg.position = CGPointMake(self.size.width/2, self.size.height/2);
    [self addChild:bg];
}

-(void) initButtons {
    Button *chordAttackButton = [[Button alloc] initButtonWithImage:@"chordattackbutton"
                                                      selectedImage:@"chordattackbuttonpressed"];
    chordAttackButton.position = CGPointMake(self.size.width/2, self.size.height/2);
    chordAttackButton.name = @"chordAttackButton";
    [self addChild:chordAttackButton];

    Button *noteBlasterButton = [[Button alloc] initButtonWithImage:@"noteblasterbutton"
                                                      selectedImage:@"noteblasterbuttonpressed"];
    noteBlasterButton.position = CGPointMake(self.size.width/2, self.size.height/2 - 150);
    noteBlasterButton.name = @"noteBlasterButton";
    [self addChild:noteBlasterButton];
}

-(void)mouseDown:(NSEvent *)theEvent {
    CGPoint location = [theEvent locationInNode:self];
    NSArray *nodes = [self nodesAtPoint:location];

    NSLog(@"I'm being pressed");

    for (SKNode *node in nodes) {
        if ([node isKindOfClass:[Button class]]) {
            Button *button = (Button*)node;

            if ([button.name isEqualToString:@"chordAttackButton"]) {
                SKScene *scene = [ChordAttackMenu sceneWithSize:CGSizeMake(1280, 720)];
                [self.view presentScene:scene transition:[SKTransition fadeWithDuration:0.55]];
            }
            else if ([button.name isEqualToString:@"noteBlasterButton"]) {
                SKScene *scene = [NoteBlasterMenu sceneWithSize:CGSizeMake(1280, 720)];
                [self.view presentScene:scene transition:[SKTransition fadeWithDuration:0.55]];
            }
        }
    }
}

@end

AppDelegate.m

....(header files etc)
@implementation AppDelegate

@synthesize window = _window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    /* Set up the window for the app */
    NSRect frame = [_window frame];
    frame.size = CGSizeMake(1280, 740);
    [_window setFrame: frame display: YES animate: NO];
    [_window center]; //sets the window to the centre of the screen

    /* Pick a size for the scene */
    //SKScene *scene = [ChordAttackMenu sceneWithSize:CGSizeMake(1280, 720)]; //ChordAttack Menu
    //SKScene *scene = [MyScene sceneWithSize:CGSizeMake(1280, 720)]; //ChordAttack
    //SKScene *scene = [NoteBlasterMenu sceneWithSize:CGSizeMake(1280, 720)]; //BassBlaster Menu
    //SKScene *scene = [NoteBlaster sceneWithSize:CGSizeMake(1280, 720)]; //BassBlaster
    SKScene *scene = [GameMenu sceneWithSize:CGSizeMake(1280, 720)];

    /* Set the scale mode to scale to fit the window */
    //scene.scaleMode = SKSceneScaleModeAspectFit;
    scene.scaleMode = SKSceneScaleModeAspectFill;

    [self.skView presentScene:scene];

    self.skView.showsFPS = YES;
    self.skView.showsNodeCount = YES;
}

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
    return YES;
}

2 个答案:

答案 0 :(得分:1)

在GameMenu.m的initButtons方法中,为每个按钮设置下一个响应者

chordAttackButton.nextResponder = self;
noteBlasterButton.nextResponder = self;

在Button类中,通过

将鼠标向下/向上传递到响应者链中
-(void)mouseDown:(NSEvent *)theEvent {
    [self setButtonState:@"mousedown"];
    [super mouseDown:theEvent];
}

-(void)mouseUp:(NSEvent *)theEvent {
    [self setButtonState:@"mouseup"];
    [super mouseUp:theEvent];
}

答案 1 :(得分:0)

所以这很奇怪。你可以说,我不是最好的Objective c。但是在处理事件之后,根据apple Event Handling Guide,您可以使用

将其传递给响应者链
[super theEvent];

但在这种情况下,GameScene是父按钮而不是其超视图。所以,你需要做的是像这样调用事件:

[self.parent theEvent];

[self setNextResponder:referenceToGameScene];
[self.nextResponder theEvent];

最好让控制器以较少复杂的方式管理这些事件。因为每个孩子都补充说你想要传递事件,响应者链需要实现上面的代码。