Scene transition in spritekit not transitioning - ios

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)

Related

Change view from SKScene to a ViewController

I am making a game using ARKit. Im having trouble witching to the ARSCNview from a SKSecene.
I have this so far:
import Foundation
import SpriteKit
//Back button
let backToBrand = SKLabelNode(fontNamed: "Electric Boots")
class Lamborghini: SKScene {
override func didMove(to view: SKView) {
//Background
let menuBackground = SKSpriteNode(imageNamed: "Background")
menuBackground.setScale(1)
menuBackground.position = CGPoint(x: self.size.width/2, y:
self.size.height/2)
menuBackground.zPosition = 0
self.addChild(menuBackground)
//Back button
backToBrand.text = "Back"
backToBrand.fontSize = 50
backToBrand.fontColor = SKColor.white
backToBrand.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.left
backToBrand.position = CGPoint(x: self.size.width*0.05, y: self.size.height*0.67)
backToBrand.zPosition = 1
self.addChild(backToBrand)
//Test button
let test = SKLabelNode(fontNamed: "Electric Boots")
test.text = "test AR"
test.fontSize = 100
test.fontColor = SKColor.white
test.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
test.zPosition = 2
test.name = "test"
self.addChild(test)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let pointOfTouch = touch.location(in: self)
let nodeITapped = atPoint(pointOfTouch)
if nodeITapped == backToBrand {
let sceneToMOveTo = BrandMenu(size: self.size)
sceneToMOveTo.scaleMode = self.scaleMode
let sceneTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMOveTo, transition: sceneTransition)
}
if nodeITapped.name == "test"{
let sceneToMOveTo = ARView(size: self.size)
sceneToMOveTo.scaleMode = self.scaleMode
let sceneTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMOveTo, transition: sceneTransition)
}
}
}
The part having the problem is:
if nodeITapped.name == "test" {
let sceneToMOveTo = ARView(size: self.size)
sceneToMOveTo.scaleMode = self.scaleMode
let sceneTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMOveTo, transition: sceneTransition)
}
The AR scene is in a ViewController within the Main.Storyboard.
I can't get the Game Scene to move to the ViewController and move back.

Setting position of custom SKSpriteNode from GameScene

