TouchesBegan does not work - ios

In the last label lblTryAgain I want to return to another class named GameScene but the tap action does not enter to the function touchesBegan.
I am just following a tutorial to learn how to create games with SpriteKit if someone want to follow the tutorial or see the entire code is available in https://www.raywenderlich.com/87231/make-game-like-mega-jump-sprite-kit-swift-part-1
import SpriteKit
class EndGameScene: SKScene {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(size: CGSize) {
super.init(size: size)
// Stars
let star = SKSpriteNode(imageNamed: "Star")
star.position = CGPoint(x: 25, y: self.size.height-30)
addChild(star)
let lblStars = SKLabelNode(fontNamed: "ChalkboardSE-Bold")
lblStars.fontSize = 30
lblStars.fontColor = SKColor.white
lblStars.position = CGPoint(x: 50, y: self.size.height-40)
lblStars.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.left
lblStars.text = String(format: "X %d", GameState.sharedInstance.stars)
addChild(lblStars)
// Score
let lblScore = SKLabelNode(fontNamed: "ChalkboardSE-Bold")
lblScore.fontSize = 60
lblScore.fontColor = SKColor.white
lblScore.position = CGPoint(x: self.size.width / 2, y: 300)
lblScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.center
lblScore.text = String(format: "%d", GameState.sharedInstance.score)
addChild(lblScore)
// High Score
let lblHighScore = SKLabelNode(fontNamed: "ChalkboardSE-Bold")
lblHighScore.fontSize = 30
lblHighScore.fontColor = SKColor.cyan
lblHighScore.position = CGPoint(x: self.size.width / 2, y: 150)
lblHighScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.center
lblHighScore.text = String(format: "High Score: %d", GameState.sharedInstance.highScore)
addChild(lblHighScore)
// Try again
let lblTryAgain = SKLabelNode(fontNamed: "ChalkboardSE-Bold")
lblTryAgain.fontSize = 30
lblTryAgain.fontColor = SKColor.white
lblTryAgain.position = CGPoint(x: self.size.width / 2, y: 50)
lblTryAgain.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.center
lblTryAgain.text = "Tap To Try Again"
lblTryAgain.isUserInteractionEnabled = true
addChild(lblTryAgain)
}
func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
// Transition back to the Game
let reveal = SKTransition.fade(withDuration: 0.5)
let gameScene = GameScene(size: self.size)
self.view!.presentScene(gameScene, transition: reveal)
}
}

touchesBegan is a override func which only works in self.viewand it will not work in other UIs
try this
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("working")
}

make sure isUserInteractionEnabled is checked and the print statement may not work. add or update sceneDidLoad and print isUserInteractionEnabled

Related

SpriteKit Fast Movement Frame Rate Drop

