Android Question How to stop libGDX bodies colliding

noclass1980

Active Member
Licensed User
Longtime User
Hi, can anyone help me with this? I create bottle (as a Body) with balls inside it (also as Bodies). How do I write the code so that the balls collide with the walls of the bottle but not with each other. The code below creates the balls. I think I need to create a Collision Group but don't know how. Thanks.
B4X:
Sub Create_Balls
    Dim Loaderball As lgBox2DBodyEditorLoader
    Loaderball.InitializeWithFile("AllBodies/ball.json")
    Dim rndx, rndy As Float
 
        For i=1 To ballmaxnum
        Dim bdball As lgBox2DBodyDef
        rndx=Rnd(-100,0)
        rndx=rndx/1000
        rndy=Rnd(500,600)
        rndy=rndy/1000
        bdball.Position.Set(rndx, rndy)
        bdball.Type = World.BODYTYPE_Dynamic
        bdball.angle=0
         
        Dim fd As lgBox2DFixtureDef
        fd.Density = 1
        fd.Friction = 0.75
        fd.Restitution = 0.1
     
        Bodball(i) = World.CreateBody(bdball)
             
        Loaderball.AttachFixture(Bodball(i),"Circ1", fd, ballScale)
        TexturesBall.Initialize("AllBodies/Circ1.png")
        TexturesBall.EnforcePowerOfTwoImages=False
        SpritesBall(i).InitializeWithTexture(TexturesBall)
        SpritesBall(i).SetSize(ballScale, ballScale * SpritesBall(i).Height / SpritesBall(i).Width)
     
        Next
     
        OriginBall = Loaderball.GetOrigin("Circ1", ballScale)
        For i=1 To ballmaxnum
        SpritesBall(i).SetOrigin(OriginBall.X*ballScale, OriginBall.Y*ballScale)
     
        Next
End Sub
 

noclass1980

Active Member
Licensed User
Longtime User
Hi, according to the tutorial, I can change the filter value at run time. I added the code below in an LG_Touchdown event to make the balls collide but it didnt work even though the log shows he change. How do I update the filter? Theres a refilter if the fixture is a lgbox2DFixture but not for lgbox2DFixtureDef. Any suggestions? Thanks
B4X:
fd.filter.groupindex=1
 
Upvote 0

notedop

Member
Licensed User
Longtime User
How do you assign multiple MASK_BITS?

In the tutorial its written as following:
"BOUNDARY | FRIENDLY_SHIP | ENEMY_SHIP"

