在Sprite Kit中创buildbutton的正确方法?
我正在做一个游戏,我想要一个button。 我如何处理窃听呢? 我使用单独的类为UI,它是SKSpriteNode持有所有的button和界面元素,我不希望场景来处理这些button触摸我的触摸开始方法。
据我所知,我们可以检查在触摸点被触摸的节点开始,所以要实现正常的button与触摸里面我需要在touchesBegan和touchesEnded编写代码,这看起来有点矫枉过正。
或者我应该使用普通的UIButton? 但我知道,你不能dynamic地添加这些,只有在didMoveToView方法,这看起来不好。
我刚才在网上发现了这个消息,由一位格拉芙名字的会员提供,这对我的问题很好。
#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
不久前我创build了一个使用SKSpriteNode作为button的类。 你可以在GitHub上find它。
AGSpriteButton
它的实现基于UIButton,所以如果你已经熟悉iOS,你会发现它很容易处理。
它还包括一个设置标签的方法。
一个button通常会被声明如下:
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)