0
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return}
        let location = touch.location(in: self)
        lastTouchPosition = location
    
        let bullet = SKSpriteNode(imageNamed: "bullet")
        bullet.name = "bullet"
        bullet.position = player.position
        bullet.physicsBody?.categoryBitMask = CollisionTypes.enemy.rawValue
        bullet.physicsBody?.contactTestBitMask = CollisionTypes.enemy.rawValue
        bullet.physicsBody?.collisionBitMask = CollisionTypes.enemy.rawValue
        
        bullet.size = CGSize(width: 40, height: 30)
        bullet.physicsBody = SKPhysicsBody(circleOfRadius: bullet.size.width / 2)
        addChild(bullet)
    }

I added collision to my bullet with SKPhysicsBody and it shoots and collides with my enemy. However, everytime I touch the screen to shoot, my player gets knocked back, almost like it has recoil. If I do remove SKPhysicsBody from bullet, everything works fine but then my bullet will just go through my enemy.

    player.physicsBody?.categoryBitMask = CollisionTypes.player.rawValue
    player.physicsBody?.contactTestBitMask = CollisionTypes.enemy.rawValue
    player.physicsBody?.collisionBitMask = CollisionTypes.enemy.rawValue
    player.physicsBody?.collisionBitMask &= ~CollisionTypes.bullet.rawValue 

     playerNode.physicsBody?.restitution = -1.0
     playerNode.physicsBody?.friction = 0.0
     playerNode.physicsBody?.angularDamping = 0.0
     playerNode.physicsBody?.linearDamping = 0.5
nathandr
  • 27
  • 3
  • It depends on how you assign a physics category to each character. – El Tomato Oct 05 '21 at 20:29
  • You need to show the code for the physicsbody for the player as well as your `didBegin(contact:)`. From what you're saying, it seems as though the player is colliding with the bullet. – Steve Ives Oct 06 '21 at 07:47

1 Answers1

1

You need to show the code for the physicsbody for the player as well as your didBegin(contact:). From what you're saying, it seems as though the player is colliding with the bullet, which it will do unless you take specific action to prevent it.

The bullet is created with the player's position so they are trying to occupy the same space. If you haven't switched off collisions between the player and the bullet then the player will collide with the bullet and be 'pushed' away - 'knocked back' as you put it. The bullet is unaffected because you have set the bullet's collisionBitMask to only be the enemy.

To switch off collision between the player and the bullet without affecting anything else the player might collide it, you can use:

player.physicsBody?.collisionBitMask &= ~CollisionTypes.bullet.rawValue  

