How detect collision between a box object and ball - swift

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let location = touch.location(in: self) // locates touches on the screen
let objects = nodes(at: location) // shows all objects were screen was touched
if objects.contains(editLabel) { // checking if appropriate array of objects contains the editLabel
editingMode.toggle()
} else {
if editingMode {
let size = CGSize(width: Int.random(in: 16...128), height: 16)
let box = SKSpriteNode(color: UIColor(red: CGFloat.random(in: 0...1), green: CGFloat.random(in: 0...1), blue: CGFloat.random(in: 0...1), alpha: 1), size: size)
box.zRotation = CGFloat.random(in: 0...3)
box.position = location // add the box ob ject were the user taps
box.name = "box"
box.physicsBody = SKPhysicsBody(rectangleOf: box.size)
box.physicsBody!.contactTestBitMask = box.physicsBody!.collisionBitMask
box.physicsBody?.isDynamic = false // box object will not move when impact happens
addChild(box) // box object will be added to the screen
} else if usedBalls != 0 {
let ball = SKSpriteNode(imageNamed: allBalls.randomElement() ?? "ballRed.png") // pulls out the red ball from app bundle
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width / 2.0) // animates the ball object
ball.physicsBody!.contactTestBitMask = ball.physicsBody!.collisionBitMask
ball.physicsBody?.restitution = 0.4 // determines the ball object bounciness
ball.position = location // ball will appear where the user tapped on the screen
ball.name = "ball"
// ball.position = CGPoint (x: 550, y: 700)
addChild (ball) // adds the ball object to the screen
usedBalls -= 1
}
}
}
func makeBouncer(at position: CGPoint) {
let bouncer = SKSpriteNode(imageNamed: "bouncer.png")
bouncer.position = position
bouncer.physicsBody = SKPhysicsBody(circleOfRadius: bouncer.size.width / 2.0)
bouncer.physicsBody?.isDynamic = false // bouncer object is fixed to the bottom of the screen
addChild(bouncer)
}
func makeSlot(at position: CGPoint, isGood: Bool) {
var slotBase: SKSpriteNode
var slotGlow: SKSpriteNode
if isGood {
slotBase = SKSpriteNode(imageNamed: "slotBaseGood.png")
slotGlow = SKSpriteNode(imageNamed: "slotGlowGood.png")
slotBase.name = "good"
} else {
slotBase = SKSpriteNode(imageNamed: "slotBaseBad.png")
slotGlow = SKSpriteNode(imageNamed: "slotGlowBad.png")
slotBase.name = "bad"
}
slotBase.position = position
slotGlow.position = position
slotBase.physicsBody = SKPhysicsBody(rectangleOf: slotBase.size)
slotBase.physicsBody?.isDynamic = false
addChild(slotBase)
addChild(slotGlow)
let spin = SKAction.rotate(byAngle: .pi, duration: 10)
let spinForever = SKAction.repeatForever(spin)
slotGlow.run(spinForever)
}
func collisionBetween(ball: SKNode, object: SKNode) {
if object.name == "good" { // green slot
destroy(ball: ball)
score += 1
usedBalls += 1
} else if object.name == "bad" { // red slot
destroy(ball: ball) // the ball will be removed once drops into a green or red slot
score -= 1
}
}
func boxandballCollision(box: SKNode, ball: SKNode) {
if ball.name == "ball" {
destroyObject(box: box)
}
}
func destroyObject(box: SKNode) {
if let fireParticles = SKEmitterNode(fileNamed: "FireParticles") {
fireParticles.position = box.position
addChild(fireParticles)
}
box.removeFromParent() // box should be removed when a ball will hit it
}
func destroy(ball: SKNode) {
if let fireParticles = SKEmitterNode(fileNamed: "FireParticles") {
fireParticles.position = ball.position
addChild(fireParticles)
}
ball.removeFromParent() // ball object is removed from scene when hits a slot
}
func didBegin(_ contact: SKPhysicsContact) {
guard let nodeA = contact.bodyA.node else { return }
guard let nodeB = contact.bodyB.node else { return }
if nodeA.name == "ball" {
collisionBetween(ball: nodeA, object: nodeB)
} else if nodeB.name == "ball" {
collisionBetween(ball: nodeB, object: nodeA)
}
}
func begin(_ contact: SKPhysicsContact) {
guard let nodeA = contact.bodyA.node else { return }
guard let nodeB = contact.bodyB.node else { return }
if nodeA.name == "box" {
boxandballCollision(box: nodeA, ball: nodeB)
} else if nodeB.name == "box" {
boxandballCollision(box: nodeB, ball: nodeA)
}
}
I want to remove any box object when a ball will hit it, is just a simple game for studying purposes, but I'm struggling with it. I have used exactly same methods for the box object and this to get notifications about every collision " box.physicsBody!.contactTestBitMask = box.physicsBody!.collisionBitMask".

