getting the sprite attached to a SKPhysicsBody - swift

I'm animating a sprite, and when it touches another one, a physics contact function is called. Than, in this function, I'm trying to get the sprite with touched the other. Its body is bodyA but it's a SKPhysicsBody, and it can not be converted as a SKSpriteNode. Do you have any ideas?
The function is correctly called when contact, I just try to get the sprite which body makes the contact. The final idea is getting the actions attached to the sprite with I'm looking for but I suppose when you have the sprite it's easy.
let shootCategory: UInt32 = 0x1 << 0
let enemyCategory: UInt32 = 0x1 << 1
// Declaration of the SKPhysicsBody of the sprite wich will touch the other one
sprite.physicsBody = SKPhysicsBody(circleOfRadius: (20))
sprite.physicsBody?.usesPreciseCollisionDetection = true
sprite.physicsBody?.categoryBitMask = shootCategory
sprite.physicsBody?.collisionBitMask = shootCategory | enemyCategory
sprite.physicsBody?.contactTestBitMask = shootCategory | enemyCategory
sprite.physicsBody?.affectedByGravity = false
// Declaration of the SKPhysicsBody of the sprite wich will be touched
sprite.run(SKAction.group([moveAction, fadeInAction]))
sprite.physicsBody = SKPhysicsBody(circleOfRadius: (20))
sprite.physicsBody?.usesPreciseCollisionDetection = true
sprite.physicsBody?.categoryBitMask = enemyCategory
sprite.physicsBody?.collisionBitMask = shootCategory | enemyCategory
sprite.physicsBody?.contactTestBitMask = shootCategory | enemyCategory
sprite.physicsBody?.affectedByGravity = false
func didBegin(_ contact: SKPhysicsContact) {
if (contact.bodyA.categoryBitMask == enemyCategory) && (contact.bodyB.categoryBitMask == shootCategory){
// I tried this to get the sprite wich the bodyB is attached to but it doesn't even build
let sprite: SKSpriteNode = sprite.contact.bodyB
contact.bodyA.removeAction(forKey: "moveToAction")
}
}

I finally found the solution with is really simple:
let Node = contact.bodyB.node as! SKSpriteNode

Related

Why is my code never detecting any contact with my SKPhysicsBody?

The problem I am running in to is that the code I created to detect contact is not working. I wanted it to work when the ball category touched the obstacle category. What is wrong with my code? Thank you so much, any help is appreciated!
Heres where I define the categories:
let ballCategory : UInt32 = 0x1 << 1
let obstacleCategory : UInt32 = 0x1 << 2
Heres where I create the physics aspect of my ball:
leftBall.physicsBody = SKPhysicsBody(rectangleOf: leftBall.size)
leftBall.physicsBody?.categoryBitMask = ballCategory
leftBall.physicsBody?.contactTestBitMask = obstacleCategory
leftBall.physicsBody?.affectedByGravity = false
leftBall.physicsBody?.isDynamic = false
leftBall.physicsBody?.collisionBitMask = 0
Heres where I create the physics aspect of an obstacle:
obstacleSquare.physicsBody = SKPhysicsBody(rectangleOf: obstacleSquare.size)
obstacleSquare.physicsBody?.categoryBitMask = obstacleCategory
obstacleSquare.physicsBody?.contactTestBitMask = ballCategory
obstacleSquare.physicsBody?.affectedByGravity = false
obstacleSquare.physicsBody?.isDynamic = false
obstacleSquare.physicsBody?.collisionBitMask = 1
And heres my collision detection function:
func didBegin(_ contact: SKPhysicsContact) {
print("CONTACT")
if contact.bodyA.categoryBitMask == obstacleCategory {
print("CONTACT")
gameOver()
}
if contact.bodyB.categoryBitMask == obstacleCategory {
print("CONTACT")
gameOver()
}
if contact.bodyA.categoryBitMask == ballCategory {
print("CONTACT")
gameOver()
}
if contact.bodyB.categoryBitMask == ballCategory {
print("CONTACT")
gameOver()
}
}
Both of your object’s physics bodies have their isDynamic Property set to false. At least one of them needs to have this property set to true for any contacts to be registered.

