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
Related
I am trying to play a sound when the UIButton: "StartButton" is clicked. However, I get an error that reads:
Argument type 'CGPoint' does not conform to expected type 'UIFocusEnvironment'
I created the button as below and assigned a CGRect poisiton to it, and I am trying to use the touchesBeagn function to detect the location of the touch and determine if it matches the location of the Button and if so call playButtonSound() function.
This is my code in the MainMenu.swift file:
// MainMenuScene.swift
import Foundation
import SpriteKit
import AVFoundation
let startButton:UIButton = UIButton(type: UIButtonType.roundedRect)
class MainMenuScene: SKScene
{
var buttonSound = AVAudioPlayer()
override func didMove(to view: SKView) {
let background = SKSpriteNode(imageNamed: "background")
background.size = self.size
background.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
background.zPosition = 0
self.addChild(background)
let menuLabel1 = SKLabelNode(fontNamed: "The Bold Font")
menuLabel1.text = "Hit"
menuLabel1.position = CGPoint(x: self.size.width * 0.45, y: self.size.height * 0.78)
menuLabel1.fontSize = 300
menuLabel1.fontColor = UIColor.yellow
menuLabel1.colorBlendFactor = 1
menuLabel1.zPosition = 1
self.addChild(menuLabel1)
let menuLabel2 = SKLabelNode(fontNamed: "The Bold Font")
menuLabel2.text = "&"
menuLabel2.position = CGPoint(x: self.size.width * 0.55, y: self.size.height * 0.64)
menuLabel2.fontSize = 350
menuLabel2.fontColor = UIColor.red
menuLabel2.colorBlendFactor = 1
menuLabel2.zPosition = 1
self.addChild(menuLabel2)
let menuLabel3 = SKLabelNode(fontNamed: "The Bold Font")
menuLabel3.text = "Go"
menuLabel3.position = CGPoint(x: self.size.width * 0.60, y: self.size.height * 0.52)
menuLabel3.fontSize = 300
menuLabel3.fontColor = UIColor.yellow
menuLabel3.colorBlendFactor = 1
menuLabel3.zPosition = 1
self.addChild(menuLabel3)
startButton.frame = CGRect(x: (self.view?.center.x)! * 0.5 , y: (self.view?.center.y)! * 1.5 , width: 200, height: 50)
startButton.backgroundColor = .red
startButton.setTitleColor(.white, for: .normal)
startButton.titleLabel?.adjustsFontSizeToFitWidth = true
startButton.layer.cornerRadius = 10
startButton.clipsToBounds = true
startButton.setTitle("Start Game", for: .normal)
startButton.titleLabel!.font = UIFont(name: "The Bold Font", size: 60)
startButton.addTarget(self, action:#selector(self.startButtonClicked), for: .touchUpInside)
self.view?.addSubview(startButton)
}
#objc func startButtonClicked() {
let sceneToMoveTo = GameScene(size: self.size)
sceneToMoveTo.scaleMode = self.scaleMode
let myTransition = SKTransition.reveal(with: .right , duration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: myTransition)
}
#objc func playButtonSound(filename: String) {
let url = Bundle.main.url(forResource: "button.mp3" , withExtension: nil)
guard let newURL = url else {
print("Could not find file: \(filename)")
return
}
do {
buttonSound = try AVAudioPlayer(contentsOf: newURL)
buttonSound.numberOfLoops = -1
buttonSound.prepareToPlay()
buttonSound.setVolume(0.50, fadeDuration: 0.1)
buttonSound.play()
} catch let error as NSError {
print(error.description)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
var pointOfTouch = touch.location(in: self)
if startButton.contains(pointOfTouch)
{
playButtonSound(filename: "button.mp3")
}
}
}
}
What is the reason for the error?
The problem is that you are calling the wrong contains method.
You are calling the method on UIButton, which has this signature:
public func contains(_ environment: UIFocusEnvironment) -> Bool
What you probably meant to call was the method on the button's frame:
if startButton.frame.contains(pointOfTouch)
You may want to read the docs to make sure that using the frame is what you want.
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
I have added a share menu to my game, when the game is over the game over pop up appears with a share menu. when i press anywhere on the screen the share menu pops up and the game goes back to the beginning prompting the player to Tap to play again. Then when the player taps on the screen the share menu pops up again which makes the game unplayable after the first play through. I think i need to set the share menu to pop up only when SKSpriteNode for the share button is pressed, if the player taps anywhere else on the screen the game should just reset. Would be grateful if you could take a look at code and see where i am going wrong.
import SpriteKit
import GameplayKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var shareButton = SKSpriteNode()
var santa = SKSpriteNode()
var bg = SKSpriteNode()
var scoreLabel = SKLabelNode()
var tapToPlayLabel = SKLabelNode()
var score = 0
var gameOverScreen = SKSpriteNode()
var timer = Timer()
enum ColliderType: UInt32 {
case santa = 1
case Object = 2
case Gap = 4
}
enum ButtonName: String {
case play
case share
}
var gameOver = false
func makeBlocks() {
let moveBlocks = SKAction.move(by: CGVector(dx: -2 * self.frame.width, dy: 0), duration: TimeInterval(self.frame.width / 100))
let gapHeight = santa.size.height * 4
let movementAmount = arc4random() % UInt32(self.frame.height / 2)
let blockOffset = CGFloat(movementAmount) - self.frame.height / 4
let blockTexture = SKTexture(imageNamed: "block1.png")
let block1 = SKSpriteNode(texture: blockTexture)
block1.position = CGPoint(x: self.frame.midX + self.frame.width, y: self.frame.midY + blockTexture.size().height / 2 + gapHeight / 2 + blockOffset)
block1.run(moveBlocks)
block1.physicsBody = SKPhysicsBody(rectangleOf: blockTexture.size())
block1.physicsBody!.isDynamic = false
block1.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
block1.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
block1.physicsBody!.collisionBitMask = ColliderType.Object.rawValue
block1.zPosition = -2
self.addChild(block1)
let block2Texture = SKTexture(imageNamed: "block2.png")
let block2 = SKSpriteNode(texture: block2Texture)
block2.position = CGPoint(x: self.frame.midX + self.frame.width, y: self.frame.midY - block2Texture.size().height / 2 - gapHeight / 2 + blockOffset)
block2.run(moveBlocks)
block2.physicsBody = SKPhysicsBody(rectangleOf: blockTexture.size())
block2.physicsBody!.isDynamic = false
block2.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
block2.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
block2.physicsBody!.collisionBitMask = ColliderType.Object.rawValue
block2.zPosition = -2
self.addChild(block2)
let gap = SKNode()
gap.position = CGPoint(x: self.frame.midX + self.frame.width, y: self.frame.midY + blockOffset)
gap.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: blockTexture.size().width, height: gapHeight))
gap.physicsBody!.isDynamic = false
gap.run(moveBlocks)
gap.physicsBody!.contactTestBitMask = ColliderType.santa.rawValue
gap.physicsBody!.categoryBitMask = ColliderType.Gap.rawValue
gap.physicsBody!.collisionBitMask = ColliderType.Gap.rawValue
self.addChild(gap)
}
func didBegin(_ contact: SKPhysicsContact) {
if gameOver == false {
if contact.bodyA.categoryBitMask == ColliderType.Gap.rawValue || contact.bodyB.categoryBitMask == ColliderType.Gap.rawValue {
score += 1
scoreLabel.text = String(score)
} else {
self.speed = 0
gameOver = true
timer.invalidate()
let gameOverScreenTexture = SKTexture(imageNamed: "GameOverPopup.jpg")
var j: CGFloat = 0
gameOverScreen = SKSpriteNode(texture: gameOverScreenTexture, size: CGSize(width: 600, height: 600))
gameOverScreen.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
gameOverScreen.size.height = self.frame.height / 3
gameOverScreen.zPosition = -1
self.addChild(gameOverScreen)
//share button
let shareButtonTexture = SKTexture(imageNamed: "shareButton.png")
var k: CGFloat = 0
shareButton = SKSpriteNode(texture: shareButtonTexture, size: CGSize(width: 500, height: 100))
shareButton.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
shareButton.size.height = self.frame.height / 10
shareButton.name = "shareButton"
shareButton.zPosition = 0
self.addChild(shareButton)
}
}
}
func openShareMenu(value: String, image: UIImage?) {
guard let view = view else { return }
// Activity items
var activityItems = [AnyObject]()
// Text
let text = "Can you beat my score "
activityItems.append(text as AnyObject)
// Add image if valid
if let image = image {
activityItems.append(image)
}
// Activity controller
let activityController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
// Excluded activity types
activityController.excludedActivityTypes = [
UIActivityType.airDrop,
UIActivityType.print,
UIActivityType.assignToContact,
UIActivityType.addToReadingList,
]
// Present
view.window?.rootViewController?.present(activityController, animated: true)
}
override func didMove(to view: SKView) {
addChild(shareButton)
self.physicsWorld.contactDelegate = self
setupGame()
}
func setupGame() {
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(self.makeBlocks), userInfo: nil, repeats: true)
let bgTexture = SKTexture(imageNamed: "bg.png")
let moveBGAnimation = SKAction.move(by: CGVector(dx: -bgTexture.size().width, dy: 0), duration: 7)
let shiftBGAnimation = SKAction.move(by: CGVector(dx: bgTexture.size().width, dy: 0), duration: 0)
let moveBGForever = SKAction.repeatForever(SKAction.sequence([moveBGAnimation, shiftBGAnimation]))
var i: CGFloat = 0
while i < 3 {
bg = SKSpriteNode(texture: bgTexture)
bg.position = CGPoint(x: bgTexture.size().width * i, y: self.frame.midY)
bg.size.height = self.frame.height
bg.run(moveBGForever)
bg.zPosition = -3
self.addChild(bg)
i += 1
}
let santaTexture = SKTexture(imageNamed: "santa1.png")
let santaTexture2 = SKTexture(imageNamed: "santa2.png")
let animation = SKAction.animate(with: [santaTexture, santaTexture2], timePerFrame: 0.1)
let makeSantaMove = SKAction.repeatForever(animation)
santa = SKSpriteNode(texture: santaTexture)
santa.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
santa.run(makeSantaMove)
santa.physicsBody = SKPhysicsBody(circleOfRadius: santaTexture.size().height / 2)
santa.physicsBody!.isDynamic = false
santa.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
santa.physicsBody!.categoryBitMask = ColliderType.santa.rawValue
santa.physicsBody!.collisionBitMask = ColliderType.santa.rawValue
self.addChild(santa)
let ground = SKNode()
ground.position = CGPoint(x: self.frame.midX, y: -self.frame.height / 2)
ground.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: self.frame.width, height: 1))
ground.physicsBody!.isDynamic = false
ground.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
ground.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
ground.physicsBody!.collisionBitMask = ColliderType.Object.rawValue
self.addChild(ground)
scoreLabel.fontName = "Helvetica"
scoreLabel.fontSize = 60
scoreLabel.text = "0"
scoreLabel.position = CGPoint(x: self.frame.midX, y: self.frame.height / 2 - 220)
self.addChild(scoreLabel)
tapToPlayLabel.fontName = "Helvetica"
tapToPlayLabel.fontSize = 70
tapToPlayLabel.text = "Tap to Play!"
tapToPlayLabel.position = CGPoint(x: self.frame.midX, y: self.frame.height / 2 - 500)
self.addChild(tapToPlayLabel)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if gameOver == false {
tapToPlayLabel.isHidden = true
santa.physicsBody!.isDynamic = true
santa.physicsBody!.velocity = CGVector(dx: 0, dy: 0)
santa.physicsBody!.applyImpulse(CGVector(dx: 0, dy: 320))
} else {
tapToPlayLabel.isHidden = false
gameOver = false
score = 0
self.speed = 1
self.removeAllChildren()
setupGame()
}
if let name = shareButton.name {
if name == "shareButton" {
openShareMenu(value: "\(self.score)", image: nil)
}
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
You are calling the touches method wrong. You are not using the name of the touched node to see if it is the share button. You merely assign a property (if let name = ...) and see if its the share button. You need to compare with the name of the actual node that is touched. You are also running your gameOver code anytime touchesBegan fires, you need to differentiate.
Try this
override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self) // get location of touch
let nodeTouched = atPoint(location) // get touched node
// Pressed button
if let nodeName = nodeTouched.name {
switch nodeName {
case ButtonName.share.rawValue:
openShareMenu(value: "\(self.score)", image: nil)
return // return early if share button is pressed so your gameOver code below etc doesnt fire.
default:
break
}
}
// Did not press button, usual code
if gameOver == false {..... }
}
}
Hope this helps
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?
I am in sprite kit making a game in swift. (I am new to swift) And I would like to transition a scene when a node is pressed. I looked it up and the proper way to transition is
let transition = SKTransition.revealWithDirection(SKTransitionDirection.Down, duration: 1.0)
let scene = GameScene(size: self.scene.size)
scene.scaleMode = SKSceneScaleMode.AspectFill
self.scene.view.presentScene(scene, transition: transition)
But when I am programming it doesn't like the self.scene.size and puts a question mark on scene. Here is my code
let playView = PlayScene(size: self.scene?.size)
And I don't know how to fix this. Any suggestions? (Or it might be just a simple error in my part because I am new to swift.
Here is more of my code
In the GameScene.swift File
class GameScene: SKScene {
var playButton = SKSpriteNode(imageNamed: "Play")
var levelsButton = SKSpriteNode(imageNamed: "Levels")
var optionsButton = SKSpriteNode(imageNamed: "Options")
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let myLabel = SKLabelNode(fontNamed:"Helvetica-Light")
myLabel.text = "Mini Golf";
myLabel.fontSize = 30;
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:525);
println(size.height)
println(size.width)
let backgroundNode = SKSpriteNode(imageNamed: "Background")
backgroundNode.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame));
playButton.position = CGPoint(x: CGRectGetMidX(self.frame), y: 360)
levelsButton.position = CGPoint(x: CGRectGetMidX(self.frame), y: 295)
optionsButton.position = CGPoint(x: CGRectGetMidX(self.frame), y: 230)
self.addChild(backgroundNode)
self.addChild(playButton)
self.addChild(levelsButton)
self.addChild(optionsButton)
self.addChild(myLabel)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
super.touchesBegan(touches, withEvent: event)
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
//let touchedNode = nodeAtPoint(Location)
//touchedNode.postiion =location
let transitionToPlayScene = SKTransition.revealWithDirection(SKTransitionDirection.Down, duration: 1.0)
if CGRectContainsPoint(playButton.frame, location) {
let playView = PlayScene(size: self.scene?.size)
}
}
}
This is the code in the PlayScene.swift file
import Foundation
import UIKit
import SpriteKit
private let WALL_CATEGORY: UInt32 = 0x1 << 0
private let HOLE_CATEGORY: UInt32 = 0x1 << 1
private let GOLF_CLUB_CATEGORY: UInt32 = 0x1 << 2
private let BALL_CATEGORY: UInt32 = 0x1 << 4
private let DECORATION_BORDER_CATEGORY: UInt32 = 0x1 << 5
class PlayScene: SKScene, SKPhysicsContactDelegate {
var ballNode = SKSpriteNode(imageNamed: "Ball")
var flag = SKSpriteNode(imageNamed: "Flag")
var club = SKSpriteNode(imageNamed: "Golf Club")
var tee = SKSpriteNode(imageNamed: "Tee")
var hole = SKSpriteNode(imageNamed: "Hole")
var decoBorder1 = SKSpriteNode(imageNamed: "Border 1")
var decoBorder2 = SKSpriteNode(imageNamed: "Border 2")
override func didMoveToView(view: SKView) {
//Setting up the view's physics
let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame);
self.physicsBody = borderBody
self.physicsBody?.friction = 0.0
self.physicsBody?.categoryBitMask = WALL_CATEGORY
self.physicsWorld.gravity = CGVectorMake(0.0 ,0.0);
self.physicsWorld.contactDelegate = self
//Setting the ball's properties
ballNode.position = CGPoint(x: CGRectGetMidX(self.frame), y: 100);
ballNode.physicsBody = SKPhysicsBody(rectangleOfSize: ballNode.frame.size);
ballNode.physicsBody?.categoryBitMask = BALL_CATEGORY
ballNode.physicsBody?.mass = 50.0
ballNode.physicsBody?.dynamic = true
ballNode.physicsBody?.allowsRotation = true
self.addChild(ballNode)
//Setting the club's properties
club.position = CGPoint(x: CGRectGetMidX(self.frame)-20, y: 75);
club.physicsBody = SKPhysicsBody(rectangleOfSize: self.frame.size);
club.physicsBody?.categoryBitMask = GOLF_CLUB_CATEGORY
club.physicsBody?.mass = 150.0
club.physicsBody?.dynamic = true
club.physicsBody?.allowsRotation = false
self.addChild(club)
//Setting the Tee's properties
tee.position = CGPoint(x: CGRectGetMidX(self.frame), y: 70);
//self.addChild(tee)
//Setting the decoration border nodes
decoBorder1.position = CGPoint(x: CGRectGetMinX(self.frame), y: 500);
decoBorder2.position = CGPoint(x: CGRectGetMaxX(self.frame), y:500);
decoBorder1.physicsBody = SKPhysicsBody(rectangleOfSize: self.frame.size);
decoBorder2.physicsBody = SKPhysicsBody(rectangleOfSize: self.frame.size);
decoBorder1.physicsBody?.categoryBitMask = DECORATION_BORDER_CATEGORY
decoBorder1.physicsBody?.dynamic = false;
decoBorder1.physicsBody?.allowsRotation = false
decoBorder2.physicsBody?.categoryBitMask = DECORATION_BORDER_CATEGORY
decoBorder2.physicsBody?.dynamic = false;
decoBorder2.physicsBody?.allowsRotation = false
//self.addChild(decoBorder1)
//self.addChild(decoBorder2))
//Setting the Hole properties
hole.position = CGPoint(x: CGRectGetMidX(self.frame), y: 550);
hole.physicsBody = SKPhysicsBody(rectangleOfSize: self.frame.size);
hole.physicsBody?.categoryBitMask = HOLE_CATEGORY
hole.physicsBody?.dynamic = false
hole.physicsBody?.allowsRotation = false
//self.addChild(hole)
}
The question mark comes from optional chaining because your scene property must have been declared like this SKScene?. This isn't a problem though, it just means that if your scene is nil, it won't get the size property.
The real problem is probably this line:
self.scene.view.presentScene(scene, transition: transition)
Reason being, your scene probably doesn't have a view before it's presented.
You probably wanted something like this:
(self.view as SKView).presentScene(scene, transition: transition)
You'll notice I said probably a lot. I'm only speculating on the problem because I don't see enough code, but I appreciate the effort to try and narrow down your problem. You should post more though because it may be somewhere else.
Edit
Try replacing this:
let transitionToPlayScene = SKTransition.revealWithDirection(SKTransitionDirection.Down, duration: 1.0)
if CGRectContainsPoint(playButton.frame, location) {
let playView = PlayScene(size: self.scene?.size)
}
With this
if CGRectContainsPoint(playButton.frame, location) {
let transitionToPlayScene = SKTransition.revealWithDirection(SKTransitionDirection.Down, duration: 1.0)
let nextScene = PlayScene(size: self.size)
self.view!.presentScene(nextScene, transition: transitionToPlayScene)
}
What ended up working for me was this:
let transition = SKTransition.revealWithDirection(SKTransitionDirection.Down, duration: 1.0)
let scene = GameScene(size: (self.scene as SKScene!).size)
scene.scaleMode = SKSceneScaleMode.AspectFill
(self.view as SKView!).presentScene(scene, transition: transition)