Related

sprite kit collision not working

This is a game I have been working on. In summary there is a moving block named enemy and I want it to collide with an invisible static block called invisibleGround2. I have it printing hit when they supposedly collide but they are not colliding. Ive read every swift collision documentation by apply and others out there and I dont know whats wrong. Any help would be much appreciated!
import SpriteKit
import GameplayKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var orb = SKSpriteNode(imageNamed: "orb")
var scrollingG:scrollingGround?
var invisibleGround = SKSpriteNode(imageNamed: "invisible")
var invisibleGround2 = SKSpriteNode(imageNamed: "invisible")
let enemies = [SKSpriteNode(imageNamed: "blueE.png"), SKSpriteNode(imageNamed: "redE.png")]
let enemyCategory : UInt32 = 1
let jumperCategory : UInt32 = 1
let rotateDuration = 2
let enemyMoveSpeed = 5
let groundScrollingSpeed = 5
func createOrb(){
let orbConst = frame.size.width/2
let xConstraint = SKConstraint.positionX(SKRange(constantValue: orbConst))
orb.position = CGPoint(x: frame.size.width/2, y: 480)
orb.physicsBody = SKPhysicsBody(texture: orb.texture!, size: orb.texture!.size())
orb.constraints = [xConstraint]
self.addChild(orb)
}
func createScrollingGround () {
scrollingG = scrollingGround.scrollingNodeWithImage(imageName: "ground", containerWidth: self.size.width)
scrollingG?.scrollingSpeed = CGFloat(groundScrollingSpeed)
scrollingG?.anchorPoint = .zero
self.addChild(scrollingG!)
}
func createGround(){
invisibleGround2.size.width = 1
invisibleGround2.size.height = 1
invisibleGround2.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width:1, height: 100))
invisibleGround2.physicsBody?.isDynamic = false
invisibleGround2.position = CGPoint(x: 530, y: 191)
invisibleGround2.physicsBody?.categoryBitMask = jumperCategory
invisibleGround2.physicsBody?.collisionBitMask = enemyCategory
invisibleGround2.physicsBody?.contactTestBitMask = enemyCategory
invisibleGround2.name = "jumper"
invisibleGround.position = CGPoint(x: 0, y: 190)
invisibleGround.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: self.size.width * 3, height: 10))
invisibleGround.physicsBody?.isDynamic = false
self.addChild(invisibleGround2)
self.addChild(invisibleGround)
}
func getRandomEnemy(fromArray array:[SKSpriteNode])->SKSpriteNode{
return array[Int(arc4random_uniform(UInt32(array.count)))]
}
func spawnEnemy() {
if let enemy = getRandomEnemy(fromArray: enemies).copy() as? SKSpriteNode {
enemy.position = CGPoint(x: frame.size.width + frame.size.width/3, y: 440)
enemy.physicsBody = SKPhysicsBody(texture: enemy.texture!, size: enemy.texture!.size())
if enemy.size.width < 95 {
enemy.physicsBody?.categoryBitMask = enemyCategory
enemy.physicsBody?.collisionBitMask = jumperCategory
enemy.physicsBody?.contactTestBitMask = jumperCategory
}
enemy.name = "enemy"
self.addChild(enemy)
let moveLeft = SKAction.moveBy(x: -1500, y: 0, duration: TimeInterval(enemyMoveSpeed))
enemy.run(moveLeft)
}
}
func addEnemies () {
self.run(SKAction.repeatForever(SKAction.sequence([SKAction.run {
self.spawnEnemy()
}, SKAction.wait(forDuration: 4)])))
}
func jump() {
orb.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 335))
}
func rotate() {
let rotate = SKAction.rotate(byAngle: CGFloat(M_PI * -2.55), duration: TimeInterval(rotateDuration))
let repeatAction = SKAction.repeatForever(rotate)
orb.run(repeatAction)
}
override func didMove(to view: SKView) {
createScrollingGround()
createOrb()
createGround()
rotate()
addEnemies()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
jump()
}
override func update(_ currentTime: TimeInterval) {
if self.scrollingG != nil {
scrollingG?.update(currentTime: currentTime)
func didBegin(_ contact: SKPhysicsContact) {
let bodyA = contact.bodyA.categoryBitMask
let bodyB = contact.bodyB.categoryBitMask
if bodyA == jumperCategory && bodyB == enemyCategory {
print("hit")
} else if bodyA == enemyCategory && bodyB == jumperCategory {
print("hit 2")
}
}
}
}
}
Not an swer, but some things to check:
Have you set the scene’s physicsworld delegate property set to
self?
Move didBegin outside of update
Is the 'enemy' sprite's width < 95?
Add a print("Contact detected") as the first line of your relocated didBegin so you at least know that some contact has been detected.
See my answer here https://stackoverflow.com/a/43605825/1430420 for a simple SK collision demo which might help - I think it needs updates to Swift 4 which I'll try and do.

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

