Thiết lập các nút trong SKScene


81

Tôi phát hiện ra rằng UIButtonsnó không hoạt động tốt vớiSKScene , Vì vậy, tôi đang cố gắng phân lớp con SKNodeđể tạo một nút vào SpriteKit.

Cách tôi muốn nó hoạt động là nếu tôi khởi tạo một nút trong SKScene và bật các sự kiện cảm ứng, thì nút đó sẽ gọi một phương thức trong của tôi SKScenekhi nó được nhấn.

Tôi đánh giá cao bất kỳ lời khuyên nào sẽ giúp tôi tìm ra giải pháp cho vấn đề này. Cảm ơn.


2
Tôi đang tìm kiếm thêm kinh nghiệm học tập cũng như giải pháp. Tôi nghĩ rằng giải pháp thích hợp sẽ là thiết lập SKScene làm đại biểu của nút, nhưng tôi không chắc về cách thực hiện điều này. Tôi có thể thiết lập SKScene như một biến thể hiện của nút và gọi một phương thức của nó không?
AlexHeuman 29/09/13

Bạn có thể thực hiện một số việc, ủy quyền hoặc sử dụng linh hoạt hơn NSNotification để bất kỳ nút nào cũng có thể phản hồi nó. Nếu bạn sử dụng ủy quyền, hãy đảm bảo đặt thuộc tính ủy quyền thành yếu.
LearnCocos2D

Tôi thấy mã này hữu ích cho việc tạo các nút bộ sprite. Nó mở rộng SKSpriteKitNode và cho phép bạn dễ dàng thêm văn bản vào các nút.
sager89

Câu trả lời:


102

bạn có thể sử dụng SKSpriteNode làm nút của mình và sau đó khi người dùng chạm vào, hãy kiểm tra xem đó có phải là nút được chạm hay không. Sử dụng thuộc tính tên của SKSpriteNode để xác định nút:

//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;
}

Thêm nút vào cảnh của bạn:

[self addChild: [self fireButtonNode]];

Xử lý chạm:

//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...
    }
}

8
Nếu bạn thêm iVar làm nút, bạn có thể loại bỏ kiểm tra tên và chỉ sử dụng nếu ([_fireNode chứaPoint: vị trí]) thực hiện điều tương tự chỉ khác.
DogCoffee

3
So sánh các chuỗi đó là một giải pháp bẩn. Mặc dù giải pháp của @Smick tốt hơn, nhưng không có cách nào khác rõ ràng hơn để đạt được điều này?
Esteban Bouza

hey, chúng tôi không thể thêm nút trong SpriteKit như SkLabelNode?
Omer Obaid

điều này có cho phép các sự kiện đa chạm không? ví dụ 2 nút bấm đồng thời? một trong số đó là nút chuyển động, nút khác là nút lửa.
duxfox--

52

Tôi đã tạo Lớp Nút của riêng mình mà tôi đang làm việc. 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

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);
}

Ví dụ: Để khởi tạo một nút, bạn viết các dòng sau:

    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];

Hơn nữa, bạn cần có phương thức 'buttonAction' trong lớp của mình. * Không bảo hành rằng lớp này hoạt động bình thường trong mọi trường hợp. Tôi vẫn còn khá mới đối với mục tiêu-c. *

Nếu bạn nghĩ việc phải làm điều này thật khó chịu và vô nghĩa, bạn có thể tắt kiểm tra trong cài đặt bản dựng bằng cách đặt 'Bật kiểm tra nghiêm ngặt đối objc_msgSend Calls'với No'


Cám ơn vì đã chia sẻ. Có một lý do tại sao bạn sử dụng objc_msgSendthay vì [target performSelector:selector]?
Jeffrey W.

2
À vâng, ARC yêu. Tôi quên mất cảnh báo đó: | Đây là một tác phẩm hay nếu bạn quan tâm stackoverflow.com/questions/11895287/…
Jeffrey W.

Đoạn mã trên rất tuyệt, nhưng tôi gặp lỗi khi cố gắng sử dụng - (void) changeToScene: (SKButtonNode *) sender {} làm @selector. Tôi muốn sử dụng một phương pháp duy nhất để chuyển đổi các cảnh bằng cách sử dụng sender.name nếu tôi có thể.
Beau Nouvelle

