2
votes

(If you want to cut to the chase go to the bold section).

I am having an unwanted collision in my simulation. My simulation has the following groups:

TeethTop (this is a group of objects)
TeethBottom (this is a group of objects)
Ball (the main object that is moved in the game)
Line (one line that is drawn occasionally only to detect if user swiped to a tooth)
Boundries (boundaries of screen)

Here are the rules I need

  • I need SKcontacts generated when
    • ball hits any teeth (top or bottom)
    • TeethTop hits any teeth
    • Line hits any teeth
  • As far as physical contacts and reactions (who can hit who and have physics simulated)
    • The line can not impede movement or hit the ball
    • The ball must land on the teeth but never move the teeth
    • No tooth must ever physically move due to physics
    • No tooth must ever react to a contact with another tooth
    • The ball needs to never pass through the boundaries
  • Ill throw in gravity
    • The ball is the only thing that reacts to gravity
  • Things that are dynamic (not in code)
    • The ball is dynamic because it reacts to gravity and hitting other teeth
    • Everything else stays put no matter what (however I had to tell the teeth that they were dynamic so I could have SKPhysicsContacts when the top hits the bottom)

Basically what happens is their are two rows of teeth, top and bottom. And they do their thing and become a stage. The walls are the same way. The ball moves around inside the mouth are like a platformer hitting and bounding off teeth.

On swipes a SKPhysicsNode line is created following the swipe and detecting which tooth the user swiped towards (**** MAYBE their is a better way then making a SKPhyiscsNode for the swipe line... I still need to detect if the user swiped in the direction of a tooth). And everything is dandy for awhile, then the mouth closes and stops when a tooth from the top hits a tooth from the bottom.

I had things all fine and dandy with things set as thus

BottomTeethGroup = 10
TopTeethGroup = 31
playergroup = 2
wallgroup = 1
lineleart = 99
  • Top Teeth
    • affectedbygravity = false
    • collisionbitmask = 0
    • categorybitmask = BottomTeethGroup
    • contacttTest = TopTeethGroup
    • dynamic = false
  • Bottom Teeth
    • affectedbygravity = false
    • collisionbitmask = 0
    • categorybitmask = TopTeethGroup
    • contacttTest = BottomTeethGroup
    • dynamic = false
  • Ball
    • affectedbygravity = false
    • the collision bit mask is never set so it collides with everything
    • categorybitmask = playergroup
    • contacttTest = playergroup
    • Dynamic = true
  • Boundaries
    • categorybitmask = wallgroup
    • dynamic = false
  • Line
    • collisionbitmask = 0
    • categorybitmask = lineleart
    • I have tried setting physics properties to crazy values but I just cant get the ball to pass through

The problem arises when I add the line. Everything with detection works fine until you add the line. Unfortunately the ball collides with the line creating a physical reaction which just isn't good! The ball should not physically collide with the line!

