Swift Sprite Kit passing Bool - ios

I got a Image with 2 faces, Up and Down ( Imagine a Card ).
Whenever you tap the Image, it changes it image.
I used a Bool to get the expression. However, after the Scene is presented again, I want to show the image which was Up/Down in the last Scene. Note that this is only 1 Scene, and it presents itself again.
How can I pass a Bool value between the Scene?
//Update:
My Code:
....
var FaceUp = true
....
override func didMoveToView(view: SKView) {
TTexture = SKTexture(imageNamed: "TCard.png")
TTexture.filteringMode = .Nearest
T2Texture = SKTexture(imageNamed: "T2Card.png")
T2Texture.filteringMode = .Nearest
Card = SKSpriteNode(texture: TTexture)
Card.position = CGPoint(x: Rate.position.x - (TransparentLayer.size.width / 3), y: Rate.position.y)
Card.size = CGSize(width: 50, height: 50)
Card.name = "Card"
Card.zPosition = 100
self.addChild(Card)
flip(FaceUp)
}
func flip(state : Bool) {
FaceUp = state
if (!state) {
Card.texture = TTexture //Error
Player.texture = T1
Player.runAction(RunAnimation1)
FaceUp = true
} else {
Card.texture = T2Texture //Error
Player.texture = T2
Player.runAction(RunAnimation2)
FaceUp = false
}
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
let touch:UITouch = touches.anyObject() as UITouch
let touchLocation = touch.locationInNode(self)
let Node:SKNode = self.nodeAtPoint(touchLocation)
if Node.name == "Card" {
let Scale1 = SKAction.scaleTo(0.7, duration: 0.1)
let Scale2 = SKAction.scaleTo(1, duration: 0.1)
let Scaling = SKAction.sequence([Scale1, Scale2])
Card.runAction(Scaling)
self.flip(FaceUp)
}
}
func Restart(){
self.saveHighScore()
LastScore = Score
self.addLeaderboardScore(self.Score)
let Transition = SKTransition.fadeWithDuration(1.8)
let Scene = GameScene(size: self.frame.size)
Scene.LastScore = Score
Scene.FaceUp = FaceUp
scene?.scaleMode = SKSceneScaleMode.AspectFill
self.scene?.view?.presentScene(Scene, transition: Transition)
}

