SKScene में बटन सेट करना


81

मुझे पता है कि मैं UIButtonsबहुत अच्छी तरह से काम नहीं कर SKSceneरहा हूं, इसलिए मैं SKNodeएक बटन बनाने के लिए उपवर्ग का प्रयास कर रहा हूं SpriteKit

मेरे काम करने का तरीका यह है कि अगर मैं बटन को इनिशियलाइज़ करूँ SKSceneऔर टच इवेंट्स को इनेबल करूँ , तो बटन मेरे SKSceneदबाने पर एक मेथड को कॉल करेगा ।

मैं किसी भी सलाह की सराहना करता हूं जो मुझे इस समस्या का समाधान खोजने के लिए प्रेरित करेगा। धन्यवाद।


2
मैं एक सीखने के अनुभव के साथ-साथ समाधान के लिए भी देख रहा हूं। मुझे लगता है कि बटन के एक प्रतिनिधि के रूप में SKScene स्थापित करने के लिए उचित समाधान होगा, लेकिन मैं यह करने के लिए अनिश्चित हूं कि यह कैसे करना है। क्या मैं बटन के उदाहरण चर के रूप में SKScene सेट कर सकता हूं और इसकी एक विधि कह सकता हूं?
अलेक्सहेमैन

आप कई चीजें कर सकते हैं, प्रतिनिधिमंडल या अधिक लचीले ढंग से NSNotification का उपयोग कर सकते हैं ताकि कोई भी नोड इसका जवाब दे सके। यदि आप प्रतिनिधि का उपयोग करते हैं तो प्रतिनिधि संपत्ति को कमजोर करने के लिए सेट करना सुनिश्चित करें।
LearnCocos2D

मैंने पाया है कि यह कोड स्प्राइट किट बटन बनाने में मददगार है। यह SKSpriteKitNode का विस्तार करता है और आपको बटन पर आसानी से पाठ जोड़ने की अनुमति देता है।
1889 में sager89

जवाबों:


102

आप अपने बटन के रूप में SKSpriteNode का उपयोग कर सकते हैं, और फिर जब उपयोगकर्ता स्पर्श करता है, तो जांचें कि क्या नोड स्पर्श किया गया था। नोड की पहचान करने के लिए SKSpriteNode की नाम संपत्ति का उपयोग करें:

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

अपने दृश्य में नोड जोड़ें:

[self addChild: [self fireButtonNode]];

हैंडल छूता है:

//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
यदि आप एक iVar को बटन के रूप में जोड़ते हैं, तो आप नाम की जाँच को हटा सकते हैं और यदि ([_fireNode:
डॉग कॉफ़ी

3
तार की तुलना यह एक गंदा समाधान है। हालांकि @Smick का समाधान बेहतर है, क्या इसे प्राप्त करने के लिए कोई अन्य क्लीनर तरीका नहीं है?
एस्टेबन बुजा

हे हम SkiteabelNode की तरह SpriteKit में बटन नहीं जोड़ सकते हैं?
ओमर ओबैद

क्या यह बहु स्पर्श घटनाओं की अनुमति देता है? उदाहरण के लिए 2 बटन एक साथ क्लिक किए गए? उनमें से एक एक आंदोलन बटन, दूसरा एक आग बटन है।
duxfox-- 18

52

मैंने अपना स्वयं का बटन-वर्ग बनाया है, जिसके साथ मैं काम कर रहा हूं। 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);
}

एक उदाहरण: एक बटन को इनिशियलाइज़ करने के लिए, आप निम्नलिखित पंक्तियाँ लिखते हैं:

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

इसके अलावा आपको अपनी कक्षा में 'बटनएक्शन' विधि की आवश्यकता है। * कोई वारंटी नहीं कि यह वर्ग हर मामले में सही काम कर रहा है। मैं अभी भी ऑब्जेक्टिव-सी के लिए काफी नया हूं। *

