SKSpriteNode image not displaying - swift

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))

Related

My SKTexture is size wrong for my SKSpriteNode

I have a 200 x 100 box-like menu button SKSpriteNode declared below.
menuBtn.size = CGSize(width: scrWidth * 1.5, height: 100)
menuBtn.texture = SKTexture(image: UIImage(named: "menuBtn")!)
The problem is, the hitbox for the button is still right, and the width of the SKTexture is fine, but the height of the SKTexture is around 1/2 the size of the actual menuBtn. It is a png, and I've checked and there's no clear textures around the sprite (just the transparent png ones), what am I doing wrong?
Pic of button: https://imgur.com/a/8BtXGLC
Pic of button in App: https://imgur.com/a/ZfW3xDL
Pic of how I want it to look: https://imgur.com/a/2zlSv8y
The texture's png image size is 1044x1044 if that has any impact.
First of all, make sure you are sending the correct size to your scene from GameViewController to your scene, in this example GameScene.
// without .sks
class GameViewController: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
// ...
if let view = self.view as! SKView?
{
let scene = GameScene()
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFit
// Set anchorPoint and pass scene.size
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
scene.size = view.bounds.size
// Present the scene
view.presentScene(scene)
}
// ...
}
// with .sks
class GameViewController: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
// ...
if let view = self.view as! SKView?
{
if let scene = SKScene(fileNamed: "GameScene.sks")
{
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFit
// Pass scene.size
scene.size = view.bounds.size
// Present the scene
view.presentScene(scene)
}
}
// ...
}
In your GameScene create the object. I recommend working in screenWidth and screenHeight when you create objects so they scale to all iOS devices.
class GameScene: SKScene
{
override func didMove(to view: SKView)
{
// ...
// scene width / height
let sceneWidth = size.width
let sceneHeight = size.height
// object
let menu : SKSpriteNode = SKSpriteNode()
menu.texture = SKTexture(imageNamed: "menu")
menu.size = CGSize(width: sceneWidth * 0.75, height: 100)
let y_pos : CGFloat = -sceneHeight * 0.5 + menu.size.height * 0.5
menu.position = CGPoint(x: 0, y: y_pos)
menu.zPosition = 1
addChild(menu)
// ...
}
}
The problem I had was that there were extra transparent pixels in my base image, all I had to do was remove them with GIMP.

SKCropNode doesn't display anything

I can't get SKCropNode to cooperate. I've played with this for HOURS I've copied verbatim hackingwithswifts guide and the only difference being my image and it will not work. So then I dumbed it down for myself with the code below and it still doesn't work.
I've tried the guide directly from hacking with swift and it didn't work. I copied code directly from apple documentation that also didn't work. I've wasted wayyyy too much time on the simple task of cropping an image.
import SpriteKit
import GameplayKit
import UIKit
class ProcGenPlanet: SKScene{
//Background
//let background = SKSpriteNode()
var square = SKSpriteNode()
override func didMove(to view: SKView) {
square = SKSpriteNode(imageNamed: "redSquare")
square.size = CGSize(width: 1000, height: 1000)
square.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
let mask = SKSpriteNode(color: SKColor.black, size: CGSize(width: 100, height: 100))
let cropNode = SKCropNode()
cropNode.maskNode = mask
cropNode.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
cropNode.addChild(square)
}
}
I am creating 1000x1000 red square. The whole image is red. Then I am trying to crop it to 100x100 with the following code but instead NOTHING shows up.

How to place SKSpriteNode in front of CAShapeLayer?

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)

Couldn't add NSButton to the Sprite-Kit scene

I'm a newbie to OS X programming. I'm building a simple game for Mac with Sprite-Kit, and stuck with the problem of adding NSButton (and other NSObjects) to the view. It just doesn't work - no button shows up.
My code:
class LaunchScene: SKScene {
override func didMoveToView(view: SKView) {
let background = SKSpriteNode(imageNamed: "Wall")
background.size = CGSize(width: 1600, height: 1200)
background.position = CGPoint(x: CGRectGetMidX(self.frame),
y: CGRectGetMidY(self.frame))
self.addChild(background)
let button = NSButton(frame: NSRect(x: self.frame.width/2,
y: self.frame.height/2, width: 50, height: 25))
self.view!.addSubview(button) //button doesn't show up
How could I fix it?
P.S. I tried to add a layer to my view, as some bloggers recommended, in this situation the button actually does show up but the screen turns completely black or renders only glitches.
let layer = CALayer()
self.view!.layer = layer
self.view!.wantsLayer = true
OK, finally I figured out how to do that (don't need to assign a layer to your view if self.view!.wantsLayer is equal to "true"):
class LaunchScene: SKScene {
override func didMoveToView(view: SKView) {
let background = SKSpriteNode(imageNamed: "Wall")
background.size = CGSize(width: 1600, height: 1200)
background.position = CGPoint(x: CGRectGetMidX(self.frame),
y: CGRectGetMidY(self.frame))
self.addChild(background)
self.view!.wantsLayer = true
let button = NSButton(frame: NSRect(x: self.frame.width/2,
y: self.frame.height/2, width: 50, height: 25))
self.view!.addSubview(button)

Draw a hole in a rectangle with SpriteKit?

How to draw a hole in a rectangle?
I want to draw a rectangle which has a empty hole inside it and the background can be show.
I am using SKShapeNode to create a rectangle, but I have no idea how to make a hole (circle) inside it.
This is what I run your code, but my circle is not empty, the circle is black, I want it to be empty.
Is there any mistake I didn't mention?
Here's the code.
import SpriteKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
let effect = SKEffectNode()
addChild(effect)
let rect = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 400, height: 200))
rect.fillColor = .green
effect.addChild(rect)
let hole = SKShapeNode(circleOfRadius: 40)
hole.position = CGPoint(x: 200, y: 100)
hole.fillColor = .white
hole.blendMode = .subtract
rect.addChild(hole)
}
}
As you can see I create an SKEffectNode. Then I add to it the rectangle. Finally I add the hole to the rectangle.