subclassed SKLabelNode to present scene, how? - swift

I have a subclass of SKLabelNode that's instanced three or four times, each with a name, and a destination:
//
import SpriteKit
class MenuButton: SKLabelNode {
var goesTo = SKScene()
override init() {
super.init()
print("test... did this get called? WTF? HOW/WHY/WHERE?")
}
convenience init(text: String, color: SKColor, destination: SKScene){
self.init()
self.text = text
self.color = color
goesTo = destination
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let nextScene = goesTo
// .....?????????????????
// HOW DO I GET THIS TO FIND ITS SCENE...
// THEN ITS VIEW, THEN PRESENT this nextScene????
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I'm at a loss as to how to get at the view I need to call the scene change on.

Every SKNode has a scene property which returns the scene where the node lives.
And every SKScene as a view property, so
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let nextScene = goesTo
self.scene?.view?.presentScene(nextScene)
}

Related

How do I make a SKSpritenode move to the touch location in swift SpriteKit

Hi I am making a game where a node should move to the touch location and I have asked before and it is still not working. Here is my code, hopefully you can help me. I have a file called Player.swift with this code inside it:
import SpriteKit
class Player: SKSpriteNode {
let playerTexture = SKTexture(imageNamed: "head")
init() {
super.init(texture: playerTexture, color: .clear, size: playerTexture.size())
}
// Satisfy the NSCoder required init.
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}}
and then I have the gamescene.swift file with this inside of it:
import SpriteKit
class GameScene: SKScene {
let player = Player()
override func didMove(to view: SKView) {
addChild(player)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
player.position = touch.location(in: self)
}
}
}
Are you sure your touch event is registered? Just put a print("moved") in the touches moves function to be sure.

Drag - drop custom SKSpriteNode position issue

