Moving between scenes crashes game with EXC_BAD_ACCESS error - swift

First I would like to say that my game moves between scenes just fine (The first time). It starts with the menu scene that right now just has a button that says play game.
let play = UIButton.buttonWithType(UIButtonType.System) as UIButton
play.frame = CGRect(x: size.width * 0.5, y: size.height * 0.4, width: 100, height: 100)
play.setTitle("PLAY GAME", forState: UIControlState.Normal)
play.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
play.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
self.view?.addSubview(play)
func buttonAction(sender:UIButton!)
{
var gameScene = GameScene(size: self.frame.size)
var transition = SKTransition.flipVerticalWithDuration(1.0)
gameScene.scaleMode = SKSceneScaleMode.AspectFill
let skView = view as SKView!
skView.presentScene(gameScene, transition: transition)
play.removeFromSuperview()
}
This button takes you to the other scene where you play the game. When you lose this function is called.
func gameOver(){
let alert = UIAlertView()
alert.title = "Game Over"
alert.message = "Score: " + String(score)
alert.addButtonWithTitle("Okay")
alert.show()
var gameStartScene = GameStartScene(size: self.frame.size)
var transition = SKTransition.flipVerticalWithDuration(1.0)
gameStartScene.scaleMode = SKSceneScaleMode.AspectFill
let skView = view as SKView!
skView.presentScene(gameStartScene, transition: transition)
}
This take you back to the first sceen with the play button but when you press the "play game" button again for the second time the game crashes with the EXC_BAD_ACCESS error. Any ideas??

Related

How would I call a scene by pressing a button on swift playground