आप इस कष्टप्रद है क्या करने वाले सोचते हैं और व्यर्थ आप सेटिंग से निर्माण सेटिंग में जांच को निष्क्रिय कर सकते हैं 'की सख्त जांच सक्षम objc_msgSend Calls'करने के लिए' No'


साझा करने के लिए धन्यवाद। क्या कोई कारण है जिसके objc_msgSendबजाय आप इसका उपयोग करते हैं [target performSelector:selector]?
जेफरी डब्लू।

2
आह हां, डार एआरसी। मैं उस चेतावनी के बारे में भूल गया: | यदि आप रुचि रखते हैं तो एक अच्छा काम यहाँ है, आप रुचि रखते हैं stackoverflow.com/questions/11895287/…
जेफरी डब्ल्यू।

उपरोक्त कोड बहुत अच्छा है, लेकिन मैं त्रुटियों का उपयोग करने की कोशिश कर रहा हूं - (शून्य) changeToScene: (SKButtonNode *) प्रेषक {} @selector के रूप में। अगर मैं कर सकता था तो मैं प्रेषक.नाम का उपयोग करके दृश्यों को स्विच करने के लिए एक ही विधि का उपयोग करूंगा।
ब्यू नौवेल्ले

1
इसे साझा करने के लिए धन्यवाद! मैं इसे अपने कोड में शामिल कर रहा हूं। अगर यह काम करता है तो हम देखेंगे। एक सुझाव: SKButton से वर्ग का नाम बदलकर आपके लिए कुछ और अनोखा उदाहरण के लिए, GRFButton। कुछ बिंदु पर, Apple एक SKButton पेश कर सकता है और आप नाम स्थान को भ्रमित नहीं करना चाहते हैं और बाद में अपना कोड तोड़ सकते हैं।
जेम्स पॉल मेसन

1
@ ब्यूयॉन्ग - यह तब काम करता है जब आप selfअंत में इस तरह जोड़ते हैं :objc_msgSend(_targetTouchUpInside, _actionTouchUpInside, self)
जिनी

19

स्विफ्ट में अपने गेम लिखने वाले लोगों के लिए! मैंने ग्रेफ के समाधान के आवश्यक भागों को एक तेज वर्ग में फिर से लिखा है। आशा है कि इससे सहायता मिलेगी:

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

यदि आप चाहें, तो आप 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) {
                     ;
                   }];
}

जब तक आप दूर नहीं जाते, तब तक आपको जानबूझकर उन्हें उस दृश्य से दूर करने की आवश्यकता होगी, जब तक कि यह उनके लिए वहाँ बने रहने के लिए पूरी तरह समझ में नहीं आता।

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

प्रोग्राम बनाने के साथ अपरिचित लोगों के लिए 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;
}

अनुस्मारक: UIViewमूल ऊपरी बाएँ में है, SKSceneमूल निचले बाएँ में है।


3

मैंने ग्रेफ द्वारा SKButton वर्ग का उपयोग किया है ।

मैं सीन नेविगेशन करने के लिए SKButton का उपयोग करता हूं। उपयोगकर्ता द्वारा SKButton को दबाने पर दूसरा दृश्य प्रस्तुत करता है। मुझे इसमें EXC_BAD_ACCESSत्रुटि मिलती है touchesEnded->[self setIsSelected:NO]। यह तेजी से सीपीयू के साथ नवीनतम iPad पर विशेष रूप से अक्सर होता है।

जाँच और समस्या निवारण के बाद, मुझे एहसास हुआ कि फ़ंक्शन को कॉल किए जाने पर SKButton ऑब्जेक्ट पहले से ही "डीललॉक्ड" है setIsSelected। ऐसा इसलिए है क्योंकि मैं SKButton का उपयोग अगले दृश्य पर जाने के लिए करता हूं और इसका मतलब यह भी है कि वर्तमान दृश्य को किसी भी समय निपटाया जा सकता है।

मैंने निम्न के रूप में "और" भाग में सेटआईलेक्टेड डालकर एक छोटा सा परिवर्तन किया।