How to change physics body and sprite image of existing sprite after contact

I have created two sprites with physics bodies and handled their contact. How can I change the physics body and sprite image for one of sprites when the contact occurs? Please see relevant code below:
// circle Sprite
circleSprite.name = circleSpriteCategoryName
circleSprite.position = CGPointMake(2*self.frame.size.width/3, 2*self.frame.size.height/3)
circleSprite.zPosition = 10
self.addChild(circleSprite)
circleSprite.physicsBody = SKPhysicsBody(circleOfRadius: circleSprite.frame.size.width/2)
circleSprite.physicsBody?.friction = 0
circleSprite.physicsBody?.restitution = 1
circleSprite.physicsBody?.linearDamping = 0
circleSprite.physicsBody?.angularDamping = 0
circleSprite.physicsBody?.allowsRotation = false
circleSprite.physicsBody?.applyImpulse(CGVectorMake(4, -4))
// square sprite
let squareSprite = SKSpriteNode(imageNamed: "square.png")
squareSprite.position = CGPointMake(CGRectGetWidth(frame)*0.4, CGRectGetHeight(frame)*0.8)
squareSprite.physicsBody = SKPhysicsBody(rectangleOfSize: squareSprite.frame.size)
squareSprite.physicsBody?.friction = 0.0
squareSprite.name = squareSpriteCategoryName
squareSprite.physicsBody?.categoryBitMask = squareSpriteCategory
squareSprite.zPosition = 10
addChild(squareSprite)
// contact in didBeginContact
if firstBody.categoryBitMask == circleSpriteCategory && secondBody.categoryBitMask == squareSpriteCategory {
println("contact works")
}
EDIT 1
I would like to change update the physics body and image of circleSprite to have the following properties:
circleSprite = SKSpriteNode(imageNamed: "recto.png")
circleSprite.physicsBody = SKPhysicsBody(rectangleOfSize: circleSprite.frame.size)
circleSprite.physicsBody?.friction = 0.0
circleSprite.name = newSpriteCategoryName
circleSprite.physicsBody?.categoryBitMask = newSpriteCategory
EDIT 2
I managed to get change the sprite image thanks to help from Max_Power89. But the image has been reduced to the dimensions of the physics body. Please see the relevant code below:
if firstBody.categoryBitMask == circleSpriteCategory && secondBody.categoryBitMask == squareSpriteCategory {
if let newSprite = firstBody.node {
let newImage = SKTexture(imageNamed: "newSprite.png")
let action = SKAction.setTexture(newImage)
newSprite.runAction(action)
}
}
You can implement SKPhysicsContactDelegate
then in your didBeginContact delegate you can do something like this
func didBeginContact(contact: SKPhysicsContact) {
// Return whatever it's the other body
let other = contact.bodyA.categoryBitMask == PhisicsCategory.Player ? contact.bodyB : contact.bodyA
if other.categoryBitMask == PhisicsCategory.Playe1 {
//Change sprite
let deadTexture = SKTexture(imageNamed: "Your image name")
let action = SKAction.setTexture(deadTexture)
player1.runAction(action)
}
}

Static bodies still moving

