I am creating a game in which balls spawn on top and after they fall down and bounce off the ground(this works),I am working on collisions now, my bullets hit the ball and kind of bounces off. If you need any additional code I will post it. (Edited)
import Foundation
import SpriteKit
Did move to view
struct PhysicsCategory {
static let none: UInt32 = 0b0
static let player: UInt32 = 0b1
static let ball: UInt32 = 0b10
static let bullet: UInt32 = 0b100
static let ground: UInt32 = 0b1000
}
class GameScene: SKScene, SKPhysicsContactDelegate {
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
let sceneBody = SKPhysicsBody(edgeLoopFrom: self.frame)
sceneBody.friction = 0
self.physicsBody = sceneBody
player.position = CGPoint(x: self.size.width/2, y: self.size.height / 8)
var timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(spawnBullet), userInfo: nil, repeats: true)
player.size = CGSize(width: 100, height: 100)
player.physicsBody = SKPhysicsBody(circleOfRadius: player.size.width/2)
player.physicsBody?.affectedByGravity = false
player.physicsBody?.isDynamic = true
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width/2)
ball.physicsBody?.restitution = 1
ball.physicsBody?.linearDamping = 0
bullet.size = CGSize(width: 30, height: 30)
bullet.zPosition = -5
bullet.position = CGPoint(x: player.position.x, y: player.position.y)
let action = SKAction.moveTo(y: self.size.height + 30, duration: 1.0)
bullet.run(SKAction.repeatForever(action))
bullet.physicsBody = SKPhysicsBody(circleOfRadius: bullet.size.width/2)
bullet.name = "bullet"
player.physicsBody?.categoryBitMask = PhysicsCategory.player
player.physicsBody?.collisionBitMask = PhysicsCategory.none
player.physicsBody?.contactTestBitMask = PhysicsCategory.ball
bullet.physicsBody?.categoryBitMask = PhysicsCategory.bullet
bullet.physicsBody?.collisionBitMask = PhysicsCategory.none
bullet.physicsBody?.contactTestBitMask = PhysicsCategory.ball
ball.physicsBody?.categoryBitMask = PhysicsCategory.ball
ball.physicsBody?.contactTestBitMask = PhysicsCategory.bullet
ball.physicsBody?.collisionBitMask = PhysicsCategory.ground
ground.physicsBody?.categoryBitMask = PhysicsCategory.ground
ground.physicsBody?.collisionBitMask = PhysicsCategory.ball
ground.physicsBody?.contactTestBitMask = PhysicsCategory.none
player.name = "player"
addChild(player)
ballSpawner(delay: 2.0)
spawnGround()
}
//didBegin function
func didBegin(_ contact: SKPhysicsContact) {
// print("didBeginContact entered for \(String(describing: contact.bodyA.node!.name)) and \(String(describing: contact.bodyB.node!.name))")
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
I THINK THIS PART IS WRONG Is my case right? Because when I try to write a bullet and ball it gives me an error - " Binary operator '|' cannot be applied to two 'SKSpriteNode' operands". So only default case is called.
switch contactMask {
//This case never gets called, i can't see it in the console when i run it
case PhysicsCategory.bullet | PhysicsCategory.ball:
let bullet = contact.bodyA.categoryBitMask ==
PhysicsCategory.bullet ? contact.bodyA.node : contact.bodyB.node
let ball = contact.bodyA.categoryBitMask ==
PhysicsCategory.ball ? contact.bodyA.node : contact.bodyB.node
collisionBulletAndBall(ball: (ball)!, bullet: (bullet)!)
print("bullet and ball have contacted.")
case PhysicsCategory.bullet:
print("bullet contact")
case PhysicsCategory.ball & PhysicsCategory.bullet:
print("collision ball with bullet")
default:
print("Some other contact occurred")
}
}
func gameOver() {
print("game over")
}
func collisionBulletAndBall(ball: SKNode, bullet: SKNode) {
ball.removeFromParent()
bullet.removeFromParent()
print("collision")
}
@objc func spawnBullet() {
var bullet = SKSpriteNode(imageNamed: "bullet")
bullet.size = CGSize(width: 30, height: 30)
bullet.zPosition = -5
bullet.position = CGPoint(x: player.position.x, y: player.position.y)
let action = SKAction.moveTo(y: self.size.height + 30, duration: 1.0)
bullet.run(SKAction.repeatForever(action))
bullet.name = "bullet"
self.addChild(bullet)
bullets.append(bullet)
}
func spawnScoreBall() {
var ballSize = CGSize(width: 30, height: 30)
//Random Size
let randomSize = arc4random() % 3
switch randomSize {
case 1:
ballSize.width *= 1.2
ballSize.height *= 1.2
case 2:
ballSize.width *= 1.5
ballSize.height *= 1.5
default:
break
}
var ball = SKSpriteNode(imageNamed: "ball")
ball.size = ballSize
let y = size.height-ballSize.height/2
//Random x
var randomX = CGFloat(arc4random() % UInt32(size.width - ballSize.width))
randomX -= size.width/2-ballSize.width*4
ball.position = CGPoint(x: randomX, y: y)
//Moving logic
// let moveDownAction = SKAction.moveBy(x: 0, y: -size.height + ball.size.height, duration: 2.0)
// let destroyAction = SKAction.removeFromParent()
// let sequenceAction = SKAction.sequence([moveDownAction, destroyAction])
// ball.run(sequenceAction)
//Rotation
var rotateAction = SKAction.rotate(byAngle: 1, duration: 1)
let randomRotation = arc4random() % 2
if randomRotation == 1 {
rotateAction = SKAction.rotate(byAngle: -1, duration: 1)
}
let repeatForeverAction = SKAction.repeatForever(rotateAction)
ball.run(repeatForeverAction)
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width/2)
ball.physicsBody?.affectedByGravity = true
ball.physicsBody?.restitution = 1
ball.physicsBody?.linearDamping = 0
ball.zPosition = 3
blocks.append(ball)
self.addChild(ball)
}
Spawn ground action
func spawnGround() {
ground = SKSpriteNode(color: UIColor.white, size: CGSize(width: self.frame.size.width, height: 50))
ground.position = CGPoint(x: self.size.width/2, y: 0)
}