how would I make this button open the GameScene1 when clicked?
This is my code so far.
class GameScene1: SKScene{
override func didMove(to view: SKView){
}
}
let scene1 = GameScene1(size: CGSize(width: 400, height: 640))
scene1.scaleMode = .aspectFill
scene1.backgroundColor = .blue
let view2 = SKView(frame: CGRect(x:0, y:0, width: scene1.size.width, height: scene1.size.height
view2.presentScene(scene)
PlaygroundPage.current.liveView = view2
class Receiver{
#objc func buttonClicked(){
}
}
let view1 = UIView()
let receiver = Receiver()
let button = UIButton(frame: CGRect(x:10, y:10, width:100, height:50))
button.setTitle("start", for: .normal)
button.addTarget(receiver, action: #selector(Receiver.buttonClicked), for: .touchUpInside)
view.addSubview(button)
I have no idea how to do this.
Okay, I don't have a lot of experience with SKScene's, but this is what I would do. You really only need one SKView in your playground, which you could store as a static let inside a file with game variables. You could then create different scenes, for instance one for the menu, one for the first level, second level etc.
The following code creates a button and gives it an action. The action creates a constant called scene, which is the scene you want to move to next. Then you just call presentScene() with the scene, and a SKTransition, like the one below, which is simply a 2.5 second sliding animation from the right.
ButtonNode class, which is simply a node that acts as a button, which you can add to your scene.
class ButtonNode: SKSpriteNode {
var action: ((ButtonNode) -> Void)?
var isSelected: Bool = false {
didSet {
alpha = isSelected ? 0.8 : 1
}
}
required init(coder: NSCoder) {
fatalError("NSCoding not supported")
}
init(texture: SKTexture, size: CGSize) {
super.init(texture: texture, color: SKColor.white, size: size)
isUserInteractionEnabled = true
}
override func touchesBegan(with event: NSEvent) {
action?(self)
}
override func mouseDown(with event: NSEvent) {
action?(self)
}
}
Creating the button and giving it the action to move to a next scene. This can be done in any SKScene class.
startButton = ButtonNode(texture: SKTexture(imageNamed: "start-button"), size: CGSize(width: 184, height: 72))
startButton.position = CGPoint(x: 0.0, y: 0.0)
startButton.action = { (button) in
if let scene = IntroCutScene(fileNamed: "IntroCutScene") {
// Set the scale mode to scale to fit the window
self.scene!.scaleMode = .aspectFill
// Present the scene
GameVariables.sceneView.presentScene(scene, transition: SKTransition.moveIn(with: SKTransitionDirection.right, duration: 2.5))
}
}
self.addChild(startButton)

Programatically added UIButton doesn't go away after switching scenes

I'm using a game app template in Swift 3 and when I transition from my 'start' screen to my 'Game' scene, the button from the 'start' screen doesn't go away. I read other people posts similar to this but nothing helped. My button is a programatically added uibutton with a uibezierpath rounded rectangle behind the button to make it look nice. The problem is, it(the button, and the UIBezierpath) won't go away when I change scenes - it's in the exact same spot as the 'start' screen.
My Button code with the UIBezierpath:
let playAgain = UIButton()
playAgain.frame = CGRect(x: 225, y: 247, width: 115, height: 36)
playAgain.backgroundColor = SKColor.lightGray
playAgain.setTitle("Play", for: .normal)
playAgain.setTitleColor(.black, for: .normal)
self.view?.addSubview(playAgain)
playAgain.addTarget(self, action: #selector(playAgainTapped(_:)), for: .touchUpInside)
//now for the bezierpath/ rounded rect
//let doYourPath = UIBezierPath(rect: CGRect(x: 20, y: 20, width: 100, height: 36))
//this also works
let roundRect = UIBezierPath(roundedRect: CGRect(x: 218, y: 240, width: 130, height: 50), cornerRadius: 18)
let layer = CAShapeLayer()
layer.path = roundRect.cgPath
layer.strokeColor = UIColor.black.cgColor
layer.fillColor = UIColor.lightGray.cgColor
self.view?.layer.addSublayer(layer)
func playAgainTapped(_ sender: Any?) -> Void {
print("***********")
backToGame()
}
Switch scenes code:
func backToGame(){
removeAllChildren()
run(SKAction.sequence([
SKAction.wait(forDuration: 3.0),
SKAction.run() {
// 5
let reveal = SKTransition.flipHorizontal(withDuration: 0.5)
let scene = GameScene(size: self.size)
self.view?.presentScene(scene, transition:reveal)
}
]))
}
Any ideas?
You are presenting the scene on the same view as the button's superview.
Since the scene is independent from the views that are on the scene, your button will remain untouched, so you should explicitly remove the button if you want it to be removed.
Declare the button and the rounded rectangle globally and remove them from their superview/superlayer in backToGame.
let playAgain = UIButton()
let layer = CAShapeLayer()
func backToGame(){
removeAllChildren()
playAgain.removeFromSuperview()
layer.removeFromSuperlayer()
run(SKAction.sequence([
SKAction.wait(forDuration: 3.0),
SKAction.run() {
// 5
let reveal = SKTransition.flipHorizontal(withDuration: 0.5)
let scene = GameScene(size: self.size)
self.view?.presentScene(scene, transition:reveal)
}
]))
}

UIButton Not Working After Updated to Xcode 8.3

After I updated to Xcode 8.3 the following code is not working in Xcode Playgrounds. Before on Xcode 8.2.1, I was able to click on the button and the action would follow, but now nothing is happening when I click the button.
import UIKit
import SpriteKit
import PlaygroundSupport
let view = SKView(frame: CGRect(x: 0, y: 0, width: 550, height: 575))
let scene = SKScene(size: CGSize(width: 550, height: 575))
scene.backgroundColor = UIColor.white
scene.scaleMode = SKSceneScaleMode.aspectFit
view.presentScene(scene)
class Responder: NSObject {
#objc func nextScene() {
print("Next button pressed!")
}
}
let responder = Responder()
let nextButton = UIButton(type: .system)
nextButton.frame = CGRect(x: 250, y: 557.5, width: 40, height: 15)
nextButton.setTitle("Next", for: .normal)
nextButton.titleLabel?.font = UIFont(name: "Marker Felt", size: 17)
nextButton.tintColor = .black
nextButton.addTarget(responder, action: #selector(Responder.nextScene), for: .touchUpInside)
view.addSubview(nextButton)
PlaygroundPage.current.liveView = view
EDIT: I updated my code so that it includes PlaygroundPage.current.liveView = view and the code for setting up the view and scene.
You do not set a live view for the playground in your code. Normally, a playground will execute the code and stop - it does not wait for input or events etc, unless you explicitly specify it should.
You should add the following line at the end of the playground to specify that canvas is a live view - provided it is, I can't know since you have not provided the implementation for canvas.
PlaygroundPage.current.liveView = canvas

Programmed Button in swift is not working

http://pastebin.com/MgQ7wx3g
So I am currently trying to get this button to work called Play button
let playButton: UIButton = {
let button = UIButton()
let image = UIImage(named: "VideoIcon.png") as UIImage?
button.backgroundImage(for: .normal)
button.addTarget(self, action: #selector(pressBackButton(button:)), for: .touchUpInside)
button.setImage(image, for: .normal)
return button
}()
func pressBackButton(button: UIButton) {
print("test")
if let playVideoButtonURL = post?.videourl {
let player = AVPlayer(url: playVideoButtonURL as URL)
let playerLayer = AVPlayerLayer(player:player)
playerLayer.frame = CGRect(x: 100, y: 200, width: 100, height: 100)
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
self.layer.addSublayer(playerLayer)
player.play()
}
}
When I click on it nothing happens even if the video code is wrong it should still print test. It's not giving me any errors on startup to work with either. The paste bin has my full code.
I tried your code given in question, with explicitly set frame.
override func viewDidLoad() {
super.viewDidLoad()
// Set Frame
self.playButton.frame = CGRect(origin: CGPoint(x: self.view.frame.width / 2, y: self.view.frame.height / 2), size: CGSize(width: 30, height: 30))
self.view.addSubview(playButton)
}
And its working perfectly and the "Test" is printing.
Then I checked your code you posted in given link. There I found this method addConstraintsWithFormat to set autolayout with visual format language. I replaced my code using this method.
self.view.addConstraintsWithFormat(format: "H:|-280-[v0(44)]", view: playButton)
self.view.addConstraintsWithFormat(format: "V:|-90-[v0(44)]", view: playButton)
It is also working.
From your code I can find that it's a CollectionViewCell. Could please try to add subviews to its contentView?
The correct method signature is
button.addTarget(self, action: #selector(pressBackButton(_:)), for: .touchUpInside)
and
func pressBackButton(_ button: UIButton) {

Menu system for Games in SpriteKit

I've looked at a few different post surrounding menu systems in SpriteKit and nothing really focusses on how to implement from start to finish (a basic play button starting the game, background and then sharing icons).
The reason I am looking is that I am a beginner and in the process of building my first basic game. I have used a few of these guides and none seem to give a proper walk through.
Thought it would be good to create a post for all beginners to start out. I have attempted some actual code but it hasn't been successful (quite a few errors though I can post if anyone is interested in seeing what NOT to do).
Anyway, here goes nothing😊 Thanks in advance all, lets see how we can get it done!
well, i believe this is a good question and setting up something as an answer here is not a bad idea. i've setup a starting menu with a title and three buttons in this very simple menu. that can be modified to the desired result later. first of all create a new file for starting menu by adding the file through project pane on the left. then create a spritekitScene also with the same name (startMenu or whatever you want to name it) then do the same for the settings and also credits or any other item you want to add to the start menu.
the next step is the change the entry point of the game from game scene to start menu in view controller swift. change the game scene to whatever you named your menu in this line if let scene = GameScene(fileNamed:"GameScene") to if let scene = StartMenu(fileNamed:"StartMenu") that will push the start menu rather than the game scene. go the start menu and add the following codes for creating a title and buttons to the view. i created the buttons and the text and added separate functions for each for the ease of following up, and then at the end you add the functions for the selector so when the buttons are pressed the new scene gets pushed. you can also add a return button to those scenes or do whatever else you want. so here is the complete start menu code:
import Foundation
import SpriteKit
class StartMenu : SKScene {
var btnPlay : UIButton!
var btnSettings : UIButton!
var btnCredits : UIButton!
var gameTitle : UILabel!
override func didMoveToView(view: SKView) {
// self.backgroundColor = UIColor.orangeColor()
setUpTitleText()
setupButtonPlay()
setupButtonSettings()
setupButtonCredits()
}
func setUpTitleText(){
gameTitle = UILabel(frame: CGRect(x: 0, y: 0, width: view!.frame.width, height: 300))
gameTitle.textColor = UIColor.blackColor()
gameTitle.font = UIFont(name: "Futura", size: 50)
gameTitle.textAlignment = NSTextAlignment.Center
gameTitle.text = "Game Title"
//gameTitle.backgroundColor = UIColor.whiteColor()
self.view?.addSubview(gameTitle)
}
func setupButtonPlay(){
btnPlay = UIButton(frame: CGRect(x: 100, y: 100, width: 200, height: 100))
btnPlay.center = CGPoint(x: view!.frame.size.width / 2, y: 250)
btnPlay.titleLabel?.font = UIFont(name: "Futura", size: 25)
btnPlay.setTitle("Play", forState: UIControlState.Normal)
btnPlay.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
//btnPlay.backgroundColor = UIColor.grayColor()
btnPlay.addTarget(self, action: #selector(StartMenu.playTheGame), forControlEvents: UIControlEvents.TouchUpInside)
self.view?.addSubview(btnPlay)
}
func setupButtonSettings(){
btnSettings = UIButton(frame: CGRect(x: 100, y: 100, width: 200, height: 100))
btnSettings.center = CGPoint(x: view!.frame.size.width / 2, y: 350)
btnSettings.titleLabel?.font = UIFont(name: "Futura", size: 25)
btnSettings.setTitle("Settings", forState: UIControlState.Normal)
btnSettings.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
//btnSettings.backgroundColor = UIColor.grayColor()
btnSettings.addTarget(self, action: #selector(StartMenu.pressTheSettings), forControlEvents: UIControlEvents.TouchUpInside)
self.view?.addSubview(btnSettings)
}
func setupButtonCredits(){
btnCredits = UIButton(frame: CGRect(x: 100, y: 100, width: 200, height: 100))
btnCredits.center = CGPoint(x: view!.frame.size.width / 2, y: 450)
btnCredits.titleLabel?.font = UIFont(name: "Futura", size: 25)
btnCredits.setTitle("Credits", forState: UIControlState.Normal)
btnCredits.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
//btnCredits.backgroundColor = UIColor.grayColor()
btnCredits.addTarget(self, action: #selector(StartMenu.pressTheCredits), forControlEvents: UIControlEvents.TouchUpInside)
self.view?.addSubview(btnCredits)
}
func playTheGame(){
self.view?.presentScene(GameScene(), transition: SKTransition.crossFadeWithDuration(1.0))
btnPlay.removeFromSuperview()
gameTitle.removeFromSuperview()
btnCredits.removeFromSuperview()
btnSettings.removeFromSuperview()
if let scene = GameScene(fileNamed: "GameScene"){
let skView = self.view! as SKView
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
func pressTheSettings(){
self.view?.presentScene(TheSettings(), transition: SKTransition.crossFadeWithDuration(1.0))
btnPlay.removeFromSuperview()
gameTitle.removeFromSuperview()
btnCredits.removeFromSuperview()
btnSettings.removeFromSuperview()
if let scene = TheSettings(fileNamed: "TheSettings"){
let skView = self.view! as SKView
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
func pressTheCredits(){
self.view?.presentScene(TheCredits(), transition: SKTransition.crossFadeWithDuration(1.0))
btnPlay.removeFromSuperview()
gameTitle.removeFromSuperview()
btnCredits.removeFromSuperview()
btnSettings.removeFromSuperview()
if let scene = TheCredits(fileNamed: "TheCredits"){
let skView = self.view! as SKView
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
}
in this scenario i have hard coded the titles and the buttons, but you can add your own images if you want. this is just a simple way of creating a menu but there are many other ways to do this. as you go along you can build your own in anyway you like.
good luck.