1
Cảm ơn vì đã chia sẻ điều này! Tôi đưa nó vào mã của mình. Chúng tôi sẽ xem nếu nó hoạt động. Một gợi ý: thay đổi tên của lớp từ SKButton thành một cái gì đó độc đáo hơn đối với bạn, ví dụ: GRFButton. Tại một số thời điểm, Apple có thể giới thiệu SKButton và bạn không muốn nhầm lẫn vùng tên và phá vỡ mã của bạn sau này.
James Paul Mason

1
@BeauYoung - Nó hoạt động khi bạn thêm selfvào cuối như vậy:objc_msgSend(_targetTouchUpInside, _actionTouchUpInside, self)
Genki

19

Dành cho những người viết trò chơi của họ bằng Swift! Tôi đã viết lại những phần thiết yếu của giải pháp Graf cho một lớp nhanh. Hy vọng nó giúp:

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)
        }
    }

}

5

Nếu muốn, bạn có thể sử dụng UIButton (hoặc bất kỳ UIView nào khác).

Khi một SKSceneđược tạo, nó chưa tồn tại trong một SKView. Bạn nên triển khai didMoveToView:trên SKScenelớp con của mình . Tại thời điểm này, bạn có quyền truy cập vào SKViewcảnh được đặt và bạn có thể thêm UIKitcác đối tượng vào đó. Vì sự xinh đẹp, tôi đã làm mờ chúng trong…

- (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) {
                     ;
                   }];
}

bạn sẽ cần phải cố tình xóa chúng khỏi cảnh khi bạn chuyển đi, trừ khi tất nhiên là hoàn toàn hợp lý khi chúng vẫn ở đó.

- (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];
                 }];
  }
}

Đối với những người không quen với việc tạo lập trình UIButton, đây là một ví dụ (bạn có thể làm 100 điều khác nhau ở đây)…

- (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;
}

Nhắc nhở: điểm UIViewgốc ở phía trên bên trái, điểm SKScenegốc ở phía dưới bên trái.


3

Tôi đã sử dụng lớp SKButton của Graf .

Tôi sử dụng SKButton để điều hướng cảnh. tức là trình bày một cảnh khác khi người dùng nhấn SKButton. Tôi nhận được EXC_BAD_ACCESSlỗi tại touchesEnded->[self setIsSelected:NO]. Điều này đặc biệt thường xuyên xảy ra trên iPad mới nhất với CPU nhanh.

Sau khi kiểm tra và khắc phục sự cố, tôi nhận ra rằng đối tượng SKButton đã được "phân bổ" khi setIsSelectedhàm đang được gọi. Điều này là do tôi sử dụng SKButton để điều hướng đến cảnh tiếp theo và điều này cũng có nghĩa là cảnh hiện tại có thể được phân bổ bất cứ lúc nào.

Tôi đã thực hiện một thay đổi nhỏ bằng cách đặt setIsSelected trong phần "else" như sau.

Hy vọng điều này sẽ giúp ích cho các nhà phát triển khác, những người cũng gặp lỗi tương tự.

(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);
    } else {
       [self setIsSelected:NO];
    }
    objc_msgSend(_targetTouchUp, _actionTouchUp);
}

Vui lòng định dạng bài đăng và mã nguồn của bạn, rất khó đọc theo cách này!
Uli Köhler

2

Đây là một phiên bản khác dựa trên mã Swift của Filip. Tôi vừa đơn giản hóa nó một chút và cho phép nó nhận các khối thay vì chỉ các bộ chọn:

import Foundation
import SpriteKit

enum FTButtonTarget {
    case aSelector(Selector, AnyObject)
    case aBlock(() -> Void)
}

class FTButtonNode: SKSpriteNode {

    var actionTouchUp : FTButtonTarget?
    var actionTouchUpInside : FTButtonTarget?
    var actionTouchDown : FTButtonTarget?

    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)

}

var disabledTexture: SKTexture?

