Reputation: 590
I am trying to create a collision between an SKShapeNode instance and the edges of the screen but for some reason the ShapeNode still goes beyond the limits of the screen. I have implemented code that I believe should take care of the collision but I am new to SpriteKit so I am not entirely sure. Here's a snippet of the code:
//
// GameScene.swift
// SpriteKitTest
//
// Created by 580380 on 3/10/16.
// Copyright (c) 2016 580380. All rights reserved.
//
import SpriteKit
import UIKit
import CoreMotion
class GameScene: SKScene {
//MARK: - Global variables
let motionManager = CMMotionManager()
var circleNode = SKShapeNode()
var destX : CGFloat = 0.0
var destY : CGFloat = 0.0
enum Collision :UInt32 {
case ball = 1
case wall = 2
}
//MARK: - Sprite kit functionality
override func didMoveToView(view: SKView) {
backgroundColor = UIColor.whiteColor()
createCircleNode()
moveCircleNode()
self.addChild(circleNode)
}
//Setup and configuring the SKShapeNode object
private func createCircleNode() {
circleNode.path = UIBezierPath(arcCenter: CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame)), radius: 20, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true).CGPath
circleNode.fillColor = UIColor.redColor()
circleNode.strokeColor = UIColor.blueColor()
circleNode.lineWidth = 1
}
private func moveCircleNode() {
circleNode.physicsBody = SKPhysicsBody()
circleNode.physicsBody?.dynamic = true
circleNode.physicsBody?.affectedByGravity = false
if motionManager.accelerometerAvailable {
motionManager.accelerometerUpdateInterval = 0.1
motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue.mainQueue(), withHandler: { (data, error) -> Void in
self.destX = self.circleNode.position.x + CGFloat(data!.acceleration.x*100)
self.destY = self.circleNode.position.y + CGFloat(data!.acceleration.y*200)
})
}
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody!.dynamic = true
self.physicsBody!.affectedByGravity = false
self.physicsBody!.categoryBitMask = Collision.wall.rawValue
self.physicsBody!.collisionBitMask = Collision.ball.rawValue
}
override func update(currentTime: NSTimeInterval) {
let destXAction = SKAction.moveToX(destX, duration: 0.1)
let destYAction = SKAction.moveToY(destY, duration: 0.1)
self.circleNode.runAction(destXAction)
self.circleNode.runAction(destYAction)
}
}
Any idea where I could be going wrong?
Upvotes: 1
Views: 1228
Reputation: 1109
The main issue here I will assume is that the Game Scene never actually gets its size set.
In your GameViewController
add the line scene.size = skView.bounds.size
under let skView = self.view as! SKView
.
This will set the size of your scene correctly, so now your ball should collide with your screen edge.... however when you set your circleNode
path, the way you implemented it with offset your circle by half the size of the screen.
If you want your circle to appear in the middle of the screen, a better solution would be to have circleNode = SKShapeNode(circleOfRadius: 20)
instead of circleNode.path = UIBezierPath(arcCenter: CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame)), radius: 20, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true).CGPath
. Then set it to be in the center with circleNode.position = CGPointMake(frame.width/2, frame.height/2)
.
This should solve your issue as a whole, however something you may notice is that the ball may disappear through the edge the screen. To fix this, change your update method to something like this
func clamp(value: CGFloat, min: CGFloat, max: CGFloat) -> CGFloat {
if value > max {
return max
}
if value < min {
return min
}
return value
}
override func update(currentTime: NSTimeInterval) {
let ballRadius: CGFloat = 10
destX = clamp(destX, min: ballRadius, max: frame.width - ballRadius)
destY = clamp(destY, min: ballRadius, max: frame.height - ballRadius)
let destXAction = SKAction.moveToX(destX, duration: 0.1)
let destYAction = SKAction.moveToY(destY, duration: 0.1)
self.circleNode.runAction(destXAction)
self.circleNode.runAction(destYAction)
}
This will make it so the ball should never try to go outside the bounds of the screen. I would also suggest adding circleNode.physicsBody?.usesPreciseCollisionDetection = true
so your collisions are more accurate.
Upvotes: 1