在SKScene中设置按钮

Ale*_*man 79 objective-c uibutton ios sprite-kit

我发现它UIButtons不能很好地工作SKScene,所以我试图子类化SKNode来制作一个按钮SpriteKit.

我希望它工作的方式是,如果我初始化一个按钮SKScene并启用触摸事件,那么按钮将在我SKScene按下时调用我的方法.

我很感激任何能让我找到解决这个问题的建议.谢谢.

And*_*yOS 102

您可以使用SKSpriteNode作为按钮,然后当用户触摸时,检查是否触摸了节点.使用SKSpriteNode的name属性来标识节点:

//fire button
- (SKSpriteNode *)fireButtonNode
{
    SKSpriteNode *fireNode = [SKSpriteNode spriteNodeWithImageNamed:@"fireButton.png"];
    fireNode.position = CGPointMake(fireButtonX,fireButtonY);
    fireNode.name = @"fireButtonNode";//how the node is identified later
    fireNode.zPosition = 1.0;
    return fireNode;
}
Run Code Online (Sandbox Code Playgroud)

将节点添加到场景中:

[self addChild: [self fireButtonNode]];
Run Code Online (Sandbox Code Playgroud)

处理接触:

//handle touch events
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInNode:self];
    SKNode *node = [self nodeAtPoint:location];

    //if fire button touched, bring the rain
    if ([node.name isEqualToString:@"fireButtonNode"]) {
         //do whatever...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你添加一个iVar作为按钮,你可以删除名称检查,只需使用if([_ fireNode containsPoint:location])做同样的事情只是不同. (8认同)
  • 比较字符串,这是一个肮脏的解决方案.虽然@Smick的解决方案更好,但是没有其他更清洁的方法来实现这一目标吗? (3认同)

den*_*tra 52

我已经制作了自己的Button-Class,我正在使用它.SKButton.h:

#import <SpriteKit/SpriteKit.h>
@interface SKButton : 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;

- (id)initWithTextureNormal:(SKTexture *)normal selected:(SKTexture *)selected;
- (id)initWithTextureNormal:(SKTexture *)normal selected:(SKTexture *)selected disabled:(SKTexture *)disabled; // Designated Initializer

- (id)initWithImageNamedNormal:(NSString *)normal selected:(NSString *)selected;
- (id)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
Run Code Online (Sandbox Code Playgroud)

SKButton.m:

#import "SKButton.h"
#import <objc/message.h>


@implementation SKButton

#pragma mark Texture Initializer

/**
 * Override the super-classes designated initializer, to get a properly set SKButton in every case
 */
- (id)initWithTexture:(SKTexture *)texture color:(UIColor *)color size:(CGSize)size {
    return [self initWithTextureNormal:texture selected:nil disabled:nil];
}

- (id)initWithTextureNormal:(SKTexture *)normal selected:(SKTexture *)selected {
    return [self initWithTextureNormal:normal selected:selected disabled:nil];
}

/**
 * This is the designated Initializer
 */
- (id)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

- (id)initWithImageNamedNormal:(NSString *)normal selected:(NSString *)selected {
    return [self initWithImageNamedNormal:normal selected:selected disabled:nil];
}

- (id)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]) {
        objc_msgSend(_targetTouchDown, _actionTouchDown);
        [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)) {
        objc_msgSend(_targetTouchUpInside, _actionTouchUpInside);
    }
    [self setIsSelected:NO];
    objc_msgSend(_targetTouchUp, _actionTouchUp);
}
Run Code Online (Sandbox Code Playgroud)

示例:要初始化按钮,请编写以下行:

    SKButton *backButton = [[SKButton alloc] initWithImageNamedNormal:@"buttonNormal" selected:@"buttonSelected"];
    [backButton setPosition:CGPointMake(100, 100)];
    [backButton.title setText:@"Button"];
    [backButton.title setFontName:@"Chalkduster"];
    [backButton.title setFontSize:20.0];
    [backButton setTouchUpInsideTarget:self action:@selector(buttonAction)];
    [self addChild:backButton];
Run Code Online (Sandbox Code Playgroud)

此外,您需要在班级中使用'buttonAction'方法. *不保证本课程在每种情况下都正常工作.我对Objective-c还很新.*

如果您认为有做,这是恼人的和毫无意义的,你可以通过设置禁用构建设置检查"启用严格的检查objc_msgSend Calls',以" No'

  • 啊,是的,给了ARC.我忘记了那个警告:| 如果您有兴趣,这里有一个很好的工作http://stackoverflow.com/questions/11895287/performselector-arc-warning (2认同)

Gro*_*oot 19

对于在Swift中编写游戏的人来说!我已经将格拉夫解决方案的基本部分重写为快速课程.希望能帮助到你:

import Foundation
import SpriteKit

class FTButtonNode: SKSpriteNode {

    enum FTButtonActionType: Int {
        case TouchUpInside = 1,
        TouchDown, TouchUp
    }

    var isEnabled: Bool = true {
    didSet {
        if (disabledTexture != nil) {
            texture = isEnabled ? defaultTexture : disabledTexture
        }
    }
    }
    var isSelected: Bool = false {
    didSet {
        texture = isSelected ? selectedTexture : defaultTexture
    }
    }
    var defaultTexture: SKTexture
    var selectedTexture: SKTexture

    required init(coder: NSCoder) {
        fatalError("NSCoding not supported")
    }