func callTarget(buttonTarget:FTButtonTarget) {

    switch buttonTarget {
    case let .aSelector(selector, target):
        if target.respondsToSelector(selector) {
            UIApplication.sharedApplication().sendAction(selector, to: target, from: self, forEvent: nil)
        }
    case let .aBlock(block):
        block()
    }

}

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

    if (!isEnabled) {
        return
    }
    isSelected = true

    if let act = actionTouchDown {
        callTarget(act)
    }

}

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

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

     if (CGRectContainsPoint(frame, touchLocation) ) {

         if let act = actionTouchUpInside {
             callTarget(act)
         }
     }

     if let act = actionTouchUp {
         callTarget(act)
     }
 }
}

Sử dụng nó như thế này:

       aFTButton.actionTouchUpInside = FTButtonTarget.aBlock({ () -> Void in
        println("button touched")
    })

Hi vọng điêu nay co ich.


2

Chỉnh sửa: Tôi đã tạo một repo github cho SKButtonNode của mình mà tôi hy vọng sẽ luôn cập nhật và cập nhật khi phát triển nhanh chóng!

SKButtonNode


Rất tiếc, tôi chưa thể bình luận về việc Filip triển khai nhanh chóng SKButton trong Swift. Rất vui vì anh ấy đã làm được điều này bằng Swift! Nhưng, tôi nhận thấy rằng anh ấy không bao gồm chức năng thêm văn bản vào nút. Đây là một tính năng rất lớn đối với tôi, vì vậy bạn không cần phải tạo các nội dung riêng biệt cho mỗi nút đơn lẻ, mà chỉ tạo nền và thêm văn bản động.

Tôi đã thêm một chức năng đơn giản để thêm nhãn văn bản vào SKButton. Nó có thể không hoàn hảo - tôi mới làm quen với Swift cũng giống như những người khác! Hãy bình luận và giúp tôi cập nhật điều này tốt nhất có thể. Hy vọng các bạn thích!

 //Define label with the textures
 var defaultTexture: SKTexture
 var selectedTexture: SKTexture

 //New defining of label
 var label: SKLabelNode

 //Updated init() function:

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

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

    //New initialization of label
    self.label = SKLabelNode(fontNamed: "Helvetica");

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

    //Creating and adding a blank label, centered on the button
    self.label.verticalAlignmentMode = SKLabelVerticalAlignmentMode.Center;
    self.label.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Center;
    addChild(self.label)

    // 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)

  }




    /*
      New function for setting text. Calling function multiple times does 
      not create a ton of new labels, just updates existing label.
      You can set the title, font type and font size with this function
    */

    func setButtonLabel(#title: NSString, font: String, fontSize: CGFloat) {
        var title = title
        var font = font
        var fontSize = fontSize

        self.label.text = title
        self.label.fontSize = fontSize
        self.label.fontName = font        
     } 

Tạo mẫu nút:

    var buttonTexture = SKTexture(imageNamed: "Button");
    var buttonPressedTexture = SKTexture(imageNamed: "Button Pressed");
    var button = SKButton(normalTexture:buttonTexture, selectedTexture:buttonPressedTexture, disabledTexture:buttonPressedTexture);
    button.setButtonLabel(title: "Play",font: "Helvetica",fontSize: 40);
    button.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
    self.addChild(button);

Toàn bộ lớp được liệt kê bên dưới:

import Foundation
import SpriteKit


class SKButton: 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
var label: SKLabelNode


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
    self.label = SKLabelNode(fontNamed: "Helvetica");
    super.init(texture: defaultTexture, color: UIColor.whiteColor(), size: defaultTexture.size())
    userInteractionEnabled = true


    self.label.verticalAlignmentMode = SKLabelVerticalAlignmentMode.Center;
    self.label.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Center;
    addChild(self.label)

    // 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
    }

}


func setButtonLabel(#title: NSString, font: String, fontSize: CGFloat) {
    var title = title;
    var font = font;
    var fontSize = fontSize;

    self.label.text = title;
    self.label.fontSize = fontSize;
    self.label.fontName = font;

}

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)
    }
}

}


Đã cập nhật mã cho swift 2.1 tại đây: gist.github.com/richy486/5d408c442ac1c0c2891f
richy

