SpriteKit - Collision Off after HIT - sprite-kit

I am writing a spritekit game and I have a problem, I would like the framework not to detect collisions after it is detected. For example, the player is dealt damage and becomes insensitive to attacks, e.g. for 20 seconds. Now when a collision is detected, it is detected all the time (e.g. 50 times)
Is there a way to temporarily disable collisions ??
Player code :
func createPlayer() {
var walkFrames: [SKTexture] = []
var walkFrames2: [SKTexture] = []
var walkFrames3: [SKTexture] = []
var walkFrames4: [SKTexture] = []
// let spaceShipTexture = SKTexture(imageNamed: "p2.png")
let playerAnimatedAtlas = SKTextureAtlas(named: "walk")
let playerAnimatedAtlas_idle = SKTextureAtlas(named: "idle")
let playerAnimatedAtlas_jump = SKTextureAtlas(named: "jump")
let playerAnimatedAtlas_attack = SKTextureAtlas(named: "attack")
var _: [SKTexture] = []
for i in 0...6 {
let playerTextureName = "1_entity_000_WALK_00\(i).png"
walkFrames.append(playerAnimatedAtlas.textureNamed(playerTextureName))
}
for z in 0...6 {
let playerTextureName_idle = "1_entity_000_IDLE_00\(z).png"
walkFrames2.append(playerAnimatedAtlas_idle.textureNamed(playerTextureName_idle))
}
for p in 0...6 {
let playerTextureName_jump = "1_entity_000_JUMP_00\(p).png"
walkFrames3.append(playerAnimatedAtlas_jump.textureNamed(playerTextureName_jump))
}
for k in 0...6 {
let playerTextureName_attack = "1_entity_000_ATTACK_00\(k).png"
walkFrames4.append(playerAnimatedAtlas_attack.textureNamed(playerTextureName_attack))
}
playerWalkingFrames = walkFrames
let firstFrameTexture = playerWalkingFrames[0]
player.position = CGPoint(x: -1050, y: -90 )
//player.setScale(0.090)
player.size = CGSize(width: 170, height: 120)
// player.physicsBody = SKPhysicsBody(rectangleOf:CGSize(width: 35, height: 100))
let spaceShipTexture = SKTexture(imageNamed: "p2.png")
let texturedSpaceShip = SKSpriteNode(texture: spaceShipTexture)
player.physicsBody = SKPhysicsBody(texture: spaceShipTexture , size: CGSize(width: player.size.width,
height: player.size.height));
player.physicsBody?.usesPreciseCollisionDetection = true
//player.physicsBody = SKPhysicsBody(texture: play, size: player.size)
player.physicsBody?.allowsRotation = false
player.physicsBody?.categoryBitMask = playerCategory
player.physicsBody?.collisionBitMask = enemy1Category
//player.physicsBody?.contactTestBitMask = enemy1Category
playerWalkingFrames_idle = walkFrames2
playerWalkingFrames_jump = walkFrames3
playerWalkingFrames_attack = walkFrames4
self.addChild(player)
}
collision code :
func didBegin(_ contact: SKPhysicsContact) {
let collison: UInt32 = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
if collison == playerCategory | enemy1Category{
print("COLLISION") }
else {
//print("Brak Kolizji" )
}
if collison == playermieczCategory | enemy1Category {
print("miecz")
}
if collison == playermieczCategory | piratkaCategory {
print("miecz_Piratka")
// health -= 0.2
// piratka.isHidden = true
}
if collison == playerCategory | piratkaCategory{
// if collison == nil {return}
player.physicsBody?.contactTestBitMask = 0
// czarny.physicsBody?.applyImpulse(CGVector(dx: 10, dy: 0))
// DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(5)) {
// self.playerhealth -= 0.01
// print("nico")
print("HIT3")
// }
}

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")
}

Node not being removed from parent (spritekit)