    init(normalTexture defaultTexture: SKTexture!, selectedTexture:SKTexture!, disabledTexture: SKTexture?) {

        self.defaultTexture = defaultTexture
        self.selectedTexture = selectedTexture
        self.disabledTexture = disabledTexture

        super.init(texture: defaultTexture, color: UIColor.whiteColor(), size: defaultTexture.size())

        userInteractionEnabled = true

        // Adding this node as an empty layer. Without it the touch functions are not being called
        // The reason for this is unknown when this was implemented...?
        let bugFixLayerNode = SKSpriteNode(texture: nil, color: nil, size: defaultTexture.size())
        bugFixLayerNode.position = self.position
        addChild(bugFixLayerNode)

    }

    /**
    * Taking a target object and adding an action that is triggered by a button event.
    */
    func setButtonAction(target: AnyObject, triggerEvent event:FTButtonActionType, action:Selector) {

        switch (event) {
        case .TouchUpInside:
            targetTouchUpInside = target
            actionTouchUpInside = action
        case .TouchDown:
            targetTouchDown = target
            actionTouchDown = action
        case .TouchUp:
            targetTouchUp = target
            actionTouchUp = action
        }

    }

    var disabledTexture: SKTexture?
    var actionTouchUpInside: Selector?
    var actionTouchUp: Selector?
    var actionTouchDown: Selector?
    weak var targetTouchUpInside: AnyObject?
    weak var targetTouchUp: AnyObject?
    weak var targetTouchDown: AnyObject?

    override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!)  {
        let touch: AnyObject! = touches.anyObject()
        let touchLocation = touch.locationInNode(parent)

        if (!isEnabled) {
            return
        }
        isSelected = true
        if (targetTouchDown != nil && targetTouchDown!.respondsToSelector(actionTouchDown!)) {
            UIApplication.sharedApplication().sendAction(actionTouchDown!, to: targetTouchDown, from: self, forEvent: nil)
        }


    }

    override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!)  {

        if (!isEnabled) {
            return
        }

        let touch: AnyObject! = touches.anyObject()
        let touchLocation = touch.locationInNode(parent)

        if (CGRectContainsPoint(frame, touchLocation)) {
            isSelected = true
        } else {
            isSelected = false
        }

    }

    override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) {

        if (!isEnabled) {
            return
        }

        isSelected = false

        if (targetTouchUpInside != nil && targetTouchUpInside!.respondsToSelector(actionTouchUpInside!)) {
            let touch: AnyObject! = touches.anyObject()
            let touchLocation = touch.locationInNode(parent)

            if (CGRectContainsPoint(frame, touchLocation) ) {
                UIApplication.sharedApplication().sendAction(actionTouchUpInside!, to: targetTouchUpInside, from: self, forEvent: nil)
            }

        }

        if (targetTouchUp != nil && targetTouchUp!.respondsToSelector(actionTouchUp!)) {
            UIApplication.sharedApplication().sendAction(actionTouchUp!, to: targetTouchUp, from: self, forEvent: nil)
        }
    }

}
Run Code Online (Sandbox Code Playgroud)


bsh*_*ley 5

如果您愿意,可以使用UIButton(或任何其他UIView).

SKScene被创建,它还不在一个存在SKView.您应该didMoveToView:在您的SKScene子类上实现.此时,您可以访问SKView放置的场景,并可以向其添加UIKit对象.为了美观,我褪了他们......

- (void)didMoveToView:(SKView *)view {
  UIView *b = [self _createButton];  // <-- performs [self.view addSubview:button]
  // create other UI elements, also add them to the list to remove …
  self.customSubviews = @[b];

  b.alpha = 0;

  [UIView animateWithDuration:0.4
                        delay:2.4
                      options:UIViewAnimationOptionCurveEaseIn
                   animations:^{
                     b.alpha = 1;
                   } completion:^(BOOL finished) {
                     ;
                   }];
}
Run Code Online (Sandbox Code Playgroud)

当你过渡时,你需要刻意将它们从场景中移除,除非它们完全有意义留在那里.

- (void)removeCustomSubviews {
  for (UIView *v in self.customSubviews) {
    [UIView animateWithDuration:0.2
                          delay:0
                        options:UIViewAnimationOptionCurveEaseIn
                     animations:^{
                       v.alpha = 0;
                   } completion:^(BOOL finished) {
                       [v removeFromSuperview];
                 }];
  }
}
Run Code Online (Sandbox Code Playgroud)

对于那些不熟悉以编程方式创建的人UIButton,这里有一个例子(你可以在这里做100件不同的事情)......

- (UIButton *)_createButton {
  UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
  [b setTitle:@"Continue" forState:UIControlStateNormal];
  [b setBackgroundImage:[UIImage imageNamed:@"GreenButton"] forState:UIControlStateNormal];
  [b setBackgroundImage:[UIImage imageNamed:@"GreenButtonSelected"] forState:UIControlStateHighlighted];
  b.titleLabel.adjustsFontSizeToFitWidth = YES;
  b.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue-Bold" size:36];
  b.frame = CGRectMake(self.size.width * .7, self.size.height * .2, self.size.width * .2, self.size.height * .1);
  [b addTarget:self action:@selector(continuePlay) forControlEvents:UIControlEventTouchUpInside];
  [self.view addSubview:b];

  return b;
}
Run Code Online (Sandbox Code Playgroud)

提醒:UIView原点位于左上角,SKScene原点位于左下角.