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.
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
Replaykit Startrecording Sometimes Never Enters Completion Handler
Self Sizing Uitextview Till Specific Height
Wake Up Application in Background Using Audiosession Like Alarmy iOS App
Double Tap Necessary to Select Tableview Item with Search Bar
Core Data Entity Unique Constraint Does Not Work
Getting Error Ambiguous Use of Tableview(_:Numberofrowsinsection:)
-[Uithreadsafenode Canperformaction:Withsender:]: Unrecognized Selector Sent to Instance
Avmutablevideocomposition Output Video Shrinked
How to Make a Bullet List with Swift
Swift Get Specific Value from Firebase Database
Caching Images in Collectionviewcell in Swift
Openurl in Appdelegate Conversion Error Nsstring -> String (Swift & iOS8)
Spritekit/Swift - How to Check Contact of Two Nodes When They Are Already in Contact
Uisearchcontroller Searchbar Delegate Not Working
Swiftui - Navigationview Title and Back Button Clipped Under Status Bar After Orientation Change