1

Hi go easy on me as I'm still pretty new to swift. I'm creating a game in which your character (on the left of the screen) must swipe up or down to change lanes (4 lanes) or jump by tapping the right side of the screen, in order to dodge obstacles coming from the right side of the screen. This has presented the problem that when the character sprite is in one lane, some of it's pixels are in the lane above, so being in a different lane doesn't shield the character from collision. (This problem also exists for when the character jumps) Is there a way to program it so the character and obstacles only collide if they are in the same lane?

I've tried to make it so the .collisionBitMask and .categoryBitMask change depending on the position of either the obstacle or character but I can't figure out how to code it correctly. I'm pretty lost to be honest. Here is some code:

runningDoggo.physicsBody = SKPhysicsBody(texture: doggoTexture, size: runningDoggo.size)
runningDoggo.physicsBody?.affectedByGravity = false
runningDoggo.physicsBody?.isDynamic = true
runningDoggo.physicsBody?.collisionBitMask = 0x1 << 2
bush.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "8-bit bush"), size: bush.size)
bush.physicsBody?.isDynamic = true
bush.physicsBody?.affectedByGravity = false
bush.physicsBody?.categoryBitMask = 0x1 << 1

And then I have a set of switch cases in a function for randomly selecting which lane the bush comes in

    switch randomLane{
    case 1:
        bush.position = CGPoint(x: 0.4*UIScreen.main.bounds.width, y:-0.07*UIScreen.main.bounds.height)
        if(bush.position.y < runningDoggo.position.y) {
            bush.zPosition = 6
        }
        self.addChild(bush)
    case 2:
        bush.position = CGPoint(x: 0.4*UIScreen.main.bounds.width, y:-0.18*UIScreen.main.bounds.height)
        if(bush.position.y < runningDoggo.position.y)  {
            bush.zPosition = 6
        }
        self.addChild(bush)
    case 3:
        bush.position = CGPoint(x: 0.4*UIScreen.main.bounds.width, y:-0.29*UIScreen.main.bounds.height)
        if(bush.position.y < runningDoggo.position.y) {
            bush.zPosition = 6
        }
        self.addChild(bush)
    case 4:
        bush.position = CGPoint(x: 0.4*UIScreen.main.bounds.width, y:-0.4*UIScreen.main.bounds.height)
        if(bush.position.y < runningDoggo.position.y) {
            bush.zPosition = 6
        }
        self.addChild(bush)
    default:
        print("How is this not 1,2,3, or 4?")
    }
    bush.run(moveAndRemoveBush)

I want it to only collide (EDIT: Not to collide but to contact) the runningDoggo sprite with the bush sprite if they were in the same lane and pass by without colliding if the character isn't in the obstacle's lane.

1 Answers1

0

Firstly, that complicated switch could be simplified to something like this (anytime you write the same code more than once, think if you can simplify it):

bush.position.x = 0.40 * UIScreen.main.bounds.width
bush.position.y = 0.07 * randomLane * UIScreen.main.bounds.height) // 0.07, 0.14, 0.21 or 0.28 for lanes 1-4 
if (bush.position.y < runningDoggo.position.y) bush.zPosition = 6
self.addChild(bush)
bush.run(moveAndRemoveBush)

OK - I know that the y values of 0.07, 0.14, 0.21 and 0.28 don't match up with your values of 0.07, 0.18, 0.29 and 0.40 but maybe that's some thing you can tweek, or define an offset array as a property:

let bushYOffset = [0.07, 0.18, 0.29, 0.40]

and then just pick the offset corresponding to the lane

bush.position.x = 0.40 * UIScreen.main.bounds.width
bush.position.y = bushYOffset[randonLane-1] * UIScreen.main.bounds.height)
if (bush.position.y < runningDoggo.position.y) bush.zPosition = 6
self.addChild(bush)
bush.run(moveAndRemoveBush)

To address your main problem, you could create a bitmask for each lane in an array:

let laneMask: [UInt32] = [1<<1, 1<<2, 1<<3, 1<<4]

When Doggo moves to a new lane, give Doggo's physicsBody corresponding to collisonBitmask the lane it has just moved into:

runningDoggo.physicsBody?.collisionBitMask = laneMask[doggoLane - 1] // Arrays start at 0

When you spawn an obstacle, also give it the collision bitMask for the lane it is in:

bush.physicsBody?.collisionBitMask = laneMask[randomLane - 1] // Arrays start at 0

Now Doggo and the bush will only collide if they are in the same lane. If they are in different lanes they won't, even if some of their pixels overlap.

You may have to adjust this if there are other sprites on screen that doggo and the bush need to interact with.

NOTE:

Are you sure you want them to collide and not contact? Collisions occur when sprites collide and bounce off each other and fly around the screen; contacts are where 2 sprites touch and your code gets called and you can make one explode, or losee a life, or increase a score etc.

Edit: my step-by-step guide for collisions and contacts: https://stackoverflow.com/a/51041474/1430420

And a guide to collision and contactTest bit masks: https://stackoverflow.com/a/40596890/1430420

Manipulating bit masks to turn individual collision ans contacts off and on. https://stackoverflow.com/a/46495864/1430420

Steve Ives
  • 7,894
  • 3
  • 24
  • 55
  • Thanks a bunch Steve for the great tips. And yes you're correct I meant that i want them to contact not collide as contacting a bush in the correct lane should end the game and trigger my restart screen. Is it the same solution just replacing collisionBitMask with contactBitMask? – I Math Sometimes Jun 18 '19 at 22:26
  • It’s ‘contactTestBitMask’ but you’ll also need to make your scene a contact delegate and set up the ‘didBegib(contact:)’ function. The ‘step-by-step guide for collisikns and contacts’ should help. – Steve Ives Jun 18 '19 at 22:42
  • I do have the didBegin(contact:) function that seems to work. The problem was just that it worked for all lanes, rather than only the particular one I needed. as for the contact delegate, I've been using "self.physicsWorld.contactDelegate = self" Is that right? (*Every time I type the contactTestBitMask I forget the 'test' part, my bad) – I Math Sometimes Jun 19 '19 at 02:22
  • @IMathSometimes If you;re 'didBegin' is firing when it should, then you're 90% of the way there :-) – Steve Ives Jun 19 '19 at 08:41