2013-11-15 120 views
15

我在做一個遊戲,我想要一個按鈕。我如何處理竊聽? 我使用單獨的類UI,它是SKSpriteNode保存所有按鈕和界面元素,而我不想場景來處理這些按鍵操作,我在開始接觸的方法。在Sprite Kit中創建按鈕的正確方法是什麼?

據我們所知,我們可以檢查觸摸中觸摸的節點是否開始,因此要實現內部觸摸的常規按鈕,我需要在touchesBegan和touchesEnded中編寫代碼,這看起來有點矯枉過正。

或者我應該使用常規的UIButton?但我知道你不能動態添加這些,只能在didMoveToView方法中,這看起來很糟糕。

+0

您必須使用touchesBegan/Ended,否則您將獲得觸摸輸入嗎?這樣做的一個方法:https://github.com/KoboldKit/KoboldKit/blob/master/KoboldKit/KoboldKitFree/Framework/Behaviors/UserInterface/KKButtonBehavior.m – LearnCocos2D

+0

我的切換按鈕,例如http://stackoverflow.com/questions/ 19688451/how-to-make-a-toggle-button-on-spritekit/19694729#19694729 – DogCoffee

+0

在didMoveToView中添加UIButton對你來說有什麼不好?如果顯示比場景加載稍後一點,請嘗試設置「pausesIncomingScene」或SKTransition,以用於顯示SKScene..I personaly,使用帶觸摸的SKSpriteNode開始方法... – BSevo

回答

11

我發現這個網上前一段時間,誰的推移格拉芙的名成員的禮遇,這很好地工作了我的問題。

#import <SpriteKit/SpriteKit.h> 
@interface SKBButtonNode : SKSpriteNode 

@property (nonatomic, readonly) SEL actionTouchUpInside; 
@property (nonatomic, readonly) SEL actionTouchDown; 
@property (nonatomic, readonly) SEL actionTouchUp; 
@property (nonatomic, readonly, weak) id targetTouchUpInside; 
@property (nonatomic, readonly, weak) id targetTouchDown; 
@property (nonatomic, readonly, weak) id targetTouchUp; 

@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; // Designated Initializer 

- (instancetype)initWithImageNamedNormal:(NSString *)normal selected:(NSString *)selected; 
- (instancetype)initWithImageNamedNormal:(NSString *)normal selected:(NSString *)selected disabled:(NSString *)disabled; 

/** Sets the target-action pair, that is called when the Button is tapped. 
"target" won't be retained. 
*/ 
- (void)setTouchUpInsideTarget:(id)target action:(SEL)action; 
- (void)setTouchDownTarget:(id)target action:(SEL)action; 
- (void)setTouchUpTarget:(id)target action:(SEL)action; 

@end 

和實現

// 
// 
// Courtesy of Graf on Stack Overflow 
// 
// 
// 
#import "SKBButtonNode.h" 



@implementation SKBButtonNode 

#pragma mark Texture Initializer 

/** 
* Override the super-classes designated initializer, to get a properly set SKButton in every case 
*/ 
- (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]; 
} 

/** 
* This is the designated Initializer 
*/ 
- (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 Setting Target-Action pairs 

- (void)setTouchUpInsideTarget:(id)target action:(SEL)action { 
    _targetTouchUpInside = target; 
    _actionTouchUpInside = action; 
} 

- (void)setTouchDownTarget:(id)target action:(SEL)action { 
    _targetTouchDown = target; 
    _actionTouchDown = action; 
} 

- (void)setTouchUpTarget:(id)target action:(SEL)action { 
    _targetTouchUp = target; 
    _actionTouchUp = action; 
} 

#pragma - 
#pragma mark Setter overrides 

- (void)setIsEnabled:(BOOL)isEnabled { 
    _isEnabled = isEnabled; 
    if ([self disabledTexture]) { 
     if (!_isEnabled) { 
      [self setTexture:_disabledTexture]; 
     } else { 
      [self setTexture:_normalTexture]; 
     } 
    } 
} 

- (void)setIsSelected:(BOOL)isSelected { 
    _isSelected = isSelected; 
    if ([self selectedTexture] && [self isEnabled]) { 
     if (_isSelected) { 
      [self setTexture:_selectedTexture]; 
     } else { 
      [self setTexture:_normalTexture]; 
     } 
    } 
} 

#pragma - 
#pragma mark Touch Handling 

/** 
* This method only occurs, if the touch was inside this node. Furthermore if 
* the Button is enabled, the texture should change to "selectedTexture". 
*/ 
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    if ([self isEnabled]) { 
     if (_actionTouchDown){ 
      [self.parent performSelectorOnMainThread:_actionTouchDown withObject:_targetTouchDown waitUntilDone:YES]; 
      [self setIsSelected:YES]; 
     } 
    } 
} 

