This Swift w/ SpriteKit code does not do what is intended - ios

I am very new to Swift and iOS development. I was watching tutorials on iOS development w/ Swift and SpriteKit. Following the tutorials I opened Xcode, new project, game, universal; and all I changed was the GameScene.swift. Here is the new code:
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
var node1 = SKNode()
node1.position = CGPoint(x: 100, y: 100)
self.addChild(node1)
var spr1 = SKSpriteNode(imageNamed: "Spaceship")
spr1.position = CGPointZero
spr1.zPosition = 1
node1.addChild(spr1)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
Note: the Spaceship image is provided by default.
So in the tutorials, this code added a spaceship to the scene. However, when I run the simulator, the scene remains blank. What can be the problem? If more info is needed, please say so and I will provide.

It could be running correctly, and you just can't see it on the screen. Depending on the device that you're emulating, you may be showing the spaceship off screen. Try a different, smaller device, to emulate, and check if you can see it.

Try going into your GameViewController.swift and making sure that you see something along the lines of this:
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene(fileNamed:"GameScene") {
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
scene.size = skView.bounds.size
skView.presentScene(scene)
}
}
}

Related

Cannot load new SpriteKit SKScene with touch of the button

I can not load the new scene with touch of the button on the scene.
Button named: BuStartGame
Scene to load: CategoriesScene
Scene to load class: CategoriesSceneClass.
Here is my code.
import Foundation
import SpriteKit
import GameplayKit
import UIKit
class GameScene: SKScene {
override func touchesBegan(_ touches: Set<UITouch>, with event:UIEvent?){
for touch in touches {
let location = touch.location(in: self);
//Mark: ===================== StartGame
if atPoint(location).name == "BuStartGame"{
if let scene = CategoriesSceneClass(fileNamed:"CategoriesScene"){
scene.scaleMode = .aspectFill
view!.presentScene(scene, transition: SKTransition.doorsOpenVertical(withDuration: 2))
}
}
}
}
}
EDITED:
I see that the problem is in this code. When I delete IF it works, but as a button work the whole scene.
if atPoint(location).name == "BuStartGame"{
I struggled with a demo game in SpriteKit last year, here is some code I used for a similar button transition, changed class name and file name to yours below. Try replacing this in your "if let scene" section.
if let scene = CategoriesSceneClass(fileNamed:"CategoriesScene") {
// Configure the view.
let skView = self.view!
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = false
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene, transition: SKTransition.doorsOpenVertical(withDuration: 2))
This code solved problem
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self);
if atPoint(location).name == "Start" {
print("I'm at start point")
if let view = self.view {
print("gonna create scene")
if let scene = GameplaySceneClass(fileNamed: "GameplayScene") {
scene.scaleMode = .aspectFill
print("prepare to transition")
view.presentScene(scene,transition:
SKTransition.doorsOpenVertical(withDuration:
TimeInterval(2)));
}
}
}
}

Share a variable between swift files

Explanation
My question is pretty straight forward: how do I print a variable from GameScene on GameViewController?
Code
I created this code below so it's easier to get the idea.
GameScene.swift
import SpriteKit
class GameScene: SKScene {
var variable = Int()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
variable = 50
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
NSNotificationCenter.defaultCenter().postNotificationName("calledFromGameSceneVC", object: nil)
}
}
GameViewController.swift
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Set view size.
let scene = GameScene(size: view.bounds.size)
// Configure the view.
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .ResizeFill
skView.presentScene(scene)
//------------------------------//
//Register observer
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameViewController.calledFromGameScene), name: "calledFromGameSceneVC", object: nil)
}
func calledFromGameScene(){
//Print variable
let scene = GameScene(size: view.bounds.size)
print("My variable from GameScene is: ", scene.variable)
}
}
Sorry for the brief explanation.
Thanks in advance,
Luiz.
The type of inter-object communication you are trying to achieve is probably best addressed through a delegation pattern using a protocol:
GameScene.swift
import SpriteKit
protocol GameSceneDelegate {
func calledFromGameScene(scene: GameScene)
}
class GameScene: SKScene {
var variable = Int()
var gameDelegate: GameSceneDelegate?
override func didMoveToView(view: SKView) {
/* Setup your scene here */
variable = 50
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
gameDelegate?.calledFromGameScene(self)
}
}
GameViewController.swift
class GameViewController: UIViewController, GameSceneDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Set view size.
let scene = GameScene(size: view.bounds.size)
// Configure the view.
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .ResizeFill
/* Set the delegate */
scene.gameDelegate = self
skView.presentScene(scene)
}
func calledFromGameScene(scene:GameScene){
//Print variable
print("My variable from GameScene is: ", scene.variable)
}
}
Note that you can't use the property name delegate on your GameScene as SKScene already has a delegate property