How to make shape not to go to GameOver? -SpriteKit

I am creating a game where there is a square shape and every time the player taps on the square, it goes to GameOver scene. All I want to do is when the square shape is tapped, it will be allotted different position of the screen to be tapped on the squares.
Here is my code:
let touch:UITouch = touches.first!
let positionInScene = touch.location(in: self)
let touchedNode = self.atPoint(positionInScene)
if let name = touchedNode.name
{
//The first ball that shows up
if name == "startball"
{
print("Touched", terminator: "")
addBall(ballSize)
self.addChild(score)
}
else if name == "shape"{
scoreCount += 1
addBall(ballSize)
audioPlayer.play()
}
}
else {
let scene = GameOver(size: self.size)
scene.setMyScore(0)
let skView = self.view! as SKView
skView.ignoresSiblingOrder = true
scene.scaleMode = .resizeFill
scene.size = skView.bounds.size
scene.setMessage("You Lost!")
scene.setEndGameMode(va)
gameTimer.invalidate()
shownTimer.invalidate()
print(" timers invalidated ", terminator: "")
ran = true
skView.presentScene(scene, transition: SKTransition.crossFade(withDuration: 0.25))
}
if firstTouch {
shownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(GameScene.decTimer), userInfo: nil, repeats: true)
gameTimer = Timer.scheduledTimer(timeInterval: TIME_INCREMENT, target:self, selector: Selector("endGame"), userInfo: nil, repeats: false)
firstTouch = false
}
if touchCount > 5 {
for touch: AnyObject in touches {
let skView = self.view! as SKView
skView.ignoresSiblingOrder = true
var scene: Congratz!
scene = Congratz(size: skView.bounds.size)
scene.scaleMode = .aspectFill
skView.presentScene(scene, transition: SKTransition.doorsOpenHorizontal(withDuration: 1.0))
}
}
touchCount += 1
}
override func update(_ currentTime: TimeInterval) {
super.update(currentTime)
}
func endGame(){
shownTimer.invalidate()
gameTimer.invalidate()
let scene = GameOver(size: self.size)
scene.setMyScore(scoreCount)
if let skView = self.view {
skView.ignoresSiblingOrder = false
scene.scaleMode = .resizeFill
scene.size = skView.bounds.size
scene.setMessage("Times up")
skView.presentScene(scene, transition: SKTransition.crossFade(withDuration: 0.25))
}
}
override func addBall(_ size: Int) {
// Add the ball
let currentBall = SKShapeNode(circleOfRadius: CGFloat(size))
let viewMidX = view!.bounds.midX
let viewMidY = view!.bounds.midY
currentBall.fillColor = pickColor()
currentBall.position = randomBallPosition()
if scoreCount != 0{
if scoreCount == 1{
self.addChild(score)
self.addChild(timeLeftLabel)
self.childNode(withName: "welcome")?.removeFromParent()
}
self.childNode(withName: "ball")?.run(getSmaller)
self.childNode(withName: "ball")?.removeFromParent()
}
currentBall.name = "ball"
self.addChild(currentBall)
}
func addSquare(_ size: Int) {
// Add the square
let shape = SKShapeNode(rectOf: CGSize(width:CGFloat(size), height:CGFloat(size)))
shape.path = UIBezierPath(roundedRect: CGRect(x: 64, y: 64, width: 160, height: 160), cornerRadius: 50).cgPath
shape.fillColor = pickColor()
shape.position = randomBallPosition()
shape.name = "shape"
self.addChild(shape)
}
func randomBallPosition() -> CGPoint {
let xPosition = CGFloat(arc4random_uniform(UInt32((view?.bounds.maxX)! + 1)))
let yPosition = CGFloat(arc4random_uniform(UInt32((view?.bounds.maxY)! + 1)))
return CGPoint(x: xPosition, y: yPosition)
}
What I would suggest would be to make something like an enum for the different shapes, so you can keep track of what shape you're using.
enum GameShape: Int {
case circle = 0
case square = 1
}
Then create a GameShape property at the top of your GameScene:
var currentShape: GameShape = .circle
Then you could create some sort of updateShape method, which you could call in your touchesBegan method instead of just addBall
func updateShape(shapeSize: CGSize) {
switch currentShape {
case .circle:
addCircle(shapeSize)
case .square:
addSquare(shapeSize)
default:
break
}
// However you want to setup the condition for changing shape
if (condition) {
currentShape = .square
}
}
func addBall(_ size: CGSize) {
// Add the ball
}
func addSquare(_ size: CGSize) {
// Add the square
}
Now in your touchesBegan method, instead of calling addBall(size, you could call updateShape:
override func touchesBegan(_ touches: Set<UITouch>!, with event: UIEvent?) {
// Setup your code for detecting position for shape origin
updateShape(shapeSize)
}
EDIT - Your code is a mess. You really should take the time to make sure it's properly formatted when you submit it, otherwise it's really hard to help you. Indentation helps to see where a closure begins and ends. From what I can tell, it looks like you have two or more functions nested within your addBall method. This is not good. I tried my best to clean it up for you. You'll still need to write the code to make the shape a square, but I've lead you in the right direction to start to make that happen:
func addBall(_ size: CGSize) {
// Add the ball
let currentBall = SKShapeNode(circleOfRadius: CGFloat(size))
let viewMidX = view!.bounds.midX
let viewMidY = view!.bounds.midY
currentBall.fillColor = pickColor()
shape.path = UIBezierPath(roundedRect: CGRect(x: 64, y: 64, width: 160, height: 160), cornerRadius: 50).cgPath
shape.fillColor = pickColor()
currentBall.position = randomBallPosition()
shape.position = randomBallPosition()
self.addChild(shape)
if scoreCount != 0{
if scoreCount == 1{
self.addChild(score)
self.addChild(timeLeftLabel)
self.childNode(withName: "welcome")?.removeFromParent()
}
self.childNode(withName: "ball")?.run(getSmaller)
self.childNode(withName: "ball")?.removeFromParent()
}
currentBall.name = "ball"
shape.name = "ball"
self.addChild(currentBall)
}
func addSquare(_ size: CGSize) {
// Add the square
}
func randomBallPosition() -> CGPoint {
let xPosition = CGFloat(arc4random_uniform(UInt32((view?.bounds.maxX)! + 1)))
let yPosition = CGFloat(arc4random_uniform(UInt32((view?.bounds.maxY)! + 1)))
return CGPoint(x: xPosition, y: yPosition)
}
Now the above code assumes you have some property named shape because from what I could tell you never explicitly instantiated that, but you begin manipulating it.

My nodes are not colliding, am I missing something in my code?

I followed many different tutorials on collision and created my own game where i want to declare a collision between a coin and a player. However, after implementing the collision code my two nodes are not responding to the collision...can someone help me out please?
import SpriteKit
import GameplayKit
// Collision categories
enum ColliderType: UInt32 {
case playerCase = 1
case coinCase = 2
case borderCase = 3
}
class GameScene: SKScene, SKPhysicsContactDelegate {
let player = SKSpriteNode(imageNamed:"block")
let buttonDirLeft = SKSpriteNode(imageNamed: "left")
let buttonDirRight = SKSpriteNode(imageNamed: "right")
let coins = SKSpriteNode(imageNamed: "coins")
let background = SKSpriteNode(imageNamed: "background")
var pressedButtons = [SKSpriteNode]()
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
//score label
let points = SKLabelNode(text: "0")
points.position = CGPoint(x: 530, y: 260)
points.zPosition = 6
points.fontColor = UIColor.black
points.fontSize = 50
addChild(points)
//Set Background
background.zPosition = 1
background.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
background.size.width = 580
background.size.height = 320
addChild(background)
// Player
player.position = CGPoint(x: 250, y: 40)
player.zPosition = 2
player.texture?.filteringMode = .nearest
// player!.collisionBitMask = 0 //
player.physicsBody = SKPhysicsBody(circleOfRadius: player.size.height / 2.0)
player.physicsBody?.isDynamic = false
player.physicsBody?.allowsRotation = false
player.physicsBody?.affectedByGravity = false
player.physicsBody!.categoryBitMask = ColliderType.playerCase.rawValue
player.physicsBody!.contactTestBitMask = ColliderType.coinCase.rawValue
player.physicsBody!.collisionBitMask = ColliderType.coinCase.rawValue
self.addChild(player)
// button left
buttonDirLeft.position = CGPoint(x: 30, y: 35)
buttonDirLeft.zPosition = 4
buttonDirLeft.size.width = 270
buttonDirLeft.size.height = 320
buttonDirLeft.alpha = 0.0
self.addChild(buttonDirLeft)
// button right
buttonDirRight.position = CGPoint(x: 530, y: 35)
buttonDirRight.zPosition = 4
buttonDirRight.size.width = 270
buttonDirRight.size.height = 320
buttonDirRight.alpha = 0.0
self.addChild(buttonDirRight)
// setting border around game
let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
//ENEMY SETTINGS START
//repeat coing spawning
run(SKAction.repeatForever(
SKAction.sequence([
SKAction.run(spawnCoins),
SKAction.wait(forDuration: 1.0)])))
}
//coin settings
func random() -> CGFloat {
return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
}
func random(min: CGFloat, max: CGFloat) -> CGFloat {
return random() * (max - min) + min
}
//spawn coins
func spawnCoins() {
// 2
let coins = SKSpriteNode(imageNamed: "coins")
coins.zPosition = 2
coins.size.width = 40
coins.size.height = 40
let action = SKAction.moveTo(y: -350, duration: TimeInterval(random(min: 1, max: 5)))
let remove = SKAction.run({coins.removeFromParent(); print("coins removed from scene")})
let sequence = SKAction.sequence([action,remove])
coins.physicsBody = SKPhysicsBody(rectangleOf: coins.size )
coins.physicsBody?.isDynamic = false
coins.physicsBody!.affectedByGravity = false
coins.physicsBody!.categoryBitMask = ColliderType.coinCase.rawValue
coins.physicsBody!.contactTestBitMask = ColliderType.playerCase.rawValue
coins.physicsBody!.collisionBitMask = ColliderType.playerCase.rawValue
coins.run(sequence)
coins.size.width = 20
coins.size.height = 20
coins.name = "coins"
// coins.physicsBody!.collisionBitMask = 0
coins.position = CGPoint(x: frame.size.width * random(min: 0, max: 1), y: frame.size.height + coins.size.height/2)
addChild(coins)
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
/* Called before each frame is rendered */
if pressedButtons.index(of: buttonDirLeft) != nil {
player.position.x -= 3.0
}
if pressedButtons.index(of: buttonDirRight) != nil {
player.position.x += 3.0
}
// Update entities
}
//MOVEMENT FUNCTIONS START HERE
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
for button in [buttonDirLeft, buttonDirRight] {
// I check if they are already registered in the list
if button.contains(location) && pressedButtons.index(of: button) == nil {
pressedButtons.append(button)
}
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
for button in [buttonDirLeft, buttonDirRight] {
// if I get off the button where my finger was before
if button.contains(previousLocation)
&& !button.contains(location) {
// I remove it from the list
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
// if I get on the button where I wasn't previously
else if !button.contains(previousLocation)
&& button.contains(location)
&& pressedButtons.index(of: button) == nil {
// I add it to the list
pressedButtons.append(button)
}}}}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
for button in [buttonDirLeft, buttonDirRight] {
if button.contains(location) {
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
else if (button.contains(previousLocation)) {
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
}
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
for button in [buttonDirLeft, buttonDirRight] {
if button.contains(location) {
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
else if (button.contains(previousLocation)) {
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
}
}
}
func didBeginContact(contact: SKPhysicsContact){
print("colliding!")
}
Contact will happen only if at least one body is dynamic. So either set your player or coin to be dynamic and if everything else is set correctly (if categories are set properly and didBeginContact method implementation is correct) your bodies will now collide / make contacts. If you are interested only in contacts, set collision bit mask to 0.

touchesBegin not being called on Sprit Node

I have SpritNodes that are in my scene and I want a method to be called when I touch it. I have isUserInteractionEnabled set to true for my node, but touchesBegan still does not get called when I touch the nodes. (Note: I am using Swift 3.0)
Code:
import SpriteKit
class MainScene: SKScene, SKPhysicsContactDelegate {
var didStart = false
var background = SKSpriteNode(imageNamed: "background")
var backDrop = SKShapeNode()
var emailNodes: [SKSpriteNode] = []
let emailCatagory: UInt32 = 0x1 << 0
let dropCatagory: UInt32 = 0x1 << 1
override func sceneDidLoad() {
startCountDown()
}
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
background.position = CGPoint(x: frame.midX, y:frame.midY)
}
public func startCountDown(){
var times = 4
let countdownTimer = SKLabelNode()
countdownTimer.text = "3"
countdownTimer.position = CGPoint(x: frame.midX, y: frame.midY)
countdownTimer.fontSize = 120.0
countdownTimer.fontName = "Lao MN"
countdownTimer.fontColor = UIColor.black()
backDrop = SKShapeNode()
backDrop = SKShapeNode(rectOf: CGSize(width: frame.width, height: 100))
backDrop.position = CGPoint(x: frame.midX, y: 10)
backDrop.physicsBody = SKPhysicsBody(rectangleOf: backDrop.frame.size)
//backDrop.size = CGSize(width: 1000, height: 2)
backDrop.physicsBody?.affectedByGravity = false
backDrop.physicsBody?.usesPreciseCollisionDetection = true
backDrop.name = "backDrop"
backDrop.physicsBody?.collisionBitMask = 0
backDrop.physicsBody?.categoryBitMask = dropCatagory
addChild(countdownTimer)
addChild(backDrop)
//addChild(background)
Timer.every(1.2.seconds) { (timer: Timer) in
if(times<=0){
timer.invalidate()
countdownTimer.removeFromParent()
self.didStart = true
self.startDropping()
}else{
print("\(times)")
times = times - 1
countdownTimer.text = "\(times)"
}
}
}
func startDropping(){
Timer.every(1.2.seconds) { (timer: Timer) in
let which = Int(arc4random_uniform(2) + 1)
let ee = self.getEmailNode(type: which)
self.addChild(ee)
ee.physicsBody?.applyImpulse(CGVector(dx: 0.0, dy: -5.0))
}
}
func getEmailNode(type: Int) -> SKSpriteNode{
var email = SKSpriteNode()
if(type == 1){
email = SKSpriteNode(imageNamed: "normal_email")
email.name = "normal_email"
}
if(type == 2){
email = SKSpriteNode(imageNamed: "classified_email")
email.name = "classified_email"
}
email.setScale(3)
email.position = CGPoint(x: getRandomColumn(), y: frame.height)
email.physicsBody = SKPhysicsBody(rectangleOf: email.frame.size)
email.physicsBody?.usesPreciseCollisionDetection = true
email.physicsBody?.categoryBitMask = emailCatagory
email.isUserInteractionEnabled = true
email.physicsBody?.affectedByGravity = false
email.physicsBody?.collisionBitMask = 0
email.physicsBody?.contactTestBitMask = emailCatagory | dropCatagory
emailNodes.append(email)
return email
}
func getRandomColumn() -> CGFloat{
let which = Int(arc4random_uniform(3) + 1)
let gg = frame.size.width/3
switch(which){
case 1:
return gg / 2
case 2:
return frame.midX
case 3:
return (gg * 3) - gg / 2
default:
return (gg * 3) + gg / 2
}
}
func didBegin(_ contact: SKPhysicsContact) {
if (contact.bodyA.categoryBitMask == dropCatagory) &&
(contact.bodyB.categoryBitMask == emailCatagory) {
let node = contact.bodyB.node as! SKSpriteNode
node.removeFromParent()
while emailNodes.contains(node) {
if let itemToRemoveIndex = emailNodes.index(of: node) {
emailNodes.remove(at: itemToRemoveIndex)
}
}
}
}
func doesContainNode(sk: SKSpriteNode) -> Bool {
for it in emailNodes{
if(it == sk){
return true
}
}
return false
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
enumerateChildNodes(withName: "//*", using:
{ (node, stop) -> Void in
print("\(node.name)")
print("\(node)")
if((node.name?.contains("email")) != nil){
print("Touched!")
}
})
}
}
You should try the following in order to be able to get the user's position and know when the sprite has been touched. Add the following inside the touchesEnabled function.
for touch in touches {
let userTouch = touch.locationInNode(self)
}
And then check if the sprite was touched by using:
node.containsPoint(userTouch)
See if that works. The way you have your code setup, you might need to nest the above function right after checking if it's nil. As for the userInteractionEnabled, I don't use it at all when using the above code.
You do not want userInteractionEnabled set on any of your nodes, you want that only on the scene. Use userInteractionEnabled only when you are subclassing your node, this way you can use touchesBegan inside your subclassed file. What is happening is your touch is going into your node and being absorbed, which does nothing, and is being ignored by the scene since the node absorbed it.
Edit: Sorry #MarkBrownsword I did not see your comment, if you post it as an answer, I will upvote and delete my answer.
I found a solution. I removed isUserInteractionEnabled and touchesBegan was still not being called. So I went through each of the properties of the "email" node and for some reason the following properties made it where touchesBegan would not be called.
email.physicsBody?.affectedByGravity = false
email.physicsBody?.collisionBitMask = 0
So I removed those and now touchesBegan is being properly called.