this may be a duplicate of
Static Physics body still moving with contact
but I have not the reputation to add a comment.
My problem is with collisions and static bodies. I'm working on a little game and I have a player, so configured (from sks file):
player = worldNode.childNodeWithName("player") as! SKSpriteNode
let playerBodyTexture = SKTexture(imageNamed: "player_physicBody_mask")
player.physicsBody = SKPhysicsBody(texture: playerBodyTexture, size: CGSizeMake(player.size.width, player.size.height))
player.physicsBody!.usesPreciseCollisionDetection = true
player.physicsBody!.categoryBitMask = PhysicsCategory.player
player.physicsBody!.collisionBitMask = PhysicsCategory.ground | PhysicsCategory.enemies
player.physicsBody!.contactTestBitMask = PhysicsCategory.enemies
player.physicsBody!.restitution = 0
player.physicsBody!.friction = 0
player.physicsBody!.allowsRotation = false}
an enemy:
worldNode.enumerateChildNodesWithName("enemy") { node, _ in
let enemy = node as! SKSpriteNode
enemy.name = "enemy"
enemy.physicsBody = SKPhysicsBody(circleOfRadius: 17)
enemy.physicsBody!.dynamic = true
enemy.physicsBody!.mass = 0.4
enemy.physicsBody!.restitution = 0
enemy.physicsBody!.categoryBitMask = PhysicsCategory.enemies
enemy.physicsBody!.collisionBitMask = PhysicsCategory.ground | PhysicsCategory.player
enemy.physicsBody!.contactTestBitMask = PhysicsCategory.player}
and I have the platfrom brick, so configured:
worldNode.enumerateChildNodesWithName("fixedBlock") { node, _ in
let fixedBlock = node as! SKSpriteNode
fixedBlock.name = "fixedBlock"
let fixedBlockBodyTexture = SKTexture(imageNamed: "tripleBlocks_physicBody_mask")
fixedBlock.physicsBody = SKPhysicsBody(texture: fixedBlockBodyTexture, size: CGSizeMake(fixedBlock.size.width, fixedBlock.size.height))
fixedBlock.physicsBody!.categoryBitMask = PhysicsCategory.ground
fixedBlock.physicsBody!.collisionBitMask = PhysicsCategory.player | PhysicsCategory.enemies
fixedBlock.physicsBody!.contactTestBitMask = 0
fixedBlock.physicsBody!.dynamic = false
fixedBlock.physicsBody!.affectedByGravity = false
fixedBlock.physicsBody!.allowsRotation = false
fixedBlock.physicsBody!.pinned = false
fixedBlock.physicsBody!.friction = 0.3
fixedBlock.physicsBody!.restitution = 0}
When the player jumps on the enemies, he has an impulse (like Super Mario :-)), so I have this:
func didBeginContact(contact: SKPhysicsContact) {
let collision: UInt32 = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
if collision == PhysicsCategory.player | PhysicsCategory.enemies {
self.player.physicsBody!.applyImpulse(CGVectorMake(0, 500))}}
Ok... sometimes, often, when the player jumps on enemy, the impulse appens correctly, but the ground tile moves down, also if its dynamic propriety is set on false. I tried to apply a JointFixed on the ground tile but when it is pushed down, its physic body "glitch"; I tried to print the physicsBody velocity propierty of the ground tile and when the problem occours, the velocity's dx vector is >100, but should static bodies not be affected by forces?
Any idea?
Many thanks

How to detect collisions between two fast moving objects?