Show ad banner by touching a button

Explanation
The title pretty much asks for itself. I'm trying to make a button activate an ad banner, but Xcode returns me this message below; so, because of the UIViewController, I saw that this banner should be called on GameViewController, not GameScene. I looked for it everywhere, but did not find how to call this banner from GameScene or another way to activate this banner by a button.
Cannot convert value of type 'GameScene' to expected argument type 'UIViewController!'
Code
This code below is pretty simple. It has a button on its attempt to call an ad banner.
import SpriteKit
import Ads
class GameScene: SKScene {
var button = SKSpriteNode()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
button = SKSpriteNode(imageNamed: "button")
button.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2)
button.setScale(0.4)
addChild(button)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
let location = touch.locationInNode(self)
let node = nodeAtPoint(location)
if node == button{
Ads.showAd(AdsShowStyle.BannerBottom, rootViewController: self) //issue line
}
}
}
}
Attempt
After some research, I found out that it might be possible by using delegation. Following the highest voted answer of this question, I came up to this code below, but I'm having many issues that I'm, unsuccessfully, struggling to solve.
GameScene.swift
GameViewController.swift
Thanks in advance,
Luiz.
Since you are using SpriteKit but we don't know what ad network you are using, I would recommend using a NSNotificationCenter command in GameViewController and use a postNotificationName command in the GameScene.swift instead of a ViewControllerDelegate. This would allow your ad code to be used in any other .swift files. Here's a better explanation of this from another post if needed
Note: This may or may not work depending on ad network
GameViewController.swift (from my project)
import UIKit
import SpriteKit
import GoogleMobileAds
class GameViewController: UIViewController, GADAdDelegate {
var adMobBanner : GADBannerView!
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
adMobBanner = GADBannerView(adSize: kGADAdSizeSmartBannerPortrait)
adMobBanner.adUnitID = "your ad unit id"
adMobBanner.rootViewController = self
adMobBanner.frame = CGRectMake(0, view.bounds.height - adMobBanner.frame.size.height, adMobBanner.frame.size.width, adMobBanner.frame.size.height)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameViewController.showAdMob), name: "showAdMobKey", object: nil)
}
func showAdMob() {
let request : GADRequest = GADRequest()
adMobBanner.loadRequest(request)
self.view.addSubview(adMobBanner)
print("adMob")
}
GameScene.swift (edited yours)
import SpriteKit
import Ads
class GameScene: SKScene {
var button = SKSpriteNode()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
button = SKSpriteNode(imageNamed: "button")
button.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2)
button.setScale(0.4)
addChild(button)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
let location = touch.locationInNode(self)
if (button.containsPoint(location)) {
NSNotificationCenter.defaultCenter().postNotificationName("showAdMobKey", object: nil)
}
}
}
}

SKSpriteNode hidden under a UI Background Image