..và tôi đã cập nhật lên Swift 3 tại đây: github.com/jglasse/SKButtonSwift3
jglasse 14/01/17

2

Thật là nhiều giải pháp tuyệt vời cho vấn đề này! Đối với những chiếc máy cuộn hạng nặng đã làm được điều này, bạn sẽ được thưởng thức! Tôi đã phân lớp SKScenevà cần MỘT lệnh gọi hàm để đăng ký BẤT KỲ nút nào để hoạt động như một UIButton! Đây là lớp học:

class KCScene : SKScene {
//------------------------------------------------------------------------------------
//This function is the only thing you use in this class!!!
func addButton(_ node:SKNode, withCompletionHandler handler: @escaping ()->()) {
    let data = ButtonData(button: node, actionToPerform: handler)
    eligibleButtons.append(data)
}
//------------------------------------------------------------------------------------
private struct ButtonData {
    //TODO: make a dictionary with ()->() as the value and SKNode as the key.
    //Then refactor this class!
    let button:SKNode
    let actionToPerform:()->()
}

private struct TouchTrackingData {
    //this will be in a dictionary with a UITouch object as the key
    let button:SKNode
    let originalButtonFrame:CGRect
}

private var eligibleButtons = [ButtonData]()
private var trackedTouches = [UITouch:TouchTrackingData]()
//------------------------------------------------------------------------------------
//TODO: make these functions customizable,
//with these implementations as defaults.
private func applyTouchedDownEffectToNode(node:SKNode) {
    node.alpha  = 0.5
    node.xScale = 0.8
    node.yScale = 0.8
}
private func applyTouchedUpEffectToNode(node:SKNode)   {
    node.alpha  = 1
    node.xScale = 1
    node.yScale = 1
}
//------------------------------------------------------------------------------------
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        let touchLocation = touch.location(in: self)
        let touchedNode = atPoint(touchLocation)

        for buttonData in eligibleButtons {
            if touchedNode === buttonData.button {
                //then this touch needs to be tracked, as it touched down on an eligible button!
                for (t, bD) in trackedTouches {
                    if bD.button === buttonData.button {
                        //then this button was already being tracked by a previous touch, disable the previous touch
                        trackedTouches[t] = nil
                    }
                }
                //start tracking this touch
                trackedTouches[touch] = TouchTrackingData(button: touchedNode, originalButtonFrame: touchedNode.frameInScene)
                applyTouchedDownEffectToNode(node: buttonData.button)
            }
        }
    }
}
//------------------------------------------------------------------------------------
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        if trackedTouches[touch] == nil {continue}
        //Now we know this touch is being tracked...
        let touchLocation = touch.location(in: self)
        //TODO: implement an isBeingTouched property on TouchTrackingData, so 
        //applyTouchedDown(Up)Effect doesn't have to be called EVERY move the touch makes
        if trackedTouches[touch]!.originalButtonFrame.contains(touchLocation) {
            //if this tracked touch is touching its button
            applyTouchedDownEffectToNode(node: trackedTouches[touch]!.button)
        } else {
            applyTouchedUpEffectToNode(node: trackedTouches[touch]!.button)
        }

    }
}
//------------------------------------------------------------------------------------
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        if trackedTouches[touch] == nil {continue}
        //Now we know this touch is being tracked...
        let touchLocation = touch.location(in: self)

        if trackedTouches[touch]!.originalButtonFrame.contains(touchLocation) {
            applyTouchedUpEffectToNode(node: trackedTouches[touch]!.button)

            for buttonData in eligibleButtons {
                if buttonData.button === trackedTouches[touch]!.button {
                    buttonData.actionToPerform()
                }
            }
        }
        trackedTouches[touch] = nil
    }
}
//------------------------------------------------------------------------------------
override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
    for touch in touches! {
        if trackedTouches[touch] == nil {continue}
        //Now we know this touch is being tracked...
        //Since this touch was cancelled, it will not be activating a button,
        //and it is not worth checking where the touch was
        //we will simply apply the touched up effect regardless and remove the touch from being tracked
        applyTouchedUpEffectToNode(node: trackedTouches[touch]!.button)
        trackedTouches[touch] = nil
    }
}
//------------------------------------------------------------------------------------

}