Edit: (You're right - didBegin not necessary for collisions)

You have an issue I think in defining the physicsBody for the bullet:

bullet.physicsBody?.categoryBitMask = CollisionTypes.enemy.rawValue
bullet.physicsBody?.contactTestBitMask = CollisionTypes.enemy.rawValue
bullet.physicsBody?.collisionBitMask = CollisionTypes.enemy.rawValue
bullet.size = CGSize(width: 40, height: 30)
bullet.physicsBody = SKPhysicsBody(circleOfRadius: bullet.size.width / 2)

For the first 3 references to the bullet's physicsBody, you are using an optional (bullet.physicsBody?) which says "If the physicsBody isn't null, then do this... Except it will be null. You need the line that creates the physicsBody (the last line of the block above) to be the first line to actually create the physicsBody. Currently your categoryBitMask, collisionBitMask and contactTestBitMask aren't getting set for the bullet. although that should make the bullet 'collide' with and bounce off the player too.

Are you doing something similar for the player, as it certainly sounds as though collision detection is causing it to bounce off the bullet.

This might help - apologies if you know this stuff. : How to Detect collision in Swift, Sprite kit

and here's a small sample project with collisions: https://stackoverflow.com/a/43605825/1430420

Both answers are a few years old, so I hope they still work with the latest versions of iOS, SpriteKit and Swift.

Edit2:

Also I just noticed this :

    bullet.physicsBody?.categoryBitMask = CollisionTypes.enemy.rawValue

You are trying to give the bullet a category of enemy. Did you mean to? Although as the physicsBody for the bullet hasn't been set yet, this line of code has no effect.

What actually happens is that when you create the bullet's actual physicsBody, the default for the categoryBitMask is set to all 1s. (https://developer.apple.com/documentation/spritekit/skphysicsbody/1519869-categorybitmask) meaning it collides with everything. Then when you turn off collisions between the player and the bullet category:

player.physicsBody?.collisionBitMask &= ~CollisionTypes.bullet.rawValue 

the player and the bullet still collide because you've switch off collisions between player and physicsBodies with a category of only bullet, but bullet's physicsBody has a category of eveything i.e. player's collisionBitMask is:

11111111111111111111111111111101 (assuming the enemy category is 2)

and bullet's bitMask is:

11111111111111111111111111111111 because you haven't changed it after creating the physicsBody.

When you moved the definition of bullet's physicsBody to before the bitMask settings, then you have the situation where player's collisionBitMask is still:

11111111111111111111111111111101 (assuming the enemy category is 2)

but bullet's collisionBitMask is now:

00000000000000000000000000000100 (assuming your enemy category is 4), because you gave bullet's physicsBody category BitMask enemy's category, and they still collide because bit 2 is 1 in both bitmasks.

Steve Ives
  • 7,894
  • 3
  • 24
  • 55
  • i tried changing it for player and bullet but unfortunately, it still doesnt work. I also dont have my didBegin(contact:) code because i just want to make it collide for now, which it worked for player. Do i need SKPhysicsBody for my bullet to collide with enemy – nathandr Oct 06 '21 at 23:59
  • i also tried to set Collision to zero. Nothing works. Player and bullet still somehow collide with one another – nathandr Oct 07 '21 at 03:52
  • How did you set collision to zero? Also I've added stuff to my answer that might help - see the Edit – Steve Ives Oct 07 '21 at 13:12
  • Yes - if you are just testing collisions then `didBegin()` isn't required, not do you need to set `physicsWorld.contactDelegate = self` or make your class an `SKPhysicsContactDelegate` – Steve Ives Oct 07 '21 at 13:27
  • Ok ty, i will take a look at those examples. I updated my code at the top to show what i have for my player that might've caused this collision problem. bullet.physicsBody?.collisionBitMask = 0; is how i did set my. collision to zero but didnt help nor did setting isDynamic = false. – nathandr Oct 07 '21 at 15:02
  • If optional might be the problem, would making it non optional fix it – nathandr Oct 07 '21 at 16:02
  • No - making it non-optional will crash your program because the physicsBody doesn't exist until your line `bullet.physicsBody = SKPhysicsBody...`. But having it crash can be a good thing, because then you know there is a problem (the physicsBody doesn't yet exist) rather than having your program behave strangely :-). Similarly for the player - are you definitely creating the player's physicsBody before you are setting the player's physicsBody's properties such as the collision bit masks? – Steve Ives Oct 07 '21 at 16:26
  • I tried putting the line of code above, but it caused more problems so I dont think thats it – nathandr Oct 07 '21 at 16:29
  • Yes, the physicsbody for the player is set before the bitmasks – nathandr Oct 07 '21 at 16:31
  • I think i might've just fixed it. i changed my value of physicsbody of bullet from 2 to 4 and it slowed down the recoil. Then i changed to 16 and now its barely noticeable. I think its not 100% fixed but do you think this means anything? – nathandr Oct 07 '21 at 16:42
  • Do you mean one of the physicsBody properties from 2 to 4 and then 16? Which property? Also I've noticed something else - see my Edit2 :-) – Steve Ives Oct 07 '21 at 17:32
  • Yes that CategoryBitMask was a mistake, i actually didnt notice until you mentioned it. The physicsbody im talking about is this code bullet.physicsBody = SKPhysicsBody(circleOfRadius: bullet.size.width / 2) so i just changed 2 to 4 just because of curiosity. It seemed to work so i just started to play around with different values and i eventually left it at 100. Now, it really does look like the player doesnt move when i shoot or maybe i just made really really small and eventually if i tap enough i might notice that it moved a bit – nathandr Oct 08 '21 at 03:39
  • Yes - you’ve just made the physicsBody of the bullet really small. So you tap the screen to create a bullet at the player’s position, the player gets knocked back as the bullet moves towards the enemy? Is that the original situation? – Steve Ives Oct 08 '21 at 06:46
  • Because you've made the physicsBody of the bullet really small, the player won't have to move very far so that it's not overlapping the bullet, which is why the effect is reduced. But you shouldn't have to do that - simply get collisions switched off between the bullet and the player. – Steve Ives Oct 08 '21 at 07:42
  • Yes that was the original situation, I have tried turning the collision off between them but it hasnt worked. – nathandr Oct 09 '21 at 04:23