SKScene and Swift Files are not linking - xcode

In my xcode project I am trying to transition from one SKScene to another. What triggers the transition is the touching of a SKLabelNode. All of that is working correctly. But after the scene changes none of my code from my class that controls the "StartScence.sks" works. It seems as if my "StartScene.swift" and my "StartScene.sks" are not linked.
This is the code in my GameScene,
import SpriteKit
class GameScene: SKScene {
var isTouched: Bool = false
var booleanTouched: Bool!
let ns = SKScene(fileNamed: "StartScene")
let crosswf = SKTransition.crossFadeWithDuration(2)
override func didMoveToView(view: SKView) {
let backgroundimage = SKSpriteNode(imageNamed: "ipbg")
backgroundimage.size = CGSize(width: self.frame.size.width, height: self.frame.size.height)
backgroundimage.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height / 2)
addChild(backgroundimage)
let playButton = SKLabelNode(fontNamed: "")
playButton.name = "play"
playButton.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height / 2 + 100)
playButton.text = "Play"
let wait = SKAction.waitForDuration(2)
let run = SKAction.runBlock({
let randomNumber = Int(arc4random_uniform(UInt32(4)))
switch(randomNumber){
case (0):
playButton.fontColor = UIColor.blueColor()
case 1:
playButton.fontColor = UIColor.yellowColor()
case 2:
playButton.fontColor = UIColor.purpleColor()
case 3:
playButton.fontColor = UIColor.orangeColor()
default: print("default")
}
})
addChild(playButton)
var repeatActionForever = SKAction.repeatActionForever(SKAction.sequence([wait, run]))
runAction(repeatActionForever)
backgroundimage.zPosition = 1
playButton.zPosition = 2
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first! as UITouch
let touchLocation = touch.locationInNode(self)
let touchedNode = nodeAtPoint(touchLocation)
if (touchedNode.name == "play"){
scene!.view?.presentScene(ns!, transition: crosswf)
}else{
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
And this is the code that is my "StartScene.swift" that isnt controlling the "StartScene.sks" properly.
import SpriteKit
class StartScene: SKScene {
override func didMoveToView(view: SKView) {
print("Scene Loaded")
}
}

There's two things to be aware of.
In your code you are currently loading your .SKS file like this
let ns = SKScene(fileNamed: "StartScene")
Your new scene will load, as all SKS Files are of the class SKScene.
But, it will only use code from that class.
If you want it to load with the code in your class StartScene, a subclass of SKScene. Change the line to this
let ns = StartScene(fileNamed: "StartScene")
We can also make the SKS File have a custom class instead of it's default SKScene. So when it's loaded it uses a custom class.
Open the SKS File in Xcode so you can give the scene a Custom Class. In the scene editor and with nothing selected. Click in the utilities area, switch to the Custom Class Inspector, which is the last tab on the right.
Give it a Custom Class of StartScene.
It should work.

Related

Run an SKSpriteNode object along a line drawn with the mouse in Swift

If you let go of the left mouse button, my SKSpriteNode object should move along the line previously "drawn" with the mouse.
My problem is that my sprite node is moving down when I release the left mouse button.
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
let object: SKSpriteNode = SKSpriteNode(imageNamed: "rabbit")
var actionArray = [SKAction()]
override func didMove(to view: SKView) {
physicsWorld.gravity = CGVector(dx: 0, dy: 0)
physicsWorld.contactDelegate = self
object.setScale(0.2)
object.position = CGPoint(x: size.width / 2, y: size.height / 2)
object.zPosition = 0
object.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "rabbit"), size: object.size)
object.physicsBody?.mass = 0
object.physicsBody?.categoryBitMask = 0
object.physicsBody?.contactTestBitMask = 1
object.physicsBody?.collisionBitMask = 0
addChild(object)
}
override func mouseDragged(with event: NSEvent) {
actionArray.append(SKAction.move(to: event.location(in: self), duration: 1))
}
override func mouseUp(with event: NSEvent) {
object.run(SKAction.sequence(actionArray))
// Remove all actions from 'actionArray'.
actionArray.removeAll()
}
}
I have already tried it as shown below. Now my sprite node moves to the first point, where I pressed down the left mouse button.
override func mouseUp(with event: NSEvent) {
let removeAllFromActionArray = SKAction.run {
self.actionArray.removeAll()
}
actionArray.append(removeAllFromActionArray)
object.run(SKAction.sequence(actionArray))
}
I've already tried view! .Convert (event.locationInWindow, to: view! .Scene!) Instead of event.location (in: self), as indicated in Position of mouse click relative to scene, not window, but the result was the same.
I suspect that the bug lies in override func mouseUp(with event: event).
Where does the error lie or is there another solution?

