Swift 2 PhysicsBody not working - swift2

i have a code where i two spaceships floating around the screen however they can't break through the top of the screen and the motto. however they can fly through i sides. i've look at endless about of sites and done some many different types of skphysicsbodys but none of them help.
code example.
class GameScene: SKScene, SKPhysicsContactDelegate {
var player = SKSpriteNode(imageNamed: "spaceship.png")
var player2 = SKSpriteNode(imageNamed: "spaceship.png")
var timer = NSTimer()
var tapsValid:Bool?
var playerRight:Bool?
var playerChange:Bool?
override func didMoveToView(view: SKView) {
let sceneBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
sceneBody.friction = 0
self.physicsBody = sceneBody
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
tapsValid = true
playerRight = true
self.scene?.backgroundColor = UIColor.whiteColor()
player.position = CGPointMake(self.size.width / 2, self.size.height / 1.8 + 280)
player.physicsBody = SKPhysicsBody(rectangleOfSize: player.size)
player.physicsBody?.dynamic = false
player.physicsBody?.affectedByGravity = false
player.physicsBody?.restitution = 1
player.physicsBody?.friction = 0
player.physicsBody?.linearDamping = 0
player.physicsBody?.angularDamping = 0
player2.position = CGPointMake(self.size.width / 2, self.size.height / 14)
player2.physicsBody = SKPhysicsBody(rectangleOfSize: player2.size)
player2.physicsBody?.affectedByGravity = false
player2.physicsBody?.dynamic = false
player2.physicsBody?.restitution = 1
player2.physicsBody?.friction = 0
player.physicsBody?.linearDamping = 0
player.physicsBody?.angularDamping = 0
self.addChild(player)
self.addChild(player2)
can anyone help me out here. i just want to add physics to the edges of the screen. Thanks,

You should define your colliderTypes and categories for your nodes. That way you can check to see what hits what
enum ColliderType: UInt32 {
case Spaceship = 0
case CornerCategory = 1
}
self.physicsBody!.categoryBitMask = ColliderType.CornerCategory.rawValue
player.physicsBody?.contactTestBitMask = ColliderType.CornerCategory.rawValue
player2.physicsBody?.contactTestBitMask = ColliderType.CornerCategory.rawValue
func didBeginContact(contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
//If it is true. Means that bodyA is the spaceship. Because it's 0
firstBody = contact.bodyA
secondBody = contact.bodyB
}else{
//Either way. firstBody will always be the spaceship
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if firstBody.categoryBitMask == ColliderType. Spaceship.rawValue && secondBody.categoryBitMask == ColliderType.CornerCategory.rawValue{
//means that Spaceship and wall touches
print("Spaceship hits wall")
}
}

Related

Detect collision between the player and an object with Sprite kit

I am making a game with sprite kit in xcode and i want let the game finish when the player touch the monster, do you know how to use categorymask?
here is part of the code :
import SpriteKit
import GameplayKit
import CoreMotion
class GameScene: SKScene, SKPhysicsContactDelegate {
var player : SKSpriteNode!
var playerCategory : UInt32 = 0x1 << 0
var gameTimer2 : Timer!
var possiblealien = ["alien", "alien2", "alien3"]
let alienCategory : UInt32 = 0x1 << 1
override func didMove(to view: SKView) {
player = SKSpriteNode (imageNamed: "player")
player.position = CGPoint (x: self.frame.size.width / 2 - 500 , y:
player.size.height / 2 - 560)
player.size = CGSize(width: player.size.width * 6 ,
height: player.size.height * 6)
self.addChild(player)
player.zPosition = 2
self.physicsWorld.gravity = CGVector (dx: 0 , dy: 0 )
self.physicsWorld.contactDelegate = self
player.physicsBody?.contactTestBitMask = playerCategory
player.physicsBody? = SKPhysicsBody(rectangleOf: player.size)
player.physicsBody?.isDynamic = true
player.physicsBody?.categoryBitMask = monsterCategory
player.physicsBody?.collisionBitMask = 0
gameTimer2 = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(addalien), userInfo: nil, repeats: true)
motionManager.accelerometerUpdateInterval = 0.2
motionManager.startAccelerometerUpdates(to: OperationQueue.current!) { ( data: CMAccelerometerData?, error:Error?)in
if let accelerometerData = data {
let acceleration = accelerometerData.acceleration
self.xAcceleration = CGFloat(acceleration.x) * 0.65 + self.xAcceleration * 0.25
}
}
#objc func addalien () {
possiblealien = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: possiblealien) as! [String]
let alien = SKSpriteNode(imageNamed: possiblealien[0])
let randomalienposition = GKRandomDistribution(lowestValue: -480, highestValue: +800 )
let position = CGFloat(randomalienposition.nextInt())
alien.position = CGPoint (x: position - 200 , y: self.frame.size.height * 0.5 + alien.size.height)
alien.physicsBody = SKPhysicsBody(rectangleOf: alien.size)
alien.physicsBody?.isDynamic = true
alien.physicsBody?.categoryBitMask = alienCategory
alien.physicsBody?.contactTestBitMask = playerCategory
alien.physicsBody?.collisionBitMask = 0
alien.zPosition = 2
alien.size = CGSize(width: alien.size.width * 1 ,
height: alien.size.height * 1)
self.addChild(alien)
let animationduration:TimeInterval = 6
var actionArray = [SKAction]()
actionArray.append(SKAction.move(to: CGPoint(x: position, y: -1000 ),duration: animationduration))
actionArray.append(SKAction.removeFromParent())
alien.run(SKAction.sequence(actionArray))
}
I see your problem, you need to declare it's physics body in a Physics Category, Otherwise, there would be no body for it at all
struct PhysicsCategory {
static let None:UInt32 = 0
static let All:UInt32 = UInt32.max
static let Player:UInt32 = 0b1
Also, The contactbitmasks should be what they will collide with along with collisiontestbitmask. catergorybitmask should be the category of the sprite in the struct
ex:
let alien = SKSpritenode()
alien.physicsBody?.categoryBitMask = PhysicsCategory.Alien
alien.physicsBody?.contactBitMask = PhysicsCategory.Player
alien.physicsBody?.collisionTestBitMask = PhysicsCategory.Player
Also, you can use | to declare if they will collide with multiple things

Collision detection in Xcode(swift) won't work, I am trying to set up boundaries in which the player cannot cross

I have the SKContactDelegate setup
class GameScene: SKScene, SKPhysicsContactDelegate
{
override func didMoveToView(view: SKView)
{
self.physicsWorld.contactDelegate = self
Here I setup the enum
enum ColliderType:UInt32
{
case Player = 1
case Boundary = 2
}
Here I make the player node.
let playerTexture = SKTexture(imageNamed: "testCircle1.png")
thePlayer = SKSpriteNode(texture: playerTexture)
thePlayer.position = CGPointMake(frame.size.width - 350, frame.size.height/2)
thePlayer.zPosition = 5
thePlayer.size = CGSize(width: 100, height: 100)
thePlayer.name = "playerNode"
thePlayer.physicsBody = SKPhysicsBody(circleOfRadius: playerTexture.size().height/2)
thePlayer.physicsBody!.dynamic = false
thePlayer.physicsBody!.allowsRotation = false
thePlayer.physicsBody!.categoryBitMask = ColliderType.Player.rawValue
thePlayer.physicsBody!.contactTestBitMask = ColliderType.Boundary.rawValue
thePlayer.physicsBody!.collisionBitMask = ColliderType.Boundary.rawValue
addChild(thePlayer)
Then I setup the Boundaries
ground = SKSpriteNode(color: UIColor.redColor(), size: CGSizeMake(frame.size.width - 150, 10))
ground.position = CGPointMake(frame.size.width/2 - 75, 96)
ground.zPosition = 5
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(ground.size.width, ground.size.height))
ground.physicsBody!.dynamic = false
ground.physicsBody!.allowsRotation = false
ground.physicsBody!.categoryBitMask = ColliderType.Boundary.rawValue
ground.physicsBody!.contactTestBitMask = ColliderType.Player.rawValue
ground.physicsBody!.collisionBitMask = ColliderType.Player.rawValue
addChild(ground)
sky = SKSpriteNode(color: UIColor.redColor(), size: CGSizeMake(frame.size.width - 150, 10))
sky.position = CGPointMake(frame.size.width/2 - 75, frame.size.height - 96)
sky.zPosition = 5
sky.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(frame.size.width - 150, 10))
sky.physicsBody!.dynamic = false
sky.physicsBody!.allowsRotation = false
sky.physicsBody!.categoryBitMask = ColliderType.Boundary.rawValue
sky.physicsBody!.contactTestBitMask = ColliderType.Player.rawValue
sky.physicsBody!.collisionBitMask = ColliderType.Player.rawValue
addChild(sky)
Then the collision detection
func didBeginContact(contact: SKPhysicsContact)
{
print("Contact")
if contact.bodyA.categoryBitMask == ColliderType.Boundary.rawValue || contact.bodyB.categoryBitMask == ColliderType.Boundary.rawValue
{
print("Contact")
thePlayer.removeAllActions()
}
}
I tried putting the print outside of the if statement to see if it was even detecting collision at all, but it wasn't.
I have looked at many tutorials and followed what they did but it just won't work and I only have a couple more weeks to turn this in.
In the player node
remove this:
thePlayer.physicsBody!.dynamic = false
That is setting the physics body to be a boundary and not a body...

Use of unresolved identifier. (doesn't make sense)

I am making a game using Sprite Kit in swift that has objects falling down the screen that need to be caught by the player(Labeled Person) at the bottom. I am trying do remove the falling objects from the screen when they contact the player but I cant call on the falling object (labeled Ice) inside of the function did begin contact. I am able to call on other objects like the person or the score label but not the object falling down the screen (Labeled Ice). Why is this I will post my full code below. This has really been bugging me. (ps. I am given the error "use of unresolved identifier")
import SpriteKit
struct physicsCatagory {
static let person : UInt32 = 0x1 << 1
static let Ice : UInt32 = 0x1 << 2
static let IceTwo : UInt32 = 0x1 << 3
static let IceThree : UInt32 = 0x1 << 4
static let Score : UInt32 = 0x1 << 5
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var scorenumber = Int()
var person = SKSpriteNode(imageNamed: "Person")
let Score = SKSpriteNode()
var ScoreLable = SKLabelNode()
override func didMoveToView(view: SKView) {
self.scene?.backgroundColor = UIColor.purpleColor()
physicsWorld.contactDelegate = self
self.scene?.size = CGSize(width: 640, height: 1136)
Score.size = CGSize(width: 648, height: 1)
Score.position = CGPoint(x: 320, y: -90)
Score.physicsBody = SKPhysicsBody(rectangleOfSize: Score.size)
Score.physicsBody?.affectedByGravity = false
Score.physicsBody?.dynamic = false
Score.physicsBody?.categoryBitMask = physicsCatagory.Score
Score.physicsBody?.collisionBitMask = 0
Score.physicsBody?.contactTestBitMask = physicsCatagory.IceThree
Score.color = SKColor.blueColor()
self.addChild(Score)
person.position = CGPointMake(self.size.width/2, self.size.height/12)
person.setScale(0.4)
person.physicsBody = SKPhysicsBody(rectangleOfSize: person.size)
person.physicsBody?.affectedByGravity = false
person.physicsBody?.categoryBitMask = physicsCatagory.person
person.physicsBody?.contactTestBitMask = physicsCatagory.Ice
person.physicsBody?.collisionBitMask = physicsCatagory.Ice
person.physicsBody?.dynamic = false
ScoreLable.position = CGPoint(x: self.frame.width / 2, y: 1000)
ScoreLable.text = "\(scorenumber)"
ScoreLable.fontColor = UIColor.yellowColor()
ScoreLable.fontSize = 100
ScoreLable.fontName = "Zapfino "
self.addChild(ScoreLable)
var IceThreeTimer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: ("spawnThirdIce"), userInfo: nil, repeats: true)
self.addChild(person)
}
func didBeginContact(contact: SKPhysicsContact) {
let firstBody = contact.bodyA
let secondBody = contact.bodyB
if firstBody.categoryBitMask == physicsCatagory.person && secondBody.categoryBitMask == physicsCatagory.IceThree || firstBody.categoryBitMask == physicsCatagory.IceThree && secondBody.categoryBitMask == physicsCatagory.person{
scorenumber++
ScoreLable.text = "\(scorenumber)"
CollisionWithPerson(firstBody.node as! SKSpriteNode, Person: secondBody.node as! SKSpriteNode)
}
if firstBody.categoryBitMask == physicsCatagory.Score && secondBody.categoryBitMask == physicsCatagory.IceThree ||
firstBody.categoryBitMask == physicsCatagory.IceThree && secondBody.categoryBitMask == physicsCatagory.Score{
self.view?.presentScene(EndScene())
}
}
func CollisionWithPerson (Ice: SKSpriteNode, Person: SKSpriteNode){
Person.removeFromParent()
}
func spawnThirdIce(){
var Ice = SKSpriteNode(imageNamed: "Ice")
Ice.setScale(0.9)
Ice.physicsBody = SKPhysicsBody(rectangleOfSize: Ice.size)
Ice.physicsBody?.categoryBitMask = physicsCatagory.IceThree
Ice.physicsBody?.contactTestBitMask = physicsCatagory.person | physicsCatagory.Score
Ice.physicsBody?.affectedByGravity = false
Ice.physicsBody?.dynamic = true
let MinValue = self.size.width / 8
let MaxValue = self.size.width - 20
let SpawnPoint = UInt32(MaxValue - MinValue)
Ice.position = CGPoint(x: CGFloat(arc4random_uniform(SpawnPoint)), y: self.size.height)
self.addChild(Ice)
let action = SKAction.moveToY(-85, duration: 2.5)
let actionDone = SKAction.removeFromParent()
Ice.runAction(SKAction.sequence([action,actionDone]))
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
person.position.x = location.x
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
person.position.x = location.x
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}

physicsBody collision with another physicsBody

Okay, so I have a really specific problem and I hope I can help you. I will attach an image to clarify what I'm talking about.
redball.physicsBody is spawning above boss.physicsBody - falling (through) the boss. Colliding with whitebar.physicsBody - bouncing back up and once again colliding with boss.physicsBody. THIS time, i want to fire an event that notices when the ball is bouncing back up and hitting the boss.
Currently. Boss & Ball shares the same collisionBitMask, so that they can pass through each other. When the ball collides with the bar, I'm trying to add ball.physicsBody?.contactTestBitMask = PhysicsCategory.boss.rawValue to the ball. So that i can notice the collision on the way back up between ball & boss. However this does not seem to work.
Does anyone have a solution to this weird problem? Super thankful for some help.
Sidenote: If someone can figure out a clever title, let me know and ill edit it!
EDIT: Adding code
enum PhysicsCategory : UInt32 {
case bar = 1
case ball = 2
case boss = 4
case noCollision = 8
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var score = Int()
var background = SKSpriteNode(imageNamed: "background.png")
var bar = SKSpriteNode(imageNamed: "bar.png")
var boss1 = SKSpriteNode(imageNamed: "boss1.png")
override func didMoveToView(view: SKView) {
self.scene?.size = CGSize(width: 640, height:1136)
physicsWorld.contactDelegate = self
background.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2)
background.zPosition = -20
self.addChild(background)
bar.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 8)
bar.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: bar.size.width, height: bar.size.height))
bar.physicsBody?.categoryBitMask = PhysicsCategory.bar.rawValue
bar.physicsBody?.contactTestBitMask = PhysicsCategory.ball.rawValue
bar.physicsBody?.collisionBitMask = PhysicsCategory.bar.rawValue
bar.physicsBody?.affectedByGravity = false
bar.physicsBody?.dynamic = false
self.addChild(bar)
boss1.position = CGPoint(x: self.frame.width, y: self.frame.height - boss1.size.height / 2)
boss1.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: boss1.size.width, height: boss1.size.height))
boss1.physicsBody?.categoryBitMask = PhysicsCategory.boss.rawValue
boss1.physicsBody?.contactTestBitMask = PhysicsCategory.ball.rawValue
boss1.physicsBody?.collisionBitMask = PhysicsCategory.noCollision.rawValue
boss1.physicsBody?.affectedByGravity = false
boss1.physicsBody?.dynamic = false
boss1.zPosition = 5
self.addChild(boss1)
boss1.runAction(SKAction.moveToX(self.frame.width / 2, duration: 1))
let spawnBallsAction = SKAction.sequence([SKAction.waitForDuration(2), SKAction.runBlock(spawnBalls)])
self.runAction(SKAction.repeatActionForever(spawnBallsAction))
}
func didBeginContact(contact: SKPhysicsContact) {
let firstBody : SKPhysicsBody = contact.bodyA
let secondBody : SKPhysicsBody = contact.bodyB
if (firstBody.categoryBitMask & PhysicsCategory.bar.rawValue == PhysicsCategory.bar.rawValue &&
secondBody.categoryBitMask & PhysicsCategory.ball.rawValue == PhysicsCategory.ball.rawValue) {
CollisionWithBar(firstBody.node as! SKSpriteNode, ball: secondBody.node as! SKSpriteNode)
}
if (firstBody.categoryBitMask & PhysicsCategory.ball.rawValue == PhysicsCategory.ball.rawValue &&
secondBody.categoryBitMask & PhysicsCategory.boss.rawValue == PhysicsCategory.boss.rawValue) {
CollisionWithBoss(firstBody.node as! SKSpriteNode, boss: secondBody.node as! SKSpriteNode)
}
}
func CollisionWithBar(bar: SKSpriteNode, ball: SKSpriteNode) {
ball.physicsBody?.applyImpulse(CGVectorMake(0, 500))
ball.physicsBody?.contactTestBitMask = PhysicsCategory.boss.rawValue //Trying to solve the problem, aint working
}
func CollisionWithBoss(ball: SKSpriteNode, boss: SKSpriteNode) {
NSLog("Ball hit the boss")
}
func spawnBalls(){
let ball = SKSpriteNode(imageNamed: "ball.png")
let MinValue = self.frame.width / 8
let MaxValue = self.frame.width - 20
let SpawnPoint = UInt32(MaxValue - MinValue)
ball.position = CGPoint(x: CGFloat(arc4random_uniform(SpawnPoint)), y: self.frame.height - 128)
ball.zPosition = 50
//Physics
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.frame.height / 2)
ball.physicsBody?.categoryBitMask = PhysicsCategory.ball.rawValue
ball.physicsBody?.contactTestBitMask = PhysicsCategory.bar.rawValue
ball.physicsBody?.collisionBitMask = PhysicsCategory.noCollision.rawValue
ball.physicsBody?.affectedByGravity = true
ball.physicsBody?.dynamic = true
self.addChild(ball)
}
This is how contacts should be done:
Upon creating a ball set the contact category to this:(which you have)
ball.physicsBody?.contactTestBitMask = PhysicsCategory.bar.rawValue
Make sure the boss contacts nobody:
boss1.physicsBody?.contactTestBitMask = PhysicsCategory.noCollision.rawValue
Then on Contact, you want to do this:
func didBeginContact(contact: SKPhysicsContact) {
let firstBody : SKPhysicsBody = (contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask) ? contact.bodyA : contact.bodyB
let secondBody : SKPhysicsBody = (contact.bodyA.categoryBitMask >= contact.bodyB.categoryBitMask) ? contact.bodyA : contact.bodyB
if (firstBody.categoryBitMask & PhysicsCategory.bar.rawValue == PhysicsCategory.bar.rawValue &&
secondBody.categoryBitMask & PhysicsCategory.ball.rawValue == PhysicsCategory.ball.rawValue) {
//This should be inside CollisionWithBar
ball.physicsBody?.contactTestBitMask = PhysicsCategory.bar.rawValue | PhysicsCategory.boss.rawValue
//the ball has hit the bar, so lets enable hitting on the boss
//normally we would only want to do this once, but since this is
//tiny, it would be more time to wrap it in ifs and putting guards on it
boss1.physicsBody?.contactTestBitMask = PhysicsCategory.ball.rawValue
CollisionWithBar(firstBody.node as! SKSpriteNode, ball: secondBody.node as! SKSpriteNode)
}
if (firstBody.categoryBitMask & PhysicsCategory.ball.rawValue == PhysicsCategory.ball.rawValue &&
secondBody.categoryBitMask & PhysicsCategory.boss.rawValue == PhysicsCategory.boss.rawValue) {
//This should be inside CollisionWithBoss
ball.physicsBody?.contactTestBitMask = PhysicsCategory.bar.rawValue
CollisionWithBoss(firstBody.node as! SKSpriteNode, boss: secondBody.node as! SKSpriteNode)
}
}
Which basically says, if the ball hits the bar, enable boss hitting, if the ball hits the boss, disable boss hitting
Edit: Upon the realization of having multiple balls, we have to change some things
Make sure the boss contacts ball upon creation again:
boss1.physicsBody?.contactTestBitMask = PhysicsCategory.ball.rawValue
Now we need to create a new category
enum PhysicsCategory : UInt32 {
case bar = 1
case ball = 2
case boss = 4
case noCollision = 8
case initialBall = 16
}
In the beginning, assign the category of ball to this:
ball.physicsBody?.categoryBitMask = initialBall
Then your CollissionWithBar will look like this:
func CollisionWithBar(bar: SKSpriteNode, ball: SKSpriteNode) {
ball.physicsBody?.applyImpulse(CGVectorMake(0, 500))
ball.physicsBody?.contactTestBitMask = PhysicsCategory.bar.rawValue | PhysicsCategory.boss.rawValue
ball.physicsBody?.categoryBitMask = PhysicsCategory.ball.rawValue
}
And your CollissionWithBolls will look like this:
func CollisionWithBoss(ball: SKSpriteNode, boss: SKSpriteNode) {
ball.physicsBody?.contactTestBitMask = PhysicsCategory.bar.rawValue
}
Finally, on Contact, you want to do this:
func didBeginContact(contact: SKPhysicsContact) {
let firstBody : SKPhysicsBody = (contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask) ? contact.bodyA : contact.bodyB
let secondBody : SKPhysicsBody = (contact.bodyA.categoryBitMask >= contact.bodyB.categoryBitMask) ? contact.bodyA : contact.bodyB
if (firstBody.categoryBitMask & PhysicsCategory.bar.rawValue == PhysicsCategory.bar.rawValue &&
secondBody.categoryBitMask & PhysicsCategory.ball.rawValue == PhysicsCategory.ball.rawValue) {
CollisionWithBar(firstBody.node as! SKSpriteNode, ball: secondBody.node as! SKSpriteNode)
}
if (firstBody.categoryBitMask & PhysicsCategory.ball.rawValue == PhysicsCategory.ball.rawValue &&
secondBody.categoryBitMask & PhysicsCategory.boss.rawValue == PhysicsCategory.boss.rawValue) {
CollisionWithBoss(firstBody.node as! SKSpriteNode, boss: secondBody.node as! SKSpriteNode)
}
}