You can define a function in GameScene like the following.
func setCardState(state : Bool) {
FaceUp = state
if (!state) {
Card.texture = Texture2
Player.texture = T2
} else {
Card.texture = Texture1
Player.texture = T1
}
}
And call it from didMoveToView in the new scene.
override func didMoveToView(view: SKView) {
TTexture = SKTexture(imageNamed: "TCard.png")
TTexture.filteringMode = .Nearest
T2Texture = SKTexture(imageNamed: "T2Card.png")
T2Texture.filteringMode = .Nearest
Card = SKSpriteNode(texture: TTexture)
Card.position = CGPoint(x: Rate.position.x - (TransparentLayer.size.width / 3), y: Rate.position.y)
Card.size = CGSize(width: 50, height: 50)
Card.name = "Card"
Card.zPosition = 100
self.addChild(Card)
setCardState(FaceUp) // added line.
}
Also set the old FaceUp value in the new scene in Restart function.
func Restart(){
self.saveHighScore()
LastScore = Score
self.addLeaderboardScore(self.Score)
let Transition = SKTransition.fadeWithDuration(1.8)
let Scene = GameScene(size: self.frame.size)
Scene.LastScore = Score
scene?.scaleMode = SKSceneScaleMode.AspectFill
Scene.FaceUp = FaceUp //changed line.
self.scene?.view?.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.

having a node follow at a constant speed

I'm trying to make a small mini game where you drag a ball around the screen and every 10 seconds a ball gets added in that follows you. so far the you can drag a ball around the screen and a ball follows you, but when another ball gets added in the balls group together. I think this is because the ball is following me depending on how fast I'm going. so is there a certain way in which I can have the balls follow me at a certain speed constantly, like 10 pixels a second or something, and that should prevent the balls from grouping together.
I am currently working on the score so it should soon go up every second you survive. and you die if you touch one of the balls.
below is the code and a short gif of my current code
!(https://gyazo.com/1d6a56527bfd0884e8a26cff730f4e03)
import SpriteKit
import GameplayKit
struct physicsCatagory{
static let me : UInt32 = 0x1 << 1
static let enemy : UInt32 = 0x1 << 2
}
class GameScene: SKScene, SKPhysicsContactDelegate {
private func makeEnemyName() -> String {
enemyCounter += 1
return "enemy\(enemyCounter)"
}
private func addEnemyToDict(enemy: SKSpriteNode, target: SKSpriteNode) {
if let name = enemy.name { spriteDictionary[name] = (enemy, target) }
else { print("enemy not found") }
}
private func removeEnemyFromDict(enemy: SKSpriteNode) {
if let name = enemy.name { spriteDictionary[name] = nil }
else { print("enemy not removed from dictionary!") }
}
private func moveFollowerToTarget(_ sprites: FollowerAndTarget) {
let action = SKAction.move(to: sprites.target.position, duration: 1)
sprites.follower.run(action)
}
private func allEnemiesMoveToTarget() {
for sprites in spriteDictionary.values {
moveFollowerToTarget(sprites)
}
}
let enemySpeed: CGFloat = 300
var me = SKSpriteNode()
// Tuple to keep track of enemy objects:
typealias FollowerAndTarget = (follower: SKSpriteNode, target: SKSpriteNode)
// [followerName: (followerSprite, targetSprite):
var spriteDictionary: [String: FollowerAndTarget] = [:]
// Give each enemy a unique name for the dictionary:
var enemyCounter = 0
var died = Bool()
override func didMove(to view: SKView) {
createScene()
}
func createEnemy () {
if died == true{
}
else {
let enemy = SKSpriteNode(imageNamed: "enemy1")
enemy.name = makeEnemyName()
addEnemyToDict(enemy: enemy, target: me)
moveFollowerToTarget((follower: enemy, target: me))
enemy.size = CGSize(width: 60, height: 60)
enemy.position = CGPoint(x:667, y: 200)
enemy.physicsBody?.restitution = 0.5
enemy.physicsBody = SKPhysicsBody(circleOfRadius: 60)
enemy.physicsBody?.affectedByGravity = false
enemy.zPosition = 2
enemy.physicsBody?.linearDamping = 0
enemy.physicsBody?.isDynamic = true
enemy.physicsBody?.categoryBitMask = physicsCatagory.enemy
enemy.physicsBody?.collisionBitMask = physicsCatagory.me
enemy.physicsBody?.contactTestBitMask = physicsCatagory.me
addChild(enemy)
}
}
func didBegin(_ contact: SKPhysicsContact) {
let firstBody = contact.bodyA
let secondBody = contact.bodyB
if firstBody.categoryBitMask == physicsCatagory.me && secondBody.categoryBitMask == physicsCatagory.enemy || firstBody.categoryBitMask == physicsCatagory.enemy && secondBody.categoryBitMask == physicsCatagory.me {
died = true
restartScene()
}
}
var lose: SKLabelNode!
func restartScene(){
self.removeAllChildren()
self.removeAllActions()
died = false
if let nextScene = GameScene(fileNamed: "menuScene"){
nextScene.scaleMode = self.scaleMode
let transition = SKTransition.fade(withDuration: 1)
view?.presentScene(nextScene, transition: transition)
}
}
func createScene(){
me = self.childNode(withName: "me") as! SKSpriteNode
me.physicsBody = SKPhysicsBody(circleOfRadius: 20)
me.physicsBody?.affectedByGravity = false
me.physicsBody?.categoryBitMask = physicsCatagory.me
me.physicsBody?.collisionBitMask = physicsCatagory.enemy
me.zPosition = 2
self.physicsWorld.contactDelegate = self
let border = SKPhysicsBody (edgeLoopFrom: self.frame)
border.friction = 0
self.physicsBody = border
run(SKAction.repeatForever(SKAction.sequence([SKAction.run(createEnemy), SKAction.wait(forDuration: 4.0)])))
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
me.run(SKAction.moveTo(x: location.x, duration: 0))
me.run(SKAction.moveTo(y: location.y, duration: 0))
allEnemiesMoveToTarget()
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
me.run(SKAction.moveTo(x: location.x, duration: 0))
me.run(SKAction.moveTo(y: location.y, duration: 0))
allEnemiesMoveToTarget()
}
}
override func update(_ currentTime: TimeInterval) {
// Will iterate through dictonary and then call moveFollowerToTarget()
// thus giving each enemy a new movement action to follow.
allEnemiesMoveToTarget()
}
}
Here you go:
import SpriteKit
import GameplayKit
struct physicsCatagory{
static let me : UInt32 = 0x1 << 1
static let enemy : UInt32 = 0x1 << 2
static let coin : UInt32 = 0x1 << 3
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var lose: SKLabelNode!
var me = SKSpriteNode()
// Tuple to keep track of enemy objects:
typealias FollowerAndTarget = (follower: SKSpriteNode, target: SKSpriteNode)
// [followerName: (followerSprite, targetSprite):
var spriteDictionary: [String: FollowerAndTarget] = [:]
// Give each enemy a unique name for the dictionary:
var enemyCounter = 0
let enemySpeed: CGFloat = 3
var died = Bool()
var timer = SKLabelNode()
var timerValue: Int = 0 {
didSet {
timer.text = "\(timerValue)"
}
}
private func makeEnemyName() -> String {
enemyCounter += 1
return "enemy\(enemyCounter)"
}
private func addEnemyToDict(enemy: SKSpriteNode, target: SKSpriteNode) {
if let name = enemy.name { spriteDictionary[name] = (enemy, target) }
else { print("enemy not found") }
}
private func removeEnemyFromDict(enemy: SKSpriteNode) {
if let name = enemy.name { spriteDictionary[name] = nil }
else { print("enemy not removed from dictionary!") }
}
// dont change anything outside of this, this is what makes the enemy follow you, so i have to have the enemy follow me at a constant speed
private func moveFollowerToTarget(_ sprites: FollowerAndTarget) {
let location = me.position
// Aim
let dx = location.x - sprites.follower.position.x
let dy = location.y - sprites.follower.position.y
let angle = atan2(dy, dx)
sprites.follower.zRotation = angle
// Seek
let vx = cos(angle) * enemySpeed
let vy = sin(angle) * enemySpeed
sprites.follower.position.x += vx
sprites.follower.position.y += vy
}
private func allEnemiesMoveToTarget() {
for sprites in spriteDictionary.values {
moveFollowerToTarget(sprites)
}
}
private func keepEnemiesSeparated() {
for sprites in spriteDictionary.values {
let iterator = sprites.follower
iterator.constraints = []
// get every other follower:
var otherFollowers: [SKSpriteNode] = []
for sprites in spriteDictionary.values {
if sprites.follower == iterator { continue }
else { otherFollowers.append(sprites.follower) }
}
// Assign constrain
for follower in otherFollowers {
let distanceBetween = CGFloat(60)
let constraint = SKConstraint.distance(SKRange(lowerLimit: distanceBetween), to: follower)
iterator.constraints!.append(constraint)
}
}
}
func createEnemy () {
if died { return }
let enemy = SKSpriteNode(color: .green, size: CGSize(width: 60, height: 60))
enemy.size = CGSize(width: 60, height: 60)
enemy.zPosition = 2
enemy.position.y -= size.height / 2
enemy.physicsBody = {
let pb = SKPhysicsBody(circleOfRadius: 30)
pb.restitution = 0.5
pb.affectedByGravity = false
pb.linearDamping = 0
pb.isDynamic = true
pb.categoryBitMask = physicsCatagory.enemy
pb.collisionBitMask = physicsCatagory.me
pb.contactTestBitMask = physicsCatagory.me
return pb
}()
enemy.name = makeEnemyName()
addEnemyToDict(enemy: enemy, target: me)
moveFollowerToTarget((follower: enemy, target: me))
keepEnemiesSeparated()
addChild(enemy)
}
func createCoin () {
let coin = SKSpriteNode(color: .yellow, size: CGSize(width: 20, height: 20))
let height = self.view!.frame.height
let width = self.view!.frame.width
let randomPosition = CGPoint( x:CGFloat( arc4random_uniform( UInt32( floor( width ) ) ) ),
y:CGFloat( arc4random_uniform( UInt32( floor( height ) ) ) )
)
coin.position = randomPosition
addChild(coin)
}
func restartScene(){
self.removeAllChildren()
self.removeAllActions()
died = false
let nextScene = GameScene(size: self.size)
nextScene.scaleMode = self.scaleMode
let transition = SKTransition.fade(withDuration: 1)
view?.presentScene(nextScene, transition: transition)
}
func createScene(){
me = SKSpriteNode(color: .blue, size: CGSize(width: 60, height: 60))
me.physicsBody = SKPhysicsBody(circleOfRadius: 30)
me.physicsBody?.affectedByGravity = false
me.physicsBody?.categoryBitMask = physicsCatagory.me
me.physicsBody?.collisionBitMask = physicsCatagory.enemy
me.zPosition = 2
timer = SKLabelNode(fontNamed: "Chalkduster")
timer.text = "\(timerValue)"
addChild(me)
addChild(timer)
let wait = SKAction.wait(forDuration: 1)
let block = SKAction.run({
[unowned self] in
if self.timerValue >= 0{
self.timerValue += 1
}else{
self.removeAction(forKey: "countdown")
}
})
let sequence = SKAction.sequence([wait,block])
run(SKAction.repeatForever(sequence), withKey: "countdown")
self.physicsWorld.contactDelegate = self
let border = SKPhysicsBody (edgeLoopFrom: self.frame)
border.friction = 0
self.physicsBody = border
run(SKAction.repeatForever(SKAction.sequence([SKAction.run(createEnemy), SKAction.wait(forDuration: 2.0)])))
run(SKAction.repeatForever(SKAction.sequence([SKAction.run(createCoin), SKAction.wait(forDuration: TimeInterval(arc4random_uniform(11) + 5))])))
}
override func didMove(to view: SKView) {
scene?.anchorPoint = CGPoint(x: 0.5, y: 0.5)
createScene()
}
func didBegin(_ contact: SKPhysicsContact) {
let firstBody = contact.bodyA
let secondBody = contact.bodyB
if firstBody.categoryBitMask == physicsCatagory.me && secondBody.categoryBitMask == physicsCatagory.enemy
|| firstBody.categoryBitMask == physicsCatagory.enemy && secondBody.categoryBitMask == physicsCatagory.me {
died = true
restartScene()
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
me.run(SKAction.moveTo(x: location.x, duration: 0))
me.run(SKAction.moveTo(y: location.y, duration: 0))
allEnemiesMoveToTarget()
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
me.run(SKAction.moveTo(x: location.x, duration: 0))
me.run(SKAction.moveTo(y: location.y, duration: 0))
allEnemiesMoveToTarget()
}
}
override func update(_ currentTime: TimeInterval) {
// Will iterate through dictonary and then call moveFollowerToTarget()
// thus giving each enemy a new movement action to follow.
allEnemiesMoveToTarget()
}
}

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)