Nó bao gồm rất nhiều ý tưởng mà tôi chưa thực hiện và một số giải thích về mã, nhưng chỉ cần sao chép và dán nó vào dự án của bạn và bạn có thể sử dụng nó như hiện tại trong cảnh của riêng bạn. Đây là một ví dụ hoàn chỉnh sử dụng:

class GameScene : KCScene {
var playButton:SKSpriteNode
override init(size:CGSize) {
    playButton = SKSpriteNode(color: SKColor.red, size: CGSize(width:200,height:200))
    playButton.position.x = size.width/2
    playButton.position.y = size.height*0.75
    super.init(size: size)
}
override func didMove(to view: SKView) {
    addChild(playButton)
    addButton(playButton, withCompletionHandler: playButtonPushed)
}
func playButtonPushed() {
    let scene = GameScene(size: CGSize(width: 768, height: 1024))
    scene.scaleMode = .aspectFill
    view!.presentScene(scene)
}
}

Thông báo trước một, là nếu bạn thực hiện touchesBegan, touchesMoved, touchesEnded, và / hoặc touchesCancelledbạn PHẢI GỌI CHO SUPER! Hoặc nếu không nó sẽ không hoạt động.

Và hãy nhận ra rằng trong ví dụ đó, thực sự chỉ có MỘT DÒNG MÃ bạn cần đưa ra BẤT KỲ UIButtonđặc điểm NÀO ! Đó là dòng này:

addButton(playButton, withCompletionHandler: playButtonPushed)

Tôi luôn cởi mở cho những ý tưởng và đề xuất. Để lại trong phần bình luận và Happy Coding !!

Rất tiếc, tôi đã quên đề cập đến việc tôi sử dụng tiện ích mở rộng tiện lợi này. Bạn có thể lấy nó ra khỏi một phần mở rộng (vì có thể bạn không cần nó trong mọi nút) và đặt nó trong lớp của tôi. Tôi chỉ sử dụng nó ở một nơi.

extension SKNode {
var frameInScene:CGRect {
    if let scene = scene, let parent = parent {
        let rectOriginInScene = scene.convert(frame.origin, from: parent)
        return CGRect(origin: rectOriginInScene, size: frame.size)
    }
    return frame
}

}


Làm thế nào để điều này đảm bảo rằng hàm hoàn thành playButtonPushing có thể truy cập được? Hoặc tôi đặt hàm playButtonPushing ở đâu để đảm bảo nó có thể truy cập được bằng phiên bản KScene, mà tôi giả sử là nút?
Nhầm lẫn

@Confused Bạn sẽ làm cho cảnh riêng của bạn một lớp con của KCScene thay vì SKScene: class ConfusedScene : KCScene {. Sau đó, bên trong ConfusedScenechỉ thực hiện một chức năng để làm những gì bạn muốn khi nút được nhấn. Tôi đã làm điều này: func playButtonPushed() { /*do whatever happens when play button is pushed*/}. Tại sao công việc này lại quá liên quan để giải thích ở đây, nhưng bạn có thể đọc về việc đóng cửa tại đây .
mogelbuster

1

Giải pháp của tôi để giải quyết vấn đề này được viết hoàn toàn bằng SWIFT, sử dụng các bao đóng.

Nó khá đơn giản để sử dụng! https://github.com/txaidw/TWControls

class Test {
    var testProperty = "Default String"

    init() {
        let control = TWButton(normalColor: SKColor.blueColor(), highlightedColor: SKColor.redColor(), size: CGSize(width: 160, height: 80))
        control.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
        control.position.allStatesLabelText = "PLAY"
        control.addClosureFor(.TouchUpInside, target: self, closure: { (scene, sender) -> () in
            scene.testProperty = "Changed Property"
        })
    }

    deinit { println("Class Released..") }
}

0

Tôi đã tạo một lớp để sử dụng SKSpriteNode làm nút cách đây khá lâu. Bạn có thể tìm thấy nó trên GitHub tại đây.

AGSpriteButton

Việc triển khai nó dựa trên UIButton, vì vậy nếu bạn đã quen với iOS, bạn sẽ thấy dễ dàng làm việc với nó.

Nó cũng có thể được gán một khối hoặc một SKAction để được thực thi khi nhấn nút.

Nó cũng bao gồm một phương pháp để thiết lập một nhãn.

Một nút thường sẽ được khai báo như vậy:

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];