I have an SKSpriteNode that functions properly. But when I add a UIImage, the SKSpriteNode becomes hidden behind the UIImage. I have been trying to figure out why, but I am having a little bit of trouble and can't seem to figure out what I am missing to allow the SKSSpriteNode to appear on top of the UI background Image, instead of behind it where it can't be seen. Any help would be greatly appreciated!
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .AllButUpsideDown
} else {
return .All
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
import SpriteKit
import SceneKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var blueBall:SKSpriteNode!
override func didMoveToView(view: SKView) {
self.physicsWorld.gravity = CGVectorMake(0.0, -5.0)
self.physicsWorld.contactDelegate = self
blueBall = SKSpriteNode( imageNamed: "ball")
blueBall.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
blueBall.physicsBody = SKPhysicsBody(circleOfRadius: blueBall.size.width / 1.5 )
blueBall.physicsBody!.dynamic = true
blueBall.physicsBody!.allowsRotation = false
self.addChild(blueBall)
}
override func touchesBegan(touches: Set<UITouch> , withEvent event: UIEvent?) {
self.blueBall.physicsBody?.velocity = CGVectorMake(35, 0)
self.blueBall.physicsBody?.applyImpulse(CGVectorMake(4, 10))
}
}
For draw order use the zPosition property:
In your case you will need to give the Sprite you want to be displayed in front a higher .zPosition value than the one to be displayed further back.
Example: ball.zPosition = 10
zPosition definition:
The height of the node relative to its parent.
Tipps:
The default value is 0.0. The positive z axis is projected toward the viewer so that nodes with larger z values are closer to the viewer.

My Sprite Kit button won't work in Swift

Hi than you for looking at this i was wondering why my code in swift sprite kit won't work i can run it but when i click on the button it does not work(it does not go to the scene) but when i add a println to the if statement and then i click it it does run the println. Thank you in advance!
Here is my code for my first scene:
//
// GameScene.swift
// Pocket Rocket
//
// Created by Lucas Farleigh on 11/11/2014.
// Copyright (c) 2014 Lucas Farleigh. All rights reserved.
//
import SpriteKit;
class GameScene: SKScene {
let background = SKSpriteNode(imageNamed:"background")
let playButton = SKSpriteNode(imageNamed: "playbutton")
override func didMoveToView(view: SKView) {
playButton.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidX(self.frame))
background.yScale = 2
background.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidX(self.frame))
self.addChild(background)
self.addChild(playButton)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
//making the scene vars
var scene = PlayScene(size: self.size)
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
let skview = self.view as SKView!
scene.size = skview.bounds.size
playButton.name = "PB"
if node.name == "PB"{
println("it worked")
skview.presentScene(scene)
}
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
And my second scene(playscene)
//
// PlayScene.swift
// Pocket Rocket
//
// Created by Lucas Farleigh on 14/11/2014.
// Copyright (c) 2014 Lucas Farleigh. All rights reserved.
//
import SpriteKit
import UIKit
import Foundation
class PlayScene:SKScene{
let background = SKSpriteNode(imageNamed: "background")
let bar1 = SKSpriteNode(imageNamed:"Bar1")
let bar2 = SKSpriteNode(imageNamed:"Bar2")
let bar3 = SKSpriteNode(imageNamed:"Bar3")
let bar4 = SKSpriteNode(imageNamed:"Bar4")
let bar5 = SKSpriteNode(imageNamed:"Bar5")
let bar6 = SKSpriteNode(imageNamed:"Bar6")
override func didMoveToView(view: SKView) {
background.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidX(self.frame))
addChild(background)
background.yScale = 2
Note that you are creating background and PlayButton nodes twice: once as a class property, and a second time as a local variable in didMoveToView. It is the local version that you are then adding to the scene as a child view. If you want to be able to test against these nodes in other methods in your class, get rid of the local declarations in didMoveToView. You can still fill in the other information about these nodes, just remove the let statements.
Then in your touchesBegan you want to get the location of the touch in the scene by passing self to touch.locationInNode(self) and then retrieve the node that corresponds to that touch:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if node == Play_Button {
println("Hello!!!!")
}
}
}
A second way to accomplish the PlayButton would be to give the node a name when you create it:
Play_Button.name = "playButton"
and then your touchesBegan would look like this:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if node.name == "playButton" {
println("Hello!!!!")
}
}
}
I agree with vacawama's answer (I use the naming option) but I'd like to add a little on my approach to buttons in SK. Usually you either have a background and a label or just a PNG image with both background and label.
When using nodeAtPoint on the label you might not have enough area. If instead you use the background area to detect taps then you might have conflicts with the label on top of the node.
To solve this I create a third element (usually an SKShapeNode) on top of both, transparent and a little bigger to make it easier for the user to tap on it.
To make sure you are positioning these tap areas on top of the buttons remember to use a higher zPosition

Resources