JoyStick only moves when Camera Controls = true Xcode, SWIFT, SpriteKit, SceneKit

Hey I have a 3D game thats not really a game yet. But it has a SceneKit 3D scene and a overlayskscene for the HUD/Controls. the "base" is the base of the joystick and the ball is the handle the problem is that the joystick does not move at all unless the scnView.allowsCameraControl = true. I find that weird. and this is my entire view controller code so nothings left out and if you want you can literally copy and paste it into Xcode to see what I'm talking about. Any help?
Code:
import iAd
import UIKit
import GameKit
import SceneKit
import StoreKit
import SpriteKit
import QuartzCore
import Foundation
import AVFoundation
import AudioToolbox
class GameViewController: UIViewController, ADBannerViewDelegate, SKPhysicsContactDelegate, SKSceneDelegate, SCNSceneRendererDelegate, SCNPhysicsContactDelegate{
var stickActive:Bool = false
let base = SKSpriteNode(imageNamed:"VirtualJoystickBase")
let ball = SKSpriteNode(imageNamed:"VirtualJoyStickHandle")
let ship = SKSpriteNode(imageNamed:"Ship")
var ButtonA = SKSpriteNode(imageNamed:"GreenAButton")
var ButtonO = SKSpriteNode(imageNamed:"CircleButton")
var ButtonY = SKSpriteNode(imageNamed:"YellowYButton")
var ButtonSquare = SKSpriteNode(imageNamed:"BlueSquareButton")
let FieldScene = SCNScene(named: "art.scnassets/TesingCampusField.dae")!
let GuyScene = SCNScene(named: "art.scnassets/Guy.dae")!
let overlayScene = SKScene(size: CGSizeMake(100, 100))
override func viewDidLoad() {
super.viewDidLoad()
let scnView = self.view as! SCNView
scnView.overlaySKScene = overlayScene
scnView.backgroundColor = UIColor.whiteColor()
scnView.scene = FieldScene
scnView.delegate = self
scnView.overlaySKScene!.delegate = self
scnView.overlaySKScene!.anchorPoint = CGPointMake(0, 0)
scnView.overlaySKScene!.physicsWorld.contactDelegate = self
scnView.overlaySKScene!.physicsWorld.gravity = CGVectorMake(0.0, 0.0)
scnView.allowsCameraControl = true
scnView.showsStatistics = false
let Guy1: SCNNode = GuyScene.rootNode.childNodeWithName("Bob_014", recursively: true)!
FieldScene.rootNode.addChildNode(Guy1)
//----Positioning-the-Base-of-the-Joystick-----------
base.size = CGSize(width: 14, height: 24)
base.position = CGPointMake(15, 19)
base.zPosition = 0
overlayScene.addChild(base)
//----Positing-the-Ball/Joystick-----------
ball.size = CGSize(width: 10, height: 17)
ball.position = base.position
ball.zPosition = 1
overlayScene.addChild(ball)
//----A-Button--Creation -------------------
ButtonA.size = CGSize(width: 6, height: 9)
ButtonA.anchorPoint = CGPointMake(-13.3, -0.5)
ButtonA.zPosition = 0
overlayScene.addChild(ButtonA)
//----B-Button--Creation -------------------
ButtonO.size = CGSize(width: 6, height: 9)
ButtonO.anchorPoint = CGPointMake(-14.4, -1.7)
ButtonO.zPosition = 0
overlayScene.addChild(ButtonO)
//----C-Button--Creation -------------------
ButtonSquare.size = CGSize(width: 6, height: 9)
ButtonSquare.anchorPoint = CGPointMake(-12.2, -1.7)
ButtonSquare.zPosition = 0
overlayScene.addChild(ButtonSquare)
//----C-Button--Creation -------------------
ButtonY.size = CGSize(width: 6, height: 9)
ButtonY.anchorPoint = CGPointMake(-13.3, -2.7)
ButtonY.zPosition = 0
overlayScene.addChild(ButtonY)
//---Setting-Up-Ships-Position/PhysicsBody---------------------
ship.position = CGPointMake(0, 100)
ship.size = CGSize(width: 80, height: 80)
ship.physicsBody?.dynamic = true
ship.physicsBody?.allowsRotation = true
ship.physicsBody?.affectedByGravity = true
ship.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Ship"), size: ship.size)
ship.physicsBody!.friction = 0
ship.physicsBody!.restitution = 0
ship.physicsBody!.linearDamping = 0
ship.physicsBody!.angularDamping = 0
//--------------------------
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
GuyScene.rootNode.addChildNode(cameraNode)
cameraNode.position = SCNVector3(x: 0, y: 5, z: 15)
//-----------------------------------------------
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = SCNLightTypeOmni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
FieldScene.rootNode.addChildNode(lightNode)
//-----------------------------------------------
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = UIColor.darkGrayColor()
FieldScene.rootNode.addChildNode(ambientLightNode)
//----------------------------------------------
}
func YButtonPressed() {
let YButtonPressed = SKTexture(imageNamed: "YellowYButtonPressed")
let OrignalButtonY = SKTexture(imageNamed:"YellowYButton")
let YButtonPressedAnimation = SKAction.animateWithTextures([YButtonPressed, OrignalButtonY], timePerFrame: 0.2)
let RunYButtonPressedAnimation = SKAction.repeatAction(YButtonPressedAnimation, count: 1)
ButtonY.runAction(RunYButtonPressedAnimation)
}
func OButtonPressed() {
let OButtonPressed = SKTexture(imageNamed: "CircleButtonPressed")
let OrignalButtonO = SKTexture(imageNamed:"CircleButton")
let OButtonPressedAnimation = SKAction.animateWithTextures([OButtonPressed, OrignalButtonO], timePerFrame: 0.2)
let RunOButtonPressedAnimation = SKAction.repeatAction(OButtonPressedAnimation, count: 1)
ButtonO.runAction(RunOButtonPressedAnimation)
}
func SquareButtonPressed() {
let SquareButtonPressed = SKTexture(imageNamed: "BlueSquareButtonPressed")
let OrignalButtonSquare = SKTexture(imageNamed:"BlueSquareButton")
let SquareButtonPressedAnimation = SKAction.animateWithTextures([SquareButtonPressed, OrignalButtonSquare], timePerFrame: 0.2)
let RunSquareButtonPressedAnimation = SKAction.repeatAction(SquareButtonPressedAnimation, count: 1)
ButtonSquare.runAction(RunSquareButtonPressedAnimation)
}
func AButtonPressed() {
let AButtonPressed = SKTexture(imageNamed: "GreenAButtonPressed")
let OrignalButtonA = SKTexture(imageNamed:"GreenAButton")
let AButtonPressedAnimation = SKAction.animateWithTextures([AButtonPressed, OrignalButtonA], timePerFrame: 0.2)
let RunAButtonPressedAnimation = SKAction.repeatAction(AButtonPressedAnimation, count: 1)
ButtonA.runAction(RunAButtonPressedAnimation)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self.overlayScene)
if (CGRectContainsPoint(base.frame, location)) {
print("stickActive = true")
stickActive = true
} else {
print("stickActive = false")
stickActive = false
}
}
for touch: AnyObject in touches {
let location1 = touch.locationInNode(self.overlayScene)
if self.overlayScene.nodeAtPoint(location1) == self.ButtonA {
AButtonPressed()
print("AButtonPressed")
}
}
for touch: AnyObject in touches {
let location2 = touch.locationInNode(self.overlayScene)
if self.overlayScene.nodeAtPoint(location2) == self.ButtonO {
OButtonPressed()
print("OButtonPressed")
}
}
for touch: AnyObject in touches {
let location3 = touch.locationInNode(self.overlayScene)
if self.overlayScene.nodeAtPoint(location3) == self.ButtonY {
YButtonPressed()
print("YButtonPressed")
}
}
for touch: AnyObject in touches {
let location4 = touch.locationInNode(self.overlayScene)
if self.overlayScene.nodeAtPoint(location4) == self.ButtonSquare {
SquareButtonPressed()
print("SquarButtonPressed")
}
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self.overlayScene)
if self.overlayScene.nodeAtPoint(location) == self.ball {
if (stickActive == true) {
let v = CGVector(dx: location.x - base.position.x, dy: location.y - base.position.y)
let angle = atan2(v.dy, v.dx)
//println( deg + 180)
let length:CGFloat = base.frame.size.height / 2
let xDist:CGFloat = sin(angle - 1.57879633) * length
let yDist:CGFloat = cos(angle - 1.57879633) * length
if (CGRectContainsPoint(base.frame, location)) {
ball.position = location
} else {
ball.position = CGPointMake( base.position.x - xDist, base.position.y + yDist)
}
ship.zRotation = angle - 1.57879633
let calcRotation : Float = Float(angle - 1.57879633) + Float(M_PI_2);
let intensity : CGFloat = 200.0 // put your value
let xVelocity = intensity * CGFloat(cosf(calcRotation))
let yVelocity = intensity * CGFloat(sinf(calcRotation))
let vector : CGVector = CGVectorMake(xVelocity, yVelocity)
//Apply force to spaceship
ship.physicsBody?.applyForce(vector)
// ends stackActive
}
}
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self.overlayScene)
if self.overlayScene.nodeAtPoint(location) == self.ball {
if (stickActive == true) {
let move:SKAction = SKAction.moveTo(base.position, duration: 0.05)
move.timingMode = .EaseOut
ball.runAction(move)
}
}
}
}
//====================================================================
override func shouldAutorotate() -> Bool {
return true
}
//====================================================================
override func prefersStatusBarHidden() -> 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.
}
}
there's an issue in SceneKit where the SpriteKit overlay isn't automatically redrawn when changes are made in the 2D scene but the 3D scene is left untouched. In other words, the 2D overlay is only redrawn when the 3D view needs to be redrawn.
You can set the playing property of the SCNView to YES to fix this. Alternatively you can call -setNeedsDisplay whenever you make a change to the overlay scene.

