In swift for spritekit, how would I change the textures of nodes when they are placed? - swift

I’m currently working on a matching game and when the user touches the nodes (Fruit match cards) I want them to display different images when a user clicks the nodes (Fruit match cards).
This is my current code:
import Foundation
import SpriteKit
class EasyScreen: SKScene {
override func didMove(to view: SKView) {
var background = SKSpriteNode(imageNamed: "Easy Screen Background")
let timerText = SKLabelNode(fontNamed: "Arial")
timerText.fontSize = 40
timerText.fontColor = SKColor.white
timerText.position = CGPoint(x: 20, y: 400)
timerText.zPosition = 1
var counter:Int = 120
timerText.run(
SKAction.repeatForever(
SKAction.sequence(
[
SKAction.run {
counter -= 1
timerText.text = " Time: \(counter)"
print("\(counter)")
if counter <= 0 {
let newScene = TryAgainScreen(fileNamed: "Try Again Screen")
newScene?.scaleMode = .aspectFill
self.view?.presentScene(newScene)
}
},
SKAction.wait(forDuration: 1)
]
)
)
)
background.position = CGPoint(x: 0, y: 0)
background.size.width = self.size.width
background.size.height = self.size.height
background.anchorPoint = CGPoint(x: 0.5,y: 0.5)
let matchCardOne = SKSpriteNode(imageNamed: "Fruit Match Card")
let matchCardTwo = SKSpriteNode(imageNamed: "Fruit Match Card")
let matchCardThree = SKSpriteNode(imageNamed: "Fruit Match Card")
let matchCardFour = SKSpriteNode(imageNamed: "Fruit Match Card")
matchCardOne.name = "FruitMatchCard1"
matchCardTwo.name = "FruitMatchCard2"
matchCardThree.name = "FruitMatchCard3"
matchCardFour.name = "FruitMatchCard4"
matchCardOne.size = CGSize(width: 150, height: 300)
matchCardTwo.size = CGSize(width: 150, height: 300)
matchCardThree.size = CGSize(width: 150, height: 300)
matchCardFour.size = CGSize(width: 150, height: 300)
matchCardOne.zPosition = 1
matchCardTwo.zPosition = 1
matchCardThree.zPosition = 1
matchCardFour.zPosition = 1
matchCardOne.anchorPoint = CGPoint(x: 0.5, y: 0.5)
matchCardTwo.anchorPoint = CGPoint(x: 0.5, y: 0.5)
matchCardThree.anchorPoint = CGPoint(x: 0.5, y: 0.5)
matchCardFour.anchorPoint = CGPoint(x: 0.5, y: 0.5)
matchCardOne.position = CGPoint(x: -125, y: 60)
matchCardTwo.position = CGPoint(x: -125, y: -260)
matchCardThree.position = CGPoint(x: 70, y: 60)
matchCardFour.position = CGPoint(x: 70 , y: -260)
addChild(background)
addChild(matchCardOne)
addChild(matchCardTwo)
addChild(matchCardThree)
addChild(matchCardFour)
addChild(timerText)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view?.isMultipleTouchEnabled = false
let touch = touches.first
let positionInScene = touch!.location(in: self)
let touchedCardOneNode = self.atPoint(positionInScene)
if let name = touchedCardOneNode.name {
if name == "FruitMatchCard1" {
let newTexture = SKTexture(imageNamed: "Apple")
FruitMatchCard1.init(texture: newTexture)
}
}
let touchTwo = touches.first
let positionInSceneTwo = touch!.location(in: self)
let touchedCardTwoNode = self.atPoint(positionInScene)
if let name = touchedCardTwoNode.name {
if name == "FruitMatchCard2" {
FruitMatchCard2.init(imageNamed: "Banana")
}
}
let touchThree = touches.first
let positionInSceneThree = touch!.location(in: self)
let touchedCardThreeNode = self.atPoint(positionInScene)
if let name = touchedCardThreeNode.name {
if name == "FruitMatchCard3" {
FruitMatchCard3.init(imageNamed: "Apple")
}
}
let touchFour = touches.first
let positionInSceneFour = touch!.location(in: self)
let touchedCardFourNode = self.atPoint(positionInScene)
if let name = touchedCardFourNode.name {
if name == "FruitMatchCard4" {
FruitMatchCard4.init(imageNamed: "Banana")
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
I’m trying to change the textures of the nodes in this part of the code. Inside the “if name == “FruitMatchCard” { } “ part of the code. However, when I launch the Xcode simulator the node’s textures aren't changing.
Any advice on how I can do this? Thanks!

Your fundamental problem is that when someone taps a card, you are creating a new card with the new texture and not doing anything with it. Take the following code you have:
FruitMatchCard2.init(imageNamed: "Banana")
This code creates a match card, but you don't do anything with the card.
To change the texture of the card, you must get the sprite node of the tapped card and change its texture. I see in your code you have the following variable:
let touchedCardTwoNode = self.atPoint(positionInScene)
This variable has the card that was touched. Set its texture to the texture you want to use.
touchedCardTwoNode.texture = SKTexture(imageNamed: "Banana")
My SpriteKit is a bit rusty so I can't guarantee that example will compile, but it gives you an idea of what you need to do to change the texture when tapping a card.

Related

In swift for sprite kit, how can I have a functionality that tracks the touches of two nodes and at a time? Along with tracking the textures?

I’m working on a matching game. In my app, I would like a functionality that tracks the touches of two nodes at time. When the user touches the nodes and if the textures displayed after the user touches the nodes match; I don’t want the user to be able to interact with the two nodes anymore.
However, if the textures displayed after the user touches the two nodes do not match. I want the two nodes the user touched to reset back to their original position before the user touched the nodes.
For example, let’s say the user touches the node named “fruit match card1” and it displays the texture of an “apple” then they touch the node named “fruit match card 2” and it also displays the texture of an “apple”. Since, these two nodes display the same texture that match. I don’t want the user to be able to interact with those nodes anymore since they clicked nodes that display the same texture.
However, let’s say the user touched the node named “Fruit match card 1” and it displays the “Apple” texture. Then they touched the node named “Fruit match Card 3” and it displays the “Grapes” texture. Since, these two nodes do not display the same texture I want those nodes to reset back to their original position before the user touched them.
Any advice or help on how I can have those kind of functionalities in my app? Basically having a functionality that tracks the touches of two nodes at a time and also a functionality that will reset the nodes back to their original position of the textures of the two nodes touched do not match? Thanks!
Here is my current code:
import Foundation
import SpriteKit
class EasyScreen: SKScene {
override func didMove(to view: SKView) {
var background = SKSpriteNode(imageNamed: "Easy Screen Background")
let timerText = SKLabelNode(fontNamed: "Arial")
timerText.fontSize = 40
timerText.fontColor = SKColor.white
timerText.position = CGPoint(x: 20, y: 400)
timerText.zPosition = 1
var counter:Int = 90
timerText.run(SKAction.repeatForever(SKAction.sequence([SKAction.run {
counter-=1
timerText.text = " Time: \(counter)"
print("\(counter)")
if counter <= 0{
let newScene = TryAgainScreen(fileNamed: "Try Again Screen")
newScene?.scaleMode = .aspectFill
self.view?.presentScene(newScene)
}
},SKAction.wait(forDuration: 1)])))
background.position = CGPoint(x: 0, y: 0)
background.size.width = self.size.width
background.size.height = self.size.height
background.anchorPoint = CGPoint(x: 0.5,y: 0.5)
let matchCardOne = SKSpriteNode(imageNamed: "Fruit Match Card")
let matchCardTwo = SKSpriteNode(imageNamed: "Fruit Match Card")
let matchCardThree = SKSpriteNode(imageNamed: "Fruit Match Card")
let matchCardFour = SKSpriteNode(imageNamed: "Fruit Match Card")
let soundButton = SKSpriteNode(imageNamed: "Sound On")
matchCardOne.name = "FruitMatchCard1"
matchCardTwo.name = "FruitMatchCard2"
matchCardThree.name = "FruitMatchCard3"
matchCardFour.name = "FruitMatchCard4"
soundButton.name = "Sound"
matchCardOne.size = CGSize(width: 150, height: 300)
matchCardTwo.size = CGSize(width: 150, height: 300)
matchCardThree.size = CGSize(width: 150, height: 300)
matchCardFour.size = CGSize(width: 150, height: 300)
soundButton.size = CGSize(width: 75, height: 75)
matchCardOne.zPosition = 1
matchCardTwo.zPosition = 1
matchCardThree.zPosition = 1
matchCardFour.zPosition = 1
soundButton.zPosition = 3
matchCardOne.anchorPoint = CGPoint(x: 0.5, y: 0.5)
matchCardTwo.anchorPoint = CGPoint(x: 0.5, y: 0.5)
matchCardThree.anchorPoint = CGPoint(x: 0.5, y: 0.5)
matchCardFour.anchorPoint = CGPoint(x: 0.5, y: 0.5)
soundButton.anchorPoint = CGPoint(x: 0.5, y: 0.5)
matchCardOne.position = CGPoint(x: -125, y: 60)
matchCardTwo.position = CGPoint(x: -125, y: -260)
matchCardThree.position = CGPoint(x: 70, y: 60)
matchCardFour.position = CGPoint(x: 70 , y: -260)
soundButton.position = CGPoint(x: -180, y: -600)
addChild(background)
addChild(matchCardOne)
addChild(matchCardTwo)
addChild(matchCardThree)
addChild(matchCardFour)
addChild(timerText)
addChild(soundButton)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view?.isMultipleTouchEnabled = false
let touch = touches.first
let positionInSceneOne = touch!.location(in: self)
let tappedNodes = nodes(at: positionInSceneOne)
for node in tappedNodes{
if let tappedCard = node as? SKSpriteNode {
if tappedCard.name == "FruitMatchCard1" {
tappedCard.texture = SKTexture(imageNamed: "Apple")
}
}
}
let touchTwo = touches.first
let positionInSceneTwo = touch!.location(in: self)
let tappedNodesTwo = nodes(at: positionInSceneTwo)
for node in tappedNodesTwo{
if let tappedCard = node as? SKSpriteNode {
if tappedCard.name == "FruitMatchCard2" {
tappedCard.texture = SKTexture(imageNamed: "Apple")
}
}
}
let touchThree = touches.first
let positionInSceneThree = touch!.location(in: self)
let tappedNodesThree = nodes(at: positionInSceneThree)
for node in tappedNodesThree{
if let tappedCard = node as? SKSpriteNode {
if tappedCard.name == "FruitMatchCard3" {
tappedCard.texture = SKTexture(imageNamed: "Grapes")
}
}
}
let touchFour = touches.first
let positionInSceneFour = touch!.location(in: self)
let tappedNodesFour = nodes(at: positionInSceneFour)
for node in tappedNodesFour{
if let tappedCard = node as? SKSpriteNode {
if tappedCard.name == "FruitMatchCard4" {
tappedCard.texture = SKTexture(imageNamed: "Grapes")
}
}
}
}
You don't want to track the textures.
The texture i.e. the image of the node is just a representation of some state that the node is in, so you need to track the node's state instead.
You could do this by either having an array of nodes and their state but a better way is to subclass SKSpriteNode to create your card node and then add a custom bool property for isFaceUp, which will make it much easier to decide if cards can be touched or matched etc.

SKAction not running when button is held

I am working/practicing with SpriteKit and making a directional pad for controls. It works to move the character, except for the SKAction. I have the actions in the Actions.sks file that based off what button is pressed determines the action that is called. When I press the button the character moves fine, but when I hold it the character glides and the walking animation is stuck on the first frame until I release. What I am trying to do is have the character move if the button is pressed, and continue moving(with walking animation) when the button is held. I am trying to make it look like the gameboy era games.
class GameScene: SKScene {
var player = SKSpriteNode()
var playerSpeed: CGFloat = 0
var previousTimeInterval:TimeInterval = 0
let buttonNorth = SKSpriteNode(imageNamed: "Directional_Button")
let buttonSouth = SKSpriteNode(imageNamed: "Directional_Button")
let buttonEast = SKSpriteNode(imageNamed: "Directional_Button2")
let buttonWest = SKSpriteNode(imageNamed: "Directional_Button2")
var moveAtEndOfRelease:Bool = true
var isPressing = false
var currentState = MoveStates.n
override func didMove(to view: SKView) {
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
// Make sure you can get teh player from the scene file
if let somePlayer = self.childNode(withName: "player") as? SKSpriteNode {
player = somePlayer
// Set physics
player.physicsBody?.isDynamic = false
} else {
print("No player")
}
let widthHalf:CGFloat = self.view!.bounds.width / 2
let heightHalf:CGFloat = self.view!.bounds.height / 2
self.addChild(buttonNorth)
buttonNorth.position = CGPoint(x: -widthHalf + 80, y: -heightHalf + 100)
self.addChild(buttonSouth)
buttonSouth.position = CGPoint(x: -widthHalf + 80, y: -heightHalf + 40)
buttonSouth.yScale = -1
self.addChild(buttonWest)
buttonWest.position = CGPoint( x: -widthHalf + 30, y: -heightHalf + 70)
self.addChild(buttonEast)
buttonEast.position = CGPoint( x: -widthHalf + 130, y: -heightHalf + 70)
buttonNorth.xScale = 0.4
buttonNorth.yScale = 0.4
buttonSouth.xScale = 0.4
buttonSouth.yScale = 0.4
buttonSouth.zRotation = CGFloat(Double.pi)
buttonEast.xScale = 0.4
buttonEast.yScale = 0.4
buttonEast.zRotation = CGFloat(Double.pi)
buttonWest.xScale = 0.4
buttonWest.yScale = 0.4
}
override func update(_ currentTime: TimeInterval) {
//player.position = CGPoint(x: player.position.x + playerSpeedx, y: player.position.y + playerSpeedy)
if (isPressing) {
moveOnRelease()
}
}
func move(facing: Facing, x: CGFloat, y: CGFloat) {
let walkAnimation = SKAction(named: "walk\(facing)")!
let moveAction = SKAction.moveBy(x: x, y: y, duration: 1)
let group = SKAction.group([walkAnimation, moveAction])
// Run the actions
player.run(group)
}
func moveSide(facing: Facing, x: CGFloat) {
let walkAnimation = SKAction(named: "walk\(facing)")!
let moveAction = SKAction.moveBy(x: x, y: 0, duration: 1)
let group = SKAction.group([walkAnimation, moveAction])
// Run the actions
player.run(group)
}
func moveUpDown(facing: Facing, y: CGFloat) {
let walkAnimation = SKAction(named: "walk\(facing)")!
let moveAction = SKAction.moveBy(x: 0, y: y, duration: 1)
let group = SKAction.group([walkAnimation, moveAction])
// Run the actions
player.run(group)
}
func moveOnRelease() {
switch (currentState) {
case .n:
moveUpDown(facing: .Back, y: 1)
case .s:
moveUpDown(facing: .Front, y: -1)
case .e:
moveSide(facing: .Right, x: 1)
case .w:
moveSide(facing: .Left, x: -1)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches ) {
let location = touch.location(in: self)
if (buttonNorth.frame.contains(location)) {
currentState = MoveStates.n
buttonNorth.texture = SKTexture(imageNamed: "Directional_Button_Lit")
isPressing = true
} else if (buttonSouth.frame.contains(location)) {
currentState = MoveStates.s
buttonSouth.texture = SKTexture(imageNamed: "Directional_Button_Lit")
isPressing = true
} else if (buttonEast.frame.contains(location)) {
currentState = MoveStates.e
buttonEast.texture = SKTexture(imageNamed: "Directional_Button2_Lit")
isPressing = true
} else if (buttonWest.frame.contains(location)) {
currentState = MoveStates.w
buttonWest.texture = SKTexture(imageNamed: "Directional_Button2_Lit")
isPressing = true
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if (moveAtEndOfRelease == true) {
buttonNorth.texture = SKTexture(imageNamed: "Directional_Button")
buttonSouth.texture = SKTexture(imageNamed: "Directional_Button")
buttonEast.texture = SKTexture(imageNamed: "Directional_Button2")
buttonWest.texture = SKTexture(imageNamed: "Directional_Button2")
//moveOnRelease()
isPressing = false
}
}
}
The reason it is stuck on the first frame is because the action is being called on every update i believe. You could check to see if the animation is already running, if so do not run it again.
To do this, for each run action give it a name.
So player.run(group) could be
player.run(group, withKey: "moveside"). Then, you can check to see if the action is already running or not like this if (player.action(forKey: "moveside") == nil). Finally, add in code to remove all other actions (like current movement or animations).
Putting it altogether:
if (player.action(forKey: "moveside") == nil) {
player.removeAllActions()
player.run(group, withKey: "moveside")
}

How can I make my level menu scrollable vertically?

I have the following level Menu (as seen below). I would like to make it vertically scrollable, resulting in a total height double that of the screen (full scroll height). How can I achieve this?
Below is the code for the image above:
class LevelMenu: SKScene {
let levelButtonSize = SKSpriteNode(imageNamed: "b1").size
let levelButton1: SKSpriteNode = SKSpriteNode(imageNamed: "b1")
let levelButton2: SKSpriteNode = SKSpriteNode(imageNamed: "b2")
let levelButton3: SKSpriteNode = SKSpriteNode(imageNamed: "b3")
let levelButton4: SKSpriteNode = SKSpriteNode(imageNamed: "b4")
let levelButton5: SKSpriteNode = SKSpriteNode(imageNamed: "b5")
let levelButton6: SKSpriteNode = SKSpriteNode(imageNamed: "b6")
let levelButton7: SKSpriteNode = SKSpriteNode(imageNamed: "b7")
let levelButton8: SKSpriteNode = SKSpriteNode(imageNamed: "b8")
let levelButton9: SKSpriteNode = SKSpriteNode(imageNamed: "b9")
let levelButton10: SKSpriteNode = SKSpriteNode(imageNamed: "b10")
let levelButton11: SKSpriteNode = SKSpriteNode(imageNamed: "b11")
let levelButton12: SKSpriteNode = SKSpriteNode(imageNamed: "b12")
override init(size: CGSize){
super.init(size: size)
let bg = SKSpriteNode(imageNamed: "bg")
backgroundImage.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
self.addChild(bg)
let column1PosX = levelButtonSize.width*cDiff
let column2PosX = levelButtonSize.width*cDiff + levelButtonSize.width*2.0
let column3PosX = levelButtonSize.width*cDiff + levelButtonSize.width*4.0
let row1PosY = self.frame.height - levelButtonSize.width*1.5
let row2PosY = row1PosY - levelButtonSize.height - levelButtonSize.width*rDiff
let row3PosY = row2PosY - levelButtonSize.height - levelButtonSize.width*rDiff
let row4PosY = row3PosY - levelButtonSize.height - levelButtonSize.width*rDiff
levelButton1.position = CGPoint(x: column1PosX, y: row1PosY)
levelButton1.zPosition = 10
self.addChild(levelButton1)
levelButton2.position = CGPoint(x: column2PosX, y: row1PosY)
self.addChild(levelButton2)
levelButton3.position = CGPoint(x: column3PosX, y: row1PosY)
self.addChild(levelButton3)
levelButton4.position = CGPoint(x: column1PosX, y: row2PosY)
self.addChild(levelButton4)
levelButton5.position = CGPoint(x: column2PosX, y: row2PosY)
self.addChild(levelButton5)
levelButton6.position = CGPoint(x: column3PosX, y: row2PosY)
self.addChild(levelButton6)
levelButton7.position = CGPoint(x: column1PosX, y: row3PosY)
self.addChild(levelButton7)
levelButton8.position = CGPoint(x: column2PosX, y: row3PosY)
self.addChild(levelButton8)
levelButton9.position = CGPoint(x: column3PosX, y: row3PosY)
self.addChild(levelButton9)
levelButton10.position = CGPoint(x: column1PosX, y: row4PosY)
self.addChild(levelButton10)
levelButton11.position = CGPoint(x: column2PosX, y: row4PosY)
self.addChild(levelButton11)
levelButton12.position = CGPoint(x: column3PosX, y: row4PosY)
self.addChild(levelButton12)
}
UPDATE
Based on Ron Myschuk's solution, the code below show's what I've been able to achieve and this link shows a .gif of the issue I am having currently, where the screen scrolls too much at the top of the menu.
class LMScene: SKScene {
let levelButtonSize = SKSpriteNode(imageNamed: "b1").size
let levelButton1: SKSpriteNode = SKSpriteNode(imageNamed: "b1")
let levelButton2: SKSpriteNode = SKSpriteNode(imageNamed: "b2")
let levelButton3: SKSpriteNode = SKSpriteNode(imageNamed: "b3")
let levelButton4: SKSpriteNode = SKSpriteNode(imageNamed: "b4")
let levelButton5: SKSpriteNode = SKSpriteNode(imageNamed: "b5")
let levelButton6: SKSpriteNode = SKSpriteNode(imageNamed: "b6")
let levelButton7: SKSpriteNode = SKSpriteNode(imageNamed: "b7")
let levelButton8: SKSpriteNode = SKSpriteNode(imageNamed: "b8")
let levelButton9: SKSpriteNode = SKSpriteNode(imageNamed: "b9")
let levelButton10: SKSpriteNode = SKSpriteNode(imageNamed: "b10")
let levelButton11: SKSpriteNode = SKSpriteNode(imageNamed: "b11")
let levelButton12: SKSpriteNode = SKSpriteNode(imageNamed: "b12")
let levelButton13: SKSpriteNode = SKSpriteNode(imageNamed: "b13")
let levelButton14: SKSpriteNode = SKSpriteNode(imageNamed: "b14")
let levelButton15: SKSpriteNode = SKSpriteNode(imageNamed: "b15")
let levelButton16: SKSpriteNode = SKSpriteNode(imageNamed: "b16")
let levelButton17: SKSpriteNode = SKSpriteNode(imageNamed: "b17")
let levelButton18: SKSpriteNode = SKSpriteNode(imageNamed: "b18")
private var scrollCell = SKSpriteNode()
private var moveAmtX: CGFloat = 0
private var moveAmtY: CGFloat = 0
private let minimum_detect_distance: CGFloat = 30
private var initialPosition: CGPoint = CGPoint.zero
private var initialTouch: CGPoint = CGPoint.zero
private var resettingSlider = false
override init(size: CGSize){
super.init(size: size)
scrollCell = SKSpriteNode(color: .blue, size: CGSize(width: self.size.width, height: 2*self.size.height - self.frame.width*0.24734))
scrollCell.position = CGPoint(x: 0, y: 0)
scrollCell.anchorPoint = CGPoint.zero
scrollCell.zPosition = 0
self.addChild(scrollCell)
let backgroundImage = SKSpriteNode(imageNamed: "bg")
backgroundImage.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
self.addChild(backgroundImage)
let column1PosX = levelButtonSize.width/2 + self.frame.width*0.14855
let column2PosX = 3*levelButtonSize.width/2 + 2*self.frame.width*0.14855
let column3PosX = 5*levelButtonSize.width/2 + 3*self.frame.width*0.14855
let row1PosY = self.frame.height - levelButtonSize.height/2 - self.frame.width*0.24734
let row2PosY = row1PosY - levelButtonSize.height - self.frame.width*0.24734
let row3PosY = row2PosY - levelButtonSize.height - self.frame.width*0.24734
let row4PosY = row3PosY - levelButtonSize.height - self.frame.width*0.24734
let row5PosY = row4PosY - levelButtonSize.height - self.frame.width*0.24734
let row6PosY = row5PosY - levelButtonSize.height - self.frame.width*0.24734
levelButton1.position = CGPoint(x: column1PosX, y: row1PosY)
levelButton1.zPosition = 10
scrollCell.addChild(levelButton1)
levelButton2.position = CGPoint(x: column2PosX, y: row1PosY)
levelButton2.zPosition = 10
scrollCell.addChild(levelButton2)
levelButton3.position = CGPoint(x: column3PosX, y: row1PosY)
levelButton3.zPosition = 10
scrollCell.addChild(levelButton3)
levelButton4.position = CGPoint(x: column1PosX, y: row2PosY)
levelButton4.zPosition = 10
scrollCell.addChild(levelButton4)
levelButton5.position = CGPoint(x: column2PosX, y: row2PosY)
levelButton5.zPosition = 10
scrollCell.addChild(levelButton5)
levelButton6.position = CGPoint(x: column3PosX, y: row2PosY)
levelButton6.zPosition = 10
scrollCell.addChild(levelButton6)
levelButton7.position = CGPoint(x: column1PosX, y: row3PosY)
levelButton7.zPosition = 10
scrollCell.addChild(levelButton7)
levelButton8.position = CGPoint(x: column2PosX, y: row3PosY)
levelButton8.zPosition = 10
scrollCell.addChild(levelButton8)
levelButton9.position = CGPoint(x: column3PosX, y: row3PosY)
levelButton9.zPosition = 10
scrollCell.addChild(levelButton9)
levelButton10.position = CGPoint(x: column1PosX, y: row4PosY)
levelButton10.zPosition = 10
scrollCell.addChild(levelButton10)
levelButton11.position = CGPoint(x: column2PosX, y: row4PosY)
levelButton11.zPosition = 10
scrollCell.addChild(levelButton11)
levelButton12.position = CGPoint(x: column3PosX, y: row4PosY)
levelButton12.zPosition = 10
scrollCell.addChild(levelButton12)
levelButton13.position = CGPoint(x: column1PosX, y: row5PosY)
levelButton13.zPosition = 10
scrollCell.addChild(levelButton13)
levelButton14.position = CGPoint(x: column2PosX, y: row5PosY)
levelButton14.zPosition = 10
scrollCell.addChild(levelButton14)
levelButton15.position = CGPoint(x: column3PosX, y: row5PosY)
levelButton15.zPosition = 10
scrollCell.addChild(levelButton15)
levelButton16.position = CGPoint(x: column1PosX, y: row6PosY)
levelButton16.zPosition = 10
scrollCell.addChild(levelButton16)
levelButton17.position = CGPoint(x: column2PosX, y: row6PosY)
levelButton17.zPosition = 10
scrollCell.addChild(levelButton17)
levelButton18.position = CGPoint(x: column3PosX, y: row6PosY)
levelButton18.zPosition = 10
scrollCell.addChild(levelButton18)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first as UITouch! {
if let touch = touches.first as UITouch! {
self.scrollCell.removeAllActions()
initialTouch = touch.location(in: self.scene!.view)
moveAmtY = 0
initialPosition = self.scrollCell.position
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first as UITouch! {
let movingPoint: CGPoint = touch.location(in: self.scene!.view)
moveAmtY = movingPoint.y - initialTouch.y
scrollCell.position = CGPoint(x: initialPosition.x, y: initialPosition.y - moveAmtY)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
checkForResettingSlider()
yMoveActions(moveTo: -moveAmtY)
}
func checkForResettingSlider() {
if resettingSlider { return }
let scrollDif: CGFloat = (scrollCell.size.height - self.size.height) / 2.0
if scrollCell.position.y > scrollDif {
let move: SKAction = SKAction.moveTo(y: scrollDif, duration: 0.3)
move.timingMode = .easeOut
scrollCell.run(move, completion: { self.resettingSlider = false })
}
if scrollCell.position.y < -scrollDif {
let move: SKAction = SKAction.moveTo(y: 0 - scrollDif, duration: 0.3)
move.timingMode = .easeOut
scrollCell.run(move, completion: { self.resettingSlider = false })
}
}
func yMoveActions(moveTo: CGFloat) {
let move: SKAction = SKAction.moveBy(x: 0, y: (moveTo * 1.5), duration: 0.3)
move.timingMode = .easeOut
self.scrollCell.run(move, completion: { self.checkForResettingSlider() })
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Here is some code that I use to scroll vertically, I've adapted it to fit your menu. It doesn't perfectly line up to all your items, but it'll give you somewhere to start. And it'll show you how to figure this out on your own.
EDIT: I've updated the code use these funds instead. Still declare your buttons the same way but call my createMenu func to actually create the menu. It is looped so it auto adjusts if you change the number of menu items. the only thing you have to be aware of is; if you add or remove buttons change the array at the top of createMenu accordingly. Also adjust the padding variable to how much vertical space you want between the items
func createMenu() {
let buttons = [levelButton1, levelButton2, levelButton3, levelButton4, levelButton5, levelButton6, levelButton7, levelButton8, levelButton9, levelButton10, levelButton11, levelButton12, levelButton13, levelButton14, levelButton15, levelButton16, levelButton17, levelButton18]
let padding: CGFloat = 400
let numberOfRows = CGFloat(buttons.count / 3)
scrollCell = SKSpriteNode(color: .blue, size: CGSize(width: 1024, height: levelButtonSize.height * numberOfRows + padding * numberOfRows))
scrollCell.position = CGPoint(x: 0 - self.size.width / 4, y: 0 - (scrollCell.size.height - self.size.height / 2))
scrollCell.anchorPoint = CGPoint.zero
scrollCell.zPosition = 0
self.addChild(scrollCell)
// let backgroundImage = SKSpriteNode(imageNamed: "bg")
// backgroundImage.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
// self.addChild(backgroundImage)
let column1PosX = scrollCell.size.width / 3 / 2
let column2PosX = scrollCell.size.width / 2
let column3PosX = scrollCell.size.width / 3 / 2 + scrollCell.size.width / 3 * 2
var colCount = 0
var rowCount = 0
for button in buttons {
var posX: CGFloat = column2PosX
if colCount == 0 {
posX = column1PosX
}
else if colCount == 2 {
posX = column3PosX
colCount = -1
}
let indexOffset = CGFloat(rowCount) * (levelButtonSize.height + padding)
let posY = scrollCell.size.height - levelButtonSize.height / 2 - (indexOffset + padding / 2)
button.position = CGPoint(x: posX, y: posY)
button.setScale(0.5)
button.zPosition = 10
scrollCell.addChild(button)
if colCount == -1 {
rowCount += 1
}
colCount += 1
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first as UITouch! {
self.scrollCell.removeAllActions()
initialTouch = touch.location(in: self.scene!.view)
moveAmtY = 0
initialPosition = self.scrollCell.position
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first as UITouch! {
let movingPoint: CGPoint = touch.location(in: self.scene!.view)
moveAmtY = movingPoint.y - initialTouch.y
scrollCell.position = CGPoint(x: initialPosition.x, y: initialPosition.y - moveAmtY)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
checkForResettingSlider()
yMoveActions(moveTo: -moveAmtY)
}
func checkForResettingSlider() {
let topPos: CGFloat = scrollCell.size.height - self.size.height / 2
let bottomPos = 0 - (self.size.height / 2)
if scrollCell.position.y > bottomPos {
let move = SKAction.moveTo(y: bottomPos, duration: 0.3)
move.timingMode = .easeOut
scrollCell.run(move)
}
if scrollCell.position.y < -topPos {
let move = SKAction.moveTo(y: -topPos, duration: 0.3)
move.timingMode = .easeOut
scrollCell.run(move)
}
}
func yMoveActions(moveTo: CGFloat) {
let move = SKAction.moveBy(x: 0, y: (moveTo * 1.5), duration: 0.3)
move.timingMode = .easeOut
self.scrollCell.run(move, completion: { self.checkForResettingSlider() })
}

How to force on touch.location to work only in special place on screen?

that is my first question here so - Hello Word.
I have a small problem with my code. I want to force on this program to make balls appear only if you will touch over and equal y: 650 point and boxes to appear only if you will touch under y: 650 point. x position makes here no role.
That is my code:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
let objects = nodes(at: location)
if objects.contains(editLabel) {
editingMode = !editingMode
} else {
if editingMode {
let size = CGSize(width: GKRandomDistribution(lowestValue: 16, highestValue: 128).nextInt(), height: 16)
let box = SKSpriteNode(color: RandomColor(), size: size)
box.zRotation = RandomCGFloat(min: 0, max: 3)
box.position = location
box.physicsBody = SKPhysicsBody(rectangleOf: box.size)
box.physicsBody!.isDynamic = false
addChild(box)
} else {
let ball = SKSpriteNode(imageNamed: "ballRed")
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width / 2.0)
ball.physicsBody!.contactTestBitMask = ball.physicsBody!.collisionBitMask
ball.physicsBody!.restitution = 0.4
ball.position = location
ball.name = "ball"
addChild(ball)
}
}
}
}
Looking forward for help :)
For me this worked:
ball.position = location
if (location.y < 500) {
ball.position.y = 500
}

Sprite-Kit Began Touch Error

Im trying to create a method that when I touch a sprite named StartSprite Through my touchesbegan function it will print out something in my console. But for some reason when I click on the sprite nothing happens. This is my code.
import SpriteKit
class GameScene: SKScene {
let StartSprite = SKSpriteNode(imageNamed: "startLabel")
override func didMoveToView(view: SKView) {
let borderRect = CGRect(x: 0 , y: 0 , width: 400, height: 725)
let welcomeLabel = SKLabelNode(fontNamed: "welcome");
welcomeLabel.text = "Welcome";
welcomeLabel.fontColor = UIColor.whiteColor()
welcomeLabel.fontSize = 65
welcomeLabel.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 + 150)
self.addChild(welcomeLabel)
//StartLabel
let rectangleBorder = SKShapeNode(rect: borderRect)
rectangleBorder.position = CGPoint(x: 315, y: 25)
rectangleBorder.strokeColor = UIColor.whiteColor()
self.addChild(rectangleBorder)
self.backgroundColor = UIColor.grayColor()
StartSprite.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2)
self.addChild(StartSprite)
println("Hello")
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
let touchLocation = touch.locationInNode(self)
if touchLocation == StartSprite.position{
println("Touches")
}
}
}
Your code requires that you touch exactly the one pixel at StartSprite.position.
Try this instead:
let p = StartSprite.convertPoint(touchLocation, fromNode: self)
if StartSprite.containsPoint(p) {
print("touched StartSprite")
}
If you're going to add more buttons, you might want to do this instead:
let target = nodeAtPoint(touchLocation)
if target == StartSprite {
print("touched StartSprite"
}
// check other buttons here