I'm trying to write a game where stars are falling from the top of the iphone screen to the bottom. I want to remove my star sprites when they're out of the screen. I've tried to use physicsContactDelegate, and create a edge around my frame with edgeFromLoop(self.frame), but didBegin is never called.
Below is my gameScene.swift file
import SpriteKit
import GameplayKit
import UIKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var entities = [GKEntity]()
var graphs = [String : GKGraph]()
private var lastUpdateTime : TimeInterval = 0
struct PhysicsCategory {
static let none: UInt32 = 0
static let all : UInt32 = UInt32.max
static let star: UInt32 = 0b1 // 1
static let edge: UInt32 = 0b10 // 2
}
private var edge: SKPhysicsBody!
override func sceneDidLoad() {
self.lastUpdateTime = 0
edge = SKPhysicsBody(edgeLoopFrom: self.frame)
edge.categoryBitMask = PhysicsCategory.edge
edge.contactTestBitMask = PhysicsCategory.star
edge.collisionBitMask = PhysicsCategory.star
}
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
run(SKAction.repeatForever(
SKAction.sequence([
SKAction.run(addStar),
SKAction.wait(forDuration: 1.0)
])
))
}
func didBegin(_ contact: SKPhysicsContact) {
print("didBegin called")
// 1
var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if((firstBody.categoryBitMask & PhysicsCategory.star != 0) &&
(secondBody.categoryBitMask & PhysicsCategory.edge != 0)){
print("call destroyStar")
if let star = firstBody.node as? SKSpriteNode {
destroyStar(star: star)
}
}
}
func addStar(){
let star = SKSpriteNode(imageNamed: "star")
let scale = CGFloat.random(in: 0.1 ... 0.5)
star.xScale = scale
star.yScale = scale
star.zPosition = 1.0
star.physicsBody = SKPhysicsBody(rectangleOf: star.size)
star.physicsBody?.linearDamping = 1.0
star.physicsBody?.friction = 1.0
star.physicsBody?.isDynamic = true // 2
star.physicsBody?.categoryBitMask = PhysicsCategory.star // 3
star.physicsBody?.contactTestBitMask = PhysicsCategory.edge // 4
star.physicsBody?.collisionBitMask = PhysicsCategory.edge
let actualX = CGFloat.random(in: (-1*size.width/2)+50 ... (size.width/2)-50)
star.position = CGPoint(x: actualX, y: self.size.height)
addChild(star)
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
// Initialize _lastUpdateTime if it has not already been
if (self.lastUpdateTime == 0) {
self.lastUpdateTime = currentTime
}
// Calculate time since last update
let dt = currentTime - self.lastUpdateTime
// Update entities
for entity in self.entities {
entity.update(deltaTime: dt)
}
self.lastUpdateTime = currentTime
}
func destroyStar(star: SKSpriteNode){
print("star destroyed")
star.removeFromParent()
}
}
And this is my GameViewController
import UIKit
import SpriteKit
import GameplayKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Load 'GameScene.sks' as a GKScene. This provides gameplay related content
// including entities and graphs.
if let scene = GKScene(fileNamed: "GameScene") {
// Get the SKScene from the loaded GKScene
if let sceneNode = scene.rootNode as! GameScene? {
// Copy gameplay related content over to the scene
sceneNode.entities = scene.entities
sceneNode.graphs = scene.graphs
// Set the scale mode to scale to fit the window
sceneNode.scaleMode = .aspectFit
// Present the scene
if let view = self.view as! SKView? {
view.presentScene(sceneNode)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
}
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override var prefersStatusBarHidden: Bool {
return true
}
}
I'm a swift beginner, I know my question is probably really basic but I'd really appreciate any help! Thanks!
You need to make edge and SKNode() and then assign the physicsBody to edge.
try this.
let edge = SKNode()
override func didMove(to View: SKView) {
edge.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
edge.physicsBody.categoryBitMask = PhysicsCategory.edge
edge.physicsBody.contactTestBitMask = PhysicsCategory.star
edge.physicsBody.collisionBitMask = PhysicsCategory.star
self.addChild(edge)
}