Sprite Kit Game Scene changes when it is not supposed to

In a game that I am currently building a person is supposed to catch balls that are falling from the sky. If the ball goes off the screen it means he didn't catch the ball, and so the scene is supposed to change to a game over scene. The problem is that even if the ball doesn't go below the screen the screen will change. But the screen will change to a blank screen so instead of the GameOverScene().
Here is the code for the GameScene()...
//
// GameScene.swift
// catch balls
//
// Created by Ankith Udupa on 8/10/15.
// Copyright (c) 2015 UdupaLabs. All rights reserved.
//
import SpriteKit
var score = 0
var lossFlag = false
class GameScene: SKScene, SKPhysicsContactDelegate {
var person = SKSpriteNode(imageNamed: "guyLeft_1.png")
var left = true
let kScoreHudName = "scoreHud"
struct PhysicsCategory {
static let None : UInt32 = 0
static let All : UInt32 = UInt32.max
static let Ball : UInt32 = 0b1
static let Person: UInt32 = 0b10
}
override func didMoveToView(view: SKView) {
var content = false
//set up screen
setUpScreen()
//set up the physics
physicsWorld.gravity = CGVectorMake(0, 0)
physicsWorld.contactDelegate = self
//add ball
runAction(SKAction.repeatActionForever(
SKAction.sequence([
SKAction.runBlock(addBall),
SKAction.waitForDuration(1.0)
])
))
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
left = !left
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if ((person.position.x > person.size.width/2) && (person.position.x < size.width-(person.size.width/2))){
if left {
var leftMove = SKAction.moveByX(5, y: 0, duration: 0.1)
person.runAction(leftMove)
}
if !left { // or use an if-else construct
var rightMove = SKAction.moveByX(-5, y: 0, duration: 0.1)
person.runAction(rightMove)
}
}
}
//random number gen functions
func random() -> CGFloat {
return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
}
func random(#min: CGFloat, max: CGFloat) -> CGFloat {
return random() * (max - min) + min
}
//add ball function
func addBall(){
//create ball sprite
var ball = SKSpriteNode(imageNamed: "ball.png")
//create physics for ball
ball.physicsBody = SKPhysicsBody(rectangleOfSize: ball.size) // 1
ball.physicsBody?.dynamic = true // 2
ball.physicsBody?.categoryBitMask = PhysicsCategory.Ball // 3
ball.physicsBody?.contactTestBitMask = PhysicsCategory.Person // 4
ball.physicsBody?.collisionBitMask = PhysicsCategory.None // 5
//generate random postion along x axis for ball to spawn
let actualX = random(min:ball.size.width/2+1, max: size.width - ball.size.width/2-1)
//set balls positon
ball.position = CGPoint(x: actualX, y: size.height - ball.size.width/2)
//add ball to scene
addChild(ball)
//determine speed of ball
let actualDuration = random(min: CGFloat(3.0), max: CGFloat(5.0))
//create movement actions and run them
let actionMove = SKAction.moveTo(CGPoint(x:actualX, y: -ball.size.width/2), duration: NSTimeInterval(actualDuration))
let actionMoveDone = SKAction.removeFromParent()
let Loss = SKAction.runBlock() {
let reveal = SKTransition.crossFadeWithDuration(0.1)
let gameOverScene = GameOverScene()
self.view?.presentScene(GameOverScene(), transition: reveal)
}
ball.runAction(SKAction.sequence([actionMove, Loss, actionMoveDone]))
}
//setUpScreen
func setUpScreen(){
self.backgroundColor = SKColor.whiteColor()
var ground = SKShapeNode(rectOfSize: CGSizeMake(self.frame.size.width, self.frame.size.height * 0.2))
ground.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height * 0.1)
ground.fillColor = SKColor.blueColor()
self.addChild(ground)
person.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height * 0.2)
setUpPersonPhysics()
self.addChild(person)
}
//set up person physics
func setUpPersonPhysics(){
person.physicsBody = SKPhysicsBody(rectangleOfSize: person.size)
person.physicsBody?.dynamic = true
person.physicsBody?.categoryBitMask = PhysicsCategory.Person
person.physicsBody?.contactTestBitMask = PhysicsCategory.Ball
person.physicsBody?.collisionBitMask = PhysicsCategory.None
person.physicsBody?.usesPreciseCollisionDetection = true
}
func didBeginContact(contact: SKPhysicsContact) {
// 1
var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
}
else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
// 2
if ((firstBody.categoryBitMask & PhysicsCategory.Ball != 0) &&
(secondBody.categoryBitMask & PhysicsCategory.Person != 0)) {
personDidCollideWithBall(secondBody.node as! SKSpriteNode, ball: firstBody.node as! SKSpriteNode)
}
}
//called when person collides with ball
func personDidCollideWithBall(person:SKSpriteNode, ball:SKSpriteNode) {
println("hit")
ball.removeFromParent()
score++
}
}
and here is the code for the gameOverScene()...
//
// gameOverScene.swift
// catch babies
//
// Created by Ankith Udupa on 8/12/15.
// Copyright (c) 2015 UdupaLabs. All rights reserved.
//
import Foundation
import SpriteKit
class GameOverScene: SKScene {
var message = "Game Over"
override func didMoveToView(view: SKView) {
self.backgroundColor = SKColor.whiteColor()
setUpTextOutPut()
}
func setUpTextOutPut(){
let gameOverLabel = SKLabelNode(fontNamed: "Superclarendon-Black")
gameOverLabel.text = message
gameOverLabel.fontSize = 40
gameOverLabel.fontColor = SKColor.orangeColor()
gameOverLabel.position = CGPoint(x: size.width/2, y: size.height/2)
addChild(gameOverLabel)
let scoreLabel = SKLabelNode(fontNamed: "Superclarendon-Black")
scoreLabel.text = "\(score)"
scoreLabel.fontSize = 40
scoreLabel.fontColor = SKColor.orangeColor()
scoreLabel.position = CGPoint(x: size.width/2, y: size.height/2-50)
addChild(scoreLabel)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
}
}
The error is with your addBall method,
//add ball function
func addBall(){
//create ball sprite
var ball = SKSpriteNode(imageNamed: "ball.png")
//create physics for ball
ball.physicsBody = SKPhysicsBody(rectangleOfSize: ball.size) // 1
ball.physicsBody?.dynamic = true // 2
ball.physicsBody?.categoryBitMask = PhysicsCategory.Ball // 3
ball.physicsBody?.contactTestBitMask = PhysicsCategory.Person // 4
ball.physicsBody?.collisionBitMask = PhysicsCategory.None // 5
//generate random postion along x axis for ball to spawn
let actualX = random(min:ball.size.width/2+1, max: size.width - ball.size.width/2-1)
//set balls positon
ball.position = CGPoint(x: actualX, y: size.height - ball.size.width/2)
//add ball to scene
addChild(ball)
//determine speed of ball
let actualDuration = random(min: CGFloat(3.0), max: CGFloat(5.0))
//create movement actions and run them
let actionMove = SKAction.moveTo(CGPoint(x:actualX, y: -ball.size.width/2), duration: NSTimeInterval(actualDuration))
let actionMoveDone = SKAction.removeFromParent()
let Loss = SKAction.runBlock() {
let reveal = SKTransition.crossFadeWithDuration(0.1)
let gameOverScene = GameOverScene()
self.view?.presentScene(GameOverScene(), transition: reveal)
}
ball.runAction(SKAction.sequence([actionMove, Loss, actionMoveDone]))
}
If you look at the method properly, you ask to run the sequence to the sprite and inside runBlock, you move to another scene. Do you need to check if the ball is outside bounds inside this block and only then present your game over scene ?
Should it be something like this,
let Loss = SKAction.runBlock() {
if ball.position.x > self.size.width + ball.frame.size.width * 0.5 || ball.position.y < ball.frame.size.height * 0.5 {
let reveal = SKTransition.crossFadeWithDuration(0.1)
let gameOverScene = GameOverScene()
self.view?.presentScene(GameOverScene(), transition: reveal)
}
}

Resources