Và đó là nó. Bạn tốt để đi.


Có lý do gì chúng ta không thể sử dụng SKColor thay vì UIColor? Nếu chúng tôi sử dụng UIColor, chúng tôi đang mắc kẹt trên iOS.
Maury Markowitz

Bạn có thể dễ dàng sử dụng SKColor thay vì UIColor
ZeMoon

0

Và vì tất cả chúng ta đều không nhắm mục tiêu vào iOS, đây là phần bắt đầu của một số đoạn mã tôi đã viết để xử lý tương tác chuột trên Mac.

Câu hỏi dành cho các chuyên gia: MacOS có cung cấp các sự kiện cảm ứng khi sử dụng bàn di chuột không? Hay chúng được gửi vào SpriteKit dưới dạng sự kiện chuột?

Một câu hỏi khác dành cho các chuyên gia, lớp này có nên được gọi đúng là SKButton Node không?

Dù sao, hãy thử cái này ...

#if os(iOS)
    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)
        }
    }
#else

    // FIXME: needs support for mouse enter and leave, turning on and off selection

    override func mouseDown(event: NSEvent) {
        if (!isEnabled) { return }

        if (targetTouchDown != nil && targetTouchDown!.respondsToSelector(actionTouchDown!)) {
            NSApplication.sharedApplication().sendAction(actionTouchDown!, to: targetTouchDown, from: self)
        }
    }

    override func mouseUp(event: NSEvent) {
        if (!isEnabled) { return }

        if (targetTouchUpInside != nil && targetTouchUpInside!.respondsToSelector(actionTouchUpInside!)) {
            let touchLocation = event.locationInNode(parent)

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

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

Theo như tôi biết Spritekit dành cho OSX chỉ quan sát những thứ chuột: / Và vâng, nó có lẽ nên có từ Node ở cuối. Giống như SKLabelNode.
CodyMace

0

Tôi đã phân lớp lớp con SKScenevà đạt được vấn đề giải các nút bấm trong dự án này.

https://github.com/Prasad9/SpriteKitButton

Trong đó, tất cả các nút cần biết khi khai thác phải được đặt tên.

Ngoài việc phát hiện chạm vào nút, dự án này cũng cho phép bạn phát hiện xem thao tác chạm vào một nút cụ thể đã bắt đầu hay đã kết thúc.

Để thực hiện thao tác nhấn, hãy ghi đè phương thức sau trong tệp Cảnh của bạn.

- (void)touchUpInsideOnNodeName:(NSString *)nodeName atPoint:(CGPoint)touchPoint {
    // Your code here.
 }

Để biết thời điểm bắt đầu chạm vào một cơ thể cụ thể, hãy ghi đè phương thức sau trong tệp Cảnh của bạn.

 - (void)touchBeginOnNodeName:(NSString *)nodeName {
    // Your code here.
 }

Để biết kết thúc liên lạc trên một cơ thể cụ thể, hãy ghi đè phương thức sau trong tệp Cảnh của bạn.

 - (void)touchEndedOnNodeName:(NSString *)nodeName {
    // Your code here.
 }

0

Giải pháp của Graf có một vấn đề. Ví dụ:

self.pauseButton = [[AGSKBButtonNode alloc] initWithImageNamed:@"ButtonPause"];
self.pauseButton.position = CGPointMake(0, 0);
[self.pauseButton setTouchUpInsideTarget:self action:@selector(pauseButtonPressed)];

[_hudLayer addChild:_pauseButton];

_hudLayer là SKNode, thuộc tính của cảnh của tôi. Vì vậy, bạn sẽ nhận được ngoại lệ, vì phương thức touchEnded trong SKButton. Nó sẽ gọi [SKSpriteNode pauseButtonPressed], không phải với cảnh.

Giải pháp để thay đổi self.parent thành target target:

- (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){
        [_targetTouchUpInside performSelectorOnMainThread:_actionTouchUpInside withObject:_targetTouchUpInside waitUntilDone:YES];
    }
}
[self setIsSelected:NO];
if (_actionTouchUp){
    [_targetTouchUp performSelectorOnMainThread:_actionTouchUp withObject:_targetTouchUp waitUntilDone:YES];
}}

