Reputation: 35
I'm writing a simple Space Invaders type game for school. I'd like to use the physics properties included in Swift for my collision detection, but I've run into some troubles. Although I've written and re-read the code multiple times, it simply does not work. There are no errors nor any results. Since the code is fairly spread throughout my file, I've included my whole GameScene page below. Any help is greatly appreciated, thank you in advance.
// --------------------------------------------------------
// | Space Invasion. |
// | Created by Kyle Herrmann on 2017-04-05. |
// | Copyright © 2017 Kyle Herrmann. All rights reserved. |
// --------------------------------------------------------
//Import the essentials.
import SpriteKit
import GameplayKit
enum BodyType:UInt32 {
case userShipBody = 1
case alienBody = 2
}
class GameScene: SKScene, SKPhysicsContactDelegate {
//Variables and Declarations.
//UserShip Variables.
let moveLeft: SKAction = SKAction.moveBy(x: -20, y: 0, duration: 0.1)
let moveRight: SKAction = SKAction.moveBy(x: 20, y: 0, duration: 0.1)
var userShipSprite: SKNode = SKNode()
var tapDetect: Bool = false
var posX = CGFloat()
var posY = CGFloat()
//Sprite Variables.
var xSpeed = CGFloat(3.5)
var ySpeed = CGFloat(3.5)
let alienMoveLeft: SKAction = SKAction.moveBy(x: -3, y: 0, duration: 0.1)
let alienMoveRight: SKAction = SKAction.moveBy(x: 3, y: 0, duration: 0.1)
let alienMoveDown: SKAction = SKAction.moveBy(x: 0, y: -4.5, duration: 0.1)
let classicAlien = SKSpriteNode(texture: SKTexture(imageNamed: "ClassicAlien"))
var aliens = [SKSpriteNode]()
var alienAmount = 6
var displayAliens = true
var xAliens = -300
var yAliens = 520
var rowCount = 5
var indexMoving = 0
//Life Variables.
var lblLife = SKLabelNode()
var lifeCounter = 3
//Detect and Save User Tap Location.
func touchDown(atPoint pos : CGPoint) {
tapDetect = true
posX = pos.x
posY = pos.y
}
//Grab our object(s).
override func didMove(to view: SKView) {
//Life Count Declaration.
lblLife = self.childNode(withName: "lblLife") as! SKLabelNode!
//User Ship.
for node in self.children {
if (node.name == "userShip") {
userShipSprite = node
}
//Set up user ship body for physics.
self.physicsWorld.contactDelegate = self
userShipSprite.physicsBody?.categoryBitMask = BodyType.userShipBody.rawValue
}
//Add and display given amount of aliens.
for index in 0...alienAmount - 1 {
aliens.append(SKSpriteNode(texture: SKTexture(imageNamed: "ClassicAlien")))
//Location
let newPosition = CGPoint(x: CGFloat(xAliens), y: CGFloat(yAliens))
xAliens += 120
aliens[index].position = newPosition
//Display
self.addChild(aliens[(index)])
//Set up physics body
aliens[index].physicsBody?.categoryBitMask = BodyType.alienBody.rawValue
//New Row
if index >= rowCount {
xAliens = -300
yAliens -= 100
rowCount += 6
}
}
}
//Physics collision and so forth.
func didBegin(_ contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask == BodyType.userShipBody.rawValue && contact.bodyB.categoryBitMask == BodyType.alienBody.rawValue {
print("Death Detected")
//Change Life.
lifeCounter -= 1
lblLife.text = "Lives:\(lifeCounter)"
}
else if contact.bodyB.categoryBitMask == BodyType.userShipBody.rawValue && contact.bodyA.categoryBitMask == BodyType.alienBody.rawValue {
print("Death Detected")
//Change Life.
lifeCounter -= 1
lblLife.text = "Lives:\(lifeCounter)"
}
}
//Detect Touch Release.
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
tapDetect = false
for t in touches { self.touchUp(atPoint: t.location(in: self)) }
}
override func update(_ currentTime: TimeInterval) {
//Alien Movement.
if userShipSprite.position.y < aliens[indexMoving].position.y { //Bottom of Map.
aliens[indexMoving].run(alienMoveDown)
}
if userShipSprite.position.x > aliens[indexMoving].position.x { //Right Side of Map.
aliens[indexMoving].run(alienMoveRight)
}
if userShipSprite.position.x < aliens[indexMoving].position.x { //Left Side of Map.
aliens[indexMoving].run(alienMoveLeft)
}
//Check for next alien.
if aliens[indexMoving].position.y < userShipSprite.position.y {
aliens[indexMoving].removeFromParent()
indexMoving += 1
//Check for end game.
if indexMoving > alienAmount {
xSpeed += 1
ySpeed += 1
alienAmount += 6
}
}
//Ship Movement.
if tapDetect == true {
//Prevent off screen movement (Right side)
if userShipSprite.position.x > 200 {
userShipSprite.run(moveLeft)
}
//Prevent off screen movement (Left side)
else if userShipSprite.position.x < -200 {
userShipSprite.run(moveRight) }
//Ship movement.
if posX > 0 && posY < -300 {
userShipSprite.run(moveRight)
}
else if posX < 0 && posY < -300 {
userShipSprite.run(moveLeft)
}
}
}
// We ain't using this stuff right now.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchDown(atPoint: t.location(in: self)) }
}
func touchMoved(toPoint pos : CGPoint) {
}
func touchUp(atPoint pos : CGPoint) {
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchMoved(toPoint: t.location(in: self)) }
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchUp(atPoint: t.location(in: self)) }
}
} //End of Class.
Upvotes: 0
Views: 102
Reputation: 86
I have skimmed thru the code. looks good. U just need to a small amount of code to give the contact bitmask and collision bitmask. So under
userShipSprite.physicsBody?.categoryBitMask = BodyType.userShipBody.rawValue
Add the code below
userShipSprite.physicsBody?.collisionBitMask = BodyType.alienBody.rawValue
userShipSprite.physicsBody?.contactTestBitMask = BodyType.alienBody.rawValue
AND for the Alien
aliens[index].physicsBody?.categoryBitMask = BodyType.alienBody.rawValue
Add the codes below because you want it to collide with and also detect contact.
aliens[index].physicsBody?.categoryBitMask = BodyType.userShipBody.rawValue
aliens[index].physicsBody?.categoryBitMask = BodyType.userShipBody.rawValue
Hope this provides the answer to the question
EDIT: Here is a sample proj you can try on
import SpriteKit
import GameplayKit
class GameScene: SKScene, SKPhysicsContactDelegate {
let newDot1 = SKSpriteNode(imageNamed: "Spaceship")
let newDot2 = SKSpriteNode(imageNamed: "Spaceship")
var reset = false
enum categoryBit: UInt32 {
case ball = 1
case ball2 = 2
}
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
physicsWorld.gravity = CGVector(dx: 0, dy: -0.3)
newDot2.setScale(0.3)
newDot2.name = "dot1"
newDot2.position = CGPoint(x: frame.midX, y: frame.maxY)
newDot2.physicsBody = SKPhysicsBody(circleOfRadius: newDot2.size.width/2)
newDot2.physicsBody?.categoryBitMask = categoryBit.ball.rawValue
newDot2.physicsBody?.collisionBitMask = categoryBit.ball2.rawValue
newDot2.physicsBody?.contactTestBitMask = categoryBit.ball2.rawValue
self.addChild(newDot2)
newDot1.setScale(0.8)
newDot1.position = CGPoint(x: frame.midX, y: frame.minY)
newDot1.physicsBody = SKPhysicsBody(circleOfRadius: newDot1.size.width/2)
newDot1.physicsBody?.isDynamic = false
newDot1.physicsBody?.categoryBitMask = categoryBit.ball2.rawValue
newDot1.physicsBody?.collisionBitMask = categoryBit.ball.rawValue
newDot1.physicsBody?.contactTestBitMask = categoryBit.ball.rawValue
newDot1.name = "dot2"
self.addChild(newDot1)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
newDot2.position = CGPoint(x: frame.midX, y: frame.maxY)
}
func didBegin(_ contact: SKPhysicsContact) {
print("contact made")
let hitDot = contact.bodyB.node! as! SKSpriteNode
let hitDot1 = contact.bodyA.node! as! SKSpriteNode
if hitDot1.name == "dot1" || hitDot.name == "dot1" {
reset = true
}
}
override func update(_ currentTime: TimeInterval) {
if reset {
newDot1.position.x = 0
reset = false
}
}
}
DELETE everything in GameViewController view didload method and add this
super.viewDidLoad()
let skview = self.view as! SKView
let scene = GameScene(size: view.bounds.size)
scene.scaleMode = .resizeFill
skview.ignoresSiblingOrder = true
skview.showsFPS = true
skview.showsNodeCount = true
skview.showsPhysics = true
skview.presentScene(scene)
Upvotes: 1