Pause in SpriteKit game - ios

func pause() {
pausedSpeed = self.speed
self.speed = 0
backgroundMusicPlayer.pause()
worldNode.alpha = 0.7
resumeButton = SKShapeNode(rectOfSize: CGSize(width: 100, height: 50))
resumeButton.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 - 50)
resumeButton.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 100, height: 50))
resumeButton.name = resumeButtonName
pauseLabel = SKLabelNode(text: "PAUSED")
pauseLabel.fontSize = 100
pauseLabel.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 + 100)
pauseLabel.fontColor = UIColor.blackColor()
worldNode.addChild(resumeButton)
worldNode.addChild(pauseLabel)
}
Even thought I set self.speed to 0, a node still keeps moving. Any ideas why this might be happening?

Do not change the speed of the node. Just change node.paused = true
In your case, you should define all your control buttons on one SKNode, and declare all the game elements on another SKNode. In that case, if you want to pause the game, just make the second SKNode pause.

Related

Weird Spritekit Collision Bug depending on SKSpriteNode position

I'm having a weird Spritekit issue where my moving SKSpriteNode is passing through a fixed SKSpriteNode depending on the position of the fixed SKSpriteNode.
UPDATE: Code works in simulator but not on real device.
Example:
Placing my bin SKSpriteNode at position x: -500, y: 100 works fine and my moving SKSpriteNode collides as expected.
Placing my bin SKSpriteNode at position x: -600, y: 100 DOES NOT work and my moving SKSpriteNode DOES NOT collide with the bin.
Using view.showsPhysics = true shows that there is physics bodies in both cases.
x values between -500 and -508 work as expected. All other values I have tried did not work.
Collisions with my other fixed SKSpriteNodes work as expected.
enum CollisionTypes: UInt32 {
case Plane = 1
case FloorAndRoof = 2
case OtherObject = 4
case FinishPoint = 8
}
Code to create levels
func createLevel(level: Int) {
switch level {
case 1:
createFloor()
createRoof()
createTable(position: CGPoint(x: 750, y: 150))
createCeilingFan(position: CGPoint(x: 750, y: 560))
createCeilingFan(position: CGPoint(x: 2000, y: 560))
createWaterDispenser(position: CGPoint(x: 1500, y: 212))
createBin(position: CGPoint(x: -500, y: 100)) // THIS IS THE PROBLEM LOCATION
createFinishPoint(position: CGPoint(x: -500, y: 100))
break
case 2:
createFloor()
createRoof()
createTable(position: CGPoint(x: 250, y: 150))
createCeilingFan(position: CGPoint(x: 750, y: 560))
createCeilingFan(position: CGPoint(x: 2000, y: 560))
createWaterDispenser(position: CGPoint(x: 1500, y: 212))
createBin(position: CGPoint(x: -600, y: 100))
createFinishPoint(position: CGPoint(x: -300, y: 200))
break
default:
break
}
}
Moving SKSpriteNode
func createPlane() {
plane = SKSpriteNode(imageNamed: "plane1")
plane.name = "plane1"
//plane.position = CGPoint(x: -UIScreen.main.bounds.width + plane.size.width , y: 0)
plane.position = CGPoint(x: 0, y: 300)
plane.zPosition = 1
//plane.physicsBody = SKPhysicsBody(texture: plane.texture!, size: plane.texture!.size())
plane.physicsBody = SKPhysicsBody(texture: planeTexture, size: planeTexture.size())
plane.physicsBody?.allowsRotation = true
plane.physicsBody?.categoryBitMask = CollisionTypes.Plane.rawValue
plane.physicsBody?.collisionBitMask = CollisionTypes.FloorAndRoof.rawValue | CollisionTypes.OtherObject.rawValue // dont collide with finish point
plane.physicsBody?.contactTestBitMask = CollisionTypes.FloorAndRoof.rawValue | CollisionTypes.OtherObject.rawValue | CollisionTypes.FinishPoint.rawValue
plane.physicsBody?.usesPreciseCollisionDetection = true
plane.physicsBody?.isDynamic = true
plane.physicsBody?.friction = 1
plane.physicsBody?.restitution = 0
plane.physicsBody?.mass = 0.1 // customise for different planes
plane.physicsBody?.angularDamping = 1
plane.physicsBody?.linearDamping = 0.2 // customise for different planes
liftFactor = 0.1 // customise for different planes
addChild(plane)
flightMode = 4 // dead, should drop to floor and change to mode 0 when at rest
//print(flightMode)
}
Bin SKSpriteNode that moving Plane should collide with.
func createBin(position: CGPoint) {
binFront = SKSpriteNode(imageNamed: "binFront")
binFront.name = "binFront"
binFront.setScale(0.15)
binFront.position = position
binFront.zPosition = 2 // in front of plane
addChild(binFront)
binBack = SKSpriteNode(imageNamed: "binBack")
binBack.name = "binBack"
binBack.setScale(0.15)
binBack.position = position
binBack.zPosition = 0 // behind plane
addChild(binBack)
binPhysicsBody = SKSpriteNode(imageNamed: "binPhysicsBody")
binPhysicsBody.name = "binPhysicsBody"
binPhysicsBody.physicsBody = SKPhysicsBody(texture: binPhysicsBody.texture!, size: binPhysicsBody.texture!.size())
binPhysicsBody.setScale(0.15)
binPhysicsBody.physicsBody?.allowsRotation = false
binPhysicsBody.physicsBody?.categoryBitMask = CollisionTypes.OtherObject.rawValue
binPhysicsBody.physicsBody?.collisionBitMask = CollisionTypes.Plane.rawValue
binPhysicsBody.physicsBody?.contactTestBitMask = CollisionTypes.Plane.rawValue
binPhysicsBody.physicsBody?.usesPreciseCollisionDetection = false
binPhysicsBody.physicsBody?.isDynamic = false
binPhysicsBody.physicsBody?.friction = 1
binPhysicsBody.physicsBody?.restitution = 0
binPhysicsBody.physicsBody?.mass = 50
binPhysicsBody.position = position
binPhysicsBody.zPosition = 0
addChild(binPhysicsBody)
}
I still don't know the cause of my issue but I got around it by changing the image used to create my physics body. I used a slightly thicker 'wall thickness' on the bin.