0

Trên thực tế, điều này hoạt động tốt trên Swift 2.2 trên Xcode 7.3

Tôi thích FTButtonNode ( richy486 / FTButtonNode.swift ) nhưng không thể chỉ định kích thước khác (thay vì sau đó là kích thước kết cấu mặc định) trực tiếp trong quá trình khởi tạo vì vậy tôi đã thêm phương thức đơn giản này:

Bạn phải sao chép nó theo phương thức init tùy chỉnh chính thức (tương tự như thế này) để bạn có một phương thức init khác để sử dụng:

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

        self.defaultTexture = defaultTexture
        self.selectedTexture = selectedTexture
        self.disabledTexture = disabledTexture
        self.label = SKLabelNode(fontNamed: "Helvetica");

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

        //Creating and adding a blank label, centered on the button
        self.label.verticalAlignmentMode = SKLabelVerticalAlignmentMode.Center;
        self.label.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Center;
        addChild(self.label)

        // 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: UIColor.clearColor(), size: size)
        bugFixLayerNode.position = self.position
        addChild(bugFixLayerNode)

    }

Một điều quan trọng khác là "thời gian lựa chọn", tôi đã thấy rằng trong các thiết bị mới (iPhone 6) đôi khi thời gian giữa touchesBegantouchesEndedquá nhanh và bạn không thấy những thay đổi giữa defaultTextureselectedTexture.

Với chức năng này:

func dispatchDelay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

bạn có thể viết lại touchesEndedphương thức để hiển thị chính xác biến thể kết cấu:

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if (!isEnabled) {
            return
        }

        dispatchDelay(0.2) {
            self.isSelected = false
        }

        if (targetTouchUpInside != nil && targetTouchUpInside!.respondsToSelector(actionTouchUpInside!)) {
            let touch: AnyObject! = touches.first
            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)
        }
}


0

Thật không may, SpriteKit không có nút nút, tôi không biết tại sao, vì nó là điều khiển rất hữu ích. Vì vậy, tôi quyết định tạo của riêng tôi và chia sẻ qua CocoaPods, hãy sử dụng nó OOButtonNode . Các nút có thể sử dụng văn bản / nền hoặc hình ảnh, được viết bằng Swift 4.


0

Đây là một nút đơn giản được viết bằng Swift hiện đại (4.1.2)

Đặc trưng

  • nó chấp nhận 2 tên hình ảnh, 1 cho trạng thái mặc định và một cho trạng thái hoạt động
  • nhà phát triển có thể đặt touchBeganCallbacktouchEndedCallbackđóng để thêm hành vi tùy chỉnh

import SpriteKit

class SpriteKitButton: SKSpriteNode {

    private let textureDefault: SKTexture
    private let textureActive: SKTexture

    init(defaultImageNamed: String, activeImageNamed:String) {
        textureDefault = SKTexture(imageNamed: defaultImageNamed)
        textureActive = SKTexture(imageNamed: activeImageNamed)
        super.init(texture: textureDefault, color: .clear, size: textureDefault.size())
        self.isUserInteractionEnabled = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("Not implemented")
    }

    var touchBeganCallback: (() -> Void)?
    var touchEndedCallback: (() -> Void)?

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.texture = textureActive
        touchBeganCallback?()
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.texture = textureDefault
        touchEndedCallback?()
    }
}

Làm thế nào để sử dụng nó

class GameScene: SKScene {

    override func didMove(to view: SKView) {

        // 1. create the button
        let button = SpriteKitButton(defaultImageNamed: "default", activeImageNamed: "active")

        // 2. write what should happen when the button is tapped
        button.touchBeganCallback = {
            print("Touch began")
        }

        // 3. write what should happen when the button is released
        button.touchEndedCallback = {
            print("Touch ended")
        }

        // 4. add the button to the scene
        addChild(button)

    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.