error removing child node from parent node in spriteKit Swift4

I made a parallax background, in GameScene.sks I added an empty node, added two sprites to an empty node. I have a reset button, when I click on it I need the background to be removed and added to its position (restarted), but when I add in scrollBg.removeAllChildren restart function I error occurs, how do I properly add and remove children from the scene ?
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var player: SKSpriteNode!
var scrollBg: SKNode!
var spawnTimer: CFTimeInterval = 0
let fixedDelta: CFTimeInterval = 1.0/60.0 /* 60 FPS */
let scrollSpeed: CGFloat = 700
var sinceTouch: CFTimeInterval = 0
func resetGameScene() {
scrollBG.removeAllChildren()
player.removeAllChildren()
player.position = CGPoint(x: 590 , y: 690)
pauseButton()
}
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
player = childNode(withName: "player") as? SKSpriteNode
scrollBg = childNode(withName: "scrollBG")!
resetGameScene()
}
func scrollWorld() {
scrollBg.position.y -= scrollSpeed * CGFloat(fixedDelta)
for ground in scrollBg.children as! [SKSpriteNode] {
let groundPosition = scrollBg.convert(ground.position, to:
self)
if groundPosition.y <= -ground.size.width {
let newPosition = CGPoint(x: groundPosition.x, y:
(self.size.width ) + ground.size.width * 2)
ground.position = self.convert(newPosition, to:
scrollBg)
}
}
}
override func update(_ currentTime: TimeInterval) {
sinceTouch+=fixedDelta
spawnTimer+=fixedDelta
scrollWorld()
}
}

How can I make SKSpriteNode positions the same for any simulator/device?

In my game, the position of my SKNodes slightly change when I run the App on a virtual simulator vs on a real device(my iPad).
Here are pictures of what I am talking about.
This is the virtual simulator
This is my Ipad
It is hard to see, but the two red boxes are slightly higher on my iPad than in the simulator
Here is how i declare the size and position of the red boxes and green net:
The following code is located in my GameScene.swift file
func loadAppearance_Rim1() {
Rim1 = SKSpriteNode(color: UIColor.redColor(), size: CGSizeMake((frame.size.width) / 40, (frame.size.width) / 40))
Rim1.position = CGPointMake(((frame.size.width) / 2.23), ((frame.size.height) / 1.33))
Rim1.zPosition = 1
addChild(Rim1)
}
func loadAppearance_Rim2(){
Rim2 = SKSpriteNode(color: UIColor.redColor(), size: CGSizeMake((frame.size.width) / 40, (frame.size.width) / 40))
Rim2.position = CGPoint(x: ((frame.size.width) / 1.8), y: ((frame.size.height) / 1.33))
Rim2.zPosition = 1
addChild(Rim2)
}
func loadAppearance_RimNet(){
RimNet = SKSpriteNode(color: UIColor.greenColor(), size: CGSizeMake((frame.size.width) / 7.5, (frame.size.width) / 150))
RimNet.position = CGPointMake(frame.size.width / 1.99, frame.size.height / 1.33)
RimNet.zPosition = 1
addChild(RimNet)
}
func addBackground(){
//background
background = SKSpriteNode(imageNamed: "Background")
background.zPosition = 0
background.size = self.frame.size
background.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
self.addChild(background)
}
Additionally my GameViewController.swift looks like this
import UIKit
import SpriteKit
class GameViewController: UIViewController {
var scene: GameScene!
override func viewDidLoad() {
super.viewDidLoad()
//Configure the view
let skView = view as! SKView
//If finger is on iphone, you cant tap again
skView.multipleTouchEnabled = false
//Create and configure the scene
//create scene within size of skview
scene = GameScene(size: skView.bounds.size)
scene.scaleMode = .AspectFill
scene.size = skView.bounds.size
//scene.anchorPoint = CGPointZero
//present the scene
skView.presentScene(scene)
}
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .Landscape
} else {
return .All
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
How can I make the positions of my nodes be the same for each simulator/physical device?
You should round those floating point values to integers via a call to (int)round(float) so that the values snap to whole pixels. Any place where you use CGPoint or CGSize should use whole pixels as opposed to floating point values.
If you are making a Universal application you need to declare the size of the scene using integer values. Here is an example:
scene = GameScene(size:CGSize(width: 2048, height: 1536))
Then when you initialize the positions and sizes of your nodes using CGPoint and CGSize, make them dependant on SKScene size. Here is an example:
node.position = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2)
If you declare the size of the scene for a Universal App like this:
scene.size = skView.bounds.size
then your SKSpriteNode positions will be all messed up. You may also need to change the scaleMode to .ResizeFill. This worked for me.