How to change the sprite image and variables

I have this game where players can buy in game upgrades to their vehicles. But I don't know how to change the image of the sprite and the variables. Please help
var tank1 = SKSpritenode(imageName: "firsttank")
var tank2 = SKSpritenode(imageName: "secoundtank")
tank1.size = cgsize(width: 100, height: 100)
tank1.position = cgpoint(x: self.frame.size,width/2, y:
self.frame.size.height/2)
self.addchild(tank1)
tank2.size = cgsize(width: 250, height: 250)
tank2.position = cgpoint(x: self.frame.size,width/2, y: self.frame.size.height/2)
self.addchild(tank2)
How can I make the first sprite (tank1) to turn into tank 2 when a button has been clicked???
You can write:
tank1.texture = tank2.texture
or:
tank1.texture = SKTexture(imageNamed: "secondtank")

SKSpriteNode creates a thin coloured line

So I am using 3 SKSpriteNode's in my application. floorSprite, leftWall and rightWall.
This is the code I am currently using:
let floorSprite = SKSpriteNode()//(imageNamed: "floor")
floorSprite.alpha = 0.0
floorSprite.anchorPoint = CGPoint(x: 0.5, y: CGPoint.zero.y)
floorSprite.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: self.frame.size.width, height: floorSprite.size.height + 12))
floorSprite.physicsBody?.isDynamic = false
floorSprite.physicsBody?.restitution = 0.4
floorSprite.position = CGPoint(x: self.frame.minX, y: self.frame.minY + (floorSprite.size.height / 2))
floorSprite.physicsBody?.contactTestBitMask = 0x1 << 1
floorSprite.physicsBody?.collisionBitMask = 0x1 << 1
floorSprite.zPosition = 4
floorSprite.aspectFillToSize(self.frame.size)
self.addChild(floorSprite)
self.floorSprite = floorSprite
let leftwall = SKSpriteNode()
leftwall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 0.1, height: self.frame.size.height*2))
leftwall.physicsBody?.collisionBitMask = 0x1 << 1
leftwall.physicsBody?.isDynamic = false
leftwall.position = CGPoint(x: 0 , y: self.frame.size.height / 2.0)
leftwall.zPosition = 4
leftwall.physicsBody?.restitution = 1.0
self.addChild(leftwall)
let rightwall = SKSpriteNode()
rightwall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 0.1, height: self.frame.size.height*2))
rightwall.physicsBody?.collisionBitMask = 0x1 << 1
rightwall.physicsBody?.isDynamic = false
rightwall.physicsBody?.restitution = 1.0
rightwall.position = CGPoint(x: self.frame.size.width , y: self.frame.size.height / 2.0)
rightwall.zPosition = 4
self.addChild(rightwall)
Here is a screenshot of the issue I have. You can see the light blue lines that shows. If I remove the self.addChild line, the Sprite is not there, and the light blue color gone.
CLICK HERE FOR IMAGE.
Any ideas what might be wrong here? I have tried adding leftWall.isHidden = true and leftWall.alpha = 0.0 but that has no effect...
This looks like you have SKScene.showPhysics on.. turn this off in your appdelegate (or didmovetoview) or wherever you turned it on, and the lines should go away.
These are caused by your physics bodies :)

