Child nodes inside SKNode disappears with fast shaking device with CMMotionManager applied to move balls - swift

I've create a SKNode with physicsBody edgeFromLoop circular inside which i've added 8 small circular nodes. and 8 circular nodes are moving with CMMotionManager inside Parent circular node. with fast motion shake some balls disappears from screen. SKScene Class given below
Balls only disappears when anyone shake mobile hard randomly.
There are 8 balls initially but after some hard shake reduced.
class GameScene: SKScene {
let motionManager = CMMotionManager()
var Circle = SKShapeNode(circleOfRadius: 108)
var sound = SKAction.playSoundFileNamed(getRandomSound(), waitForCompletion: false)
var collisionBitmasks: [UInt32] = [UInt32]()
override func didMove(to view: SKView) {
Circle.fillTexture = SKTexture.init(image: UIImage.init(named: "img_Ball") ?? UIImage())
Circle.position = CGPoint.init(x: 0, y: 0)
Circle.name = "defaultCircle"
Circle.lineWidth = 0.0
Circle.fillColor = SKColor.lightGray.withAlphaComponent(0.8)
Circle.physicsBody = SKPhysicsBody.init(edgeLoopFrom: UIBezierPath.init(ovalIn: CGRect.init(x: Circle.frame.minX + 12,
y: Circle.frame.minY + 12,
width: Circle.frame.width - 24,
height: Circle.frame.height - 24)).cgPath)
Circle.physicsBody?.isDynamic = true
Circle.physicsBody?.affectedByGravity = false
Circle.physicsBody?.allowsRotation = false
addChild(Circle)
self.physicsWorld.contactDelegate = self
startAcceleroMeter()
for index in 1...8 {
addBalls(index)
}
}
func stop() {
motionManager.stopAccelerometerUpdates()
Circle.children.forEach { (ball) in
ball.physicsBody?.isDynamic = false
ball.physicsBody?.affectedByGravity = false
}
}
func startAcceleroMeter() {
Circle.children.forEach { (ball) in
ball.physicsBody?.isDynamic = true
ball.physicsBody?.affectedByGravity = true
}
motionManager.startAccelerometerUpdates()
motionManager.accelerometerUpdateInterval = 0.1
motionManager.startAccelerometerUpdates(to: .main) { (motionData, error) in
let gravity = CGVector.init(dx: (motionData?.acceleration.x ?? 0.0) * 20, dy: (motionData?.acceleration.y ?? 0.0) * 20)
print(gravity)
self.physicsWorld.gravity = gravity
}
}
func stopPlaying() -> [String] {
var dictionary = [String]()
for (_, ball) in (Circle.children).enumerated() {
dictionary.append("\(ball.position.x), \(ball.position.y), 0.0")
}
return dictionary
}
func addBalls(_ ballNo: Int) {
let ball = SKShapeNode.init(circleOfRadius: 12)
ball.name = "ball\(ballNo)"
ball.fillTexture = SKTexture.init(linearGradientWithAngle: CGFloat.pi, colors: [BallColors(rawValue: ballNo)?.toUIColor(false) ?? UIColor(), BallColors(rawValue: ballNo)?.toUIColor(true) ?? UIColor()], locations: [0, 1], size: ball.frame.size)
ball.fillColor = UIColor.white
ball.physicsBody = SKPhysicsBody.init(circleOfRadius: 12)
ball.physicsBody?.isDynamic = true
ball.physicsBody?.affectedByGravity = true
ball.physicsBody?.allowsRotation = true
ball.physicsBody?.friction = 0.2
ball.physicsBody?.restitution = 0.9
ball.physicsBody?.linearDamping = 0.1
ball.physicsBody?.angularDamping = 0.1
ball.physicsBody?.mass = 0.349065870046616
ball.physicsBody?.usesPreciseCollisionDetection = true
ball.position = CGPoint(x: Circle.frame.midX - CGFloat(ballNo), y: Circle.frame.midY - CGFloat(ballNo))
ball.physicsBody?.fieldBitMask = 1
ball.physicsBody?.categoryBitMask = UInt32.init(ballNo + 100)
let collisionBitMask = UInt32.init(ballNo + 20) | UInt32.init(ballNo + 100)
collisionBitmasks.append(collisionBitMask)
ball.physicsBody?.collisionBitMask = collisionBitMask //To be different for each
ball.physicsBody?.contactTestBitMask = UInt32.init(ballNo + 20)
Circle.addChild(ball)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
extension GameScene: SKPhysicsContactDelegate {
func didBegin(_ contact: SKPhysicsContact) {
if collisionBitmasks.contains(contact.bodyA.collisionBitMask) && collisionBitmasks.contains(contact.bodyB.collisionBitMask) {
run(sound)
}
}
}

You need a hidden magic here. Each small ball adds a constraint that can prevent any accident from high speeds:
ball.constraints = [SKConstraint.distance(SKRange(upperLimit: 108 - 12), to: Circle)]

Related

Swift spritekit didbegincontact being called with delay

This is my GameScene code.
class GameScene: SKScene, SKPhysicsContactDelegate {
let orcWidth = UIScreen.main.bounds.width / 5
var orcCategory:UInt32 = 0x1 << 0
var knightCategory:UInt32 = 0x1 << 1
private var orc = SKSpriteNode()
private var knight = SKSpriteNode()
private var orcWalkingFrames: [SKTexture] = []
private var knightIdleFrames: [SKTexture] = []
private var knightAttackFrame: [SKTexture] = []
var background = SKSpriteNode(imageNamed: "game_background1")
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
physicsWorld.gravity = CGVector(dx: 0, dy: 0)
setupbackground()
startGame()
}
func setupbackground() {
background.zPosition = 0
background.size = self.frame.size
background.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
addChild(background)
}
func startGame() {
buildRandomOrcs()
buildKnight()
}
func stopGame() {
}
func buildOrc(yposition: CGFloat) {
var orcWalkFrames: [SKTexture] = []
let orcAnimatedAtlas = SKTextureAtlas(named: "OrcWalking")
let numImages = orcAnimatedAtlas.textureNames.count
for i in 0...numImages - 1 {
let orcTextureName = "0_Orc_Walking_\(i)"
orcWalkFrames.append(orcAnimatedAtlas.textureNamed(orcTextureName))
}
self.orcWalkingFrames = orcWalkFrames
let firstFrameTexture = orcWalkingFrames[0]
orc = SKSpriteNode(texture: firstFrameTexture)
orc.name = "orc"
orc.position = CGPoint(x: frame.minX-orcWidth/2, y: yposition)
self.orc.zPosition = CGFloat(self.children.count)
orc.scale(to: CGSize(width: orcWidth, height: orcWidth))
orc.physicsBody = SKPhysicsBody(rectangleOf: orc.size, center: orc.position)
orc.physicsBody?.affectedByGravity = false
orc.physicsBody?.isDynamic = true
orc.physicsBody?.categoryBitMask = orcCategory
orc.physicsBody?.contactTestBitMask = knightCategory
orc.physicsBody?.collisionBitMask = knightCategory
addChild(orc)
walkOrc()
moveOrcForward()
}
func buildKnight() {
var knightIdleFrames: [SKTexture] = []
let knightIdleAtlas = SKTextureAtlas(named: "KnightIdle")
let numImages = knightIdleAtlas.textureNames.count
for i in 0...numImages - 1 {
let orcTextureName = "_IDLE_00\(i)"
knightIdleFrames.append(knightIdleAtlas.textureNamed(orcTextureName))
}
self.knightIdleFrames = knightIdleFrames
let firstFrameTexture = knightIdleFrames[0]
knight = SKSpriteNode(texture: firstFrameTexture)
knight.name = "knight"
knight.position = CGPoint(x: frame.maxX-orcWidth/2, y: frame.midY)
self.knight.zPosition = 1
knight.scale(to: CGSize(width: -orcWidth, height: orcWidth))
knight.physicsBody = SKPhysicsBody(rectangleOf: knight.size, center: knight.position)
knight.physicsBody?.affectedByGravity = false
knight.physicsBody?.isDynamic = false
knight.physicsBody?.categoryBitMask = knightCategory
knight.physicsBody?.contactTestBitMask = orcCategory
knight.physicsBody?.collisionBitMask = orcCategory
addChild(knight)
idleKnight()
}
func idleKnight() {
knight.run(SKAction.repeatForever(SKAction.animate(with: knightIdleFrames, timePerFrame: 0.1)))
}
func walkOrc() {
orc.run(SKAction.repeatForever(SKAction.animate(with: orcWalkingFrames,timePerFrame: 0.025)))
}
func moveOrcForward() {
orc.run(SKAction.repeatForever(SKAction.moveBy(x: 55, y: 0, duration: 0.25)))
}
func buildRandomOrcs () {
let wait = SKAction.wait(forDuration: TimeInterval(makeRandomNumberBetween(min: 0, max: 0)))
let spawn = SKAction.run {
self.buildOrc(yposition: self.makeRandomCGFloatNumber())
}
let spawning = SKAction.sequence([spawn,wait])
self.run(SKAction.repeat(spawning, count: 10))
}
func makeRandomCGFloatNumber() -> CGFloat {
let randomNumber = arc4random_uniform(UInt32((frame.maxY-orcWidth/2) - (frame.minY+orcWidth/2))) + UInt32(frame.minY+orcWidth/2)
return CGFloat(randomNumber)
}
func makeRandomNumberBetween (min: Int, max: Int) -> Int{
let randomNumber = arc4random_uniform(UInt32(max - min)) + UInt32(min)
return Int(randomNumber)
}
func didBegin(_ contact: SKPhysicsContact) {
let collision:UInt32 = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
if collision == orcCategory | knightCategory {
self.scene?.view?.isPaused = true
print("COLLIDED")
}
}
}
The problem is that the scene pauses almost 2-3 seconds after the collision.
I changed the position of knight and delay time changed.
For example, if I set position to frame.minX+orcWidth/2 there is no delay.
What is wrong with my code?
Your problem isn't things are being delayed, your problem is your bounding box is not where you think it is
use view.showPhysics = true to determine where your boxes are
once you realize they are in the wrong spots, go to this line
knight.physicsBody = SKPhysicsBody(rectangleOf: knight.size, center: knight.position)
and fix it
knight.physicsBody = SKPhysicsBody(rectangleOf: knight.size)
Do so for the rest of your bodies
My guess is that manipulations of SKView properties must happen on main thread, i.e.
DispatchQueue.main.async { [unowned self] in
self.scene?.view?.isPaused = true
print("COLLIDED")
}

How to have a collision reset an image to a different location and update score

I would like to know what im doing wrong with my collision detection. I'm trying to make a game where the user controls a character using a virtual joystick and tries to catch donuts that fall from the top of the screen. The joystick works and having the donut fall works but when the two object collide the score isn't updated and the donut location isn't reset to its default location like I want it to. I have looked at several tutorials but can't seem to find my mistake.
import SpriteKit
import GameplayKit
struct BodyType {
static let Character: UInt32 = 1
static let Knife: UInt32 = 2
static let Donut: UInt32 = 4
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var score: Int = 0
var level: Int = 0
var scoreLabel: SKLabelNode = SKLabelNode(text: "Score: 0")
var BoostButton: SKSpriteNode = SKSpriteNode(imageNamed: "boost")
var Knife: SKSpriteNode = SKSpriteNode(imageNamed: "knife")
var Donut: SKSpriteNode = SKSpriteNode(imageNamed: "donut")
var velocityMultiplier: CGFloat = 0.15
var BoostActive: Bool = false
var KnifeVel: CGFloat = 3
var KnifeX: CGFloat = 0
var KnifeY: CGFloat = 0
var FoodX: CGFloat = 0
var FoodY: CGFloat = 0
var FoodVel: CGFloat = 3
enum NodesZPosition: CGFloat {
case Character, joystick
}
var Character: SKSpriteNode = SKSpriteNode(imageNamed: "character")
var analogJoystick: AnalogJoystick = {
let js = AnalogJoystick(diameter: 90, images: (UIImage(named: "substrate"), UIImage(named: "stick")))
js.position = CGPoint(x: 480, y: 75)
js.zPosition = NodesZPosition.joystick.rawValue
return js
}()
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
backgroundColor = UIColor.blue
self.anchorPoint = CGPoint(x: 0, y: 0)
Character.position = CGPoint(x: 100,y: 200)
Character.size = Donut.size
Character.physicsBody = SKPhysicsBody(texture: Character.texture!, size: Character.size)
Character.physicsBody?.affectedByGravity = false
Character.name = "Character"
Character.physicsBody?.isDynamic = true
Character.physicsBody?.categoryBitMask = BodyType.Character
Character.physicsBody?.collisionBitMask = BodyType.Knife | BodyType.Donut
Character.physicsBody?.contactTestBitMask = BodyType.Knife | BodyType.Donut
self.addChild(Character)
self.addChild(BoostButton)
BoostButton.position = CGPoint(x: 75, y: 75)
Knife.position = CGPoint(x: self.frame.width + 100, y: 200)
Knife.name = "Knife"
self.addChild(Knife)
Donut.position = CGPoint(x: 200, y: self.frame.height + 150)
Donut.name = "Donut"
self.addChild(Donut)
scoreLabel.position = CGPoint(x: 65, y: self.frame.height - 40)
scoreLabel.fontSize = 30
scoreLabel.fontColor = UIColor.black
self.addChild(scoreLabel)
setupJoystick()
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.friction = 0
self.physicsBody = border
}
func setupJoystick (){
addChild(analogJoystick)
analogJoystick.trackingHandler = {[unowned self] data in
self.Character.position = CGPoint(x: self.Character.position.x + (data.velocity.x * self.velocityMultiplier),y: self.Character.position.y + (data.velocity.y * self.velocityMultiplier))
self.Character.zRotation = data.angular
}
}
private func didBegin(_ contact: SKPhysicsContact) {
var firstBody = SKPhysicsBody()
var secondBody = SKPhysicsBody()
if contact.bodyA.node?.name == "Character" {
firstBody = contact.bodyA
secondBody = contact.bodyB
}
else{
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if firstBody.node?.name == "Character" && secondBody.node?.name == "Donut"{
print("collison")
score += 20
scoreLabel.text = "Score \(score)"
Donut.position.y = self.frame.height + 150
Donut.position.x = CGFloat.random(in: 100..<(self.frame.width - 100))
}
else if firstBody.node?.name == "Donut" && secondBody.node?.name == "Character"{
print("collison")
score += 20
scoreLabel.text = "Score \(score)"
Donut.position.y = self.frame.height + 150
Donut.position.x = CGFloat.random(in: 100..<(self.frame.width - 100))
}
}
func touchDown(atPoint pos : CGPoint) {
}
func touchMoved(toPoint pos : CGPoint) {
}
func touchUp(atPoint pos : CGPoint) {
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches ){
let location = touch.location(in: self)
if (BoostButton.frame.contains(location)){
BoostActive = true
}
else{
BoostActive = false
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func update(_ currentTime: TimeInterval) {
// if (BoostActive == true){
// velocityMultiplier = velocityMultiplier * 1.5
// }
// else{
// velocityMultiplier = 0.15
//}
FoodY = Donut.position.y
KnifeX = Knife.position.x
if (Knife.position.x < (self.frame.width - 20) && Knife.position.x > 20){
Knife.physicsBody = SKPhysicsBody(texture: Knife.texture!, size: Knife.size)
Knife.physicsBody?.affectedByGravity = false
Knife.physicsBody?.restitution = 0
Knife.physicsBody?.pinned = false
Knife.physicsBody?.isDynamic = true
Knife.physicsBody?.allowsRotation = false
Knife.physicsBody?.categoryBitMask = BodyType.Knife
Knife.physicsBody?.collisionBitMask = BodyType.Character
Knife.physicsBody?.contactTestBitMask = BodyType.Character
}
else{
Knife.physicsBody = nil
}
if (Donut.position.y < self.frame.height && Donut.position.y > 50){
Donut.physicsBody = SKPhysicsBody(texture: Donut.texture!, size: Donut.size)
Donut.physicsBody?.affectedByGravity = false
Donut.physicsBody?.isDynamic = false
Donut.physicsBody?.categoryBitMask = BodyType.Donut
Donut.physicsBody?.collisionBitMask = BodyType.Character
Donut.physicsBody?.contactTestBitMask = BodyType.Character
}
else{
Donut.physicsBody = nil
}
if (FoodY < 30){
Donut.position.y = self.frame.height + 150
Donut.position.x = CGFloat.random(in: 100..<(self.frame.width - 100))
}
else{
Donut.position.y = Donut.position.y - FoodVel
}
if (KnifeX < 0){
Knife.position.x = self.frame.width + 150
Knife.position.y = CGFloat.random(in: 50..<(self.frame.height - 50))
}
else{
Knife.position.x = Knife.position.x - KnifeVel
}
}
}

Second node instance SKPhysicsBody not responding to collision

I've been trying to create a simple game in SK where the ball would bounce off the tops of trampolines that spawn gradually. Collisions work fine with the first trampoline but I'm having problems registering it when ball hits second trampoline spawned in run-time. Anyone might have a clue what I've been doing wrong?
Here is the code.
import SpriteKit
import GameplayKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var ball: SKShapeNode?
var trampoline: SKShapeNode?
var cam: SKCameraNode?
var hasHit: Bool?
var hasCollided: Bool?
var hasMoved: Bool?
func createBall() {
ball = SKShapeNode(circleOfRadius: 50)
ball?.position = CGPoint(x: 0, y: -600)
ball?.fillColor = .red
ball?.strokeColor = .red
let ballPhysics = SKPhysicsBody(circleOfRadius: 50)
ball?.physicsBody = ballPhysics
ballPhysics.categoryBitMask = 1
ballPhysics.collisionBitMask = 0
ballPhysics.contactTestBitMask = 0
ballPhysics.affectedByGravity = false //NO GRAVITY!
ballPhysics.isDynamic = true
addChild(ball!)
}
func createTrampoline(x: CGFloat, y: CGFloat) {
let rect = CGRect(x: x, y: y, width: 100, height: 20)
trampoline = SKShapeNode(rect: rect)
trampoline?.fillColor = .blue
trampoline?.strokeColor = .blue
let trampolinePhysics = SKPhysicsBody(rectangleOf: CGSize(width: 100, height: 20))
trampoline?.physicsBody = trampolinePhysics
trampolinePhysics.categoryBitMask = 2
trampolinePhysics.collisionBitMask = 0
trampolinePhysics.contactTestBitMask = 1
trampolinePhysics.affectedByGravity = false //NO GRAVITY!
trampolinePhysics.isDynamic = true
addChild(trampoline!)
}
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
cam = SKCameraNode()
self.camera = cam
self.backgroundColor = .darkText
hasHit = false
hasCollided = false
hasMoved = false
createBall()
createTrampoline(x: -50, y: -10)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touches: AnyObject in touches {
let location = touches.location(in: self)
let move = SKAction.moveTo(x: location.x, duration: 0.1)
ball?.run(move)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if (!hasMoved!) {
let vect = CGVector(dx: 0, dy: 600)
ball?.physicsBody?.applyImpulse(vect)
ball?.physicsBody?.affectedByGravity = true
hasMoved = true
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
if (hasHit == true) {
cam?.position.y = (ball?.position.y)!
}
}
func didBegin(_ contact: SKPhysicsContact) {
let vect = CGVector(dx: 0, dy: 1500)
if (((contact.bodyB.node?.position.y)! - (contact.bodyA.node?.position.y)!) > 0) {
if (!hasCollided!){
hasHit = true
hasCollided = true
print("collision")
contact.bodyB.applyImpulse(vect)
createTrampoline(x: -50, y: ((ball?.position.y)! + CGFloat(3000)))
}
} else {
print("bad coll")
hasCollided = false
}
}
}
Thanks in advance.

My initial pipes are different from the following pipes

I'm making a game where the ball is suppose to go through some pipes, and when the player touches the pipes, the game stops. Kind of like flappy bird. The only problem I have is that the initial pipes blocks the entire screen, while the rest of the pipes are placed and randomized exactly as I want. How is this possible?
This is the ball class:
import SpriteKit
struct ColliderType {
static let Ball: UInt32 = 1
static let Pipes: UInt32 = 2
static let Score: UInt32 = 3
}
class Ball: SKSpriteNode {
func initialize() {
self.name = "Ball"
self.zPosition = 1
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.physicsBody = SKPhysicsBody(circleOfRadius: self.size.height /
2)
self.setScale(0.7)
self.physicsBody?.affectedByGravity = false
self.physicsBody?.categoryBitMask = ColliderType.Ball
self.physicsBody?.collisionBitMask = ColliderType.Pipes
self.physicsBody?.contactTestBitMask = ColliderType.Pipes |
ColliderType.Score
}
}
This is the Random Class:
import Foundation
import CoreGraphics
public extension CGFloat {
public static func randomBetweenNumbers(firstNum: CGFloat, secondNum:
CGFloat) -> CGFloat {
return CGFloat(arc4random()) / CGFloat(UINT32_MAX) * abs(firstNum -
secondNum) + firstNum
}
}
This is the GameplayScene:
import SpriteKit
class GameplayScene: SKScene {
var ball = Ball()
var pipesHolder = SKNode()
var touched: Bool = false
var location = CGPoint.zero
override func didMove(to view: SKView) {
initialize()
}
override func update(_ currentTime: TimeInterval) {
moveBackgrounds()
if (touched) {
moveNodeToLocation()
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event:
UIEvent?) {
touched = true
for touch in touches {
location = touch.location(in:self)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event:
UIEvent?) {
touched = false
}
override func touchesMoved(_ touches: Set<UITouch>, with event:
UIEvent?) {
for touch in touches {
location = touch.location(in: self)
}
}
func initialize() {
createBall()
createBackgrounds()
createPipes()
spawnObstacles()
}
func createBall() {
ball = Ball(imageNamed: "Ball")
ball.initialize()
ball.position = CGPoint(x: 0, y: 0)
self.addChild(ball)
}
func createBackgrounds() {
for i in 0...2 {
let bg = SKSpriteNode(imageNamed: "BG")
bg.anchorPoint = CGPoint(x: 0.5, y: 0.5)
bg.zPosition = 0
bg.name = "BG"
bg.position = CGPoint(x: 0, y: CGFloat(i) * bg.size.height)
self.addChild(bg)
}
}
func moveBackgrounds() {
enumerateChildNodes(withName: "BG", using: ({
(node, error) in
node.position.y -= 15
if node.position.y < -(self.frame.height) {
node.position.y += self.frame.height * 3
}
}))
}
func createPipes() {
pipesHolder = SKNode()
pipesHolder.name = "Holder"
let pipeLeft = SKSpriteNode(imageNamed: "Pipe")
let pipeRight = SKSpriteNode(imageNamed: "Pipe")
pipeLeft.name = "Pipe"
pipeLeft.anchorPoint = CGPoint(x: 0.5, y: 0.5)
pipeLeft.position = CGPoint(x: 350, y: 0)
pipeLeft.xScale = 1.5
pipeLeft.physicsBody = SKPhysicsBody(rectangleOf: pipeLeft.size)
pipeLeft.physicsBody?.categoryBitMask = ColliderType.Pipes
pipeLeft.physicsBody?.affectedByGravity = false
pipeLeft.physicsBody?.isDynamic = false
pipeRight.name = "Pipe"
pipeRight.anchorPoint = CGPoint(x: 0.5, y: 0.5)
pipeRight.position = CGPoint(x: -350, y: 0)
pipeRight.xScale = 1.5
pipeRight.physicsBody = SKPhysicsBody(rectangleOf: pipeRight.size)
pipeRight.physicsBody?.categoryBitMask = ColliderType.Pipes
pipeRight.physicsBody?.affectedByGravity = false
pipeRight.physicsBody?.isDynamic = false
pipesHolder.zPosition = 5
pipesHolder.position.y = self.frame.height + 100
pipesHolder.position.x = CGFloat.randomBetweenNumbers(firstNum:
-250, secondNum: 250)
pipesHolder.addChild(pipeLeft)
pipesHolder.addChild(pipeRight)
self.addChild(pipesHolder)
let destination = self.frame.height * 3
let move = SKAction.moveTo(y: -destination, duration:
TimeInterval(10))
let remove = SKAction.removeFromParent()
pipesHolder.run(SKAction.sequence([move, remove]), withKey: "Move")
}
func spawnObstacles() {
let spawn = SKAction.run({ () -> Void in
self.createPipes()
})
let delay = SKAction.wait(forDuration: TimeInterval(1.5))
let sequence = SKAction.sequence([spawn, delay])
self.run(SKAction.repeatForever(sequence), withKey: "Spawn")
}
func moveNodeToLocation() {
// Compute vector components in direction of the touch
var dx = location.x - ball.position.x
// How fast to move the node. Adjust this as needed
let speed:CGFloat = 0.1
// Scale vector
dx = dx * speed
ball.position = CGPoint(x:ball.position.x+dx, y: 0)
}
}

didBeginContact not working in Swift 2 + SpriteKit

I'm working on a game, and I'm using spritekit and Swift.
This is my code:
import SpriteKit
struct collision {
static let arrow:UInt32 = 0x1 << 1
static let runner:UInt32 = 0x1 << 2
static let target:UInt32 = 0x1 << 3
static let targetCenter:UInt32 = 0x1 << 4
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var person = SKSpriteNode()
var box = SKSpriteNode()
var screenSize:CGSize!
var gameScreenSize:CGSize!
var gameStarted:Bool = false
var moveAndRemove = SKAction()
var boxVelocity:NSTimeInterval = 5.5
override func didMoveToView(view: SKView) {
self.physicsWorld.gravity = CGVectorMake(0, -1.0)
self.physicsWorld.contactDelegate = self
screenSize = self.frame.size
gameScreenSize = view.frame.size
createPerson()
}
func createPerson() -> Void {
person.texture = SKTexture(imageNamed:"person")
person.setScale(1.0)
person.size = CGSize(width: 80, height: 80)
person.position = CGPoint(x: screenSize.width / 2, y: 150)
person.physicsBody = SKPhysicsBody(rectangleOfSize: person.size)
person.physicsBody?.affectedByGravity = false
person.physicsBody?.dynamic = false
self.addChild(person)
}
func createTarget() -> Void {
box = SKSpriteNode()
box.size = CGSize(width: 70, height: 100)
box.setScale(1.0)
box.position = CGPoint(x: (screenSize.width / 3) * 2, y: screenSize.height + box.size.height)
box.texture = SKTexture(imageNamed: "box")
box.physicsBody? = SKPhysicsBody(rectangleOfSize: box.size)
box.physicsBody?.categoryBitMask = collision.target
box.physicsBody?.collisionBitMask = collision.arrow
box.physicsBody?.contactTestBitMask = collision.targetCenter
box.physicsBody?.affectedByGravity = false
box.physicsBody?.dynamic = true
box.physicsBody?.usesPreciseCollisionDetection = true
self.addChild(box)
let distance = CGFloat(self.frame.height - box.frame.height)
let moveTargets = SKAction.moveToY(-distance, duration: boxVelocity)
let removeTargets = SKAction.removeFromParent()
moveAndRemove = SKAction.sequence([moveTargets,removeTargets])
box.runAction(moveAndRemove)
}
func createBall() ->Void {
let ball = SKSpriteNode()
ball.size = CGSize(width: 20, height: 22)
ball.zPosition = 5
let moveToXY = CGPoint(x: self.size.width, y: self.size.height)
ball.texture = SKTexture(imageNamed: "ball")
ball.position = CGPointMake(person.position.x + ball.size.width, person.position.y + ball.size.height)
ball.physicsBody? = SKPhysicsBody(rectangleOfSize: ball.size)
ball.physicsBody?.categoryBitMask = collision.arrow
ball.physicsBody?.collisionBitMask = collision.target
ball.physicsBody?.affectedByGravity = false
ball.physicsBody?.dynamic = true
ball.physicsBody?.usesPreciseCollisionDetection = true
let action = SKAction.moveTo(moveToXY, duration: 1.5)
let delay = SKAction.waitForDuration(1.5)
ball.runAction(SKAction.sequence([action,delay]))
self.addChild(ball)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if gameStarted == false {
gameStarted = true
let spawn = SKAction.runBlock { () in
self.createTarget()
}
let delay = SKAction.waitForDuration(1.5)
let spawnDelay = SKAction.sequence([spawn, delay])
let spanDelayForever = SKAction.repeatActionForever(spawnDelay)
self.runAction(spanDelayForever)
} else {
createBall()
boxVelocity -= 0.1
}
}
func didBeginContact(contact: SKPhysicsContact) {
print("Detect")
}
func didEndContact(contact: SKPhysicsContact) {
print("end detect")
}
override func update(currentTime: CFTimeInterval) {
}
}
But when I run the game, the collision between objects does not. I'm trying to solve a while, but found nothing. Can someone help me?
Project files.
Try with these to modifications:
box.physicsBody = SKPhysicsBody(rectangleOfSize: box.size)
box.physicsBody?.categoryBitMask = collision.target
box.physicsBody?.collisionBitMask = collision.arrow
box.physicsBody?.contactTestBitMask = collision.targetCenter
and
ball.physicsBody = SKPhysicsBody(rectangleOfSize: ball.size)
ball.physicsBody?.categoryBitMask = collision.arrow
ball.physicsBody?.collisionBitMask = collision.target
ball.physicsBody?.contactTestBitMask = collision.target
Note the absence of "?" while you init the physicsBody and the new contactTestBitMask