Hey so I have a problem detecting collisions. I have this project I am making based on Ray Wenderlich's tutorial on How to Make a game like Mega Jump. So everything is works great at the beginning, where platforms and stars are static in one place. But as you go further in the game, stars and platforms start moving (I am using SKActions for this), tried to do this to make it a little harder. But when I get there, collision is NOT being detected at all, player just passes by through the objects like they weren't there. I've been reading everywhere online, I am using precise collision detection but still I see no difference. Any ideas on what can be wrong or what else can I do? Here is a bit of code on how I am doing this:
player = SKSpriteNode(texture: firstFrame)
player.position = (CGPoint(x: self.size.width / 2, y: 50.0))
player.physicsBody = SKPhysicsBody(circleOfRadius: player.size.width / 2)
player.physicsBody?.dynamic = true
player.physicsBody?.allowsRotation = false
player.physicsBody?.restitution = 1.0
player.physicsBody?.friction = 0.0
player.physicsBody?.angularDamping = 0.0
player.physicsBody?.linearDamping = 0.0
player.physicsBody?.usesPreciseCollisionDetection = true
player.physicsBody?.categoryBitMask = CollisionCategoryBitmask.Player
player.physicsBody?.collisionBitMask = 0
player.physicsBody?.contactTestBitMask = CollisionCategoryBitmask.Star | CollisionCategoryBitmask.Platform | CollisionCategoryBitmask.Monster
foregroundNode.addChild(player)
func createPlatformAtPosition(position: CGPoint, ofType type: PlatformType) -> PlatformNode {
let node = PlatformNode()
let thePosition = CGPoint(x: position.x * scaleFactor, y: position.y)
node.position = thePosition
node.name = "NODE_PLATFORM"
node.platformType = type
var sprite: SKSpriteNode
var spriteFrames : [SKTexture]!
if type == .Break {
let spriteAnimatedAtlas = SKTextureAtlas(named: "CloudBreak")
var cloudFrames = [SKTexture]()
spriteFrames = cloudFrames
let firstFrame = SKTexture(imageNamed: "Cloud02")
sprite = SKSpriteNode(texture: firstFrame)
let move = SKAction.moveToX(self.position.x - 160.0, duration:2.0)
let back = SKAction.moveToX(self.position.x, duration:2.0)
let sequence = SKAction.sequence([move, back, move, back])
sprite.runAction(SKAction.repeatActionForever(sequence))
} else {
let spriteAnimatedAtlas = SKTextureAtlas(named: "Cloud")
var cloudFrames = [SKTexture]()
spriteFrames = cloudFrames
let firstFrame = SKTexture(imageNamed: "Cloud")
sprite = SKSpriteNode(texture: firstFrame)
}
node.addChild(sprite)
node.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.size)
node.physicsBody?.dynamic = false
node.physicsBody?.categoryBitMask = CollisionCategoryBitmask.Platform
node.physicsBody?.contactTestBitMask = CollisionCategoryBitmask.Player
node.physicsBody?.collisionBitMask = 0
return node
}
func didBeginContact(contact: SKPhysicsContact) {
var updateHUD = false
let whichNode = (contact.bodyA.node != player) ? contact.bodyA.node : contact.bodyB.node
let other = whichNode as GameObjectNode
updateHUD = other.collisionWithPlayer(player)
}
struct CollisionCategoryBitmask {
static let Player: UInt32 = 0x00
static let Star: UInt32 = 0x01
static let Platform: UInt32 = 0x02
static let Monster: UInt32 = 0x03
}
Slow the objects down and see if they collide. I had an issue where I was moving my nodes too fast and they were past the collision points when the new frame was rendered. If they move so fast they pass each other's physics body in the frame cycle they will not register a hit.
To detect a collision in that case, you can compare where they are in each frame, and if they have passed each other or their x/y plane values overlap, you can execute your collision code.
The collision is not detected because you didn't set the collisionBitMask.
player.physicsBody?.collisionBitMask = CollisionCategoryBitmask.Star | CollisionCategoryBitmask.Platform | CollisionCategoryBitmask.Monster
node.physicsBody?.collisionBitMask = CollisionCategoryBitmask.Player
Contact and Collision aren't the same thing. You can find more information online.
If it still doesn't work, please show us your CollisionCategoryBitmask to make sure you created it properly.
Edit :
struct CollisionCategoryBitmask {
static let Player: UInt32 = 0
static let Star: UInt32 = 0b1
static let Platform: UInt32 = 0b10
static let Monster: UInt32 = 0b100
}
Here is a table I've made for another question, that might help you too :
http://goo.gl/7D8EGY
Check out my collision physics engine, it's very simple but has support for continuous/predicting/bullet collisions. You might learn something from the code, and it's written in javascript so it should be easy to read.https://github.com/Murplyx/AAE---Axis-Aligned-Engine

iOS Swift didBeginContact not being called