SKSpriteNode not able to have multiple children

I'm trying to have multiple sprite nodes of the same type/parent, but when I try to spawn another node I get an error. 'NSInvalidArgumentException', reason: 'Attemped to add a SKNode which already has a parent'
Here's my code:
import SpriteKit
class GameScene: SKScene {
//global declarations
let player = SKSpriteNode(imageNamed: "mage")
let fireball = SKSpriteNode(imageNamed: "fireball")
override func didMoveToView(view: SKView) {
/* Setup your scene here */
createScene()
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
spawnFireball(location)
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
self.enumerateChildNodesWithName("fireball", usingBlock: ({
(node,error) in
if (self.fireball.position.x < -self.fireball.size.width/2.0 || self.fireball.position.x > self.size.width+self.fireball.size.width/2.0
|| self.fireball.position.y < -self.fireball.size.height/2.0 || self.fireball.position.y > self.size.height+self.fireball.size.height/2.0) {
self.fireball.removeFromParent()
self.fireball.removeAllChildren()
self.fireball.removeAllActions()
}
}))
}
func createScene() {
//player
player.size = CGSizeMake(100, 100)
player.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2 + 50)
player.zPosition = 2.0
self.addChild(player)
}
func spawnFireball(point: CGPoint) {
//setup
fireball.name = "fireball"
fireball.size = CGSizeMake(100, 50)
let fireballCenter = CGPointMake(fireball.size.width / 4 * 3, fireball.size.height / 2)
fireball.position = player.position
fireball.physicsBody = SKPhysicsBody(circleOfRadius: fireball.size.height/2, center: fireballCenter)
fireball.physicsBody?.affectedByGravity = false
//action
var dx = CGFloat(point.x - player.position.x)
var dy = CGFloat(point.y - player.position.y)
let magnitude = sqrt(dx * dx + dy * dy)
dx /= magnitude
dy /= magnitude
let vector = CGVector(dx: 32.0 * dx, dy: 32.0 * dy)
var rad = atan2(dy,dx)
fireball.runAction(SKAction.rotateToAngle(rad, duration: 0.0))
self.addChild(fireball)
fireball.physicsBody?.applyImpulse(vector)
}
}
You need to instantiate another SKSpriteNode. In your existing code, you create a single fireball and add it to the scene; your program crashes when you try to add the same fireball again.
First, remove your let fireball = SKSpriteNode... line. Move it to inside the spawnFireball() method, like so:
func spawnFireball(point: CGPoint) {
let fireball = SKSpriteNode(imageNamed: "fireball")
//Insert all customization here (your existing code should mostly work)
self.addChild(fireball)
}
Because the fireball variable is a local variable, you can now instantiate a new one every time you call the function. Now, just change your update() method to properly use enumerateChildrenWithName() by getting changing every self.fireball to just node.
This way, the code will loop through every existing fireball that is currently on the scene, rather than your current code, which only allows you to create one fireball.

SKShapeNode not filling on first time

When I add the follow code , the first sprite is not fill , but the others is normals ( filled red rects )
Anyone know if its is an Bug of Swift in Xcode 7.0 or something thats is missing in GCPath or SKShapeNode configuration
The code is the same of Game Template for OS X with some changes
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
}
func getSprite() -> SKShapeNode
{
let aPath = CGPathCreateMutable()
CGPathAddRect(aPath,nil, CGRect(x: 0, y: 0, width: 100, height: 100))
let shapeNode = SKShapeNode()
shapeNode.strokeColor = SKColor.redColor()
shapeNode.fillColor = SKColor.redColor()
shapeNode.lineWidth = 1
shapeNode.path = aPath
shapeNode.zPosition = 2
return shapeNode
}
override func mouseDown(theEvent: NSEvent) {
/* Called when a mouse click occurs */
let location = theEvent.locationInNode(self)
let sprite = getSprite() //SKSpriteNode(imageNamed:"Spaceship")
sprite.position = location;
sprite.setScale(0.5)
let action = SKAction.rotateByAngle(CGFloat(M_PI), duration:1)
sprite.runAction(SKAction.repeatActionForever(action))
self.addChild(sprite)
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}

Resources