I am making a custom SKSpriteNode, when I step through calling createShip the heroShip constant in the class is correct, but when I jump back to the gameScene, the heroShip constant there does not have the properties I assigned when calling createShip, I am not sure what I am doing wrong. I have tried using class function but that doesn't work using the height and width properties.
Custom SKSpriteNode class
class hero: SKSpriteNode {
var width: CGFloat = 0.0
var height: CGFloat = 0.0
func createShip() -> SKSpriteNode {
let heroShip = SKSpriteNode(imageNamed: "heroShip")
heroShip.anchorPoint = CGPointMake(1.0, 0.5)
heroShip.physicsBody = SKPhysicsBody(rectangleOfSize: heroShip.size)
heroShip.physicsBody?.usesPreciseCollisionDetection = true
heroShip.zPosition = 1.0
heroShip.physicsBody?.mass = 0.02
heroShip.physicsBody?.dynamic = true
heroShip.physicsBody?.affectedByGravity = false
heroShip.physicsBody?.categoryBitMask = ObjectCategory.collisionHeroCategory.rawValue
heroShip.physicsBody?.contactTestBitMask = ObjectCategory.sceneCategory.rawValue
heroShip.physicsBody?.collisionBitMask = 0x0 | ObjectCategory.sceneCategory.rawValue
//heroShip.position = CGPointMake((scene?.frame.size.width)!/6.0, (scene?.frame.size.height)!/2.0)
heroShip.position = CGPointMake(width, height)
return heroShip
}
}
My GameScene
class GameScene: SKScene,SKPhysicsContactDelegate{
let background = SKSpriteNode(imageNamed: "background")
var score:Int = 0
let scoreLabel = SKLabelNode(fontNamed: "Courier")
let MotionManager = CMMotionManager()
var heroShip = hero()
override func didMoveToView(view: SKView) {
heroShip.width = self.size.width/6.0
heroShip.height = self.size.height/2.0
heroShip.createShip()
let enemyShip = SKSpriteNode(imageNamed: "enemyShip")
/* Setup your scene here */
self.physicsWorld.contactDelegate = self
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: CGRectMake(0,heroShip.size.width/1.25,frame.width,frame.height - heroShip.size.width*1.6))
scene?.physicsBody?.contactTestBitMask = ObjectCategory.sceneCategory.rawValue
scene?.physicsBody?.categoryBitMask = ObjectCategory.sceneCategory.rawValue
background.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame))
scoreLabel.fontColor = SKColor.whiteColor()
scoreLabel.text = String(format: "Score: %01u",score)
scoreLabel.position = CGPointMake(frame.size.width/2, frame.size.height - scoreLabel.frame.size.width/1.2)
scoreLabel.zPosition = 1.0
enemyShip.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
enemyShip.zPosition = 1.0
enemyShip.physicsBody = SKPhysicsBody(rectangleOfSize: heroShip.size)
enemyShip.physicsBody?.usesPreciseCollisionDetection = true
enemyShip.physicsBody?.mass = 0.02
enemyShip.physicsBody?.dynamic = true
enemyShip.physicsBody?.affectedByGravity = false
enemyShip.physicsBody?.categoryBitMask = ObjectCategory.collisionEnemyCategory.rawValue
enemyShip.physicsBody?.contactTestBitMask = ObjectCategory.collisionBulletCategory.rawValue
enemyShip.physicsBody?.collisionBitMask = 0x0
self.addChild(enemyShip)
self.addChild(background)
self.addChild(self.heroShip)
self.addChild(scoreLabel)
if MotionManager.accelerometerAvailable{
MotionManager.startAccelerometerUpdates()
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let bullet = SKSpriteNode(imageNamed: "bullet")
bullet.position = CGPointMake(heroShip.position.x, heroShip.position.y)
bullet.zPosition = 1.0
// Add physics body for collision detection
bullet.physicsBody = SKPhysicsBody(rectangleOfSize: bullet.frame.size)
bullet.physicsBody?.dynamic = true
bullet.physicsBody?.affectedByGravity = false
bullet.physicsBody?.categoryBitMask = ObjectCategory.collisionBulletCategory.rawValue
bullet.physicsBody?.contactTestBitMask = ObjectCategory.collisionHeroCategory.rawValue
bullet.physicsBody?.collisionBitMask = 0x0;
let action = SKAction.moveToX(CGRectGetMaxX(self.frame) + bullet.size.width, duration: 0.75)
self.addChild(bullet)
bullet.runAction(action, completion: {
bullet.removeAllActions()
bullet.removeFromParent()
})
}
func didBeginContact(contact: SKPhysicsContact) {
if contact.bodyB.categoryBitMask == ObjectCategory.collisionBulletCategory.rawValue && contact.bodyA.categoryBitMask == ObjectCategory.collisionEnemyCategory.rawValue{
score++
}
}
override func update(currentTime: CFTimeInterval) {
let data = MotionManager.accelerometerData
if data?.acceleration.x == nil{
print("nil")
}
else if fabs((data?.acceleration.x)!) > 0.2 {
heroShip.physicsBody?.applyForce(CGVectorMake(0.0, CGFloat(40 * (data?.acceleration.x)!)))
}
scoreLabel.text = String(format: "Score: %01u",score)
}
}
You run
heroShip.createShip()
and then never do anything with the SKSpriteNode that is returned. From what I can tell, the hero class is the hero ship. I am going off of this assumption for the rest of this answer.
Going from the top of the GameScene, you should do some refactoring.
var heroShip = hero() Is going to be replaced to init using the SKSpriteNode structure:
var heroShip = hero(imageNamed: "heroShip")
Moving to hero class, func createShip() -> SKSpriteNode { should be turned into func createShip() {. As you already have the node set up with the image texture now, and are using the hero class as the node, there is no need to return a SKSpriteNode.
Delete let heroShip = SKSpriteNode(imageNamed: "heroShip") as the hero class is going to be our heroShip.
Replace any usage of the heroShip.whatever variable with self.whatever. At the end, delete the return heroShip.
You seem to not be understanding what is happening with your code.
As of right now createShip() is creating a hero ship, but you never use it.
By looking at your code, it seems like createShip() is not even needed. From looking at it, hero IS heroShip, so do the code in your init.
convenience init(imageNamed: String,sceneSize:CGSize) {
let heroTexture = SKTexture(imageNamed: imageNamed)
self.init(texture: heroTexture, color: UIColor.whiteColor(), size: heroTexture.size()) //This may need to be tweeked, my mac is dead right now to verify.
self.anchorPoint = CGPointMake(1.0, 0.5)
self.physicsBody = SKPhysicsBody(rectangleOfSize: self.size)
self.physicsBody?.usesPreciseCollisionDetection = true
self.zPosition = 1.0
self.physicsBody?.mass = 0.02
self.physicsBody?.dynamic = true
self.physicsBody?.affectedByGravity = false
heroShip.physicsBody?.categoryBitMask = ObjectCategory.collisionHeroCategory.rawValue
heroShip.physicsBody?.contactTestBitMask = ObjectCategory.sceneCategory.rawValue
heroShip.physicsBody?.collisionBitMask = 0x0 | ObjectCategory.sceneCategory.rawValue
//self.position = CGPointMake((scene?.frame.size.width)!/6.0, (scene?.frame.size.height)!/2.0)
self.position = CGPointMake(sceneSize.width, sceneSize.height)
}
You now come across another problem, and that is your SKPhysicsBody will not align to your anchor point.
To fix this, create the SKPhysicsBody like this:
let centerPoint = CGPointMake(self.size.width / 2 - (self.size.width * self.anchorPoint.x), self.size.height / 2 - (self.size.height * self.anchorPoint.y))
self.physicsBody = SKPhysicsBody(rectangleOfSize: self.size, center: centerPoint)

How to save a high score with SpriteKit?

Im starting to learn how to code and i have no clue how to save the score to stay as a high score. any help will be appreciated! i already tried and tried but i can't manage to get it right. at this point i don't know what to do.
class Game: SKScene, SKPhysicsContactDelegate {
let Ball = SKSpriteNode(imageNamed: "Red.png")
var QuitOption = SKLabelNode()
var ScoreLabel = SKLabelNode()
var timesecond = Int(60)
var locked = false
var loseOption = SKLabelNode()
var scorePoints = SKLabelNode()
var score = Int()
var highScore = SKLabelNode()
let whiteBall = SKSpriteNode(imageNamed: "fingerPointingDown.png")
struct PhysicsCategory {
static let Ball: UInt32 = 0b1
static let whiteBall: UInt32 = 0b10
}
override func didMoveToView(view: SKView) {
backgroundColor = SKColor.whiteColor() // background for the display
self.physicsWorld.gravity = CGVectorMake(0, -9.8)
self.physicsWorld.contactDelegate = self
let SceneBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
SceneBody.friction = 0
self.physicsBody = SceneBody
scorePoints = SKLabelNode(fontNamed: "Noteworthy-Light")
scorePoints.text = "0"
scorePoints.fontColor = SKColor.blackColor()
scorePoints.fontSize = 35
scorePoints.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height*1 - 120)
scorePoints.name = "Points"
scorePoints.hidden = true
addChild(scorePoints)
Ball.size = CGSize(width: 82, height: 82)
Ball.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height*0.1 - 60)
Ball.physicsBody = SKPhysicsBody(circleOfRadius: 41)
Ball.physicsBody?.affectedByGravity = true
Ball.physicsBody?.density = 10
Ball.physicsBody?.restitution = 0.1
Ball.physicsBody?.linearDamping = 0
Ball.name = "Ball"
Ball.physicsBody?.usesPreciseCollisionDetection = true
Ball.physicsBody?.categoryBitMask = PhysicsCategory.Ball
Ball.physicsBody?.contactTestBitMask = PhysicsCategory.whiteBall
Ball.physicsBody?.collisionBitMask = PhysicsCategory.whiteBall
self.addChild(Ball)
QuitOption.text = "Quit"
QuitOption.fontName = "Noteworthy-Light"
QuitOption.fontColor = SKColor.purpleColor()
QuitOption.fontSize = 35
QuitOption.position = CGPoint(x: self.frame.size.width/2 - 160, y: self.frame.size.height*1 - 110)
QuitOption.name = "Quit"
addChild(QuitOption)
ScoreLabel = SKLabelNode(fontNamed: "Noteworthy-Light")
ScoreLabel.fontColor = SKColor.redColor()
ScoreLabel.fontSize = 35 // The + will move it to the right side and - to the left side for more accuracy.
ScoreLabel.position = CGPoint(x: self.frame.size.width/2 + 160, y: self.frame.size.height/1 - 115) // position of ScoreLabelNode
ScoreLabel.name = "Score+"
ScoreLabel.hidden = false
self.addChild(ScoreLabel)
whiteBall.size = CGSize(width: 55, height: 55)
whiteBall.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height*0.8 - 30)
whiteBall.name = "whiteBall"
whiteBall.physicsBody = SKPhysicsBody(circleOfRadius: 25)
whiteBall.physicsBody?.dynamic = false
whiteBall.physicsBody?.restitution = 0.1
whiteBall.physicsBody?.usesPreciseCollisionDetection = true
whiteBall.physicsBody?.categoryBitMask = PhysicsCategory.whiteBall
whiteBall.physicsBody?.contactTestBitMask = PhysicsCategory.Ball
whiteBall.physicsBody?.collisionBitMask = PhysicsCategory.Ball
self.addChild(whiteBall)
}
// Making the ball jump after user touches ball
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
var touch = touches.first as! UITouch
var location = touch.locationInNode(self)
var node = self.nodeAtPoint(location)
if (node.name == "Quit"){
let myScene = GameScene(size: self.size)
myScene.scaleMode = scaleMode
let reveal = SKTransition.fadeWithDuration(1)
self.view?.presentScene(myScene, transition: reveal)
}
if (node.name == "Ball"){
for touch: AnyObject in touches {
Ball.physicsBody?.allowsRotation = true
Ball.physicsBody?.velocity = CGVectorMake(0, 0)
Ball.physicsBody?.applyImpulse(CGVectorMake(0, 450))
}
}
if(!self.locked){
self.locked = true
var actionrun = SKAction.waitForDuration(0.5)
var actionwait = SKAction.runBlock({
self.timesecond--
if self.timesecond == 60 {self.timesecond = 0}
self.ScoreLabel.text = "\(self.timesecond)"
if (self.timesecond == 0){
let myScene = WT(size: self.size)
myScene.scaleMode = self.scaleMode
let reveal = SKTransition.fadeWithDuration(1)
self.view?.presentScene(myScene, transition: reveal)
}
})
let loopAction = SKAction.repeatAction(SKAction.sequence([actionwait, actionrun]), count: 60)
ScoreLabel.runAction(loopAction, withKey: "scoreAction")
}
}
func didBeginContact(contact: SKPhysicsContact) {
let collision = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
if collision == PhysicsCategory.Ball | PhysicsCategory.whiteBall {
score++
scorePoints.text = "Score: \(score)"
scorePoints.hidden = false
}
}
}
The simplest way is to use NSUserDefaults.
NSUserDefaults.standardUserDefaults().setInteger(highScore, forKey: "high_score")
NSUserDefaults.synchronize() // must be used to save
You can then load the score when needed
let highScore: Int = NSUserDefaults.standardUserDefaults().integerForKey("high_score")
You can access NSUserDefaults from anywhere, saving and loading as needed.
If you have more global player state, create an object for it and you could serialize the object by making it conform to NSCoding protocol.
You would need to implement the encode and decode functions, that save aand load your object's properties.