how to make a node stack on top of another node and follow the object?

I'm trying to create a game in which i have a object 1 rotatiing in a circle and another object appears and places itself ontop of object 1. currently the object just rotates around object 1 without stacking ontop of it. how do i get the object to stack itself on top and then follow it's orbit? here's my code now.
let player = SKSpriteNode(imageNamed: "Light")
override func didMoveToView(view: SKView) {
// 2
backgroundColor = SKColor.whiteColor()
// 3
player.position = CGPoint(x: size.width * 0.5, y: size.height * 0.5)
// 4
player.size = CGSize(width:70, height:60 )
addChild(player)
let dx = player.position.x - self.frame.width / 2
let dy = player.position.y - self.frame.height / 2
let rad = atan2(dy, dx)
circle = UIBezierPath(arcCenter: CGPoint(x: size.width / 2, y: size.height / 2), radius: 120, startAngle: rad, endAngle: rad + CGFloat(M_PI * 4), clockwise: true)
let follow = SKAction.followPath(circle.CGPath, asOffset: false, orientToPath: true, speed: 100)
player.runAction(SKAction.repeatActionForever(follow))
}
func addMonster() {
let monster = SKSpriteNode(imageNamed: "plate")
// Determine where to spawn the monster along the Y axis
let actualY = random(min: monster.size.height/1, max: size.height - monster.size.height/1)
// Position the monster slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
monster.position = CGPoint(x: size.width * 0.5 + monster.size.width/2, y: actualY)
// Add the monster to the scene
addChild(monster)
// Determine speed of the monster
let actualDuration = random(min: CGFloat(2.0), max: CGFloat(3.0))
// Create the actions
let actionMove = SKAction.moveTo(CGPoint(x: -monster.size.width/2, y: actualY), duration: NSTimeInterval(actualDuration))
let follow = SKAction.followPath(circle.CGPath, asOffset: false, orientToPath:true, speed: 100)
monster.runAction(SKAction.repeatActionForever(follow))
}
Your verbal description appears to have something like the following in mind (you can copy and paste this into an iOS playground):
import UIKit
import SpriteKit
import XCPlayground
let scene = SKScene(size: CGSize(width: 400, height: 400))
let view = SKView(frame: CGRect(origin: .zero, size: scene.size))
view.presentScene(scene)
XCPlaygroundPage.currentPage.liveView = view
scene.backgroundColor = .darkGrayColor()
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
let player = SKShapeNode(rectOfSize: CGSize(width: 70, height: 60), cornerRadius: 5)
let radius: CGFloat = 120
let circle = CGPathCreateWithEllipseInRect(CGRect(x: -radius, y: -radius, width: radius * 2, height: radius * 2), nil)
let followCircle = SKAction.followPath(circle, asOffset: false, orientToPath: true, speed: 100)
player.runAction(.repeatActionForever(followCircle))
let monsterSize = CGSize(width: 35, height: 30)
let monster = SKShapeNode(rectOfSize: monsterSize, cornerRadius: 4)
monster.fillColor = .redColor()
monster.runAction(.repeatActionForever(followCircle))
scene.addChild(player)
scene.addChild(monster)
Where you make use of a random(min:max:) function that is probably implemented along the lines of:
public func random(min min: CGFloat, max: CGFloat) -> CGFloat {
return min + (CGFloat(arc4random()) / CGFloat(UInt32.max)) * (max - min)
}
But you also have the code that seems to be saying:
let y = random(
min: scene.size.height / -2 + monsterSize.height / 2,
max: scene.size.height / 2 - monsterSize.height / 2
)
let xFrom = scene.size.width / 2
let xTo = scene.size.width / -2
monster.position = CGPoint(x: xFrom, y: y)
monster.runAction(
.moveToX(xTo, duration: NSTimeInterval(random(min: 2, max: 3)))
)
But this is unused. Instead the monster is set to follow the same circle path as the player. And so I am not sure really what exactly you are trying to achieve. (By the way, the simplest way of getting the monster "stack on top" of the player would be to make it the child node of the player...)
Hope some of this guesswork helps you in some way (to refine your question and code sample if nothing else).