didBeginContact works without contact swift

I'm writing SpriteKit app for Mac OS. I have two objects (projectile and a monster):
let suric = SKSpriteNode(imageNamed: "projectile.png")
suric.position = player.position
suric.physicsBody = SKPhysicsBody(circleOfRadius: self.size.width / 2)
suric.physicsBody?.categoryBitMask = Detection.suric
suric.physicsBody?.collisionBitMask = Detection.no
suric.physicsBody?.contactTestBitMask = Detection.monster
suric.physicsBody?.usesPreciseCollisionDetection = true
suric.physicsBody?.dynamic = true
let offset = location - suric.position
if offset.x < 0 {
return
}
addChild(suric)
let direc = offset.normalized()
let shoot = direc * 1000
let dest = shoot + suric.position
let move = SKAction.moveTo(dest, duration: 2.0)
let stop = SKAction.removeFromParent()
suric.runAction(SKAction.sequence([move, stop]))
Monster code:
let monster = SKSpriteNode(imageNamed: "monster.png")
let y = random(min: monster.size.height / 2, size.height - monster.size.height)
monster.position = CGPoint(x: self.size.width + monster.size.width / 2, y: y)
monster.physicsBody = SKPhysicsBody(rectangleOfSize: monster.size)
monster.physicsBody?.usesPreciseCollisionDetection = true
monster.physicsBody?.categoryBitMask = Detection.monster
monster.physicsBody?.contactTestBitMask = Detection.suric
monster.physicsBody?.collisionBitMask = Detection.no
monster.physicsBody?.dynamic = true
addChild(monster)
let duration = random(min: 2.0, 4.0)
let move = SKAction.moveTo(CGPoint(x: -monster.size.width / 2, y: y), duration: NSTimeInterval(duration))
let done = SKAction.removeFromParent()
monster.runAction(SKAction.sequence([move, done]))
Detection structure:
struct Detection {
static var no : UInt32 = 0
static var all : UInt32 = UInt32.max
static var monster : UInt32 = 0b1
static var suric : UInt32 = 0b10
}
And then I try to check if there was a contact between these 2 objects:
func didBeginContact(contact: SKPhysicsContact) {
var first : SKPhysicsBody
var second : SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
first = contact.bodyA
second = contact.bodyB
}
else {
first = contact.bodyB
second = contact.bodyA
}
if (first.categoryBitMask & Detection.monster != 0) && (second.categoryBitMask & Detection.suric != 0) {
suricHit(first.node as? SKSpriteNode, monster: second.node as? SKSpriteNode)
}
}
It works even if they didn't actually make a contact. E.g., the projectile is near the top of the window, the monster is at the bottom, but this function works.
EDIT:
I added this code to didBeginContact:
let nodeA = (first.node as! SKSpriteNode)
let nodeB = (second.node as! SKSpriteNode)
println("\(nodeA.position)\t\(nodeA.size)")
println("\(nodeB.position)\t\(nodeB.size)")
println((contact.contactPoint))
println()
The example of out:
(510.201293945312, 285.025665283203) (54.0, 80.0)
(532.54345703125, 378.878845214844) (20.0, 20.0)
(852.469543457031, 530.415222167969)
As you can see, the x position of nodes are 510 and 532, but the contact x point is 852. I just have no idea how and why. Does anybody have a solution?
You're missing an extra set of parenthesis in the if statement.
if ((first.categoryBitMask & Detection.monster != 0) && (second.categoryBitMask & Detection.suric != 0)) {
suricHit(first.node as? SKSpriteNode, monster: second.node as? SKSpriteNode)
}
PS I followed this tutorial and put my project on GitHub, check it out!

Resources