func didBeginContact(contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask == PhysicsCategory.overPow || contact.bodyB.categoryBitMask == PhysicsCategory.overPow{
let sk = delegateForCollision!.view as! SKView
let newScene = GG(fileNamed: "GG")
newScene!.delegateFor = delegateForCollision
newScene?.scaleMode = .AspectFill
sk.presentScene(newScene)
}
if contact.bodyA.categoryBitMask == PhysicsCategory.glem && contact.bodyB.categoryBitMask == PhysicsCategory.kappa{
contact.bodyA.node?.removeFromParent()
glem++
glemLabel.text = "SKAŁY: \(glem)"
}
if contact.bodyB.categoryBitMask == PhysicsCategory.glem && contact.bodyA.categoryBitMask == PhysicsCategory.kappa{
contact.bodyB.node?.removeFromParent()
glem++
glemLabel.text = "SKAŁY: \(glem)"
}
}
glem and kappa categoryBitMask nodes are colliding so glem variable should be ++ one time then node is removed from scene but it looks like this method is called more times during next frames. I see it in logs because I added print("\(glem)") in glem didSet. Why does it happen?
I changed glem++ to if contact.bodyB.node?.parent != nil{glem++}
and now it works as it should.
Related
My bullet is finally being removed after touching the enemy however the enemy isnt being removed. Is something wrong with my physicscontact code? My player is also now going out of the screen border but i just fixed that by removing both bodyB and bodyA nil lines. I dont know if thats the best way to fix the 2nd problem and if it will mess up my enemy code in the future.
func didBegin(_ contact: SKPhysicsContact) {
if (contact.bodyA.categoryBitMask == bulletCategory) {
contact.bodyA.node?.physicsBody?.collisionBitMask = 0
contact.bodyA.node?.physicsBody?.categoryBitMask = 0
} else if (contact.bodyB.categoryBitMask == bulletCategory) {
contact.bodyB.node?.physicsBody?.collisionBitMask = 0
contact.bodyB.node?.physicsBody?.categoryBitMask = 0
}
if contact.bodyA.categoryBitMask == enemyCategory {
contact.bodyB.node?.removeFromParent()
contact.bodyB.node?.physicsBody = nil
contact.bodyB.node?.removeAllActions()
} else if contact.bodyB.categoryBitMask == enemyCategory {
contact.bodyA.node?.removeFromParent()
contact.bodyA.node?.physicsBody = nil
contact.bodyA.node?.removeAllActions()
}
}
Have that situation: I have bouncing red ball and several randomly generated platforms.
In case of contact with bottom of the platform ball should pass platform through. In other case, it will be top of platform and ball should bounce. I changing .collisionBitMask and .contactTestBitMask params for player to pass through platform or bounce on it. But my code working only for the last one platform, you can see on screenshot. For other platforms not working - ball pass it through from the top side too. I have array of that platforms and don't know how to check current platform.
Here is part of my code:
var platforms = [SKSpriteNode]()
....
extension GameScene: SKPhysicsContactDelegate {
func didBegin(_ contact: SKPhysicsContact) {
let floor = BitMaskCategory.floor
let player = BitMaskCategory.player
let platformCategory = BitMaskCategory.platform
let bodyA = contact.bodyA.categoryBitMask
let bodyB = contact.bodyB.categoryBitMask
if bodyA == player && bodyB == platformCategory || bodyA == platformCategory && bodyB == player {
for platform in platforms {
if self.player.position.y > platform.position.y {
self.player.physicsBody?.collisionBitMask = floor | platformCategory
self.player.physicsBody?.contactTestBitMask = floor | platformCategory
} else if self.player.position.y < platform.position.y {
self.player.physicsBody?.collisionBitMask = floor
self.player.physicsBody?.contactTestBitMask = floor
}
}
}
}
func didEnd(_ contact: SKPhysicsContact) {
let player = BitMaskCategory.player
let bar = BitMaskCategory.platform
let floor = BitMaskCategory.floor
let bodyA = contact.bodyA.categoryBitMask
let bodyB = contact.bodyB.categoryBitMask
if bodyA == bar && bodyB == player || bodyA == player && bodyB == bar {
for platform in platforms {
if self.player.position.y > platform.position.y {
self.player.physicsBody?.collisionBitMask = floor
self.player.physicsBody?.contactTestBitMask = floor
}
}
}
}
}
So, I don't know how to check current platform. If I placing 3 constant platforms by hand all is working fine :D
Please help, don't know how to realize this task.
I have this approach for solutions (Red platforms)
You can get code example here: https://github.com/Maetschl/SpriteKitExamples/tree/master/PlatformTest
This use object velocity for getting the direction and add collision mask
override func update(_ currentTime: TimeInterval) {
player.physicsBody?.collisionBitMask = 0b0000 // Reset the mask
// For UP only Platform
if (player.physicsBody?.velocity.dy)! < CGFloat(0.0) {
player.physicsBody?.collisionBitMask |= 0b0001 // The pipe | operator adds the mask by binary operations
}
// For Down only platforms
if (player.physicsBody?.velocity.dy)! > CGFloat(0.0) {
player.physicsBody?.collisionBitMask |= 0b0010 // The pipe | operator adds the mask by binary operations
}
}
I am trying to get a player to collide with a SKNode. Doing so, I want a particle to display an exposition where the SKNode just was(player) and display the effect. When I tried to create this, the emitter is not displaying where the player is. How can I fix this?
func didBegin(_ contact: SKPhysicsContact) {
let bodyA = contact.bodyA
let bodyB = contact.bodyB
if bodyA.categoryBitMask == 1 && bodyB.categoryBitMask == 2 || bodyB.categoryBitMask == 1 && bodyA.categoryBitMask == 2 {
let player = SKNode(fileNamed: "player")
let explostion = SKEmitterNode(fileNamed: "explosion.sks")
let addExplosion = SKAction.run {
player?.addChild(explostion!)
}
let seq = SKAction.sequence([addExplosion])
self.addChild(explostion!)
self.run(seq)
}
}
Probably one of physics body belongs to player's node? So you just can access it from body. For example let's player's body - is bodyA:
if bodyA.categoryBitMask == 1 && bodyB.categoryBitMask == 2 || bodyB.categoryBitMask == 1 && bodyA.categoryBitMask == 2 {
let player = bodyA.node
let explostion = SKEmitterNode(fileNamed: "explosion.sks")
player.addChild(explostion!)
}
}
Creating a game in Swift and SprieKit.
I have 2 nodes, a BridgeNode and WaterNode. One on top of the other.
Both have physics bodies to detect when the player is either on the bridge on in the water. Both nodes are added independently as child nodes of the Scene.
When the player node jumps onto the Bridge, DidBegin detects contact with
both the Water and Bridge nodes. I only want it to detect the Bridge node as the player is safely on the Bridge OR if the player is in the water.
func didBegin(_ contact: SKPhysicsContact) {
// Did Begin Contact - Contact Testing and actions
let player1 = (contact.bodyA.categoryBitMask == player1Mask) ? contact.bodyA : contact.bodyB
let other = (player1 == contact.bodyA) ? contact.bodyB : contact.bodyA
if other.categoryBitMask == bridgeMask {
print("BRIDGE CONTACT")
}
else if other.categoryBitMask == waterMask {
// Contacted Water
print("WATER CONTACT")
}
}
The console is printing both print statements always in a random order.
Hope someone can help me to just detect one or the other.
You mentioned that it is a top-down game, so when you have the bridge on top of the water the player will obviously contact both at the same time, there is no "blocking" of the physicsBody underneath the bridge. You need to do something like this in your SKPhysicsContactDelegate:
var playerIsOnBridge = false
func didBegin(_ contact: SKPhysicsContact) {
let player1 = (contact.bodyA.categoryBitMask == player1Mask) ? contact.bodyA : contact.bodyB
let other = (player1 == contact.bodyA) ? contact.bodyB : contact.bodyA
if other.categoryBitMask == bridgeMask || playerIsOnBridge {
playerIsOnBridge = true
print("BRIDGE CONTACT")
} else if other.categoryBitMask == waterMask {
print("WATER CONTACT")
}
}
func didEnd(_ contact: SKPhysicsContact) {
let bitmaskA = contact.bodyA.categoryBitMask
let bitmaskB = contact.bodyB.categoryBitMask
if bitmaskA == bridgeMask || bitmaskB == bridgeMask {
playerIsOnBridge = false
}
}
My didBeginContact function is detecting about 60 collisions between two SKSpriteNodes when there should only be one.
func didBeginContact(contact: SKPhysicsContact) {
let firstBody = contact.bodyA
let secondBody = contact.bodyB
if firstBody.categoryBitMask == bulletCategory && secondBody.categoryBitMask == dragonCategory || firstBody.categoryBitMask == dragonCategory && secondBody.categoryBitMask == bulletCategory{
print("collision happened")
}
}
When the nodes come into contact the console prints "collision happened" many many times.
Here is how i declare physics bodys for each SKSpriteNode
dragonNode.physicsBody = SKPhysicsBody(texture: dragonNode.texture!, size: CGSizeMake(dragonNode.size.width, dragonNode.size.height))
dragonNode.physicsBody?.affectedByGravity = false
dragonNode.physicsBody?.dynamic = true
dragonNode.physicsBody?.categoryBitMask = dragonCategory
dragonNode.physicsBody?.collisionBitMask = bulletCategory
dragonNode.physicsBody?.contactTestBitMask = bulletCategory
bulletNode.physicsBody = SKPhysicsBody(texture: texture, size: texture.size())
bulletNode.physicsBody?.affectedByGravity = false
bulletNode.physicsBody?.dynamic = true
bulletNode.physicsBody?.categoryBitMask = bulletCategory
bulletNode.physicsBody?.collisionBitMask = dragonCategory
bulletNode.physicsBody?.contactTestBitMask = dragonCategory
This is one of the last things i need to fix for my game to be completed so if anyone can help that would be great!
It's because theoretically your game is running at 60 frames per second. So every 60th of a second it is detecting the collision and printing the warning. You haven't put any code into say stop detecting this collision. You could always put a flag on the object
dragonNode.collided = true
and then detect for the collision and the flag
if (firstBody.categoryBitMask == bulletCategory && secondBody.categoryBitMask == dragonCategory || firstBody.categoryBitMask == dragonCategory && secondBody.categoryBitMask == bulletCategory) && dragonNode.collided != true {
dragonNode.collided = true
print("collision happened")
}
this way the collision only fires once