Adding nodes through update method

I awant to add SKSpriteNode's after something repositioned therefore I want to add the nodes through the update method in Swift Sprite Kit.
There are Objects ( platforms ) that move downwards the y axis, once they are out of screen they appear on the top side again ( like an infinite loop ). I visualize this in the update method. Note that the platforms dont really move, rather then I centered a camera on my Player node that moves up.
After the reposition of the platform node, I want to add an Enemy again on top of the platforms, however because I try it through the update method, it adds sometimes more than 1 node on top of it.
I cant reposition the Enemy like I do with the platforms, because it should be a random enemy node.
Any way to call the SpawnEnemy method in the update method, and check if it was called only once?
My Code:
override func didMoveToView(view: SKView) {
/* Setup your scene here */
self.World = SKNode()
self.World.name = "World"
addChild(World)
self.WorldCamera = SKNode()
self.WorldCamera.name = "Camera"
self.World.addChild(WorldCamera)
....
SpawnPlatforms()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform2.position.y + 30))
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform3.position.y + 30))
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform4.position.y + 30))
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform5.position.y + 30))
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform6.position.y + 30))
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform7.position.y + 30))
}
func SpawnPlatforms() {
Platform0 = SKSpriteNode (color: SKColor.greenColor(), size: CGSize(width: self.frame.size.width * 2 , height: 25))
Platform0.position = CGPoint(x: self.frame.size.width / 2, y: -36)
Platform0.zPosition = 1
Platform0.physicsBody = SKPhysicsBody(rectangleOfSize:Platform0.size)
Platform0.physicsBody?.dynamic = false
Platform0.physicsBody?.allowsRotation = false
Platform0.physicsBody?.restitution = 0.0
Platform0.physicsBody?.usesPreciseCollisionDetection = true
Platform0.physicsBody?.velocity = CGVectorMake(0, 0)
Platform0.physicsBody?.categoryBitMask = Platform0Category
Platform0.physicsBody?.collisionBitMask = PlayerCategory | EnemyCategory
Platform0.physicsBody?.contactTestBitMask = PlayerCategory | EnemyCategory
World.addChild(Platform0)
Platform1 = SKSpriteNode (color: SKColor.redColor(), size: CGSize(width: self.frame.size.width * 2 , height: 25))
Platform1.position = CGPoint(x: self.frame.size.width / 2, y: Platform0.position.y + self.frame.size.height / 4.5)
Platform1.zPosition = 1
Platform1.physicsBody = SKPhysicsBody(rectangleOfSize:Platform1.size)
Platform1.physicsBody?.dynamic = false
Platform1.physicsBody?.allowsRotation = false
Platform1.physicsBody?.restitution = 0
Platform1.physicsBody?.usesPreciseCollisionDetection = true
Platform1.physicsBody?.categoryBitMask = Platform1Category
Platform1.physicsBody?.collisionBitMask = PlayerCategory | EnemyCategory
Platform1.physicsBody?.contactTestBitMask = PlayerCategory | EnemyCategory
World.addChild(Platform1)
....a.s.o. for the other 6 platform nodes
}
func SpawnEnemy(position: CGPoint!){
let random = arc4random_uniform(4)
switch (random) {
case 0:
let node1 = SpawnNode1(position)
self.addChild(node1)
break
case 1:
let node2 = SpawnNode2(position)
self.addChild(node2)
break
case 2:
let node3 = SpawnNode3(position)
self.addChild(node3)
break
case 3:
break
default:
break
}
}
override func didSimulatePhysics() {
WorldCamera.position = CGPoint(x: Player.position.x, y: Player.position.y)
self.centerOnNode(WorldCamera!)
}
func centerOnNode(node: SKNode) {
let cameraPositionInScene: CGPoint = WorldCamera.scene!.convertPoint(WorldCamera.position, fromNode: World)
World.runAction(SKAction.moveTo(CGPoint(x:World.position.x , y:World.position.y - cameraPositionInScene.y), duration: 1.0))
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if(Platform1.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform1.position = CGPointMake(self.frame.size.width / 2, Platform7.position.y + self.frame.size.height / 4.5)
Platform1.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform1.position.y + 30))
}
if(Platform2.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform2.position = CGPointMake(self.frame.size.width / 2, Platform1.position.y + self.frame.size.height / 4.5)
Platform2.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform2.position.y + 30))
}
if(Platform3.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform3.position = CGPointMake(self.frame.size.width / 2, Platform2.position.y + self.frame.size.height / 4.5)
Platform3.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform3.position.y + 30))
}
if(Platform4.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform4.position = CGPointMake(self.frame.size.width / 2, Platform3.position.y + self.frame.size.height / 4.5)
Platform4.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform4.position.y + 30))
}
if(Platform5.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform5.position = CGPointMake(self.frame.size.width / 2, Platform4.position.y + self.frame.size.height / 4.5)
Platform5.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform5.position.y + 30))
}
if(Platform6.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform6.position = CGPointMake(self.frame.size.width / 2, Platform5.position.y + self.frame.size.height / 4.5)
Platform6.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform6.position.y + 30))
}
if(Platform7.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform7.position = CGPointMake(self.frame.size.width / 2, Platform6.position.y + self.frame.size.height / 4.5)
Platform7.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform7.position.y + 30))
}
}
Your problem is you do not create any kind of check that moving the platform has already spawned an enemy. Sure, you move the platform, but until your player moves, it will constantly spawn enemies. I do not see where this is happening, but you should spawn enemy when you move the platform, not on your update
Edit:
yikes, I see it now, this is some ugly code lol, In all those ifs that move the platform, you should spawn the enemy. But this needs to be worked to also check if the previous platform is below the current, not above
Edit++:
Upon further review and added details, try something like this instead:
First, give all Platforms a name "Platform"
Then
override func update(currentTime: CFTimeInterval) {
for node in scene.children
{
if (node.name == "Platform" && !node.intersectsNode(scene) && node.position.y < player.y - (self.frame.size.height / 4.5))
{
let platform = node as! SKSpriteNode
platform.position.y += (7 * (self.frame.size.height / 4.5))
platform.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: platform.position.y + 30))
}
}
}
Question: How does this even work, I would just check if a platform hits a certain point in the scene, recycle it, instead of having to check every single platform and moving it's previous one
so you're spawning an enemy on every frame.. thats going to be way too many enemies.. I'm still not totally following the exact architecture of your game, but this might help you out.
get delta time to see how much time has passed.. and every 10 seconds (or whatever) call your spawn enemy code instead of calling it on every frame
// time values
var delta = NSTimeInterval(0)
var last_update_time = NSTimeInterval(0)
let spawnTimerMax = NSTimeInterval(10)
var spawnTimer = NSTimeInterval(0)
override func update(currentTime: NSTimeInterval) {
if last_update_time == 0.0 {
delta = 0
} else {
delta = currentTime - last_update_time
}
last_update_time = currentTime
// ten seconds elapsed, spawn enemy and restart.
spawnTimer += delta
if spawnTimer >= spawnTimerMax {
// your spawn code goes here
spawnTimer = 0
}
}

Resources