आशा है कि यह अन्य डेवलपर के लिए मदद करता है जो समान त्रुटि भी देखते हैं।

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

कृपया अपने पोस्ट और सोर्सकोड को प्रारूपित करें, इस तरह से पढ़ना बहुत कठिन है!
उली कोहलर

2

यहाँ फ़िलिप के स्विफ्ट कोड पर आधारित एक और संस्करण है। मैंने इसे थोड़ा सरल किया है और इसे केवल चयनकर्ताओं के बजाय ब्लॉक लेने की अनुमति दी है:

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

इसे इस तरह उपयोग करें:

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

उम्मीद है की यह मदद करेगा।


2

संपादित करें: मैंने अपने SKButtonNode के लिए एक गितुब रेपो बनाया है, जिसे मैं उम्मीद करता हूं कि यह चालू रहेगा और तेजी से विकसित होगा!

SKButtonNode


दुर्भाग्य से मैं स्विफ्ट में SKButton के फिलिप के तेजी से कार्यान्वयन पर अभी तक टिप्पणी नहीं कर सकता। सुपर खुश है कि उसने स्विफ्ट में यह बनाया! लेकिन, मैंने देखा कि उसने बटन में टेक्स्ट जोड़ने के लिए कोई फ़ंक्शन शामिल नहीं किया था। यह मेरे लिए बहुत बड़ी विशेषता है, ताकि आपको हर एक बटन के लिए अलग-अलग संपत्ति न बनानी पड़े, बल्कि सिर्फ पृष्ठभूमि और गतिशील पाठ जोड़ना पड़े।

मैंने SKButton में एक टेक्स्ट लेबल जोड़ने के लिए एक साधारण फ़ंक्शन जोड़ा। यह सही नहीं है - मैं हर किसी की तरह स्विफ्ट के लिए नया हूँ! टिप्पणी करने के लिए स्वतंत्र महसूस करें और मुझे यह सबसे अच्छा होने के लिए अद्यतन करने में मदद करें। आशा है कि आप लोग पसंद करेंगे!

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

बटन का नमूना निर्माण:

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

नीचे सूचीबद्ध पूरी कक्षा:

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

}


स्विफ्ट 2.1 का कोड यहाँ अपडेट करें: gist.github.com/richy486/5d408c442ac1c0c2891f
अमीर

..और मैंने यहां स्विफ्ट 3 को अपडेट किया: github.com/jglasse/SKButtonSwift3
jglasse

2

इस समस्या का बहुत बड़ा समाधान क्या है! कट्टर स्क्रॉलर के लिए जो इसे नीचे तक बनाते हैं, आप एक इलाज के लिए हैं! मैंने उप-वर्ग किया है SKScene, और किसी भी नोड को रजिस्टर करने के लिए किसी भी नोड को पंजीकृत करने के लिए एक फ़ंक्शन कॉल लेता है UIButton! यहाँ वर्ग है:

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

}

इसमें बहुत सारे विचार शामिल हैं जिन्हें मैंने अभी तक लागू नहीं किया है और कोड के कुछ स्पष्टीकरण हैं, लेकिन बस इसे अपनी परियोजना में कॉपी और पेस्ट करें, और आप इसे अपने स्वयं के दृश्य में उपयोग कर सकते हैं। यहाँ एक पूर्ण उदाहरण उपयोग है:

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

एक चेतावनी यह है कि आप को लागू करता है, तो touchesBegan, touchesMoved, touchesEnded, और / याtouchesCancelled आप सुपर कॉल करना होगा! वरना काम नहीं होगा।

और कृपया महसूस करें कि उस उदाहरण में, वास्तव में केवल एक लाइन का कोड है जिसे आपको किसी भी नोड UIButtonविशेषताओं को देने की आवश्यकता है ! यह लाइन थी:

addButton(playButton, withCompletionHandler: playButtonPushed)