I've been working on a game involving fast movement in SpriteKit. I've tested and profiled the game removing multiple sections of the game and haven't been able to hold a steady 60 fps. The frame rate drop causes node movement to stutter. I decided to set up a simple program to test. With only 4 nodes on screen moving from left to right there is still a drop in frames running on iPhone 7 Plus. Is there any way to optimize fast movement in SpriteKit to hold a steady frame rate?
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ship = SKSpriteNode()
var ship2 = SKSpriteNode()
var ship3 = SKSpriteNode()
var ship4 = SKSpriteNode()
override func didMove(to view: SKView) {
ship.texture = SKTexture(imageNamed: "Spaceship")
ship.position = CGPoint(x: -300, y: 0)
ship.size = CGSize(width: 50, height: 50)
ship.setScale(1)
ship.physicsBody = SKPhysicsBody(rectangleOf: ship.size)
ship.physicsBody?.affectedByGravity = false
ship.zPosition = 2
self.addChild(ship)
ship2.texture = SKTexture(imageNamed: "Spaceship")
ship2.position = CGPoint(x: -200, y: -50)
ship2.size = CGSize(width: 50, height: 50)
ship2.setScale(1)
ship2.physicsBody = SKPhysicsBody(rectangleOf: ship.size)
ship2.physicsBody?.affectedByGravity = false
ship2.zPosition = 2
self.addChild(ship2)
ship3.texture = SKTexture(imageNamed: "Spaceship")
ship3.position = CGPoint(x: -100, y: 50)
ship3.size = CGSize(width: 50, height: 50)
ship3.setScale(1)
ship3.physicsBody = SKPhysicsBody(rectangleOf: ship.size)
ship3.physicsBody?.affectedByGravity = false
ship3.zPosition = 2
self.addChild(ship3)
ship4.texture = SKTexture(imageNamed: "Spaceship")
ship4.position = CGPoint(x: -0, y: 100)
ship4.size = CGSize(width: 50, height: 50)
ship4.setScale(1)
ship4.physicsBody = SKPhysicsBody(rectangleOf: ship.size)
ship4.physicsBody?.affectedByGravity = false
ship4.zPosition = 2
self.addChild(ship4)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
ship.position.x += 15
ship2.position.x += 15
ship3.position.x += 15
ship4.position.x += 15
if ship.position.x > 800 {
ship.position.x = -950
} else if ship2.position.x > 800 {
ship2.position.x = -900
} else if ship3.position.x > 800 {
ship3.position.x = -850
} else if ship4.position.x > 800 {
ship4.position.x = -800
}
}
}
Edit: When profiling the test program above the frame rate drops to 59 fps.

No sound without any errors

I tried to add sound when button pressed but when I press the button no sound. No mistakes in terminal.
I already tried compile on another computer, and debug on iPhone.
No sound persist.
Please help me solve this problem.
class MenuScene : SKScene {
let txtAtlas : SKTextureAtlas = SKTextureAtlas(named: "UI.atlas")
let txtAtlas2 : SKTextureAtlas = SKTextureAtlas(named: "mapbc.atlas")
let startBut = SKSpriteNode()
let tssound = SKAction.playSoundFileNamed("tssound.wav", waitForCompletion: false)
override func didMove(to view: SKView) {
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.backgroundColor = UIColor.black
let logo = SKLabelNode(fontNamed: "Helvetica")
logo.text = "Train Control"
logo.position = CGPoint(x: 0, y: 100)
logo.fontSize = 60
logo.fontColor = UIColor.green
self.addChild(logo)
startBut.texture = txtAtlas.textureNamed("stbut.png")
startBut.size = CGSize(width: 230, height: 85)
startBut.position = CGPoint(x: 0, y: -20)
startBut.name = "StartBtn"
self.addChild(startBut)
let startText = SKLabelNode(fontNamed: "AvenirNext-HeavyItalic")
startText.text = "Start Manage!"
startText.verticalAlignmentMode = .center
startText.position = CGPoint(x: 0, y: 2)
startText.fontSize = 30
startText.name = "StartBtn"
startBut.addChild(startText)
let bcmap = SKSpriteNode()
bcmap.texture = txtAtlas2.textureNamed("mapbc.png")
bcmap.zPosition = -1
bcmap.size = CGSize(width: 400.0, height: 350.0)
bcmap.position = CGPoint(x: -100, y: 0)
bcmap.alpha = 0.7
self.addChild(bcmap)
let stbutaction = SKAction.sequence([SKAction.fadeAlpha(to: 0.7, duration: 0.9),
SKAction.fadeAlpha(to: 1.0, duration: 0.9)])
startBut.run(SKAction.repeatForever(stbutaction))
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches) {
let location = touch.location(in: self)
let nodeTouched = atPoint(location)
if nodeTouched.name == "StartBtn" {
// Player touched the start text or button node
self.view?.presentScene(GameScene(size: self.size))
self.run(tssound)
}
}
}
}
You should probably initialise and run your sound inside GameScene e.g. when the scene loads. You are trying to run the sound on MenuScene which doesn't exist after you have transitioned to GameScene

Is there a way that the for loop can always check a value of variable outside this loop in swift?

