Couldn't add NSButton to the Sprite-Kit scene - swift

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)

Related

How to position an SKLabelNode on top of a UISlider in SpriteKit

I'm using UISliders in my SpriteKit game.
Sometimes I want to pause the game and add some info in an SKLabelNode but I can't find a way to position the SKLabelNode on top of a UISlider.
Here's a simplified example.
override func didMove(to view: SKView) {
let slider = UISlider(frame: CGRect(x: 100, y: 100, width: 300, height: 50))
let label = SKLabelNode(text: "Text Label should be on top of Slider")
label.fontColor = .red
label.verticalAlignmentMode = .top
label.position = CGPoint(x:160, y:self.frame.size.height - 110)
view.addSubview(slider)
self.addChild(label)
slider.layer.zPosition = 1
label.zPosition = 2
}
UISlider remains above SKLabel :-(.
Any help appreciated.
EDIT:
In response to question by #Muffinman2497 "Why not use a UILabel?"
I may have to do that but I'm actually using a custom multi line label that's been designed using spriteKit and SKLabels. So I was hoping for a simple property change rather than a redesign.
Using a UILabel definitely does work though.
let myUILabel = UILabel(frame: CGRect(x: 50, y: 0, width: 300, height: 50))
myUILabel.text = "UILabel would like to obscure UISlider"
myUILabel.backgroundColor = .red
slider.addSubview(myUILabel)
slider.layer.zPosition = 1
myUILabel.layer.zPosition = 2

SkShapeNode physicsbody weird behaviour

I created a subclass of SKNode:
class SquareDrop: SKNode {
init(image: SKSpriteNode) {
super.init()
self.setScale(0.3
//Set the starting position of the node
self.position = CGPoint(x: 0.5, y: UIScreen.main.bounds.height/2)
//Apply a physics body to the node
self.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "square"), size: CGSize(width: image.size.width * 0.3, height: image.size.height * 0.3))
self.addChild(image)
}
I created an instance in GameScene class and I set up it:
func spawnRain()
squareDrop = SquareDrop(image: SKSpriteNode(imageNamed: "square"))
squareDrop?.physicsBody?.linearDamping = 5
squareDrop?.physicsBody?.restitution = 0
self.addChild(squareDrop!)
}
It is the result:
It works like aspected, but instead of using an image I wanted to draw a square:
func spawnRain() {
//Here I did not use the class that I had created previously
let shape = SKShapeNode()
shape.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 100, height: 100), cornerRadius: 5).cgPath
shape.position = CGPoint(x: frame.midX - shape.frame.width/2 , y: UIScreen.main.bounds.height/2)
shape.fillColor = UIColor.red
shape.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 100, height: 100))
addChild(shape)
}
It doesn't seem like I aspected (the squares that I created have a strange behaviour). Any hints?
I am sorry for the question, but I am a noob of SpriteKit.

How to code the accelerometer to have a fixed x position

I have a ship that moves based on the direction of gravity which is changed by the accelerometer, but I want it to only move along the width of the screen (I already know how to do that), but I do not know how to keep it on a fixed horizontal line. Here's my code
class GameScene: SKScene {
var manager = CMMotionManager()
var ship = SKSpriteNode()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let shipTexture = SKTexture(imageNamed: "EvadersShipVert2.png")
ship = SKSpriteNode(texture: shipTexture)
ship.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame) - 250)
ship.size = CGSize(width: 90, height: 115)
shipTexture.filteringMode = SKTextureFilteringMode.Nearest
ship.zPosition = 2
ship.physicsBody = SKPhysicsBody(texture: shipTexture, size: CGSize(width: 90, height: 115))
ship.physicsBody?.dynamic = true
self.addChild(ship)
manager.startAccelerometerUpdates()
manager.accelerometerUpdateInterval = 0.1
manager.startAccelerometerUpdatesToQueue(NSOperationQueue.mainQueue()) {
(data, error) in
self.physicsWorld.gravity = CGVectorMake(CGFloat((data?.acceleration.x)!), CGFloat((data?.acceleration.y)!))
}
}
thanks in advance!
Replace
self.physicsWorld.gravity = CGVectorMake(CGFloat((data?.acceleration.x)!), CGFloat((data?.acceleration.y)!))
With
self.physicsWorld.gravity = CGVectorMake(0.0, CGFloat((data?.acceleration.y)!)
So you're not affecting the x position

SKSpriteNode image not displaying

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

Is there a way to make a responsive layer node?

I'm new to SpriteKit, I've searched for the answer to this but can't seem to find one.
Is there a way to make a node that will expand to fit whatever device you're on?
Right now I'm creating layers with either a concrete dimension or a ratio. What I'd like to do is create an expandable rectangle, attach a physics body to it and have that be the boundary for my game.
what I'm currently doing:
gamescene.swift
override func didMoveToView(view: SKView) {
let maxAspectRatio: CGFloat = 16.0 / 9.0
let maxAspectRatioheight = size.width / maxAspectRatio
let playableMargin: CGFloat = (size.height - maxAspectRatioheight) / 2
let playableRect = CGRect(x: 0, y: playableMargin, width: size.width, height: size.height - playableMargin * 2)
physicsBody = SKPhysicsBody(edgeLoopFromRect: playableRect)
}
but I've experimented with using a background as well:
// declared with the other fields outside method
var background = SKSpriteNode(imageNamed: "background")
//inside didMoveToView
let bounds = SKNode()
bounds.physicsBody = SKPhysicsBody(edgeLoopFromRect:
CGRect(x: 0, y: 0,
width: background.size.width,
height: background.size.height))
bounds.physicsBody!.categoryBitMask = PhysicsCategory.Boundary
bounds.physicsBody!.friction = 0
worldNode.addChild(bounds)
Any tips would be greatly appreciated!