Giving Properties of a Uibutton to a Skspritenode in Spritekit

Giving properties of a UIButton to a SKSpriteNode in SpriteKit

I have always achieved this by adding code to the touches began, and touches ended method. Inside of these methods I simply set the sprites color to black, and then change its color blend factor. Let me know if this works for you!

  //This will hold the object that gets darkened
var target = SKSpriteNode()
//This will keep track if an object is darkened
var have = false

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
var first = touches.first as! UITouch
var location:CGPoint = first.locationInNode(self)
touchP = location
mouse.position = touchP
var node:SKNode = self.nodeAtPoint(location)
if let button = node as? SKSpriteNode
{
target = button
have = true
}
else
{
have = false
}

if (have == true)
{
target.color = UIColor.blackColor()
target.colorBlendFactor = 0.2

}
}

override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
if (havet == true)
{
target.color = UIColor.blackColor()
target.colorBlendFactor = 0
target = SKSpriteNode()
have = false

}

}

Moving A UIButton from Sprite-Kit scene

Give your Scene a reference to its parent view controller in MyScene.h:

#import <SpriteKit/SpriteKit.h>
#import "MyViewController.h"

@interface MyScene : SKScene

@property (nonatomic,weak) MyViewController *viewController;

@end

Then in MyViewController.m when you create the scene:

// Create and configure the scene.
MyScene * scene = [MyScene sceneWithSize:skView.bounds.size];

//assign self to the view controller property
scene.viewController = self;

// Present the scene.
[skView presentScene:scene];

and create method:

-(void)moveLeaderButton{
_leaderButton.center = CGPointMake(-100, -100);
}

also put it in MyViewController.h:

-(void)moveLeaderButton;

Then in MyScene.m you can call method:

[_viewController moveLeaderButton];

Correct way to create button in Sprite Kit?

I found this online a while ago, courtesy of a member who goes by the name of Graf, this works nicely for my problems.

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

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

@property (nonatomic) BOOL isEnabled;
@property (nonatomic) BOOL isSelected;
@property (nonatomic, readonly, strong) SKLabelNode *title;
@property (nonatomic, readwrite, strong) SKTexture *normalTexture;
@property (nonatomic, readwrite, strong) SKTexture *selectedTexture;
@property (nonatomic, readwrite, strong) SKTexture *disabledTexture;

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

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

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

@end

And the implementation

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

@implementation SKBButtonNode

#pragma mark Texture Initializer

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

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

/**
* This is the designated Initializer
*/
- (instancetype)initWithTextureNormal:(SKTexture *)normal selected:(SKTexture *)selected disabled:(SKTexture *)disabled {
self = [super initWithTexture:normal color:[UIColor whiteColor] size:normal.size];
if (self) {
[self setNormalTexture:normal];
[self setSelectedTexture:selected];
[self setDisabledTexture:disabled];
[self setIsEnabled:YES];
[self setIsSelected:NO];

_title = [SKLabelNode labelNodeWithFontNamed:@"Arial"];
[_title setVerticalAlignmentMode:SKLabelVerticalAlignmentModeCenter];
[_title setHorizontalAlignmentMode:SKLabelHorizontalAlignmentModeCenter];

[self addChild:_title];
[self setUserInteractionEnabled:YES];
}
return self;
}

#pragma mark Image Initializer

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

- (instancetype)initWithImageNamedNormal:(NSString *)normal selected:(NSString *)selected disabled:(NSString *)disabled {
SKTexture *textureNormal = nil;
if (normal) {
textureNormal = [SKTexture textureWithImageNamed:normal];
}

SKTexture *textureSelected = nil;
if (selected) {
textureSelected = [SKTexture textureWithImageNamed:selected];
}

SKTexture *textureDisabled = nil;
if (disabled) {
textureDisabled = [SKTexture textureWithImageNamed:disabled];
}

return [self initWithTextureNormal:textureNormal selected:textureSelected disabled:textureDisabled];
}

#pragma -
#pragma mark Setting Target-Action pairs

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

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

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

#pragma -
#pragma mark Setter overrides

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

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

#pragma -
#pragma mark Touch Handling

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

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

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

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

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

How to make Buttons with effect in SpriteKit and Swift?

If you want the button to become small when you press on it and big when you let go, you can implement code in your Touches Began and Touches Ended (and even Touches Moved if you want):
Under Touches Began:

if button.containsPoint(location){
let scale = SKAction.scaleTo(0.7, duration: 0)
button.runAction(scale)
}

Under Touches Ended:

if button.containsPoint(location){
let scale = SKAction.scaleTo(1, duration: 0)
button.runAction(scale)
}

Under Touches Moved:

if !button.containsPoint(location){
let scale = SKAction.scaleTo(1, duration: 0)
button.runAction(scale)
}

Btw, this is untested code. Please let me know how it goes. I've posted a question like this with more code here: Giving properties of a UIButton to a SKSpriteNode in SpriteKit.

Good Luck!

Setting up buttons in SKScene

you could use a SKSpriteNode as your button, and then when the user touches, check if that was the node touched. Use the SKSpriteNode's name property to identify the node:

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

Add node to your scene:

[self addChild: [self fireButtonNode]];

Handle touches:

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

Creation of buttons for SpriteKit

I totally agree with @Whirlwind here, create a separate class for your button that handles the work for you. I do not think the advice from @ElTomato is the right advice. If you create one image with buttons included you have no flexibility on placement, size, look and button state for those buttons.

Here is a very simple button class that is a subclass of SKSpriteNode. It uses delegation to send information back to the parent (such as which button has been pushed), and gives you a simple state change (gets smaller when you click it, back to normal size when released)

import Foundation
import SpriteKit

protocol ButtonDelegate: class {
func buttonClicked(sender: Button)
}

class Button: SKSpriteNode {

//weak so that you don't create a strong circular reference with the parent
weak var delegate: ButtonDelegate!

override init(texture: SKTexture?, color: SKColor, size: CGSize) {

super.init(texture: texture, color: color, size: size)

setup()
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)

setup()
}

func setup() {
isUserInteractionEnabled = true
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
setScale(0.9)
self.delegate.buttonClicked(sender: self)
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
setScale(1.0)
}
}

This button can be instantiated 2 ways. You can create an instance of it in the Scene editor, or create an instance in code.

creating the button in Scene editor

class MenuScene: SKScene, ButtonDelegate {

private var button = Button()

override func didMove(to view: SKView) {

if let button = self.childNode(withName: "button") as? Button {
self.button = button
button.delegate = self
}

let button2 = Button(texture: nil, color: .magenta, size: CGSize(width: 200, height: 100))
button2.name = "button2"
button2.position = CGPoint(x: 0, y: 300)
button2.delegate = self
addChild(button2)
}
}

func buttonClicked(sender: Button) {
print("you clicked the button named \(sender.name!)")
}

You have to remember to make the scene conform to the delegate

class MenuScene: SKScene, ButtonDelegate

func buttonClicked(sender: Button) {
print("you clicked the button named \(sender.name!)")
}

How to fix the share button on SpriteKit Swift when Players plays the game again Share Button shows up on the game scene?

The first rule when making a SpriteKit game is to try to not use UIKit.
All of your UI should be created directly in the SKScenes using SpriteKit APIs (SKLabelNodes, SKSpriteNodes, SKNodes etc).
There are exceptions to this, like maybe using UICollectionViews for massive level select menus, but basic UI should never be done using UIKit.

So you should be making your buttons using SKSpriteNodes and add them directly to the SKScene you want.

There are plenty of tutorials to google on how to do this, a simple one is this

https://nathandemick.com/2014/09/buttons-sprite-kit-using-swift/

For a more complete one check out apples sample game "DemoBots" or have a look at these cool projects on gitHub.

https://github.com/nguyenpham/sgbutton

https://github.com/jozemite/JKButtonNode

In SpriteKit games you only tend to have 1 view Controller (GameViewController) which will present all your SKScenes (GameScene, MenuScene etc). If you use UIKit elements they get added to the GameViewController, and therefore they will be shown in all scenes (like your share button).

self.view?.addSubview(shareButton) // self.view is your GameViewController

If you have a game with more than 1 SKScene and quite a few buttons this will be madness to manage.

On the other hand if you use SpriteKit APIs, and because every SKScene starts in a clean state when you enter it, you dont have to worry about any of this.

If you insist on using UIKit than you will have to either remove or hide the share button before you transition to game scene and unhide it or add it again when you want to.

 shareButton.isHidden = true

or

 shareButton.removeFromSuperview()

Finally as good practice your properties should start with small letters not capital letters

shareButton = ...

Hope this helps



Related Topics



Leave a reply



Submit