Positioning SKSpriteNodes in GameScene - ios

I am having a little bit of trouble positioning two SKSpriteNodes correctly in my GameScene. My nodes appear in the scene, but they are zoomed in and take up most of the entire scene. I would to have the output similar to this:
Here is my current code:
let size = CGRect(x: 100, y:98, width:200, hight:271)
bottomRectangle = SKSpriteNode(imageNamed: "bottomRectangle")
bottomRectangle.zPosition = 3
bottomRectangle.size.height = self.size.height
bottomRectangle.size.width = self.size.width
bottomRectangle.position = CGPoint(x: 200, y:271)
bottomRectangle.physicsBody = SKPhysicsBody(edgeLoopFromRect: size)
self.addChild(bottomRectangle)
topRectangle = SKSpriteNode(imageNamed: "topRectangle")
topRectangle.physicsBody = SKPhysicsBody(edgeLoopFromRect: size)
topRectangle.zPosition = 4
topRectangle.size.height = self.size.height
topRectangle.size.width = self.size.width
topRectangle.position = CGPoint(x: 100, y: 98)
self.addChild(topRectangle)

You are using the size of the scene, because of:
self.size.height
You have to use you local variable:
size.height

Related

SKSpriteNode shadow rendering incorrectly?

I'm using Xcode 11.4.1 and Swift 5.2.2, and I am trying cast a shadow using an SKLightNode onto a circular SKSpriteNode.
However, the shadow is cast over the rectangular frame of the SpriteNode rather than the circle image png that I am using.
This is the desired effect
This is what happens
In the first image, I am using a 611x611px circle png while in the second I am using a 612x612 png. I have found that this "corner shadow" happens only when using specific image dimensions to create the SpriteNode.
Specifically, through my testing, square images with size <688px and >601px display no corner shadow, except sizes exactly 612 and 608. I am testing this in a playground but the same problem occurs in a full xcodeproj.
What have I done wrong here? I doubt my code is the issue but here it is:
import PlaygroundSupport
import SpriteKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
let background = SKSpriteNode(color: UIColor.blue, size: frame.size)
background.zPosition = 0
background.position = CGPoint(x: frame.midX, y: frame.midY)
background.lightingBitMask = 1
addChild(background)
let light = SKLightNode()
light.zPosition = 100
light.categoryBitMask = 1
light.falloff = 0.5
light.lightColor = UIColor.white
light.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(light)
let sprite = SKSpriteNode(imageNamed: "612.png")
sprite.color = UIColor.yellow
sprite.colorBlendFactor = 1
sprite.zPosition = 3
sprite.position = CGPoint(x: frame.midX, y: frame.midY + 100)
sprite.size = CGSize(width: 100, height: 100)
sprite.physicsBody = SKPhysicsBody(circleOfRadius: 50)
sprite.physicsBody?.categoryBitMask = 2
sprite.shadowCastBitMask = 1
sprite.lightingBitMask = 1
sprite.physicsBody?.isDynamic = false
addChild(sprite)
}
}
let sceneView = SKView(frame: CGRect(x:0 , y:0, width: 640, height: 480))
let scene = GameScene()
scene.scaleMode = .aspectFill
scene.size = sceneView.frame.size
sceneView.presentScene(scene)
PlaygroundSupport.PlaygroundPage.current.liveView = sceneView

Weird Spritekit Collision Bug depending on SKSpriteNode position