I'm my game I'm using a custom SKSpriteNode which the player are going to be able to drag and drop at a position of his/hers desire.
My custom node is made of this code in file DraggableNode.swift:
class DraggableNode : SKSpriteNode {
var nodeSelected : SKNode?
init() {
let texture = SKTexture(imageNamed: "draggableNode_1")
super.init(texture: texture, color: UIColor.white, size: texture.size())
self.isUserInteractionEnabled = true
self.zPosition = 1
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
let touchedNodes = self.nodes(at: location)
for node in touchedNodes.reversed() {
nodeSelected = node
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first, let node = self.nodeSelected {
let touchLocation = touch.location(in: self)
node.position = touchLocation
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
nodeSelected = nil
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
nodeSelected = nil
}
}
In my GameScene.swift I add the custom node in this way:
let node = DraggableNode()
node.position = CGPoint(x: randomX, y: randomY)
self.addChild(node)
Now, the problem is that when I start to drag the node it's all jump and is placed a total random place - sometimes even out of the screenarea.
I wonder if the problem consists of the fact that it's a custom node inherited from a SKSpriteNode?
If anyone can point me in the right direction, I'd be a happy man :-)

spritekit make childnode not touchable

I have a menu button (skSpriteNode) and a small play icon inside this sprite
mainButton.addChild (playIcon)
mainButton.name = "xyz"
addchild (mainButton)
ok, I gave the button the name to check if a sprite with this name is touched.
when I touch the icon child inside the button, the touchedNode.name is nil. I set isUserInteractionEnabled = false for the icon child. I want to pass the touch to the parent. how can I do this.
for touch in touches {
let location = touch.location(in: self)
let touchedNode = self.atPoint(location)
if (touchedNode.name != nil) {
print ("node \(touchedNode.name!)")
} else {
continue
}
}
You have to implement touchesBegan in a subclass of SKSpriteNode and to set its isUserInteractionEnabled = true, in order to accept and process the touches for that particular node (button).
import SpriteKit
protocol ButtonDelegate:class {
func printButtonsName(name:String?)
}
class Button : SKSpriteNode{
weak var delegate:ButtonDelegate?
init(name:String){
super.init(texture: nil, color: .purple, size: CGSize(width: 250, height: 250))
self.name = name
self.isUserInteractionEnabled = true
let icon = SKSpriteNode(color: .white, size: CGSize(width:100, height:100))
addChild(icon)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
delegate?.printButtonsName(name: self.name)
}
}
class GameScene: SKScene, ButtonDelegate {
override func didMove(to view: SKView) {
let button = Button(name:"xyz")
button.delegate = self
button.position = CGPoint(x: frame.midX - 50.0, y: frame.midY)
addChild(button)
}
func printButtonsName(name: String?) {
if let buttonName = name {
print("Pressed button : \(buttonName) ")
}
}
}
Now, this button will swallow the touches and the icon sprite will be ignored.
I just modified the code from one of my answers to make an example specific to your needs, but you can read, in that link, about whole thing more in detail if interested.
I implemented the button Touchbegan and tried to implement a subclass for a slider with a background and the child thumb inside the slider. I added the sliderDelegate Protocoll in my GameScene. the down touch is ok, but I didn't get the moved in
import Foundation
import SpriteKit
protocol SliderDelegate:class {
func touchesBeganSKSpriteNodeSlider(name:String?, location: CGPoint?)
func touchesMovedSKSpriteNodeSlider(name:String?, location: CGPoint?)
func touchesEndedSKSpriteNodeSlider(name:String?, location: CGPoint?)
}
class SKSpriteNodeSlider : SKSpriteNode{
weak var delegate:SliderDelegate?
init(imageNamed: String){
// super.init(imageNamed: imageNamed)
let texture = SKTexture(imageNamed: imageNamed)
super.init(texture: texture, color: .white, size: texture.size())
// self.name = name
self.isUserInteractionEnabled = true
// let icon = SKSpriteNode(color: .white, size: CGSize(width:100, height:100))
// addChild(icon)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// for touch in touches {
if let touch = touches.first {
let loc = touch.location(in: self)
delegate?.touchesBeganSKSpriteNodeSlider(name: self.name, location: loc)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
print ("touchesMoved")
// for touch in touches {
if let touch = touches.first {
let loc = touch.location(in: self)
delegate?.touchesMovedSKSpriteNodeSlider(name: self.name, location: loc)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let loc = touch.location(in: self)
delegate?.touchesEndedSKSpriteNodeSlider(name: self.name, location: loc)
}
}
}

Adding button to GameScene.swift programatically and transitioning scenes when pressed

I have been working forever trying to implement a way to add a button and when pressed the scene transitions to my second view. I have read other posts but have had ZERO luck for something in Swift 3. I'm really confused and have tried but failed many times. Hope you can help! Thanks!
Swift 3 in SpriteKit.
What do you mean transition to a new view?. When making SpriteKit games we tend to transition between SKScenes and not views. So do not try to create different views or viewControllers for each scene, just transition between SKScenes directly.
In regards to buttons, there is plenty tutorials available. You basically create a SKSpriteNode as a button and look for it in touchesBegan and do something when its pressed.
This is a simple example here
https://nathandemick.com/2014/09/buttons-sprite-kit-using-swift/
Essential you can create a button subclass similar to this.
class Button: SKNode {
let defaultButton: SKSpriteNode
let activeButton: SKSpriteNode
var action: () -> ()
init(defaultButtonImage: String, activeButtonImage: String, buttonAction: #escaping () -> ()) {
defaultButton = SKSpriteNode(imageNamed: defaultButtonImage)
activeButton = SKSpriteNode(imageNamed: activeButtonImage)
activeButton.isHidden = true
action = buttonAction
super.init()
isUserInteractionEnabled = true
addChild(defaultButton)
addChild(activeButton)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
activeButton.isHidden = false
defaultButton.isHidden = true
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if defaultButton.contains(location) {
activeButton.isHidden = false
defaultButton.isHidden = true
} else {
activeButton.isHidden = true
defaultButton.isHidden = false
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if defaultButton.contains(location) {
action()
}
activeButton.isHidden = true
defaultButton.isHidden = false
}
}
}
and than in your relevant SKScene add your buttons
class StartScene: SKScene {
override func didMove(to view: SKView) {
let playButton = Button(defaultButtonImage: "button", activeButtonImage: "button_active", buttonAction: loadGameScene)
playButton.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(playButton)
}
func loadGameScene() {
let scene = GameScene(...)
let transition = SKTransition....
scene.scaleMode = .aspectFill
view?.presentScene(scene, transition: transition)
}
}
You can also check out Apples sample game DemoBots for another button class example using protocols.
Hope this helps

touchesBegan function in Swift doesn't need override

I'm new to Xcode and I've been playing around with making a SpriteKit game in Swift.
In every tutorial or Stack overflow topic I've looked at, the touchesBegan function has an override before it, but when I copy that code into GameScene.swift, I get an error, "override can only be specified on class members," with an auto-fix of deleting "override."
So instead of this:override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {...}
it wants me to have this:func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {...}
I'm not sure why this is happening, and I don't know if it will affect how the function works.
My current code in GameScene.swift is:
import SpriteKit
class GameScene: SKScene {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(size: CGSize) {
super.init(size: size)
backgroundColor = SKColor.blackColor()
let stars = Stars()
var starNode:SKNode!
starNode = stars.createStars(CGFloat(30), direction: 1, scaleX: self.frame.width, scaleY: self.frame.height)
addChild(starNode)
func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
//Nothing here yet
}
}
}
Is there something else I am missing?
Thanks!
You must close the second init with a } after addChild(starNode). Your code should read:
import SpriteKit
class GameScene: SKScene {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(size: CGSize) {
super.init(size: size)
backgroundColor = SKColor.blackColor()
// let stars = Stars()
var starNode:SKNode!
starNode = stars.createStars(CGFloat(30), direction: 1,
scaleX: self.frame.width, scaleY: self.frame.height)
addChild(starNode)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
//Nothing here yet
}
}