Create enemy
touchesBegan and didBegin contact function
My enemy node is not being removed from the scene every time my sword node touches it. I'm just wondering if anyone could explain to me what I'm doing wrong?
(UPDATE BELOW)
import SpriteKit
import GameplayKit
import AVFoundation
class LevelTwo: SKScene, SKPhysicsContactDelegate{
var levelBg = SKSpriteNode(imageNamed: "level2")
var hero = SKSpriteNode()
var enemy = SKSpriteNode()
var sword = SKSpriteNode()
var health1 = SKSpriteNode(imageNamed: "playerhplv2")
var health2 = SKSpriteNode(imageNamed: "playerhplv2")
var health3 = SKSpriteNode(imageNamed: "playerhplv2")
var musicPath = URL(fileURLWithPath: Bundle.main.path(forResource: "gameMusic", ofType: "mp3")!)
var musicGamePlayer = AVAudioPlayer()
var runMonster = SKAction()
var waitMonster = SKAction()
var sequenceMonster = SKAction()
var repeatMonster = SKAction()
enum CollisionNum: UInt32{
case swordNum = 1
case enemyNum = 2
case playerNum = 4
}
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
///music
do{
musicGamePlayer = try AVAudioPlayer(contentsOf: musicPath)
musicGamePlayer.prepareToPlay()
musicGamePlayer.numberOfLoops = -1
musicGamePlayer.play()
}
catch{
print(error)
}
//bg
levelBg.position = CGPoint(x: 0, y: 0)
levelBg.zPosition = 1
levelBg.size = levelBg.texture!.size()
levelBg.setScale(1.25)
self.addChild(levelBg)
//hero
let playerTexture = SKTexture(imageNamed: "main")
hero = SKSpriteNode(texture: playerTexture)
hero.position = CGPoint(x: 0, y: 0)
hero.zPosition = 2
hero.setScale(0.6)
hero.physicsBody = SKPhysicsBody(texture: playerTexture, size: CGSize(width: hero.size.width, height: hero.size.height))
hero.physicsBody!.categoryBitMask = CollisionNum.playerNum.rawValue
hero.physicsBody!.collisionBitMask = CollisionNum.enemyNum.rawValue //player is allowed to bump into rocks and skulls
hero.physicsBody!.contactTestBitMask = CollisionNum.enemyNum.rawValue // same as collisions
hero.physicsBody!.isDynamic = false
self.addChild(hero)
//health1
health1.position = CGPoint(x: 130, y: 150)
health1.zPosition = 3
health1.setScale(0.75)
self.addChild(health1)
//health2
health2.position = CGPoint(x: 230, y: 150)
health2.zPosition = 3
health2.setScale(0.75)
self.addChild(health2)
//health3
health3.position = CGPoint(x: 320, y: 150)
health3.zPosition = 3
health3.setScale(0.75)
self.addChild(health3)
runMonster = SKAction.run(addMonster)
waitMonster = SKAction.wait(forDuration: 0.3)
sequenceMonster = SKAction.sequence([runMonster,waitMonster])
repeatMonster = SKAction.repeatForever(sequenceMonster)
run(repeatMonster)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let locale = touch.location(in: self)
hero.position.x = locale.x
hero.position.y = locale.y
}
}
func addMonster(){
//random position based off the bg size
let monsterHigherX = Int(levelBg.size.width)
let monsterHigherY = Int(levelBg.size.height)
let monsterLowerX = monsterHigherX * -1
let monsterLowerY = monsterHigherY * -1
let randomLocaleX = Int(arc4random_uniform(UInt32(monsterHigherX - monsterLowerX))) + monsterLowerX
let randomLocaleY = Int(arc4random_uniform(UInt32(monsterHigherY - monsterLowerY))) + monsterLowerY
let movementEnemy = SKAction.moveBy(x: -5, y: -5, duration: 0.2)
let movementForever = SKAction.repeatForever(movementEnemy)
let enemyTexture = SKTexture(imageNamed: "boss0")
enemy = SKSpriteNode(texture: enemyTexture)
enemy.zPosition = 2
enemy.setScale(0.5)
enemy.position = CGPoint(x: randomLocaleX, y: randomLocaleY)
enemy.physicsBody = SKPhysicsBody(texture: enemyTexture, size: CGSize(width: enemy.size.width, height: enemy.size.height))
enemy.physicsBody!.isDynamic = true
enemy.physicsBody!.affectedByGravity = false
enemy.physicsBody!.categoryBitMask = CollisionNum.enemyNum.rawValue
enemy.physicsBody!.collisionBitMask = CollisionNum.swordNum.rawValue
enemy.physicsBody!.contactTestBitMask = CollisionNum.swordNum.rawValue
enemy.run(movementForever)
self.addChild(enemy)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let swordTexture = SKTexture(imageNamed: "blade-0")
sword = SKSpriteNode(texture: swordTexture)
sword.setScale(0.50)
sword.zPosition = 2
sword.position = hero.position
sword.physicsBody = SKPhysicsBody(texture: swordTexture, size: CGSize(width: sword.size.width, height: sword.size.height))
sword.physicsBody!.velocity = CGVector(dx: 1200, dy:0)
sword.physicsBody!.isDynamic = true
sword.physicsBody!.affectedByGravity = true
sword.physicsBody!.usesPreciseCollisionDetection = true
sword.physicsBody!.categoryBitMask = CollisionNum.swordNum.rawValue
sword.physicsBody!.collisionBitMask = CollisionNum.enemyNum.rawValue
sword.physicsBody!.contactTestBitMask = CollisionNum.enemyNum.rawValue
self.addChild(sword)
}
func didBegin(_ contact: SKPhysicsContact) {
let collision: UInt32 = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
if collision == CollisionNum.swordNum.rawValue | CollisionNum.enemyNum.rawValue {
enemy.removeFromParent()
}
}
override func update(_ currentTime: TimeInterval) {
}
}
(Ive attached my whole level2 class) Thank you so much for the suggestion; however, when I tried implementing this I still run into the same problem (im running this on the iphone simulator) Im wondering whether the error is with my enum or my implementation of my physics with my nodes
You do not want to remove "enemy" because "enemy" is always the last monster you added. You need to check which contactBody is the enemy so you can remove it. You can do that by guaranteeing which node you want to associate as A, and which you want to associate as B by looking at the categoryBitMask value:
func didBegin(_ contact: SKPhysicsContact) {
//This guarantees the lower categoryBitMask (Providing you are only using one) is in A
let bodyA = contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask ? contact.bodyA : contact.bodyB
let bodyB = contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask ? contact.bodyB : contact.bodyA
if bodyA.categoryBitMask == CollisionNum.swordNum.rawValue && bodyB.categoryBitMask == CollisionNum.enemyNum.rawValue {
bodyB.node.removeFromParent()
}
}
Of course this will lead to problems with multiple collisions, so instead you may want to do:
var removeNodes = SKNode()
func didBegin(_ contact: SKPhysicsContact) {
//This guarantees the lower categoryBitMask (Providing you are only using one) is in A
let bodyA = contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask ? contact.bodyA : contact.bodyB
let bodyB = contact.bodyA.categoryBitMask > contact.bodyB.categoryBitMask ? contact.bodyB : contact.bodyA
if bodyA.categoryBitMask == CollisionNum.swordNum.rawValue && bodyB.categoryBitMask == CollisionNum.enemyNum.rawValue {
bodyB.node.moveToParent(removeNodes)
}
}
func didFinishUpdate(){
removeNodes.removeAllChildren()
}
Try this:
func didBegin(_ contact: SKPhysicsContact) {
let collision: UInt32 = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
if collision == CollisionNum.swordNum.rawValue | CollisionNum.enemyNum.rawValue {
enemy.removeFromParent()
}
}
You were only testing if bodyA is equal to the enemy, however, bodyA may be equal to the sword instead.