B4X:
balls.push_back( new Ball(m_world, 3, green, FRIENDLY_SHIP, BOUNDARY | FRIENDLY_SHIP | ENEMY_SHIP )

How would you write this in B4A?
B4X:
fd.filter.maskbits = FRIENDLY_SHIP OR BOUNDARY OR ENEMY_SHIP
 
Upvote 0

notedop

Member
Licensed User
Longtime User
This seems to be more into the right direction; below works but as soon as I change for example the player can go through objects, then none of the bitmasks are working anymore.

B4X:
Dim CATEGORY_PLAYER As Int = 1
Dim CATEGORY_BULLET As Int = 2
Dim CATEGORY_OBJECT As Int = 4
Dim CATEGORY_SCENERY As Int = 8

DimMASK_PLAYER As Short = Bit.OR(CATEGORY_OBJECT, CATEGORY_BULLET)
DimMASK_OBJECT As Short = Bit.OR(CATEGORY_BULLET, CATEGORY_PLAYER)
DimMASK_BULLET As Short = Bit.OR(CATEGORY_PLAYER, CATEGORY_OBJECT)
DimMASK_SCENERY As Short =-1
 
Upvote 0

notedop

Member
Licensed User
Longtime User
I've been thinking about this one a bit more.

OR function on bitwise basically combines bits
0001 + 0010 becomes 0011

Every bitCategory should be a power of 2, so:
0001
0010
0100
1000
etc

Due to the power of 2, you can add up the shorts to get a unique value.

In theory below should work, will test this tonight.

B4X:
Dim CATEGORY_PLAYER As short= 1
Dim CATEGORY_BULLET As short= 2
Dim CATEGORY_OBJECT As short= 4
Dim CATEGORY_SCENERY As short= 8
 
Dim MASK_PLAYER As Short =CATEGORY_OBJECT+CATEGORY_BULLET
Dim MASK_OBJECT As Short = CATEGORY_BULLET+CATEGORY_PLAYER
Dim MASK_BULLET As Short = CATEGORY_PLAYER+CATEGORY_OBJECT
Dim MASK_SCENERY As Short =-1
 
Upvote 0

Informatix

Expert
Licensed User
Longtime User
I've been thinking about this one a bit more.

OR function on bitwise basically combines bits
0001 + 0010 becomes 0011

Every bitCategory should be a power of 2, so:
0001
0010
0100
1000
etc

Due to the power of 2, you can add up the shorts to get a unique value.

In theory below should work, will test this tonight.

B4X:
Dim CATEGORY_PLAYER As short= 1
Dim CATEGORY_BULLET As short= 2
Dim CATEGORY_OBJECT As short= 4
Dim CATEGORY_SCENERY As short= 8

Dim MASK_PLAYER As Short =CATEGORY_OBJECT+CATEGORY_BULLET
Dim MASK_OBJECT As Short = CATEGORY_BULLET+CATEGORY_PLAYER
Dim MASK_BULLET As Short = CATEGORY_PLAYER+CATEGORY_OBJECT
Dim MASK_SCENERY As Short =-1
It's what I do usually with Gravity because its values are also powers of 2.
 
Upvote 0

notedop

Member
Licensed User
Longtime User
grrrr I can't get this to work properly...

B4X:
Dim CATEGORY_PLAYER As Short= 1
Dim CATEGORY_BULLET As Short= 2
Dim CATEGORY_OBJECT As Short= 4
Dim CATEGORY_SCENERY As Short= 4
Dim MASK_PLAYER As Short = CATEGORY_PLAYER
Dim MASK_OBJECT As Short = CATEGORY_BULLET
Dim MASK_BULLET As Short = CATEGORY_OBJECT
Dim MASK_SCENERY As Short =-1

This would state that player can go through objects but not through scenery
Objects collide with Bullets
Bullets collide with Objets
Scenery collides with everything

Scenery is working, but the bullets do not collide with the objects :-(

I cannot get my head on what i'm missing

B4X:
        Dim Bullet As ActiveAnimation
        Dim fd As lgBox2DFixtureDef
        Dim bd As lgBox2DBodyDef


        fd.Density = 1
        fd.restitution = 0
        fd.friction = 0
        fd.filter.categoryBits = CATEGORY_BULLET
        fd.filter.maskBits = MASK_BULLET
        fd.filter.groupIndex = 1
      
        bd.Bullet = True
        bd.Position.Set(tester.Position.x + (tester.Width/2), tester.Position.y)
        bd.gravityScale = 0
        bd.angularVelocity = 0
        bd.fixedRotation = True

        bd.Type= World.BODYTYPE_Dynamic

        Bullet.Initialize
        Bullet.Initialize3(World,"actors/bullet.json",bd,fd,False)
        Bullet.MAXVELOCITY = tester.MAXVELOCITY*4

        'add the bullet to the bullet list. We will loop through this list when drawing.
        Bullets.Add(Bullet)

Scenery and objects are declared like below.

B4X:
For i = 0 To Maps.Layers.Get2("ObjTest").Objects.GetAllObjects.Size -1
  
    Log("NUmber of Objects on MAP:" & Maps.Layers.Get2("ObjTest").Objects.GetAllObjects.Size)

    Dim bd As lgBox2DBodyDef
    bd.Type = world.BODYTYPE_Static
    bd.allowSleep = True
    bd.awake = True
  
    Dim MapObj As lgMapObject = Maps.Layers.Get2("ObjTest").Objects.Get(i)
  
    'Log("Keys" & MapObj.Properties.GetAllKeys)
    'Log("Values" &  MapObj.Properties.GetAllValues)
  
    Select MapObj.Properties.Get("type")
  
  
    Case "lgMapPolylineMapObject"        'this is the actual ground cq SCENERY
      
        Dim Obj As lgMapPolylineMapObject = Maps.Layers.Get2("ObjTest").Objects.Get(i)
        'retrieve polyline and scale the vertexes including position.
        Obj.Polyline.setPosition(Obj.Polyline.X*(scale), Obj.Polyline.y*(scale))
        Obj.Polyline.setScale(scale, scale)
      
        'create shape and use the transformed vertices as we scaled it.
        Dim eshape As lgBox2DChainShape
        eshape.createChain(Obj.Polyline.TransformedVertices)
      
        'Log("Bodyground position" & WorldGround.Polyline.X & " - " & bd.position.y)
      
        'now we have the fixture
        Dim fd As lgBox2DFixtureDef
        fd.shape = eshape
        fd.restitution = 0
        fd.friction = 0.25
        fd.filter.categoryBits = Main.CATEGORY_SCENERY
        fd.filter.maskBits = Main.MASK_SCENERY
        fd.filter.groupIndex = 1
      
        'give it to the world, baby!          
        bdyGround = world.CreateBody(bd)
        bdyGround.createFixture(fd)
        GroundList.Add(bdyGround)

        eshape.Dispose
  
    Case "lgMapEllipseMapObject"
  
        Dim ObjCircle As lgMapEllipseMapObject = Maps.Layers.Get2("ObjTest").Objects.Get(i)
        'ObjCircle.Ellipse.Set(ObjCircle.Ellipse.x*scale,ObjCircle.Ellipse.y*scale,ObjCircle.Ellipse.width*scale, ObjCircle.Ellipse.height*scale)
      
        Log("Object Circle: X-" & ObjCircle.Ellipse.x & " - Y: "  & ObjCircle.Ellipse.y)
      
        Dim V As lgMathVector2
        V.Set(ObjCircle.Ellipse.x*scale, ObjCircle.Ellipse.y*scale)
        Log("Vector: " & V)
          
        Dim CircleShape As lgBox2DCircleShape
        CircleShape.Radius = (ObjCircle.Ellipse.height/2)*scale
        CircleShape.Position.Set(0,0)
'        CircleShape.Position.x = ObjCircle.Ellipse.x*scale
'        CircleShape.Position.y = ObjCircle.Ellipse.y*scale
'        Log("Scale=" & scale & " Shape Circle: X-" & CircleShape.Position.x & " - Y: "  & CircleShape.Position.y)

        'now we have the fixture
        Dim fd As lgBox2DFixtureDef
        fd.shape = CircleShape
        fd.restitution = 0.5
        fd.friction = 0.25
        fd.filter.categoryBits = Main.CATEGORY_OBJECT
        fd.filter.maskBits = Main.MASK_OBJECT
        fd.filter.groupIndex = 1
      
        Log("Filter Ellips" & fd.filter.categoryBits & "-" &  fd.filter.maskBits & "-" & fd.filter.groupIndex)
      
        Dim WorldObject As lgBox2DBody
      
        'set the body def position
        bd.position.Set(ObjCircle.Ellipse.x*scale,ObjCircle.Ellipse.y*scale)
      
        'give it to the world, baby!          
        WorldObject = world.CreateBody(bd)
        WorldObject.createFixture(fd)
        Log("WorldObject: " & (WorldObject.Position) )
        GroundList.Add(WorldObject)
      
        CircleShape.Dispose
      
    Case "lgMapRectangleMapObject"
  
        'retreive the rectangle from the map.
        Dim ObjRectangle As lgMapRectangleMapObject = Maps.Layers.Get2("ObjTest").Objects.Get(i)
        ObjRectangle.Rectangle.setPosition2(ObjRectangle.Rectangle.x*scale,ObjRectangle.Rectangle.y*scale)
      
        'convert to a polygonshape
        Dim RectangleShape As lgBox2DPolygonShape
        Dim V As lgMathVector2
        V.Set((ObjRectangle.Rectangle.width/2)*scale, (ObjRectangle.Rectangle.height/2)*scale)
        RectangleShape.SetAsBox2((ObjRectangle.Rectangle.width*scale)/2, (ObjRectangle.Rectangle.height*scale)/2, V,0)
      
        'Start creating the body
        Dim WorldObject As lgBox2DBody
      
        'now we have the fixture
        Dim fd As lgBox2DFixtureDef
        fd.shape = RectangleShape
        fd.restitution = 0.5
        fd.friction = 0.25
        fd.filter.categoryBits = Main.CATEGORY_OBJECT
        fd.filter.maskBits = Main.MASK_OBJECT
        fd.filter.groupIndex = 1
      
      
        bd.position.Set(ObjRectangle.Rectangle.x, ObjRectangle.Rectangle.y)

        'give it to the world, baby!          
        WorldObject = world.CreateBody(bd)
        WorldObject.createFixture(fd)
        GroundList.Add(WorldObject)
        RectangleShape.Dispose
      
    Case Else
        Log("MapObjects found which have unknown type!")
  
    End Select
      
  
Next
 
Upvote 0

notedop

Member
Licensed User
Longtime User
:confused:
I finally know what went wrong here; it's an error in my ActiveAnimation class

I'm attaching a new fixturedef each draw based on the animationframe as shown in http://www.b4x.com/android/forum/th...imated-sprite-with-physics-body-editor.45899/

I'm now initialising with a custom fixturedef. I forgot to assign the custom FD to the classglobal FD. After first draw, the incorrect FD is assigned tot he body, due to this collision filtering did not have occure as expected, offcourse:eek::eek::eek:.
 
Upvote 0
Top