/** 
* If the Button is enabled: This method looks, where the touch was moved to. 
* If the touch moves outside of the button, the isSelected property is restored 
* to NO and the texture changes to "normalTexture". 
*/ 
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 
    if ([self isEnabled]) { 
     UITouch *touch = [touches anyObject]; 
     CGPoint touchPoint = [touch locationInNode:self.parent]; 

     if (CGRectContainsPoint(self.frame, touchPoint)) { 
      [self setIsSelected:YES]; 
     } else { 
      [self setIsSelected:NO]; 
     } 
    } 
} 

/** 
* If the Button is enabled AND the touch ended in the buttons frame, the 
* selector of the target is run. 
*/ 
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
    UITouch *touch = [touches anyObject]; 
    CGPoint touchPoint = [touch locationInNode:self.parent]; 

    if ([self isEnabled] && CGRectContainsPoint(self.frame, touchPoint)) { 
     if (_actionTouchUpInside){ 
      [self.parent performSelectorOnMainThread:_actionTouchUpInside withObject:_targetTouchUpInside waitUntilDone:YES]; 
     } 
    } 
    [self setIsSelected:NO]; 
     if (_actionTouchUp){ 
     [self.parent performSelectorOnMainThread:_actionTouchUp withObject:_targetTouchUp waitUntilDone:YES]; 
    } 
} 
@end 
+1

很想爲每個用戶提供-1 'objc_msgSend'。 – Sulthan

+0

在那裏,全部換成了'objc_msgSend()' – Andrew97p

+0

@ Andrew97p,你能解釋一下請,爲什麼我們需要在self.parent進行選擇,但不只是自我? – AndrewShmig

8

我創造了一個類使用SKSpriteNode作爲一個按鈕前一段。你可以在GitHub上找到它。

AGSpriteButton

它的實現是基於UIButton的,所以如果你已經熟悉了iOS上,你會發現它易於使用。

它包括設置一個標籤,以及一種方法。

A鍵通常會宣稱,像這樣:

AGSpriteButton *button = [AGSpriteButton buttonWithColor:[UIColor redColor] andSize:CGSizeMake(300, 100)]; 
[button setLabelWithText:@"Button Text" andFont:nil withColor:nil]; 
button.position = CGPointMake(self.size.width/2, self.size.height/3); 
[button addTarget:self selector:@selector(someSelector) withObject:nil forControlEvent:AGButtonControlEventTouchUpInside]; 
[self addChild:button]; 

就是這樣。你很好走。

編輯:自發布此答案以來,已對AGSpriteButton進行了一些改進。

您現在可以分配塊要在觸摸事件執行:

[button performBlock:^{ 
     [self addSpaceshipAtPoint:[NSValue valueWithCGPoint:CGPointMake(100, 100)]]; 
    } onEvent:AGButtonControlEventTouchUp]; 

此外,對SKNode的實例來執行SKAction對象(或任何它的子類)可分配:

[button addTarget:self 
     selector:@selector(addSpaceshipAtPoint:) 
     withObject:[NSValue valueWithCGPoint:CGPointMake(self.size.width/2, self.size.height/2)]   
     forControlEvent:AGButtonControlEventTouchUpInside]; 

AGSpriteButton也可以與Swift一起使用!

let button = AGSpriteButton(color: UIColor.greenColor(), andSize: CGSize(width: 200, height: 60)) 
button.position = CGPoint(x: self.size.width/2, y: self.size.height/2) 
button.addTarget(self, selector: "addSpaceship", withObject: nil, forControlEvent:AGButtonControlEvent.TouchUpInside) 
button.setLabelWithText("Spaceship", andFont: nil, withColor: UIColor.blackColor()) 
addChild(button) 
+2

您應該在代碼中使用nil而不是Nil。無是空課。 – Dvole

+0

謝謝@Dvole。將更新。 – ZeMoon

相關問題