I have been struggling for the past two days to get two SKSpriteNodes to register a collision and evoke didBegin#contact.
I've set their bit masks 'categoryBitMask', 'contactTestBitMask' and 'collisionTestBitMask' for both objects.
I've also set the 'dynamic' property for both to 'true'
initPhysics() seems to set up the physicsWorld okay.
All I'm expecting is that didBegin#Contact is called, but it is not
//Set up Physicsbody bit masks
let playerCarBitMask: UInt32 = 0x1 << 1
let slowCarBitMask: UInt32 = 0x1 << 2
//initPhysics
func initPhysics() {
println("(((((((((((((( Initiating Physicsbody ))))))))))))))")
self.physicsWorld.contactDelegate = self
self.physicsWorld.gravity = CGVector.zeroVector
println("self.physicsWorld.contactDelegate = \(self.physicsWorld.contactDelegate)")
}
//setupPlayer
func setupPlayer() {
car = SKSpriteNode(imageNamed: "redCarUp")
car.setScale(2.0)
car.position = CGPoint(x: 800, y: 400)
car.zPosition = 100
car.name = "car"
gameNode.addChild(car)
let carBody = SKPhysicsBody(
rectangleOfSize: car.frame.size, center: car.position)
carBody.dynamic = true
carBody.categoryBitMask = playerCarBitMask
carBody.contactTestBitMask = slowCarBitMask
carBody.mass = 5
carBody.collisionBitMask = slowCarBitMask
car.physicsBody = carBody
println("carBody = \(carBody)")
println("carBody.dynamic = \(carBody.dynamic)")
println("carBody.mass = \(carBody.mass)")
println("carBody.categoryBitMask = \(carBody.categoryBitMask)")
println("carBody.contactTestBitMask = \(carBody.contactTestBitMask)")
println("carBody.collisionBitMask = \(carBody.contactTestBitMask)")
slowCar = SKSpriteNode(imageNamed: "blueCarUp")
slowCar.setScale(2.0)
let slowCarScenePos = CGPoint(
x: 680,
y: 2048)
slowCar.position = gameNode.convertPoint(slowCarScenePos, fromNode: self)
println("slowCar.position = \(slowCar.position) ****")
slowCar.zPosition = 80
slowCar.name = "slowCar"
let slowCarBody = SKPhysicsBody(
rectangleOfSize: slowCar.frame.size, center: slowCar.position)
println("slowCar = \(slowCar) ****")
slowCarBody.dynamic = true
slowCarBody.categoryBitMask = slowCarBitMask
slowCarBody.contactTestBitMask = playerCarBitMask
slowCarBody.mass = 5
slowCarBody.collisionBitMask = playerCarBitMask
slowCar.physicsBody = slowCarBody
gameNode.addChild(slowCar)
}
func didBeginContact(contact: SKPhysicsContact!) {
println("*******************PhysicsContact********************")
}
'didBeginContact' has been changed to 'didBegin' in swift 3
func didBegin(_ contact: SKPhysicsContact) {
//stuff
}
I had a code from swift 2 and 'didBeginContact' was sitting there but wasn't being called. After quite a white I figured out that the function was changed. So, I thought my answer could help someone.
If you want make a contact between car and slowCar you have to init the categoryBitMask of both physicsBodies (I think you did). See the code below to get contact between two physicsBodies. When there is a contact it returns your display function :
//init your categoryBitMask :
let carCategory:UInt32 = 0x1 << 0
let SlowCarCategory:UInt32 = 0x1 << 1
//init car
car.physicsBody?.categoryBitMask = carCategory
car.physicsBody?.contactTestBitMask = slowCarCategory
//init slowCar
slowCar.physicsBody?.categoryBitMask = slowCarCategory
slowCar.physicsBody?.contactTestBitMask = CarCategory
// set your contact function
func didBeginContact(contact: SKPhysicsContact!)
{
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 & carCategory) != 0 && (secondBody.categoryBitMask & slowCarCategory) != 0)
{
displayfunction(firstBody.node as SKSpriteNode, car: secondBody.node as SKSpriteNode)
}
}
func displayFunction (slowCar : SKSpriteNode, car : SKSpriteNode)
It turned out to be a simple problem. In my original code I was setting parameters for the SKPhysicsBody detection frame like so:
let carBody = SKPhysicsBody(
rectangleOfSize: car.frame.size, center: car.position)
Similarly I was doing the same for the second node that I was testing physics collisions for.
Simply removing the 'centre:' parameters like so:
let carBody = SKPhysicsBody(rectangleOfSize: car.frame.size)
for the two sprite nodes solved the problem and the nodes now crash into each other and push themselves aside as expected.
Please Note that contact will not be detected between two static bodies
(node.physicsBody?.isDynamic = false)