Does anyone know what the code would be to make a background image that would cover the whole GameScene.swift
This is my code atm -
import SpriteKit
class GameScene: SKScene {
let playbutton = SKSpriteNode (imageNamed: "play")
let score = SKSpriteNode (imageNamed: "score")
var background = SKSpriteNode (imageNamed: "background")
override func didMoveToView(view: SKView) {
func loadBackGround()
{
background = SKSpriteNode(imageNamed: "background")
background.name = "background"
background.zPosition = 1.0
background.size = self.scene.size
scene.addChild(background)
}
self.playbutton.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
self.addChild(self.playbutton)
self.score.position = CGPointMake(CGRectGetMidX(self.frame), 100)
self.addChild(self.score)
You may have to be more specific (iOS Game, Mac Game...), but I think something like this should work:
var bgImage:SKSpriteNode
func loadBackGround()
{
bgImage = SKSpriteNode(imageNamed: "BACKGROUND IMAGE NAME")
bgImage.name = "bg"
bg.size = self.scene.size
scene.addChild(bg)
}
(you can use it outside of a function of course)
EDIT: Try this code:
import SpriteKit
class GameScene: SKScene {
let playbutton = SKSpriteNode (imageNamed: "play")
let score = SKSpriteNode (imageNamed: "score")
var background = SKSpriteNode ()
func loadBackGround() // You define the function and what it does
{
background = SKSpriteNode(imageNamed: "background")
background.name = "background"
background.size = self.scene.size
scene.addChild(background)
}
override func didMoveToView(view: SKView) {
loadBackGround() // You call the function you defined
self.playbutton.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
self.addChild(self.playbutton)
self.score.position = CGPointMake(CGRectGetMidX(self.frame), 100)
self.addChild(self.score)
}
This is the way I use:
override init(size: CGSize) {
super.init(size: size)
anchorPoint = CGPoint(x: 0.5, y: 0.5)
let background = SKSpriteNode(imageNamed: "Background")
addChild(background)
}
This loads the background image from the asset catalog and places it in the scene. Because the scene’s anchorPoint is (0.5, 0.5), the background image will always be centered on the screen on both 3.5-inch and 4-inch devices.
I get this from a good tutorial: How to Make a Game Like Candy Crush with Swift Tutorial: Part 1
Related
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.
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.
I added Score Label in my game. But It doesn't run. When I touch the ball, Score should be increase. I couldn't connect ball with score label. Can anyone help me? Here is my code :
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
physicsWorld.gravity = CGVectorMake(5, 5)
let ball = childNodeWithName(BallCategoryName) as! SKSpriteNode
ball.physicsBody!.applyImpulse(CGVectorMake(10, -10))
scoreLabel.fontName = "Helvetica Neue Light"
scoreLabel.text = "Score: 0"
scoreLabel.fontSize = 40
scoreLabel.color = SKColor.redColor()
scoreLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Left
scoreLabel.verticalAlignmentMode = SKLabelVerticalAlignmentMode.Top
scoreLabel.position = CGPoint(x: 250, y: size.height - 100)
addChild(scoreLabel)
}
And there is touch code :
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch:AnyObject in touches{
let location = (touch as! UITouch).locationInNode(self)
let nodeTouched = nodeAtPoint(location)
let ball = childNodeWithName(BallCategoryName) as! SKSpriteNode
//Detect if the ball is touched
if(nodeTouched == ball){
physicsWorld.gravity = CGVectorMake(-30, 30)
}
}
Try this instead:
if ((nodeTouched.name?.containsString(BallCategoryName)) != nil) {
//Update Score
}
Keep in mind that we don't know exactly what BallCategoryName is or how you set it up, so you have to make sure it isn't nil.
Also, if your current method in touchesBegan is running your physicsWorld.gravity = CGVectorMake(-30, 30) line successfully, then we would know that something is wrong with your scoreLabel property and not the touch detection method.
If it was me, I would just make ball a property of your scene and then test it like so in touchesBegan:
if self.ball.containsPoint(touchLocation) {
//Update Score
}
I am trying to have all the setup functions in a separate class called Setup, like this:
class Setup {
var scene: GameScene!
init(scene: GameScene){
self.scene = scene
}
func setupBackground(bg1: SKSpriteNode, bg2: SKSpriteNode) {
bg1.anchorPoint = CGPointZero
bg1.position = CGPointMake(0, 0)
bg1.size = CGSize(width: scene.size.width, height: scene.size.height)
scene.addChild(bg1)
bg2.anchorPoint = CGPointZero
bg2.position = CGPointMake(0, bg1.size.height + 1)
bg2.size = CGSize(width: scene.size.width, height: scene.size.height)
scene.addChild(bg2)
}
}
And then calling it in GameScene like this:
class GameScene: SKScene, SKPhysicsContactDelegate {
var bg1 = SKSpriteNode(imageNamed: "lightSky")
var bg2 = SKSpriteNode(imageNamed: "lightSky")
var setup = Setup(self)
override func didMoveToView(view: SKView) {
self.size = view.bounds.size
physicsWorld.gravity = CGVectorMake(0, -1.0)
physicsWorld.contactDelegate = self
setup.setupBackground(bg1, bg2: bg2)
}
}
But am getting an error:
Cannot invoke initializer for type 'Setup' with an argument list of type '(NSObject -> () -> GameScene)'
So I am guessing the type of scene parameter is wrong but don't know which one is right then.
It works with initializing it like this:
class GameScene: SKScene, SKPhysicsContactDelegate {
var bg1 = SKSpriteNode(imageNamed: "lightSky")
var bg2 = SKSpriteNode(imageNamed: "lightSky")
var setup: Setup!
override func didMoveToView(view: SKView) {
self.size = view.bounds.size
physicsWorld.gravity = CGVectorMake(0, -1.0)
physicsWorld.contactDelegate = self
setup = Setup(scene: self)
setup.setupBackground(bg1, bg2: bg2)
}
}
I have 2 files that I imported from Blender(3D design program) they are both .dae specifically they are "CampusField1.dae" CampusField is the ground/floor of the game and "Bob.dae" is the Man/character. My question is when I set CampusField1 as the scene how do I get "Bob" in the scene too. And the other question is lets say I export the .dae from blender now I put the file in the game... every things good but then is the animation for Bob already attached to the Bob.dae file or do I have to export something else from blender so that I can run the animation because I don't know what the animation ID would be or how to actually make it run and to actually make Bob do something.
Code:
import UIKit
import QuartzCore
import SceneKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scene = SCNScene(named: "art.scnassets/CampusField1.dae")!
let src = SCNSceneSource(URL: yourSceneURL, options: nil)
let node = src.entryWithIdentifier("Bob", withClass: SCNNode.self) as SCNNode
let animation = node.entryWithIdentifier("yourAnimationID", withClass: CAAnimation.self) as CAAnimation
Full GameController Below!:
import UIKit
import QuartzCore
import SceneKit
//============================================================
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//-------------------------
let scene = SCNScene(named: "art.scnassets/CampusField1.dae")!
let src = SCNSceneSource(URL: yourSceneURL, options: nil)
let node = src.entryWithIdentifier("Bob", withClass: SCNNode.self) as SCNNode
let animation = node.entryWithIdentifier("yourAnimationID", withClass: CAAnimation.self) as CAAnimation
//--------------------------
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
//-----------------------------------------------
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = SCNLightTypeOmni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
//-----------------------------------------------
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = UIColor.darkGrayColor()
scene.rootNode.addChildNode(ambientLightNode)
//----------------------------------------------
//_ = scene.rootNode.childNodeWithName("Bob", recursively: true)!
// _ = scene.rootNode.childNodeWithName("CampusField1", recursively: true)!
//--------------------------------------------------------
// Bob.runAction(SCNAction.repeatActionForever(SCNAction.rotateByX(0, y: 2, z: 0, duration: 1)))
let scnView = self.view as! SCNView
scnView.scene = scene
scnView.allowsCameraControl = true
scnView.showsStatistics = false
scnView.backgroundColor = UIColor.whiteColor()
let tapGesture = UITapGestureRecognizer(target: self, action: "handleTap:")
scnView.addGestureRecognizer(tapGesture)
}
func handleTap(gestureRecognize: UIGestureRecognizer) {
let scnView = self.view as! SCNView
let p = gestureRecognize.locationInView(scnView)
let hitResults = scnView.hitTest(p, options: nil)
if hitResults.count > 0 {
let result: AnyObject! = hitResults[0]
let material = result.node!.geometry!.firstMaterial!
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(0.5)
SCNTransaction.setCompletionBlock {
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(0.5)
material.emission.contents = UIColor.blackColor()
SCNTransaction.commit()
}
material.emission.contents = UIColor.yellowColor()
SCNTransaction.commit()
}
}
//==================================================
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.
}
}
The first thing to tell you is you have got two SCNScene; CampusField and Bob. Therefore you need to take out the character node from the Bob scene.
You need to name the node as like from the above figure. And extract that node from the scene as:
let bobScene = SCNScene(named: "Bob.dae")
let bobNode = personScene?.rootNode.childNodeWithName("person", recursively: true)
let campusFieldScene = SCNScene(named: "CampusField1.dae")
campusFieldScene.rootNode.addChildNode(bobNode)