I'm having a weird Spritekit issue where my moving SKSpriteNode is passing through a fixed SKSpriteNode depending on the position of the fixed SKSpriteNode.
UPDATE: Code works in simulator but not on real device.
Example:
Placing my bin SKSpriteNode at position x: -500, y: 100 works fine and my moving SKSpriteNode collides as expected.
Placing my bin SKSpriteNode at position x: -600, y: 100 DOES NOT work and my moving SKSpriteNode DOES NOT collide with the bin.
Using view.showsPhysics = true shows that there is physics bodies in both cases.
x values between -500 and -508 work as expected. All other values I have tried did not work.
Collisions with my other fixed SKSpriteNodes work as expected.
enum CollisionTypes: UInt32 {
case Plane = 1
case FloorAndRoof = 2
case OtherObject = 4
case FinishPoint = 8
}
Code to create levels
func createLevel(level: Int) {
switch level {
case 1:
createFloor()
createRoof()
createTable(position: CGPoint(x: 750, y: 150))
createCeilingFan(position: CGPoint(x: 750, y: 560))
createCeilingFan(position: CGPoint(x: 2000, y: 560))
createWaterDispenser(position: CGPoint(x: 1500, y: 212))
createBin(position: CGPoint(x: -500, y: 100)) // THIS IS THE PROBLEM LOCATION
createFinishPoint(position: CGPoint(x: -500, y: 100))
break
case 2:
createFloor()
createRoof()
createTable(position: CGPoint(x: 250, y: 150))
createCeilingFan(position: CGPoint(x: 750, y: 560))
createCeilingFan(position: CGPoint(x: 2000, y: 560))
createWaterDispenser(position: CGPoint(x: 1500, y: 212))
createBin(position: CGPoint(x: -600, y: 100))
createFinishPoint(position: CGPoint(x: -300, y: 200))
break
default:
break
}
}
Moving SKSpriteNode
func createPlane() {
plane = SKSpriteNode(imageNamed: "plane1")
plane.name = "plane1"
//plane.position = CGPoint(x: -UIScreen.main.bounds.width + plane.size.width , y: 0)
plane.position = CGPoint(x: 0, y: 300)
plane.zPosition = 1
//plane.physicsBody = SKPhysicsBody(texture: plane.texture!, size: plane.texture!.size())
plane.physicsBody = SKPhysicsBody(texture: planeTexture, size: planeTexture.size())
plane.physicsBody?.allowsRotation = true
plane.physicsBody?.categoryBitMask = CollisionTypes.Plane.rawValue
plane.physicsBody?.collisionBitMask = CollisionTypes.FloorAndRoof.rawValue | CollisionTypes.OtherObject.rawValue // dont collide with finish point
plane.physicsBody?.contactTestBitMask = CollisionTypes.FloorAndRoof.rawValue | CollisionTypes.OtherObject.rawValue | CollisionTypes.FinishPoint.rawValue
plane.physicsBody?.usesPreciseCollisionDetection = true
plane.physicsBody?.isDynamic = true
plane.physicsBody?.friction = 1
plane.physicsBody?.restitution = 0
plane.physicsBody?.mass = 0.1 // customise for different planes
plane.physicsBody?.angularDamping = 1
plane.physicsBody?.linearDamping = 0.2 // customise for different planes
liftFactor = 0.1 // customise for different planes
addChild(plane)
flightMode = 4 // dead, should drop to floor and change to mode 0 when at rest
//print(flightMode)
}
Bin SKSpriteNode that moving Plane should collide with.
func createBin(position: CGPoint) {
binFront = SKSpriteNode(imageNamed: "binFront")
binFront.name = "binFront"
binFront.setScale(0.15)
binFront.position = position
binFront.zPosition = 2 // in front of plane
addChild(binFront)
binBack = SKSpriteNode(imageNamed: "binBack")
binBack.name = "binBack"
binBack.setScale(0.15)
binBack.position = position
binBack.zPosition = 0 // behind plane
addChild(binBack)
binPhysicsBody = SKSpriteNode(imageNamed: "binPhysicsBody")
binPhysicsBody.name = "binPhysicsBody"
binPhysicsBody.physicsBody = SKPhysicsBody(texture: binPhysicsBody.texture!, size: binPhysicsBody.texture!.size())
binPhysicsBody.setScale(0.15)
binPhysicsBody.physicsBody?.allowsRotation = false
binPhysicsBody.physicsBody?.categoryBitMask = CollisionTypes.OtherObject.rawValue
binPhysicsBody.physicsBody?.collisionBitMask = CollisionTypes.Plane.rawValue
binPhysicsBody.physicsBody?.contactTestBitMask = CollisionTypes.Plane.rawValue
binPhysicsBody.physicsBody?.usesPreciseCollisionDetection = false
binPhysicsBody.physicsBody?.isDynamic = false
binPhysicsBody.physicsBody?.friction = 1
binPhysicsBody.physicsBody?.restitution = 0
binPhysicsBody.physicsBody?.mass = 50
binPhysicsBody.position = position
binPhysicsBody.zPosition = 0
addChild(binPhysicsBody)
}
I still don't know the cause of my issue but I got around it by changing the image used to create my physics body. I used a slightly thicker 'wall thickness' on the bin.