I am trying to create nodes through for loop in sprite kit but I want every time the "for loop" wants to create a new node to check if a value outside the loop if it is changed( depending on this value the node created).
what I want to do is in CreatSquares function
Sorry for my bad English
import SpriteKit
import GameplayKit
var Score = 0
class GameScene: SKScene {
let SquareSide = 100
var touchedNode = SKNode()
var touchLocation = CGPoint()
let ScoreLabel = SKLabelNode()
override func didMove(to view: SKView) {
CreatSquares()
}
func CreatSquares(){
for _ in 0...100{
/*===========================================================================================
(((((((( I want here while creating nodes if the score is equal (let's say) to 20 ->>>> change in SquareSide or change anything in square's properties ))))))))
The problem is that the 100 square created together
================================================================================================
*/
let square = SKShapeNode(rect: CGRect(x: Int(arc4random_uniform(UInt32(self.frame.width))), y: Int(arc4random_uniform(UInt32(self.frame.height))), width: SquareSide, height: SquareSide))
if Score <= 10{
square.fillColor = UIColor.orange}
else{
square.fillColor = UIColor.blue
}
square.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: square.frame.width, height: square.frame.height), center: CGPoint(x: square.position.x, y: square.position.y))
square.physicsBody?.affectedByGravity = false
square.physicsBody?.allowsRotation = false
square.physicsBody?.categoryBitMask = 0
square.name = "square"
self.addChild(square)
}
}
func CreatScoreLabel(){
let ScoreLabel = SKLabelNode()
ScoreLabel.text = "Your Score is:\(Score)"
ScoreLabel.position = CGPoint(x: self.frame.width/2, y: self.frame.height - 50)
ScoreLabel.color = UIColor.white
self.addChild(ScoreLabel)
}
func updatScore(){
ScoreLabel.text = "Your Score is:\(Score)"
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
touchLocation = touch.location(in: self)
touchedNode = self.atPoint(touchLocation)
if touchedNode.name == "square"{
Score += 1
touchedNode.removeFromParent()
}
}
}
override func update(_ currentTime: TimeInterval) {
updatScore()
}
}

Transition between scenes is slow on first time