why physics is not working with SKShapes?

I am trying to detect the collision between the circle called player and the balls called enemyCircle but nothing happen
func didBeginContact(contact: SKPhysicsContact) {
if let nodeA = contact.bodyA.node as? SKShapeNode, let nodeB = contact.bodyB.node as? SKShapeNode {
if nodeA.fillColor != nodeB.fillColor {
print("not same color")
}else {
print("same color")
}
}
}
private func drawPlayer(radius: CGFloat) {
player = SKShapeNode(circleOfRadius: radius)
player.physicsBody = SKPhysicsBody(circleOfRadius: radius)
player.physicsBody?.affectedByGravity = false
player.physicsBody?.isDynamic = false
player.physicsBody?.pinned = true
player.physicsBody?.categoryBitMask = bodyType.player.rawValue
player.physicsBody?.collisionBitMask = bodyType.enemy.rawValue
player.physicsBody?.contactTestBitMask = bodyType.enemy.rawValue
player.strokeColor = SKColor.purple
player.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
player.glowWidth = 2.0
world.addChild(player)
}
private func drawEnemy(radius: CGFloat, color: SKColor) {
let enemyCircle = SKShapeNode(circleOfRadius: radius)
enemyCircle.fillColor = color
enemyCircle.glowWidth = 0.5
enemyCircle.strokeColor = color
enemyCircle.physicsBody = SKPhysicsBody(circleOfRadius: radius)
enemyCircle.physicsBody?.affectedByGravity = false
enemyCircle.physicsBody?.isDynamic = false
enemyCircle.physicsBody?.collisionBitMask = bodyType.player.rawValue
enemyCircle.physicsBody?.categoryBitMask = bodyType.enemy.rawValue
let nextEnemyPosition = determineNextEnemyPosition()
let enemyPosition = spawnAtRandomPosition(edge: nextEnemyPosition)
enemyCircle.position = enemyPosition
world.addChild(enemyCircle)
numberOfEnemies += 1
enemyCircle.name = String(numberOfEnemies)
enemy.append(enemyCircle)
runToCenter(enemy: enemyCircle)
}
enum bodyType: UInt32 {
case enemy = 1
case player = 2
}
and this
class GameScene: SKScene, SKPhysicsContactDelegate
and i put this in didMove func
self.physicsWorld.contactDelegate = self
can someone explain me the issues here
Note:: I made both not dynamic as I don't want anyone to move the other or change it, just be notified when it touches so I stop the game