मैं हमेशा विचारों और सुझावों के लिए खुला हूं। टिप्पणियों में उन्हें छोड़ दो और खुश कोडिंग !!

ओह, मैं इस निफ्टी एक्सटेंशन का उपयोग करने का उल्लेख करना भूल गया। आप इसे एक विस्तार से बाहर निकाल सकते हैं (जैसा कि आपको शायद हर नोड में इसकी आवश्यकता नहीं है) और इसे मेरी कक्षा में बंद कर दें। मैं केवल एक ही स्थान पर इसका उपयोग करता हूं।

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
}

}


यह कैसे सुनिश्चित करता है कि PlayButtonPushed पूरा होने का कार्य सुलभ है? या जहाँ मैं यह सुनिश्चित करने के लिए प्लेबुटनपुश्ड फंक्शन डालूं कि यह केएसकेने उदाहरण द्वारा उपलब्ध है, जो मुझे लगता है कि बटन है?
कन्फ्यूज्ड

@Confused आप अपने सीन को SKScene के बजाय KCScene का उपवर्ग बना देंगे class ConfusedScene : KCScene {:। फिर अंदर ConfusedSceneसिर्फ एक फंक्शन करना है जो आप चाहते हैं कि बटन दबाया जाए। मैंने ऐसा किया func playButtonPushed() { /*do whatever happens when play button is pushed*/}:। यह कार्य यहाँ समझाने के लिए बहुत अधिक शामिल है, लेकिन आप यहाँ क्लोजर के बारे में पढ़ सकते हैं ।
मोगेलबस्टर

1

क्लोजर का उपयोग करके स्विफ्ट में पूरी तरह से लिखी गई इस समस्या को हल करने के लिए मेरा समाधान।

इसका उपयोग करने के लिए बहुत आसान है! 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

मैंने काफी समय पहले SKSpriteNode को एक बटन के रूप में उपयोग करने के लिए एक वर्ग बनाया था। आप इसे GitHub पर यहां पा सकते हैं।

AGSpriteButton

यह कार्यान्वयन UIButton पर आधारित है, इसलिए यदि आप पहले से ही iOS से परिचित हैं, तो आपको इसके साथ काम करना आसान लगता है।

बटन दबाए जाने पर इसे निष्पादित करने के लिए एक ब्लॉक या SKAction भी सौंपा जा सकता है।

इसमें एक लेबल सेट करने की विधि भी शामिल है।

एक बटन आमतौर पर इस तरह घोषित किया जाएगा:

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

और बस। आप जाने के लिए अच्छे हैं।


क्या कोई कारण है कि हम UIColor के बजाय SKColor का उपयोग नहीं कर सकते हैं? यदि हम UIColor का उपयोग करते हैं तो हम iOS पर अटक जाते हैं।
मारी मार्कोविट्ज़

आप UIColor के बजाय SKColor का आसानी से उपयोग कर सकते हैं
ZeMoon

0

और जब से हम सभी iOS को लक्षित नहीं कर रहे हैं, यहाँ कुछ कोड की शुरुआत मैंने मैक पर माउस इंटरैक्शन को संभालने के लिए लिखी है।

गुरुओं के लिए प्रश्न: क्या ट्रैकपैड का उपयोग करते समय मैकओएस स्पर्श की घटनाओं की पेशकश करता है? या ये माउस इवेंट के रूप में स्प्राइटिट में भेजे जाते हैं?

गुरुओं के लिए एक और सवाल, क्या इस वर्ग को ठीक से SKButton Node नहीं कहा जाना चाहिए ?

वैसे भी, यह कोशिश करो ...

#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

जहां तक ​​मुझे पता है कि OSX के लिए स्प्राइटिटक केवल माउस सामान को देखता है: / और हाँ, यह अंत में शब्द नोड होना चाहिए। SKLabelNode की तरह।
कोडीएम

0

मैंने SKSceneवर्ग को उप- वर्ग किया है और इस परियोजना में बटन नल को हल करने की समस्या को प्राप्त किया है।

https://github.com/Prasad9/SpriteKitButton

इसमें, सभी नोड्स जो टैप किए जाने के लिए आवश्यक हैं, उन्हें नाम दिया जाना चाहिए।

बटन टैप का पता लगाने के अलावा, यह परियोजना आपको यह पता लगाने में भी सक्षम बनाती है कि किसी विशेष नोड पर स्पर्श शुरू हुआ है या समाप्त हो गया है।

टैप एक्शन प्राप्त करने के लिए, अपनी दृश्य फ़ाइल में निम्न विधि को ओवरराइड करें।

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

किसी विशेष निकाय पर स्पर्श की शुरुआत जानने के लिए, अपनी दृश्य फ़ाइल में निम्न विधि को ओवरराइड करें।

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

किसी विशेष निकाय पर स्पर्श का अंत जानने के लिए, अपनी दृश्य फ़ाइल में निम्न विधि को ओवरराइड करें।

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

0

Graf`s समाधान एक मुद्दा है। उदाहरण के लिए:

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

[_hudLayer addChild:_pauseButton];

_hudLayer एक SKNode है, जो मेरे दृश्य की एक संपत्ति है। इसलिए, आप अपवाद प्राप्त करेंगे, क्योंकि विधि के कारण SKButton में स्पर्श किया गया है। इसे [SKSpriteNode pauseButtonPressed] कहा जाएगा, न कि दृश्य के साथ।

लक्ष्य को छूने के लिए स्वयं को बदलने का उपाय:

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

वास्तव में यह Xcode 7.3 पर स्विफ्ट 2.2 पर अच्छा काम करता है

मुझे FTButtonNode ( richy486 / FTButtonNode.swift पसंद है ) पसंद है, लेकिन इसे प्रारंभ करने के दौरान सीधे दूसरे आकार (बल्कि डिफ़ॉल्ट बनावट आकार) को निर्दिष्ट करना संभव नहीं है, इसलिए मैंने यह सरल विधि जोड़ी है:

आपको यह देखना होगा कि आधिकारिक कस्टम इनिट विधि (इसके समान) के तहत आपके पास उपयोग करने के लिए एक और init तरीका है:

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)

    }

एक अन्य महत्वपूर्ण बात "चयन समय" है, मैंने देखा है कि नए उपकरणों में (iPhone 6) के बीच किसी समय समय touchesBeganऔर touchesEndedबहुत तेजी से है और आप के बीच परिवर्तन देख न defaultTextureऔर selectedTexture

इस समारोह के साथ:

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

आप touchesEndedबनावट भिन्नता को सही ढंग से दिखाने के लिए विधि को फिर से लिख सकते हैं :

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

मैं उपरोक्त किसी भी विकल्प के बारे में आश्वस्त नहीं था, इसलिए नवीनतम Swift4 के आधार पर मैंने अपना समाधान बनाया ।


0

दुर्भाग्य से SpriteKit में बटन नोड नहीं है, मुझे नहीं पता कि क्यों, क्योंकि यह बहुत उपयोगी नियंत्रण है। इसलिए मैंने अपना खुद का बनाने और कोकोपोड्स के माध्यम से साझा करने का फैसला किया, कृपया इसे OOButtonNode का उपयोग करें । बटन पाठ / पृष्ठभूमि या छवियों का उपयोग कर सकते हैं, जो स्विफ्ट 4 में लिखे गए हैं।


0

यहाँ आधुनिक स्विफ्ट (4.1.2) के साथ एक साधारण बटन लिखा गया है

विशेषताएं

  • यह 2 छवि नामों को स्वीकार करता है, 1 डिफ़ॉल्ट राज्य के लिए और एक सक्रिय राज्य के लिए
  • डेवलपर कस्टम व्यवहार को जोड़ने के लिए सेट touchBeganCallbackऔर touchEndedCallbackबंद कर सकता है

कोड

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

इसका इस्तेमाल कैसे करें

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)

    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.