The way I see it their are some options:

  • Make is to the ball passes through the line, or ignores collisions between the two
  • Find a different way to detect which tooth the player swiped at (the current method is flawed anyway because the line will detect multiple teeth, just because it has a slope and doesn't stop once it hits the first). I have the coordinates of the start and end and the direction if someone has a better way.
  • Probably if we could make it so the top teeth and bottom teeth only have physical contact with ones from the other side then things would get easier.
  • Make it look like the ball is passing through the line

Edit: Perhaps my definitions of things are flawed so here is how I think contacts work:

  • collisionbitmask: will only collide with other objects that have the number you specify after it. If 0 then it collides with no objects, if not set then it collides with all
  • categorybitmask: defines what category is, if an object has a category test bit mask with this value then a SKPhysics contact will be created, however their might not necessarily be a physics reaction
  • contactTest: If it hits and the other object has the same categorybitmask as the one set here a SKphysics contact will be made
  • dynamic objects have physical reactions when they hit other dynamic objects, or non dynamic objects. SKPhysicsContacts are written up for all collisions
  • non dynamic objects will not move in any collision, and will only write up SKPhysicscontacts if the other object is static. Two non dynamic objects are not expected to collide.

List of solutions I have tried:

  • Lines collisionbitmask not set (same problem)
  • Cavities collisionbitmask set to 0 (falls through random teeth however it doesn't collide with the line but still generates a SKPhysicsContact)
  • All teeths' collision bit mask set to 4 (A BIIG MESS)
  • Top teeth collision bit mask set to 2 and bottom to 4 (less of a mess and when cavity hits a tooth it drifts like its in 0 g (it is in 0 g))

Edit:

I have been trying a bunch of things and none of them work. I got fed up and created a new project with four balls. Basically you set each ball to a specific group type and run the simulation. I have it so their are variables at the top for all the categories. If the simulation is set up right (I believe it is) the program WI simulate what would happen if all the values at the top are correct.

You can also find the code below

//

//  GameScene.swift

//  CollisionTesting

//

//  Created on 8/13/15.

//  Copyright (c) 2015 BroccoliPresentations. All rights reserved.

//

 

import SpriteKit

enum type

{

    case _toptooth

    case _bottomtooth

    case _ball

    case _line

    case _boundary

    case _none

}

class GameScene: SKScene {

    override func didMoveToView(view: SKView) {

        

        //The physics categories for each of them

        var topteethcategory:UInt32 = (0x01 << 1)

        var bottomteethcategory:UInt32 = (0x01 << 2)

        var ballcategory:UInt32 = (0x01 << 3)

        var boundriesgroup:UInt32 = (0x01 << 4)

        var linegroup:UInt32 = (0x01 << 5)

        

        //When collision reports should be written up

        var topteethcolisionreport:UInt32 = bottomteethcategory

        var bottomteethcollisionreport:UInt32 = topteethcategory

        var ballcollisionreport:UInt32 = bottomteethcategory | topteethcategory

        var boundriescollisionreport:UInt32 = 0

        var linecollisionreport:UInt32 = topteethcategory | bottomteethcategory

        

        //When they should bounce off of eachother

        var topteethphysics:UInt32 = bottomteethcategory

        var bottomteethphysics:UInt32 = topteethcategory

        var ballphysics:UInt32 = bottomteethcategory | topteethcategory | boundriesgroup

        var boundriesphysics:UInt32 = boundriesgroup

        var linecollisionphysics:UInt32 = linegroup

        

        

        //Here you can set what tope of object each color is

        var blue:type = type._toptooth

        var red:type = type._bottomtooth

        var yellow:type = type._ball

        var green:type = type._none

        

        

        var xy = CGRectGetMidX(self.frame) * 1.5

        var ball1 = SKSpriteNode(texture: SKTexture(imageNamed: "Blue"))

        ball1.position = CGPoint(x: xy, y:CGRectGetMidY(self.frame));

        ball1.size = CGSizeMake(100, 100)

        ball1.physicsBody?.affectedByGravity = false

        ball1.physicsBody = SKPhysicsBody(circleOfRadius: 50)

        ball1.physicsBody?.velocity = CGVector(dx: -100, dy: 0)

        

        var ball2 = SKSpriteNode(texture: SKTexture(imageNamed: "Red"))

        ball2.position = CGPoint(x:xy / 2, y:CGRectGetMidY(self.frame));

        ball2.size = CGSizeMake(100, 100)

        ball2.physicsBody?.affectedByGravity = false

        ball2.physicsBody = SKPhysicsBody(circleOfRadius: 50)

        ball2.physicsBody?.velocity = CGVector(dx: 100, dy: 0)

        

        var ball3 = SKSpriteNode(texture: SKTexture(imageNamed: "Yellow"))

        ball3.position = CGPoint(x:((xy / 4) + xy) / 2, y:CGRectGetMidY(self.frame) / 2);

        ball3.size = CGSizeMake(100, 100)

        ball3.physicsBody?.affectedByGravity = false

        ball3.physicsBody = SKPhysicsBody(circleOfRadius: 50)

        ball3.physicsBody?.velocity = CGVector(dx: 0, dy: 100)

        

        var ball4 = SKSpriteNode(texture: SKTexture(imageNamed: "Green"))

        ball4.position = CGPoint(x:((xy / 4) + xy) / 2, y:CGRectGetMidY(self.frame) * 1.5);

        ball4.size = CGSizeMake(100, 100)

        ball4.physicsBody?.affectedByGravity = false

        ball4.physicsBody = SKPhysicsBody(circleOfRadius: 50)

        ball4.physicsBody?.velocity = CGVector(dx: 0, dy: -100)

        self.addChild(ball1)

        self.addChild(ball2)

        self.addChild(ball3)

        self.addChild(ball4)

        

        

        switch (blue)

        {

        case type._toptooth:

                ball1.physicsBody?.categoryBitMask = topteethcategory

                ball1.physicsBody?.collisionBitMask = topteethphysics

                ball1.physicsBody?.contactTestBitMask = topteethcolisionreport

        case type._bottomtooth:

            ball1.physicsBody?.categoryBitMask = bottomteethcategory

            ball1.physicsBody?.collisionBitMask = bottomteethphysics

            ball1.physicsBody?.contactTestBitMask = bottomteethcollisionreport

        case type._ball:

            ball1.physicsBody?.categoryBitMask = ballcategory

            ball1.physicsBody?.collisionBitMask = ballphysics

            ball1.physicsBody?.contactTestBitMask = ballcollisionreport

        case type._boundary:

            ball1.physicsBody?.categoryBitMask = boundriesgroup

            ball1.physicsBody?.collisionBitMask = boundriesphysics

            ball1.physicsBody?.contactTestBitMask = boundriescollisionreport

        case type._line:

            ball1.physicsBody?.categoryBitMask = linegroup

            ball1.physicsBody?.collisionBitMask = linecollisionphysics

            ball1.physicsBody?.contactTestBitMask = linecollisionreport

        case type._none:

            ball1.position = CGPointMake(100000, 10000)

        }

        

        switch (red)

        {

        case type._toptooth:

            ball2.physicsBody?.categoryBitMask = topteethcategory

            ball2.physicsBody?.collisionBitMask = topteethphysics

            ball2.physicsBody?.contactTestBitMask = topteethcolisionreport

        case type._bottomtooth:

            ball2.physicsBody?.categoryBitMask = bottomteethcategory

            ball2.physicsBody?.collisionBitMask = bottomteethphysics

            ball2.physicsBody?.contactTestBitMask = bottomteethcollisionreport

        case type._ball:

            ball2.physicsBody?.categoryBitMask = ballcategory

            ball2.physicsBody?.collisionBitMask = ballphysics

            ball2.physicsBody?.contactTestBitMask = ballcollisionreport

        case type._boundary:

            ball2.physicsBody?.categoryBitMask = boundriesgroup

            ball2.physicsBody?.collisionBitMask = boundriesphysics

            ball2.physicsBody?.contactTestBitMask = boundriescollisionreport

        case type._line:

            ball2.physicsBody?.categoryBitMask = linegroup

            ball2.physicsBody?.collisionBitMask = linecollisionphysics

            ball2.physicsBody?.contactTestBitMask = linecollisionreport

        case type._none:

            ball2.position = CGPointMake(100000, 10000)

        }

        

        switch (blue)

        {

        case type._toptooth:

            ball3.physicsBody?.categoryBitMask = topteethcategory

            ball3.physicsBody?.collisionBitMask = topteethphysics

            ball3.physicsBody?.contactTestBitMask = topteethcolisionreport

        case type._bottomtooth:

            ball3.physicsBody?.categoryBitMask = bottomteethcategory

            ball3.physicsBody?.collisionBitMask = bottomteethphysics

            ball3.physicsBody?.contactTestBitMask = bottomteethcollisionreport

        case type._ball:

            ball3.physicsBody?.categoryBitMask = ballcategory

            ball3.physicsBody?.collisionBitMask = ballphysics

            ball3.physicsBody?.contactTestBitMask = ballcollisionreport

        case type._boundary:

            ball3.physicsBody?.categoryBitMask = boundriesgroup

            ball3.physicsBody?.collisionBitMask = boundriesphysics

            ball3.physicsBody?.contactTestBitMask = boundriescollisionreport

        case type._line:

            ball3.physicsBody?.categoryBitMask = linegroup

            ball3.physicsBody?.collisionBitMask = linecollisionphysics

            ball3.physicsBody?.contactTestBitMask = linecollisionreport

        case type._none:

            ball3.position = CGPointMake(100000, 10000)

        }

        

        switch (green)

        {

        case type._toptooth:

            ball4.physicsBody?.categoryBitMask = topteethcategory

            ball4.physicsBody?.collisionBitMask = topteethphysics

            ball4.physicsBody?.contactTestBitMask = topteethcolisionreport

        case type._bottomtooth:

            ball4.physicsBody?.categoryBitMask = bottomteethcategory

            ball4.physicsBody?.collisionBitMask = bottomteethphysics

            ball4.physicsBody?.contactTestBitMask = bottomteethcollisionreport

        case type._ball:

            ball4.physicsBody?.categoryBitMask = ballcategory

            ball4.physicsBody?.collisionBitMask = ballphysics

            ball4.physicsBody?.contactTestBitMask = ballcollisionreport

        case type._boundary:

            ball4.physicsBody?.categoryBitMask = boundriesgroup

            ball4.physicsBody?.collisionBitMask = boundriesphysics

            ball4.physicsBody?.contactTestBitMask = boundriescollisionreport

        case type._line:

            ball4.physicsBody?.categoryBitMask = linegroup

            ball4.physicsBody?.collisionBitMask = linecollisionphysics

            ball4.physicsBody?.contactTestBitMask = linecollisionreport

        case type._none:

            ball4.position = CGPointMake(100000, 10000)

        }

        

        

        

        physicsWorld.gravity = CGVector(dx: 0, dy: 0)

    }

    

 

    override func update(currentTime: CFTimeInterval) {

        /* Called before each frame is rendered */

    }

}

 

//nothing set they collide to eachother

//contactTestbitmask has nothing to do with bumping against eachother

//Category is the most important it gives it a type

//The other two decide when reactions happen, either physical or in code

//Collision bitmask is a list of groups that it actually should collide with

//Contacttestbitmask is list of groups that can trigger the code
1
This is not the solution for your problem, just a hint...From what you wrote in you question : Top Teeth ->categoryBitMask= BottomTeethGroup should be TopTeethGroup I guess, as well as Bottom Teeth->categoryBitMask= TopTeethGroup should be BottomTeethGroup. But, without code, nobody can't say for sure what's going on. Some parts of code, like where you define categories, or how you set contact, collision, and category bit masks, as well as how you check for contacts would be useful for debugging.Whirlwind
@Whirlwind Does category bit mask have anything to do with what physical collisions happen I thought it was just about When contacts were created? I will post some code.J.Doe
For the ball you say yourself "the collision bit mask is never set so it collides with everything" so why are you surprised that it collides with the line?Ben Kane
I am not very surprised. I just can't get it to collide with everything BUT the line.J.Doe
Try ball.physicsBody!.collisionBitMask ^= lineleart0x141E

1 Answers

0
votes

I have figured it out! My problem is I was making things much too complicated. I actually didnt need all of these groups! Here is what I did!

var stage:UInt32 = (0x1 << 1)
var player:UInt32 = (0x1 << 2)
var sensors:UInt32 = (0x1 << 3)

//Physics collision bitmask
var p_stage:UInt32 = 0
var p_player:UInt32 = 0 | stage
var p_sensors:UInt32 = 0

//Test bitmask
var t_stage:UInt32 = stage
var t_player:UInt32 = stage
var t_sensors:UInt32 = stage

I actually didnt need as many groups as I thought I did! However I did have to store some data in the nodes name in order to tell wether it was from the top or bottom or which row, but overall it worked awesome!

Thank you guys who looked over everything, it really means a lot!

Something I found odd was that doing

(0x1 << 1)
(0x1 << 2)
(0x1 << 3)

was better then

1
2
3

I guess I really dont know what I am doing with the (0x1 << 1) thingy but I saw it somewhere else and copied it!