Right to Left Scrolling Background Swift / Sprite Kit

I have a scrolling background, but the background image appears to be "zoomed in" compared to the original image. The background scrolls just fine, but I'm not sure why the image is "zoomed in". Any help would be greatly appreciated.
class GameScene: SKScene, SKPhysicsContactDelegate {
var blueBall:SKSpriteNode!
var backgroundImage:SKSpriteNode!
var backgroundImage2:SKSpriteNode!
override func didMoveToView(view: SKView) {
self.view!.backgroundColor = UIColor(patternImage: UIImage(imageLiteral: "backgroundImage.png"))
self.physicsWorld.gravity = CGVectorMake(0.0, -5.0)
self.physicsWorld.contactDelegate = self
blueBall = SKSpriteNode( imageNamed: "ball1111.png")
blueBall.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
blueBall.physicsBody = SKPhysicsBody(circleOfRadius: blueBall.size.width / 0.85)
blueBall.physicsBody!.dynamic = true
blueBall.physicsBody!.allowsRotation = true
self.addChild(blueBall)
blueBall.zPosition = 2
backgroundImage = SKSpriteNode(imageNamed: "backgroundImage.png")
self.addChild(backgroundImage)
backgroundImage.zPosition = 0
backgroundImage.anchorPoint = CGPoint(x: 0.5, y: 0.5)
backgroundImage.size.height = self.size.height
backgroundImage.size.width = self.size.width
backgroundImage.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
let backgroundTexture = SKTexture(imageNamed: "backgroundImage.png")
let shiftBackground = SKAction.moveByX(-backgroundTexture.size().width, y: 0, duration: 9)
let replaceBackground = SKAction.moveByX(backgroundTexture.size().width, y:0, duration: 0)
let movingAndReplacingBackground = SKAction.repeatActionForever(SKAction.sequence([shiftBackground,replaceBackground]))
for var i:CGFloat = 0; i<3; i++ {
let background = SKSpriteNode(texture: backgroundTexture)
background.position = CGPoint(x: backgroundTexture.size().width/2 + (backgroundTexture.size().width * i), y: CGRectGetMidY(self.frame))
background.size.height = self.frame.height
background.runAction(movingAndReplacingBackground)
self.addChild(background)
}
}
You have an issue with the image not being loaded correctly, so your numbers are off. Basically by loading SKSpriteNode(imageNamed: "backgroundImage.png") with the png extension, you are loading the actual file, not conforming to any retina rules. The width and height then would not be adjusted to handle this case. If you use an atlas inside the xcassets folder, it will allow you to specify the graphics for all display sizes, and will pick the correct one that is supported by the device.

SpriteKit: Rotating SKNode falls off screen when adding another physics body

The code below causes the rotateLayer physics body to fall off the screen after a few seconds. Commenting out the circle physics body, however, keeps rotateLayer on screen. Is it not possible to add a physics body to a node, and then rotate the parent node? Conceptually, the goal is to rotate the circle around a fixed point, as described here, but attach a physics body to the circle while also controlling rotation through angular velocity as opposed to zRotation.
let size = CGSize(width: 10, height: 250)
rotateLayer = SKNode()
gameLayer.addChild(rotateLayer)
let circleSize = CGSize(width: 10, height: 10)
let circle = SKSpriteNode(color: SKColor.whiteColor(), size: circleSize)
circle.position = CGPoint(x: 0, y: size.height/2 + circleSize.height/2)
circle.physicsBody = SKPhysicsBody(rectangleOfSize: circleSize)
circle.physicsBody?.affectedByGravity = false
circle.physicsBody?.friction = 0
circle.physicsBody?.linearDamping = 0
circle.physicsBody?.angularDamping = 0
circle.physicsBody?.collisionBitMask = 0
circle.physicsBody?.dynamic = false
rotateLayer.addChild(circle)
rotateLayer.physicsBody = SKPhysicsBody(rectangleOfSize: size)
rotateLayer.physicsBody?.affectedByGravity = false
rotateLayer.physicsBody?.friction = 0
rotateLayer.physicsBody?.linearDamping = 0
rotateLayer.physicsBody?.angularDamping = 0
rotateLayer.physicsBody?.angularVelocity = -3.0
Adding rotateLayer.collisionBitMask = 0 fixed the problem. No clue why.

How can I apply friction to a circular SKPhysicsBody

I am trying to understand friction, or some other aspect of physics, in SpriteKit. I created a circle that rotates. I placed a square on top of the rotating circle. I expected the square to rotate along with the circle and fall off, but the square does not move. I set physicsBody.friction = 1.0 in an attempt to make the surfaces sticky but it does not help. What changes to physics do I need to make so that the square is affected by the circle's rotation?
I created a self-contained example using a Playground. To test:
Download attached bluecircle.png and place it on your desktop (or wherever)
Copy code below into your Playground
Change NSImage path to wherever you saved bluecircle.png
Code:
import Cocoa
import SpriteKit
import XCPlayground
let screenWidth = 1400.0
let screenHeight = 1000.0
let xOffset = 300.0
let smallsquareSize = CGSize(width: 100, height: 100)
let bluesquareSize = CGSize(width: 400 , height: 400)
// the img is a blue circle w/ radius of 200 located on my desktop
let img = NSImage(byReferencingFile: "/Users/CHANGETHIS/Desktop/bluecircle.png")
class PlayScene: SKScene {
let redsquare = SKSpriteNode(color: SKColor.redColor(), size: smallsquareSize)
let greensquare = SKSpriteNode(color: SKColor.greenColor(), size: smallsquareSize)
let bluesquare = SKSpriteNode(color: SKColor.blueColor(), size: bluesquareSize)
let bluecircle = SKSpriteNode(texture: SKTexture(image: img))
var lastTime = NSTimeInterval(0)
init(size: CGSize) {
super.init(size: size)
}
override func didMoveToView(view: SKView!) {
backgroundColor = SKColor.blackColor()
// RED SQUARE
redsquare.position = CGPoint(x: screenWidth/2 - xOffset, y: screenHeight - 100)
redsquare.physicsBody = SKPhysicsBody(rectangleOfSize: smallsquareSize)
redsquare.physicsBody.friction = 1.0
addChild(redsquare)
// BLUE SQUARE
bluesquare.position = CGPoint(x: screenWidth / 2 - xOffset, y: screenHeight / 2)
bluesquare.physicsBody = SKPhysicsBody(rectangleOfSize: bluesquareSize)
bluesquare.physicsBody.dynamic = false
bluesquare.physicsBody.affectedByGravity = false
bluesquare.physicsBody.friction = 1.0
addChild(bluesquare)
// GREEN SQUARE
greensquare.position = CGPoint(x: screenWidth/2 + xOffset, y: screenHeight - 100)
greensquare.physicsBody = SKPhysicsBody(rectangleOfSize: smallsquareSize)
greensquare.physicsBody.friction = 1.0
addChild(greensquare)
// BLUE CIRCLE
bluecircle.position = CGPoint(x: screenWidth / 2 + xOffset, y: screenHeight / 2)
bluecircle.physicsBody = SKPhysicsBody(circleOfRadius: 200)
bluecircle.physicsBody.dynamic = false
bluecircle.physicsBody.affectedByGravity = false
bluecircle.physicsBody.friction = 1.0
addChild(bluecircle)
}
override func update(currentTime: NSTimeInterval) {
let delta = currentTime - lastTime
lastTime = currentTime
bluesquare.zRotation += delta
bluecircle.zRotation += delta
}
}
var view = SKView(frame:NSRect(x: 0.0, y: 0.0, width: screenWidth, height: screenHeight))
var playScene = PlayScene(size: CGSize(width: screenWidth, height: screenHeight))
view.presentScene(playScene)
view.showsFPS = true
view.showsDrawCount = true
view.showsNodeCount = true
XCPShowView("View", view)
`
I think the answer to your question are Joints . Creating a fixed joint between your nodes I believe will solve your problem .
https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKPhysicsJoint_Ref/Reference/Reference.html

Resources