I tried to move between GameScene to SettingsScene and is works perfect expect first time.
In first time the game is "stuck" for 1-3 seconds and presented the SettingsScene without the transition, after first time the transition and game works perfect.
The back (between SettingsScene to GameScene) works good also in first time.
The transition code between GameScene to SettingsScene
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
self.removeAllActions()
// Get the location of the touch in this scene
let location = touch.location(in: self)
// Check if the location of the touch is within the button's bounds
//Play Button
if PlayButton.contains(location) {
bannerView.isHidden = true
let newScene = PlayScene(size: (view?.bounds.size)!)
newScene.scaleMode = .aspectFill
let reveal = SKTransition.crossFade(withDuration: 1.0)
self.view?.presentScene(newScene, transition: reveal)
//Settings Button
}else if SettingsButton.contains(location) {
bannerView.isHidden = true
settingsscene?.scaleMode = .resizeFill
let reveal = SKTransition.push(with: SKTransitionDirection.down, duration: 0.7)
self.view?.presentScene(settingsscene!, transition: reveal)
}
}
}
GameScene:
var settingsscene: SKScene?
override func didMove(to view: SKView) {
/* Setup your scene here */
//
let size = self.size
DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async {
[weak self] () -> Void in
self?.settingsscene = SettingsScene(size: (view.bounds.size))
}
SettingsScene:
override func didMove(to view: SKView) {
//Settings Background
settingsBackground.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2)
settingsBackground.zPosition = -1
}
override init(size: CGSize) {
super.init()
//Settings Label
settingsLabel.text = "Settings"
settingsLabel.fontName = "AvenirNext-Bold"
settingsLabel.fontColor = UIColor.white
settingsLabel.horizontalAlignmentMode = .center
settingsLabel.verticalAlignmentMode = .center
adjustLabelFontSizeToFitRect(labelNode: settingsLabel, rect: CGRect(x:self.frame.midX, y:self.frame.midY, width: 180, height: 110), center: true)
settingsLabel.setScale(self.frame.width * 0.001)
settingsLabel.position = CGPoint(x: self.frame.midX, y: self.frame.maxY - settingsLabel.frame.height)
settingsLabel.zPosition = 1
addChild(settingsLabel)
/**** Labels ****/
//Sounds Label
soundsLabel.text = "Sounds"
soundsLabel.fontName = "AvenirNext"
soundsLabel.fontColor = UIColor.white
adjustLabelFontSizeToFitRect(labelNode: soundsLabel, rect: CGRect(x:self.frame.midX, y:settingsLabel.position.y - 20, width:110, height: 70), center: true)
soundsLabel.setScale(self.frame.width * 0.001)
soundsLabel.zPosition = 1
//Rate Label
rateLabel.text = "Rate Game"
rateLabel.fontName = "AvenirNext"
rateLabel.fontColor = UIColor.white
adjustLabelFontSizeToFitRect(labelNode: rateLabel, rect: CGRect(x:self.frame.midX, y:50, width:120, height: 110), center: true)
rateLabel.setScale(frame.width * 0.001)
rateLabel.zPosition = 1
//Twitter Label (Follow me)
twiterLabel.text = "Follow me"
twiterLabel.fontName = "AvenirNext"
twiterLabel.fontColor = UIColor.white
adjustLabelFontSizeToFitRect(labelNode: twiterLabel, rect: CGRect(x:self.frame.midX, y:10, width:17, height: 110), center: true)
twiterLabel.setScale(frame.width * 0.001)
twiterLabel.zPosition = 1
//iAP Label (Remove Ads)
iapLabel.text = "Remove Ads"
iapLabel.fontName = "AvenirNext"
iapLabel.fontColor = UIColor.white
adjustLabelFontSizeToFitRect(labelNode: iapLabel, rect: CGRect(x:self.frame.midX, y:70, width:40, height: 110), center: true)
iapLabel.setScale(frame.width * 0.001)
iapLabel.zPosition = 1
//Restore iAP Label
restoreLabel.text = "Restore Purchase"
restoreLabel.fontName = "AvenirNext"
restoreLabel.fontColor = UIColor.white
adjustLabelFontSizeToFitRect(labelNode: restoreLabel, rect: CGRect(x:self.frame.midX, y:308, width:102, height: 110), center: true)
restoreLabel.setScale(frame.width * 0.001)
restoreLabel.zPosition = 1
//About Label
aboutLabel.text = "Restore Purchase"
aboutLabel.fontName = "AvenirNext"
aboutLabel.fontColor = UIColor.white
adjustLabelFontSizeToFitRect(labelNode: aboutLabel, rect: CGRect(x:self.frame.midX, y:18, width:123, height: 312), center: true)
aboutLabel.setScale(frame.width * 0.001)
aboutLabel.zPosition = 1
//Back Button
backButton.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
backButton.zPosition = 1
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func SettingsSetup() {
addChild(settingsBackground)
addChild(myLabels)
addChild(backButton)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch:AnyObject in touches {
let location = touch.location(in:self)
//BackButton Action
if backButton.contains(location) {
let newScene = GameScene(fileNamed: "GameScene")
newScene?.scaleMode = .aspectFill
let reveal = SKTransition.push(with: SKTransitionDirection.up, duration: 0.7)
self.view?.presentScene(newScene!, transition: reveal)
}
}
}
How can I fix it?

Create HUD in Sprite Kit that remains static on screen

I'm trying to create a static HUD that stays at the top of the screen throughout the game in a jump game from this tutorial. I'm still new to Swift, so maybe it's a convention I don't see easily:
http://www.raywenderlich.com/87232/make-game-like-mega-jump-sprite-kit-swift-part-2
In the tutorial, he puts the HUD in the override init(size: CGSize) function:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(size: CGSize) {
super.init(size: size)
...
// Build the HUD
// HUD
hudNode = SKNode()
hudNode.zPosition = 1000
addChild(hudNode)
// Coins
// 1
let coin = SKSpriteNode(imageNamed: "powerup05_1")
coin.position = CGPoint(x: 300, y: self.size.height-100)
coin.zPosition = 1000
hudNode.addChild(coin)
// 2
lblCoins = SKLabelNode(fontNamed: "ChalkboardSE-Bold")
lblCoins.fontSize = 70
lblCoins.fontColor = SKColor.whiteColor()
lblCoins.position = CGPoint(x: 375, y: self.size.height-100)
lblCoins.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Left
lblCoins.zPosition = 1000
// 3
lblCoins.text = String(format: "X %d", GameState.sharedInstance.coins)
hudNode.addChild(lblCoins)
// Score
// 4
lblScore = SKLabelNode(fontNamed: "ChalkboardSE-Bold")
lblScore.fontSize = 70
lblScore.fontColor = SKColor.whiteColor()
lblScore.position = CGPoint(x: self.size.width-325, y: self.size.height-100)
lblScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Right
lblScore.zPosition = 1000
// 5
lblScore.text = "0"
hudNode.addChild(lblScore)
}
However, if I try to use this function in my game I get an error:
Argument labels '(fileNamed:)' do not match any available overloads
In this function:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
switch gameState.currentState {
case is WaitingForTap:
gameState.enterState(WaitingForBomb)
// Switch to playing state
self.runAction(SKAction.waitForDuration(2.0),
completion:{
self.gameState.enterState(Playing)
})
case is GameOver:
// Error! Argument labels '(fileNamed:)' do not match any available overloads
let newScene = GameScene(fileNamed:"GameScene")
newScene!.scaleMode = .AspectFill
let reveal = SKTransition.flipHorizontalWithDuration(0.5)
self.view?.presentScene(newScene!, transition: reveal)
default:
break
}
}
So I've resorted to putting it in the override func didMoveToView(view: SKView), but the HUD moves once the player jumps up:
override func didMoveToView(view: SKView) {
....
// Build the HUD
// HUD
hudNode = SKNode()
hudNode.zPosition = 1000
addChild(hudNode)
// Coins
// 1
let coin = SKSpriteNode(imageNamed: "powerup05_1")
coin.position = CGPoint(x: 300, y: self.size.height-100)
coin.zPosition = 1000
hudNode.addChild(coin)
// 2
lblCoins = SKLabelNode(fontNamed: "ChalkboardSE-Bold")
lblCoins.fontSize = 70
lblCoins.fontColor = SKColor.whiteColor()
lblCoins.position = CGPoint(x: 375, y: self.size.height-100)
lblCoins.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Left
lblCoins.zPosition = 1000
// 3
lblCoins.text = String(format: "X %d", GameState.sharedInstance.coins)
hudNode.addChild(lblCoins)
// Score
// 4
lblScore = SKLabelNode(fontNamed: "ChalkboardSE-Bold")
lblScore.fontSize = 70
lblScore.fontColor = SKColor.whiteColor()
lblScore.position = CGPoint(x: self.size.width-325, y: self.size.height-100)
lblScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Right
lblScore.zPosition = 1000
// 5
lblScore.text = "0"
hudNode.addChild(lblScore)
}
Adding your hudNode to the cameraNode makes the HUD move together with the camera so that it will look static on screen. That is to change addChild(hudNode) to cameraNode.addChild(hudNode).
Then use convert(_:to:) to change the point from the current scene coordinate to the cameraNode coordinate. That will set HUD's position in the new coordinate with just a little modification. For instance, change coin.position like this:
coin.position = convert(CGPoint(x: 300, y: self.size.height-100), to: cameraNode)
Do the same thing to the other HUD:
lblCoins.position = convert(CGPoint(x: 375, y: self.size.height-100), to: cameraNode)
lblScore.position = convert(CGPoint(x: self.size.width-325, y: self.size.height-100), to: cameraNode)
The result after those 4 lines modification:

Resources