Display Current Score in Game using Sprite Kit and Swift

I have been working on a Flappy Bird type game for a couple of days now in Sprite Kit. I am new to programming so I have been trying to teach myself to make the game through various online videos and tutorials. I have come to the point where I need to create a scoring system that will display the current score on the screen in real time. I have looked and looked for a good tutorial on this but have had no luck finding one. I have a score label set up already in the code below. I have included below my entire scene. All I need to know is how to update the score label text each time the bird flies through a pipe. Any advice or suggestions would be greatly appreciated, thank you.
//
// ArcheryScene.swift
// FlappyBird (swift)
//
// Created by Brandon Ballard on 1/6/15.
// Copyright (c) 2015 Brandon Ballard. All rights reserved.
//
import UIKit
import SpriteKit
class ArcheryScene: SKScene, SKPhysicsContactDelegate {
var bird = SKSpriteNode()
var pipeUpTexture = SKTexture()
var pipeDownTexture = SKTexture()
var pipesMoveAndRemove = SKAction()
var impulse = 1
var count = 0
var scoreLabel = SKLabelNode()
let scoreLabelName = "scoreLabel"
let pipeGap = 150.0
enum ColliderType:UInt32 {
case BIRD = 1
case PIPE = 2
}
override func didMoveToView(view: SKView) {
/* Setup your scene here */
backgroundColor = SKColor.cyanColor()
//physics
self.physicsWorld.gravity = CGVectorMake(0.0, -15.0);
self.physicsWorld.contactDelegate = self
//Bird
var birdTexture = SKTexture(imageNamed:"Bird")
birdTexture.filteringMode = SKTextureFilteringMode.Nearest
bird = SKSpriteNode(texture: birdTexture)
bird.setScale(0.6)
bird.position = CGPoint(x: self.frame.width * 0.35 + 20, y: self.frame.size.height * 0.95)
bird.physicsBody = SKPhysicsBody(circleOfRadius: bird.size.height / 2.0)
bird.physicsBody?.dynamic = true
bird.physicsBody?.allowsRotation = true
bird.physicsBody?.affectedByGravity = true
bird.physicsBody!.collisionBitMask = ColliderType.BIRD.rawValue
bird.physicsBody!.contactTestBitMask = ColliderType.PIPE.rawValue
self.addChild(bird)
//Ground
var groundTexture = SKTexture(imageNamed: "Ground")
var sprite = SKSpriteNode(texture: groundTexture)
sprite.setScale(2.0)
sprite.position = CGPointMake(self.size.width / 2, sprite.size.height / 2.0)
self.addChild(sprite)
var ground = SKNode()
ground.position = CGPointMake(0, groundTexture.size().height + 0)
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, groundTexture.size().height * 2.0))
ground.physicsBody?.dynamic = false
self.addChild(ground)
//Score Label
scoreLabel = SKLabelNode(fontNamed: "ScoreLabel")
scoreLabel.name = scoreLabelName
scoreLabel.fontSize = 125
scoreLabel.fontColor = SKColor.whiteColor()
scoreLabel.text = "\(count)"
println(size.height)
scoreLabel.position = CGPointMake(frame.size.width / 2, frame.size.height / 14)
self.addChild(scoreLabel)
//Pipes
//Create the Pipes
pipeUpTexture = SKTexture(imageNamed: "PipeUp")
pipeDownTexture = SKTexture(imageNamed: "PipeDown")
//Movement of Pipes
let distanceToMove = CGFloat(self.frame.size.width + 2.0 * pipeUpTexture.size().width)
let movePipes = SKAction.moveByX(-distanceToMove, y: 0.0, duration: NSTimeInterval(0.01 * distanceToMove))
let removePipes = SKAction.removeFromParent()
pipesMoveAndRemove = SKAction.sequence([movePipes,removePipes])
//Spawn Pipes
let spawn = SKAction.runBlock({() in self.spawnPipes()})
let delay = SKAction.waitForDuration(NSTimeInterval(2.0))
let spawnThenDelay = SKAction.sequence([spawn,delay])
let spawnThenDelayForever = SKAction.repeatActionForever(spawnThenDelay)
self.runAction(spawnThenDelayForever)
}
func spawnPipes() {
let pipePair = SKNode()
pipePair.position = CGPointMake(self.frame.size.width + pipeUpTexture.size().width * 2, 0)
pipePair.zPosition = -10
let height = UInt32(self.frame.size.height / 4)
let y = arc4random() % height + height
var pipeDown = SKSpriteNode(texture: pipeDownTexture)
pipeDown.setScale(2.0)////////
pipeDown.position = CGPointMake(3.0, CGFloat(y) + pipeDown.size.height + CGFloat(pipeGap) )
pipeDown.physicsBody = SKPhysicsBody(rectangleOfSize: pipeDown.size)
pipeDown.physicsBody?.dynamic = false
pipeDown.physicsBody!.affectedByGravity = false
pipeDown.physicsBody!.collisionBitMask = ColliderType.PIPE.rawValue
pipePair.addChild(pipeDown)
var pipeUp = SKSpriteNode(texture: pipeUpTexture)
pipeUp.setScale(2.0)
pipeUp.position = CGPointMake(0.0, CGFloat(y))
pipeUp.physicsBody = SKPhysicsBody(rectangleOfSize: pipeUp.size )
pipeUp.physicsBody?.dynamic = false
pipeUp.physicsBody!.affectedByGravity = false
pipeUp.physicsBody!.collisionBitMask = ColliderType.PIPE.rawValue
pipePair.addChild(pipeUp)
pipePair.runAction(pipesMoveAndRemove)
self.addChild(pipePair)
}
func didBeginContact(contact: SKPhysicsContactDelegate) {
impulse = 0
let fadeOut = SKAction.sequence([SKAction.waitForDuration(3.0)])
let welcomeReturn = SKAction.runBlock({
let Transition = SKTransition.revealWithDirection(SKTransitionDirection.Down, duration: 1.0)
let welcomeScene = GameScene(fileNamed: "GameScene")
welcomeScene.scaleMode = .AspectFill
self.scene!.view?.presentScene(welcomeScene, transition: Transition)
})
let sequence = SKAction.sequence([fadeOut, welcomeReturn])
self.runAction(sequence)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if bird.position.y > (self.frame.size.height * 0.999){
impulse = 0
}
if impulse == 1 {
bird.physicsBody?.velocity = CGVectorMake( 0, 0 )
bird.physicsBody?.applyImpulse(CGVectorMake(0,25))
}
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
Just set up an invisible sprite between your pipes. when your bird passes through it, you can detect that and increase your score.
you can make an invisible sprite like this
let scoreSprite = SKSpriteNode(color: SKColor.clearColor(), size: theSize)
add a physics body to that, and youre good to go.

My Sprites Are Scrunched in Sprite Kit using Swift

I am creating my first game with Sprite Kit. It is a Flappy Bird type game. The image on the left is what the game looked like earlier today. I ended up creating an entirely new project. I copied the code for the previous project and pasted it into the current one. I placed the same exact images as the previous project into the current one as well. There are no compiling errors and everything works the same except that the game now looks like the image on the right. As you can see the images widths are smaller. Any advice would be greatly appreciated, if you would like me to provide all of the code in this question let me know, thank you.
This is all of the code for the Archery Scene:
//
// ArcheryScene.swift
// FlappyBird (swift)
//
// Created by Brandon Ballard on 1/6/15.
// Copyright (c) 2015 Brandon Ballard. All rights reserved.
//
import UIKit
import SpriteKit
class ArcheryScene: SKScene, SKPhysicsContactDelegate {
var bird = SKSpriteNode()
var pipeUpTexture = SKTexture()
var pipeDownTexture = SKTexture()
var pipesMoveAndRemove = SKAction()
var score = 0
let pipeGap = 150.0
enum ColliderType:UInt32 {
case BIRD = 1
case PIPE = 2
}
override func didMoveToView(view: SKView) {
/* Setup your scene here */
backgroundColor = SKColor.cyanColor()
//physics
self.physicsWorld.gravity = CGVectorMake(0.0, -15.0);
self.physicsWorld.contactDelegate = self
//Bird
var birdTexture = SKTexture(imageNamed:"Bird")
birdTexture.filteringMode = SKTextureFilteringMode.Nearest
bird = SKSpriteNode(texture: birdTexture)
bird.setScale(0.6)
bird.position = CGPoint(x: self.frame.width * 0.35 + 20, y: self.frame.size.height * 0.95)
bird.physicsBody = SKPhysicsBody(circleOfRadius: bird.size.height / 2.0)
bird.physicsBody?.dynamic = true
bird.physicsBody?.allowsRotation = true
bird.physicsBody?.affectedByGravity = true
bird.physicsBody!.collisionBitMask = ColliderType.BIRD.rawValue
bird.physicsBody!.contactTestBitMask = ColliderType.PIPE.rawValue
self.addChild(bird)
//Ground
var groundTexture = SKTexture(imageNamed: "Ground")
var sprite = SKSpriteNode(texture: groundTexture)
sprite.setScale(2.0)
sprite.position = CGPointMake(self.size.width / 2, sprite.size.height / 2.0)
self.addChild(sprite)
var ground = SKNode()
ground.position = CGPointMake(0, groundTexture.size().height + 0)
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, groundTexture.size().height * 2.0))
ground.physicsBody?.dynamic = false
self.addChild(ground)
//Pipes
//Create the Pipes
pipeUpTexture = SKTexture(imageNamed: "PipeUp")
pipeDownTexture = SKTexture(imageNamed: "PipeDown")
//Movement of Pipes
let distanceToMove = CGFloat(self.frame.size.width + 2.0 * pipeUpTexture.size().width)
let movePipes = SKAction.moveByX(-distanceToMove, y: 0.0, duration: NSTimeInterval(0.01 * distanceToMove))
let removePipes = SKAction.removeFromParent()
pipesMoveAndRemove = SKAction.sequence([movePipes,removePipes])
//Spawn Pipes
let spawn = SKAction.runBlock({() in self.spawnPipes()})
let delay = SKAction.waitForDuration(NSTimeInterval(2.0))
let spawnThenDelay = SKAction.sequence([spawn,delay])
let spawnThenDelayForever = SKAction.repeatActionForever(spawnThenDelay)
self.runAction(spawnThenDelayForever)
}
func spawnPipes() {
let pipePair = SKNode()
pipePair.position = CGPointMake(self.frame.size.width + pipeUpTexture.size().width * 2, 0)
pipePair.zPosition = -10
let height = UInt32(self.frame.size.height / 4)
let y = arc4random() % height + height
var pipeDown = SKSpriteNode(texture: pipeDownTexture)
pipeDown.setScale(2.0)////////
pipeDown.position = CGPointMake(3.0, CGFloat(y) + pipeDown.size.height + CGFloat(pipeGap) )
pipeDown.physicsBody = SKPhysicsBody(rectangleOfSize: pipeDown.size)
pipeDown.physicsBody?.dynamic = false
pipeDown.physicsBody!.affectedByGravity = false
pipeDown.physicsBody!.collisionBitMask = ColliderType.PIPE.rawValue
pipePair.addChild(pipeDown)
var pipeUp = SKSpriteNode(texture: pipeUpTexture)
pipeUp.setScale(2.0)
pipeUp.position = CGPointMake(0.0, CGFloat(y))
pipeUp.physicsBody = SKPhysicsBody(rectangleOfSize: pipeUp.size )
pipeUp.physicsBody?.dynamic = false
pipeUp.physicsBody!.affectedByGravity = false
pipeUp.physicsBody!.collisionBitMask = ColliderType.PIPE.rawValue
pipePair.addChild(pipeUp)
pipePair.runAction(pipesMoveAndRemove)
self.addChild(pipePair)
}
func didBeginContact(contact: SKPhysicsContactDelegate) {
scene?.view?.paused = true
//gameOver()
}
func createScoreNode() -> SKLabelNode {
let scoreNode = SKLabelNode(fontNamed: "Brandon Ballard")
scoreNode.name = "scoreNode"
let newScore = "\(score)"
scoreNode.text = newScore
scoreNode.fontSize = 125
scoreNode.fontColor = SKColor.cyanColor()
scoreNode.position = CGPointMake(CGRectGetMidX(self.frame), 58)
self.addChild(scoreNode)
return scoreNode
}
func gameOver() {
let scoreNode = self.createScoreNode()
self.addChild(scoreNode)
let fadeOut = SKAction.sequence([SKAction.waitForDuration(3.0), SKAction.fadeOutWithDuration(3.0)])
let welcomeReturn = SKAction.runBlock({
let transition = SKTransition.revealWithDirection(SKTransitionDirection.Down, duration: 1.0)
let welcomeScene = GameScene(fileNamed: "GameScene")
self.scene!.view?.presentScene(welcomeScene, transition: transition)
})
let sequence = SKAction.sequence([fadeOut, welcomeReturn])
self.runAction(sequence)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
bird.physicsBody?.velocity = CGVectorMake( 0, 0 )
bird.physicsBody?.applyImpulse(CGVectorMake(0,25))
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
All I needed to do to fix my problem was add a simple line of code to my GameScene file. Here is the code I had in the GameScene file before I solved the problem that presents the ArcheryScene:
welcomeNode?.runAction(fadeAway, completion: {
let doors = SKTransition.pushWithDirection(SKTransitionDirection.Down, duration: 1.0)
let archeryScene = ArcheryScene(fileNamed: "ArcheryScene")
self.view?.presentScene(archeryScene, transition: doors)
})
All I had to do was add this line of code after I created "archeryScene":
archeryScene.scaleMode = .AspectFill
This made the images "fit to screen size". The exact description of ".AspectFill" used by Apple is:
"The scaling factor of each dimension is calculated and the larger of the two is chosen. Each axis of the scene is scaled by the same scaling factor. This guarantees that the entire area of the view is filled but may cause parts of the scene to be cropped."

Resources