skphysicsbody to skspritenode error

Here is the code:
import SpriteKit
import CoreMotion
struct PhysicsCatagory {
static let Player :UInt32 = 0x1 << 0
static let shark :UInt32 = 0x1 << 1
static let jellyfish :UInt32 = 0x1 << 2
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var Player = SKSpriteNode()
var game = true
var playerPos = false
var ScoreCount = 0
let myLabel = SKLabelNode(fontNamed: "3D-Thirteen-Pixel-Fonts")
var HighScore = 0
let DisplayScore = SKLabelNode(fontNamed: "3D-Thirteen-Pixel-Fonts")
let LeaderBoardScore = SKLabelNode(fontNamed: "3D-Thirteen-Pixel-Fonts")
let LeaderBoardHighscore = SKLabelNode(fontNamed: "3D-Thirteen-Pixel-Fonts")
var CheckGameState = false
let playButton = SKSpriteNode(imageNamed: "Play")
let Scores = SKSpriteNode(imageNamed: "LeaderBoard")
var PlayerUpState = false
var PlayerDownState = false
var ifPlayerDrawJustCalled = false
var TextureAtlas = SKTextureAtlas()
var TextureArray = [SKTexture]()
var TextureAtlas2 = SKTextureAtlas()
var TextureArray2 = [SKTexture]()
var TextureAtlas3 = SKTextureAtlas()
var TextureArray3 = [SKTexture]()
var motionManager: CMMotionManager!
var fishYpos = 115.0
let shark = SKSpriteNode(imageNamed: "shark")
let jellyfish = SKSpriteNode(imageNamed: "jellyfish")
override func didMoveToView(view: SKView) {
print("called")
motionManager = CMMotionManager()
motionManager.startGyroUpdates()
motionManager.gyroUpdateInterval = 0.02
backgroundColor = UIColor(red: 0.0, green: 7.0, blue: 1.0, alpha: 1.0)
let HighscoreDefault = NSUserDefaults.standardUserDefaults()
if(HighscoreDefault.valueForKey("Highscore") != nil){
HighScore = HighscoreDefault.valueForKey("Highscore") as! Int
}
TextureAtlas = SKTextureAtlas(named: "Images")
TextureArray.append(SKTexture(imageNamed: "win_1.png"))
TextureArray.append(SKTexture(imageNamed: "win_2.png"))
TextureArray.append(SKTexture(imageNamed: "win_3.png"))
TextureArray.append(SKTexture(imageNamed: "win_4.png"))
TextureAtlas3 = SKTextureAtlas(named: "Images")
TextureArray3.append(SKTexture(imageNamed: "jellyfish_1.png"))
TextureArray3.append(SKTexture(imageNamed: "jellyfish_2.png"))
TextureArray3.append(SKTexture(imageNamed: "jellyfish_3.png"))
TextureArray3.append(SKTexture(imageNamed: "jellyfish_4.png"))
TextureArray3.append(SKTexture(imageNamed: "jellyfish_5.png"))
TextureArray3.append(SKTexture(imageNamed: "jellyfish_6.png"))
TextureArray3.append(SKTexture(imageNamed: "jellyfish_7.png"))
TextureArray3.append(SKTexture(imageNamed: "jellyfish_8.png"))
TextureAtlas2 = SKTextureAtlas(named: "Images")
TextureArray2.append(SKTexture(imageNamed: "shark_1.png"))
TextureArray2.append(SKTexture(imageNamed: "shark_2.png"))
TextureArray2.append(SKTexture(imageNamed: "shark_3.png"))
TextureArray2.append(SKTexture(imageNamed: "shark_4.png"))
TextureArray2.append(SKTexture(imageNamed: "shark_5.png"))
TextureArray2.append(SKTexture(imageNamed: "shark_6.png"))
Player = SKSpriteNode(imageNamed: TextureAtlas.textureNames[0])
self.physicsWorld.contactDelegate = self
Player.zPosition = 10.0
Player.position = CGPoint(x: 80, y: fishYpos)
Player.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 30, height: 30))
Player.physicsBody?.dynamic = false
Player.physicsBody?.affectedByGravity = false
myLabel.text = "\(ScoreCount)"
myLabel.fontSize = 70
myLabel.position = CGPointMake(CGRectGetMidX(self.frame), frame.size.height-150)
myLabel.zPosition = 18.0
addChild(myLabel)
addChild(Player)
Player.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(TextureArray, timePerFrame: 0.20)))
var BubbleTimer = NSTimer.scheduledTimerWithTimeInterval(1, target:self,selector: "addBubble", userInfo: nil, repeats: true)
var Gyro = NSTimer.scheduledTimerWithTimeInterval(0.02, target:self,selector: "gyroFunction", userInfo: nil, repeats: true)
var MainTimer1 = NSTimer.scheduledTimerWithTimeInterval(1, target:self,selector: "RunTimeTimer", userInfo: nil, repeats: true)
var sharkTimer = NSTimer.scheduledTimerWithTimeInterval(0.70, target: self, selector: "RunSharkTimer", userInfo: nil, repeats: true)
var jellyfishTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "RunJellyfishTimer", userInfo: nil, repeats: true)
}
func addBubble(){
let randomNum1 = Int(arc4random_uniform(3))
if(randomNum1 == 2){
let randomNum2 = Int(arc4random_uniform(2))
if(randomNum2 == 1){
let Bubble1 = SKSpriteNode(imageNamed: "Bubble1")
Bubble1.position.x = Player.position.x+9
Bubble1.position.y = Player.position.y
Bubble1.zPosition = 2.0
addChild(Bubble1)
Bubble1.runAction(SKAction.moveToY( frame.size.height+20, duration: 3.0))
}
if(randomNum2 == 0){
let Bubble2 = SKSpriteNode(imageNamed: "Bubble2")
Bubble2.position.x = Player.position.x+9
Bubble2.position.y = Player.position.y
Bubble2.zPosition = 3.0
addChild(Bubble2)
Bubble2.runAction(SKAction.moveToY( frame.size.height+20, duration: 3.0))
}
}
}
func RunTimeTimer(){
if(game == true){
timer()
}
}
func RunSharkTimer(){
if(game == true){
addShark()
}
}
func RunJellyfishTimer(){
if(game == true){
addJellyfish()
}
}
func gyroFunction(){
if let gyro_y = motionManager.gyroData?.rotationRate.y {
if(fishYpos+gyro_y*(-10) > 115){
if(CGFloat(fishYpos+gyro_y*(-10)) < frame.size.height-115){
fishYpos = fishYpos+gyro_y*(-10)
let fishAction = SKAction.moveToY(CGFloat(fishYpos), duration: 0.05)
Player.runAction(fishAction)
}
}
}
}
func didBeginContact(contact: SKPhysicsContact) {
let firstBody = contact.bodyA as! SKSpriteNode
let secondBody = contact.bodyB as! SKSpriteNode
if(((firstBody.name == "Player") && (secondBody.name == "shark")) || (firstBody.name == "shark") && (secondBody.name == "Player") || ((firstBody.name == "Player") && (secondBody.name == "jellyfish")) || (firstBody.name == "jellyfish") && (secondBody.name == "Player")){
game = false
if(CheckGameState == false){
playButton.xScale = 1.9
playButton.yScale = 1.9
playButton.zPosition = 12.0
playButton.position = CGPoint(x: frame.midX-50, y: frame.midY-140)
playButton.name = "playButton"
playButton.userInteractionEnabled = false
addChild(playButton)
if(ScoreCount>HighScore){
HighScore = ScoreCount
let HighscoreDefault = NSUserDefaults.standardUserDefaults()
HighscoreDefault.setInteger(HighScore, forKey: "Highscore")
}
LeaderBoardScore.text = "\(ScoreCount)"
LeaderBoardHighscore.text = "\(HighScore)"
LeaderBoardHighscore.position = CGPoint(x: frame.midX+30 , y: frame.midY+5)
LeaderBoardHighscore.xScale = 2.0
LeaderBoardHighscore.yScale = 2.0
LeaderBoardHighscore.zPosition = 15.0
LeaderBoardHighscore.fontColor = UIColor.purpleColor()
LeaderBoardScore.position = CGPoint(x: frame.midX+60 , y: frame.midY+72)
LeaderBoardScore.fontColor = UIColor.purpleColor()
LeaderBoardScore.xScale = 2.0
LeaderBoardScore.zPosition = 15.0
LeaderBoardScore.yScale = 2.0
addChild(LeaderBoardHighscore)
addChild(LeaderBoardScore)
Scores.xScale = 2
Scores.yScale = 2
Scores.zPosition = 11.0
Scores.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(Scores)
CheckGameState = true
}
}
}
func addShark(){
Player.physicsBody?.collisionBitMask = PhysicsCatagory.shark
Player.physicsBody?.contactTestBitMask = PhysicsCatagory.shark
Player.name = "Player"
Player.physicsBody?.dynamic = true
Player.physicsBody?.affectedByGravity = false
let randomNumShark = arc4random_uniform(2)
if(randomNumShark == 1){
let shark = SKSpriteNode(imageNamed: "shark_1.png")
shark.position.x = frame.size.width
let PositionY = arc4random_uniform(UInt32(frame.size.height))
shark.position.y = CGFloat(PositionY)
addChild(shark)
let sharkGoForward = SKAction.moveToX(CGFloat(-1100), duration: 1.5)
shark.runAction(sharkGoForward)
shark.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: shark.size.width, height:shark.size.height))
shark.physicsBody?.categoryBitMask = PhysicsCatagory.Player
shark.physicsBody?.contactTestBitMask = PhysicsCatagory.Player
shark.physicsBody?.collisionBitMask = PhysicsCatagory.Player
shark.physicsBody?.dynamic = true
shark.physicsBody?.affectedByGravity = false
shark.name = "shark"
shark.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(TextureArray2, timePerFrame: 0.05)))
}
}
func addJellyfish(){
Player.physicsBody?.collisionBitMask = PhysicsCatagory.jellyfish
Player.physicsBody?.contactTestBitMask = PhysicsCatagory.jellyfish
Player.name = "Player"
Player.physicsBody?.dynamic = true
Player.physicsBody?.affectedByGravity = false
let randomNumJelly = arc4random_uniform(2)
if(randomNumJelly == 1){
let jellyfish = SKSpriteNode(imageNamed: "jellyfish")
jellyfish.position.y = 0
let PositionX = arc4random_uniform(UInt32(frame.size.width))
jellyfish.position.x = CGFloat(PositionX)
addChild(jellyfish)
let jellyfishGoUp = SKAction.moveToY(CGFloat(frame.size.height+100), duration: 2.0)
jellyfish.runAction(jellyfishGoUp)
jellyfish.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: jellyfish.size.width, height:jellyfish.size.height))
jellyfish.physicsBody?.categoryBitMask = PhysicsCatagory.Player
jellyfish.physicsBody?.contactTestBitMask = PhysicsCatagory.Player
jellyfish.physicsBody?.collisionBitMask = PhysicsCatagory.Player
jellyfish.physicsBody?.dynamic = true
jellyfish.physicsBody?.affectedByGravity = false
jellyfish.name = "jellyfish"
jellyfish.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(TextureArray3, timePerFrame: 0.05)))
}
}
func timer(){
if(game == true){
ScoreCount++
myLabel.text = "\(ScoreCount)"
}
}
func rePositionPlayer(){
Player.removeFromParent()
Player.position = CGPoint(x: 80, y: 220)
addChild(Player)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location = touch.locationInNode(self)
if(game == false){
if playButton.containsPoint(location){
game = true
LeaderBoardHighscore.removeFromParent()
LeaderBoardScore.removeFromParent()
playButton.removeFromParent()
Scores.removeFromParent()
CheckGameState = false
rePositionPlayer()
ScoreCount = 0
fishYpos = 220
}
}
if(game == true){
}
}
}
override func update(currentTime: CFTimeInterval) {
}
}
My error is at the line
let secondbody = contact.bodyB as! SKSpriteNode
It says
can cast SKPhysicsBody to unrealted SKSpriteNode
How to fix this issue?
Try saying let secondbody.node = contact.bodyB as! SKSpriteNode

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