I'm relatively new to learning the Swift language so I don't know what I'm missing, but I can't seem to see why this would not be working. My goal is to add a background to my scene using SpriteKit, but whenever I try to add one, playgrounds takes a second and then displays an error that says:
There was a problem running this playground.
I already have a scene set up using SpriteKit so when this piece of code is not present I do get a black screen, but for some reason everything seems to fail when this segment is in:
let bg = SKSpriteNode(texture: SKTexture(image: #imageLiteral(resourceName: "IMG_0483.jpg")))
bg.setScale(2.0)
bg.zPosition = -10
bg.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(bg)
Here is the larger context of the script:
import SpriteKit
public class GameScene: SKScene {
var player: SKSpriteNode!
public override func didMove(to view: SKView) {
// Backround
let bg = SKSpriteNode(texture: SKTexture(image: #imageLiteral(resourceName: "IMG_0483.jpg")))
bg.setScale(2.0)
bg.zPosition = -10
bg.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(bg)
}
}
and here is my main where I'm calling it
import UIKit
import SpriteKit
import PlaygroundSupport
let skView = SKView(frame: .zero)
let gameScene = GameScene(size: UIScreen.main.bounds.size)
gameScene.scaleMode = .aspectFill
skView.presentScene(gameScene)
PlaygroundPage.current.liveView = skView
PlaygroundPage.current.wantsFullScreenLiveView = true
Try this:
let bg = SKSpriteNode(imageNamed: "image.jpg")
bg.setScale(2.0)
bg.zPosition = -10
bg.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(bg)
Where you display the scene:
let skView = SKView(frame: UIScreen.main.bounds)
let gameScene = GameScene(fileNamed: "GameScene")
gameScene?.scaleMode = .aspectFill
skView.presentScene(gameScene)
PlaygroundPage.current.liveView = skView
Related
I have this code in my GameScene swift file:
var background = SKSpriteNode(imageNamed: "background")
let blockImage = SKTexture(imageNamed: "block")
let blockSize = CGSize(width: 64, height: 64)
override func didMove(to view: SKView) {
setUpGame()
}
func setUpGame(){
background.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
addChild(background)
let block = SKSpriteNode(texture: blockImage, size: blockSize)
block.position.x = block.frame.width/2
block.position.y = frame.height - block.frame.height/2
addChild(block)
}
This is my code in my GameController file:
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
let scene = GameScene(size: self.view.bounds.size)
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
// added to see physics body
view.showsPhysics = true
}
}
why does it take multiple runs for my block node to appear on the simulator except for my background? After the block finally show, it will continue to show after every run until I edit my code. Ive tried removing my background node just in case that might be the issue, but it didn't change anything
I´ve made a game with SpriteKit with different bricks falling down on a hill. When these physical bodies fall down they usually bounce off the hill and change their alignment(they spin a couple of times). If I transition to the GameOver scene and press replay(back to the GameScene) the physics bodies are still aligned like when I left the scene. But I want them to have a horizontal alignment like in the beginning.
GameScene:
import SpriteKit
import GameplayKit
let hillTexture = SKTexture(imageNamed: "HillIllustration")
let hillIllustration = SKSpriteNode(texture: hillTexture)
let brickTexture = SKTexture(imageNamed: "BrickIllustration")
let brick = SKSpriteNode(texture: brickTexture)
class GameScene: SKScene {
//Hill
hillIllustration.setScale(0.7)
hillIllustration.position = CGPoint(x: self.size.width / 2, y: self.size.height * 0.16)
hillIllustration.zPosition = 2
hillIllustration.physicsBody = SKPhysicsBody(polygonFrom: clipPath)
hillIllustration.physicsBody?.isDynamic = false
hillIllustration.physicsBody?.categoryBitMask = CollisionBitMask.Hill
hillIllustration.physicsBody?.affectedByGravity = false
self.addChild(hillIllustration)
//The brick is a child of the hill node
brick.setScale(1)
brick.position = CGPoint(x: -350, y: self.size.height * 0.5)
brick.zPosition = 1
brick.physicsBody = SKPhysicsBody(polygonFrom: clipPath2)
brick.physicsBody?.isDynamic = true
brick.physicsBody?.categoryBitMask = CollisionBitMask.Brick
brick.physicsBody?.affectedByGravity = true
hillIllustration.addChild(brick)
}
Transition to GameOver:
let transition = SKTransition.crossFade(withDuration: 0)
let gameScene = GameOver(size: self.size)
self.view?.presentScene(gameScene, transition: transition)
Transition back to GameScene:
let transition = SKTransition.crossFade(withDuration: 0)
let gameScene = GameScene(size: self.size)
self.view?.presentScene(gameScene, transition: transition)
Somehow when I transition scenes the information of how the bricks were aligned gets saved. How can I change that?
if you want that after you restart the game the brick node go back to start rotation than call:
brick.zRotation = 0
if you want that during the game the node do not rotate than you may put this code in the update func that already have in all spritekit files:
override func update(_ currentTime: TimeInterval) {
brick.zRotation = 0
}
Hope this helps
Somebody told me in one of my other questions that SpriteKit was easier than UI. I searched online on how to get started with SpriteKit, and I got this: https://www.raywenderlich.com/145318/spritekit-swift-3-tutorial-beginners. I put the images in and everything, I put this code in:
import SpriteKit
class GameScene: SKScene {
// 1
let player = SKSpriteNode(imageNamed: "player")
override func didMove(to view: SKView) {
// 2
backgroundColor = SKColor.white
// 3
player.position = CGPoint(x: size.width * 0.1, y: size.height * 0.5)
// 4
addChild(player)
}
}
(the code they told me to put in), and when I run it, I just see a blank screen. On the tutorial, it had a ninja, but mine is just a blank screen.
Can anyone help with this?
if the screen is white try this :
import SpriteKit
class GameScene: SKScene {
// 1
var player = SKSpriteNode()
override func didMove(to view: SKView) {
// 2
backgroundColor = SKColor.white
// 3
let image = UIImage(named: "player")
let texture = SKTexture(image: image!)
player = SKSpriteNode(texture: texture)
player.position = CGPoint(x: size.width * 0.1, y: size.height * 0.5)
// 4
addChild(player)
}
}
If the screen not white : make sure the scene presented correctly .
If you have the GameScene.sks :
In GameViewController :
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
let scene = SKScene(fileNamed: "GameScene")
scene.scaleMode = .aspectFill
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
If you don't have GameScene.sks File
In GameViewController :
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
let scene = GameScene(size : view.frame.size)
scene.scaleMode = .aspectFill
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
I want to display a SKSpriteNode in front of a CAShapeLayer and this is the code that I am using :
import SpriteKit
import GameplayKit
import UIKit
class GameScene: SKScene {
let progressLayer = CAShapeLayer()
override func didMove(to view: SKView) {
let circle = UIView(frame: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
view.addSubview(circle)
view.sendSubview(toBack: circle)
progressLayer.frame = view.bounds
progressLayer.path = progressPath.cgPath
progressLayer.fillColor = UIColor.clear.cgColor
progressLayer.strokeColor = UIColor.green.cgColor
progressLayer.lineWidth = 20.0
let animation2 = CABasicAnimation(keyPath: "strokeEnd")
animation2.fromValue = 0.0
animation2.toValue = 1.0
animation2.duration = 1
animation2.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
progressLayer.add(animation2, forKey: "drawLineAnimation")
circle.layer.addSublayer(progressLayer)
var popup = SKSpriteNode(imageNamed: "popupWorking.png")
popup.anchorPoint = CGPoint(x: 0.5, y: 0.5)
popup.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
popup.size = CGSize(width: 400, height: 200)
popup.zPosition = 10
self.addChild(popup)
}
}
But when I run the code, the CAShapeLayer appears in front of the SKSpriteNode, how do I make the SKSpriteNode appear in front of the CAShapeLayer?
You'll need to change your view hierarchy at the view controller level. By default the view controller's view is an SKView. If you want to place a different UIView behind your SKView, you will need to adjust the view hierarchy.
Modify the view controller's view to be a UIView instead of an SKView. Then, add your shape layer's view as a subview to this main view. After that, add your SKView as a subview of the main view.
Your new view hierarchy should look like this:
View Controller
– view (UIView)
- circle view (UIView with your CAShapeLayer as a sublayer)
- spritekit view (SKView)
While it is possible to combine UIKit and SpriteKit in this way, it may be easier to stay within the SpriteKit world and recreate the circle animation using SKSpriteNodes instead of a CAShapeLayer.
Here is a playground that shows one way of doing it. I followed suggestion by #nathan .
Yellow line is drawn using SKShapeNode. The red shadow needs to be animated behind it and hence uses CAShapeLayer. (Note: I needed to mix the two as animating shadow path would be much more complicated in pure Sprite)
import SpriteKit
import PlaygroundSupport
private func invert(_ path: CGMutablePath) -> CGPath {
var rotation = CGAffineTransform(scaleX: 1.0, y: -1.0);
return path.copy(using: &rotation)!;
}
let bounds = CGRect(x: 0, y: 0, width: 400, height: 200)
let uiview = UIView(frame: bounds)
let pathview = UIView(frame: bounds)
let skview = SKView(frame: bounds)
PlaygroundPage.current.liveView = uiview
// Define the path
let path: CGMutablePath = CGMutablePath();
path.move(to: CGPoint(x:0, y:0))
path.addLine(to: CGPoint(x:200, y:100))
// Use CAShapeLayer to draw the red line
var pathLayer: CAShapeLayer = CAShapeLayer()
pathLayer.position = CGPoint(x: uiview.bounds.minX, y: uiview.bounds.minY + 200)
pathLayer.path = invert(path)
pathLayer.strokeColor = UIColor.red.cgColor
pathLayer.fillColor = nil
pathLayer.lineWidth = 10.0
pathLayer.lineJoin = kCALineJoinBevel
pathLayer.lineCap = kCALineCapRound
pathLayer.zPosition = 3;
let strokeAnimation = CABasicAnimation(keyPath: "strokeAnimation")
strokeAnimation.duration = 2;
strokeAnimation.fromValue = 0;
pathview.layer.addSublayer(pathLayer);
pathLayer.add(strokeAnimation, forKey: "strokePath");
uiview.addSubview(pathview)
//Use SKShapeNode to draw the yellow line
let pathShape: SKShapeNode = SKShapeNode(path: path);
pathShape.strokeColor = .white;
pathShape.lineWidth = 2.0;
pathShape.zPosition = 20;
// Create SK Scene
let scene = SKScene(size: CGSize(width: 400, height: 200))
scene.scaleMode = SKSceneScaleMode.aspectFill
scene.size = skview.bounds.size
scene.addChild(pathShape);
scene.backgroundColor = UIColor.clear;
skview.backgroundColor = UIColor.clear
skview.presentScene(scene);
uiview.insertSubview(skview, aboveSubview: pathview)
When the view is presented, I would like the image named "Player" (set) which is in my images.xcassets to show on the scene.
Currently the scene just loads up blue. Not sure why, as even when adding a color to change the image color did nothing.
import SpriteKit
class CharacterScene: SKScene {
var Circle = SKSpriteNode(imageNamed: "Player")
override func didMoveToView(view: SKView) {
backgroundColor = SKColor.blackColor()
Circle.size = CGSize(width: 40, height: 40)
Circle.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
Circle.color = SKColor.brownColor()
self.addChild(Circle)
}
}
You need to initialize the size of CharacterScene before presenting it on the screen. Here you go:
self.scene!.view!.presentScene(CharacterScene(size: self.scene!.size), transition: SKTransition.pushWithDirection(SKTransitionDirection.Up, duration: 0.3))