Games Game X2 No contact

developer_123

Active Member
Licensed User
Longtime User
In the development of my Game, I want to identify when my character is without any type of contact with another body, in order to define a variable at that moment. Once it comes into contact with any element, make that variable change its value. In the BeginContact, EndContact, Presolve, Postsolve routines, it is a bit complex to understand this, since I have tried in BegingContact to implement the conditional "If bodies.otherbody = null Then ...." but apparently this instruction is not correct for what I wish. I appreciate if someone tells me which would be the right path.
 

ilan

Expert
Licensed User
Longtime User
I am not sure i have understood your question. Can you explain what kind of game it is and why u need to know when the character is not touching any body?

what is happening in that moment? Or what should happen?

if u can provide more info i can try to give u a solution for your problem.
 

developer_123

Active Member
Licensed User
Longtime User
I am not sure i have understood your question. Can you explain what kind of game it is and why u need to know when the character is not touching any body?

what is happening in that moment? Or what should happen?

if u can provide more info i can try to give u a solution for your problem.
Ilan, thank you for your support.

Answering your question, the game type is cross-platform B4A, B4i and B4J using x2. I need to identify when there is no contact since my character jumps in the air and at that moment it is necessary to change the animation. However, I already managed to solve this last night using a combination between the BegingContact and End Contact routine like this:

B4X:
    Private Sub World_BeginContact (Contact As B2Contact)
        Dim bodies As X2BodiesFromContact = X2.GetBodiesFromContact(Contact, "character")
        If bodies.ThisBody=mCharacter.bw Then
            mCharacter.in_air=False
        End If
    End sub
    .
    .
    .
rivate Sub World_EndContact(Contact As B2Contact)
    If  bodies.ThisBody=mCharacter.bw Then       
        mCharacter.in_air=True
    End If
End Sub
 

ilan

Expert
Licensed User
Longtime User
Ilan, thank you for your support.

Answering your question, the game type is cross-platform B4A, B4i and B4J using x2. I need to identify when there is no contact since my character jumps in the air and at that moment it is necessary to change the animation. However, I already managed to solve this last night using a combination between the BegingContact and End Contact routine like this:

B4X:
    Private Sub World_BeginContact (Contact As B2Contact)
        Dim bodies As X2BodiesFromContact = X2.GetBodiesFromContact(Contact, "character")
        If bodies.ThisBody=mCharacter.bw Then
            mCharacter.in_air=False
        End If
    End sub
    .
    .
    .
rivate Sub World_EndContact(Contact As B2Contact)
    If  bodies.ThisBody=mCharacter.bw Then      
        mCharacter.in_air=True
    End If
End Sub

your code will fail in a game.

you check if your character has begun any contact then he is not in the air (jumping) but this is wrong. any body in your world that will start contact with your character will trigger that event. the same when your character is ending a contact. let say a bullet hit your contact it will trigger the beginContact event and you will set your mCharacter.in_air to false but that also could happen in the air and then if you are alrady walking on the ground body and a bullet hits you than the begincontact will be triggered and after bullet disappear the endcontact will be triggered what means mCharacter.in_air=True even if you are still on the ground and you will draw the wrong sprite.

note that there is no constant check for starting or ending a contact so don't think that if you are on the ground body and you put log() inside begincontact that you will get on every game loop a log() that your character is touching the ground. that is not the case. you will ONLY get a log() when a CONTACT in your WOLRD between 2 bodies has started and when that CONTACT has ended!


so lets take a closer look of your problem.

a character can me in the air in 2 scenarios:

- jumping
- falling

so basically what we can check is the y- velocity of the body. if it is higher than 0 then the body is jumping if it is lower the 0 he is falling.

so what i do is in the game loop where i have my drawing function i check the velovity of the x and y. if x changes i know body is moving and i can know in what direction and also if i need to draw a running sprite or standing sprite. the same i do for the y velocity. i check if body is jumping or falling.
the y velocity check should be before the x velocity check.

NOW with this solution, we created another problem. (after making so many games i think i already know all scenarios that can happen in a game 😁)
anyway, the problem we just created is that the body y-velocity can be different than 0 even if he is not falling or jumping. HOW???

very simple, in 2 NEW scenarios:

- standing on a elevator that is moving up/down
- sliding

to solve this issue what i do is i check inside the beginContact event if the character hit the elevator_ground and if yes i dont draw the jumping falling sprite.
the same i do for sliding_ground

this is the code from my PixelKnight Game (it is written using libgdx framework):
note that i make a lot of checks like if my player is on a train or on a lift or flying or jumping or falling or sliding....


B4X:
Sub drawPlayer         
    If medead Then
        player.setLinearVelocity2(0,0)
        player.GravityScale = 0
        Return
    End If
    If Not(gamepause = True And medead = False) Then
        If frames Mod 5 = 0 Then playerindex = playerindex + 1
    End If
    Dim objcordinate As objcor
    objcordinate = player.UserData
    
    Dim vec2 As lgMathVector2
    vec2 = PosCon.box2d2world(player.Position.x,player.Position.y,0,0)
    
    If bottleON Then
        Batch.DrawTex2(playerFlyTexture, vec2.x-(vpW*0.08), vec2.y-(vpW*0.08), vpW*0.16,vpW*0.16)
    End If
    
    'check if exit gate now
    Dim gateobj As objcor = gate.UserData
    If gateobj.exitnow Then
        If player.getLinearVelocityFromWorldPoint(player.WorldCenter).x = 0 And player.getLinearVelocityFromWorldPoint(player.WorldCenter).y = 0 Then
            If exitCD < 0 Then Return
            Batch.SetColorRGBA(1,1,1,mapping(exitCD,120,0,1,0))
            Batch.DrawTex2(playervictory,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)
            Batch.SetColorRGBA(1,1,1,1)
            Return           
        End If   
    End If
    
    If ontrain Then
        If Abs(player.getLinearVelocityFromWorldPoint(player.WorldCenter).x) - Abs(trainbody.getLinearVelocityFromWorldPoint(trainbody.WorldCenter).x) > 1 Then
            If drawleft Then
                Batch.DrawRegion2(player_framesflip(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
            Else
                Batch.DrawRegion2(player_frames(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
            End If   
        Else
            If drawleft Then
                Batch.DrawRegion2(playeridle_framesflip(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
            Else
                Batch.DrawRegion2(playeridle_frames(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)
            End If   
        End If
        Return
    End If

    If onlift Then
        If objcordinate.horizontal = 0 Then
            If player.getLinearVelocityFromWorldPoint(player.WorldCenter).x <> liftonBody.getLinearVelocityFromWorldPoint(liftonBody.WorldCenter).x Then
                If drawleft Then
                    Batch.DrawRegion2(player_framesflip(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
                Else
                    Batch.DrawRegion2(player_frames(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
                End If   
            Else
                If drawleft Then
                    Batch.DrawRegion2(playeridle_framesflip(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
                Else
                    Batch.DrawRegion2(playeridle_frames(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)
                End If   
            End If
        Else
            If Abs(player.getLinearVelocityFromWorldPoint(player.WorldCenter).x) > 0.2 Then
                If drawleft Then
                    Batch.DrawRegion2(player_framesflip(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
                Else
                    Batch.DrawRegion2(player_frames(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
                End If   
            Else
                If drawleft Then
                    Batch.DrawRegion2(playeridle_framesflip(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
                Else
                    Batch.DrawRegion2(playeridle_frames(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)
                End If   
            End If               
        End If       
        Return
    End If
        
    If Abs(player.getLinearVelocityFromWorldPoint(player.WorldCenter).y) < 0.2 And Abs(player.getLinearVelocityFromWorldPoint(player.WorldCenter).x) < 0.2 Then
        'IDLE
        If drawleft Then
            Batch.DrawRegion2(playeridle_framesflip(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
        Else
            Batch.DrawRegion2(playeridle_frames(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)
        End If       
    Else
        If player.getLinearVelocityFromWorldPoint(player.WorldCenter).y > 1 Then 'JUMP
            If drawleft Then
                Batch.DrawTex2(playerjumpflip,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)               
            Else
                Batch.DrawTex2(playerjump,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
            End If   
        else if player.getLinearVelocityFromWorldPoint(player.WorldCenter).y < -0.2 Then 'FALL
            If drawleft Then
                Batch.DrawTex2(playerfallflip,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)       
            Else
                Batch.DrawTex2(playerfall,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)       
            End If   
        Else 'RUN
            If flynow Then
                If drawleft Then
                    Batch.DrawTex2(playerjumpflip,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)               
                Else
                    Batch.DrawTex2(playerjump,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
                End If   
            Else
                If drawleft Then
                    Batch.DrawRegion2(player_framesflip(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
                Else
                    Batch.DrawRegion2(player_frames(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)   
                End If                   
            End If   
        End If       
    End If
End Sub


so again the idea is checking the player body velocity to understand how your player is moving: RIGHT, LEFT, UP, DOWN

and draw the correct sprite but in special scenario act different like on lift even if player y velocity is > 0 dont draw jumping sprite else draw correct sprite after endcontact between lift and char act with the default drawing scenario.

i hope it is not too complicated what i wrote in this post :rolleyes:
 

developer_123

Active Member
Licensed User
Longtime User
your code will fail in a game.

you check if your character has begun any contact then he is not in the air (jumping) but this is wrong. any body in your world that will start contact with your character will trigger that event. the same when your character is ending a contact. let say a bullet hit your contact it will trigger the beginContact event and you will set your mCharacter.in_air to false but that also could happen in the air and then if you are alrady walking on the ground body and a bullet hits you than the begincontact will be triggered and after bullet disappear the endcontact will be triggered what means mCharacter.in_air=True even if you are still on the ground and you will draw the wrong sprite.

note that there is no constant check for starting or ending a contact so don't think that if you are on the ground body and you put log() inside begincontact that you will get on every game loop a log() that your character is touching the ground. that is not the case. you will ONLY get a log() when a CONTACT in your WOLRD between 2 bodies has started and when that CONTACT has ended!


so lets take a closer look of your problem.

a character can me in the air in 2 scenarios:

- jumping
- falling

so basically what we can check is the y- velocity of the body. if it is higher than 0 then the body is jumping if it is lower the 0 he is falling.

so what i do is in the game loop where i have my drawing function i check the velovity of the x and y. if x changes i know body is moving and i can know in what direction and also if i need to draw a running sprite or standing sprite. the same i do for the y velocity. i check if body is jumping or falling.
the y velocity check should be before the x velocity check.

NOW with this solution, we created another problem. (after making so many games i think i already know all scenarios that can happen in a game 😁)
anyway, the problem we just created is that the body y-velocity can be different than 0 even if he is not falling or jumping. HOW???

very simple, in 2 NEW scenarios:

- standing on a elevator that is moving up/down
- sliding

to solve this issue what i do is i check inside the beginContact event if the character hit the elevator_ground and if yes i dont draw the jumping falling sprite.
the same i do for sliding_ground

this is the code from my PixelKnight Game (it is written using libgdx framework):
note that i make a lot of checks like if my player is on a train or on a lift or flying or jumping or falling or sliding....


B4X:
Sub drawPlayer        
    If medead Then
        player.setLinearVelocity2(0,0)
        player.GravityScale = 0
        Return
    End If
    If Not(gamepause = True And medead = False) Then
        If frames Mod 5 = 0 Then playerindex = playerindex + 1
    End If
    Dim objcordinate As objcor
    objcordinate = player.UserData
   
    Dim vec2 As lgMathVector2
    vec2 = PosCon.box2d2world(player.Position.x,player.Position.y,0,0)
   
    If bottleON Then
        Batch.DrawTex2(playerFlyTexture, vec2.x-(vpW*0.08), vec2.y-(vpW*0.08), vpW*0.16,vpW*0.16)
    End If
   
    'check if exit gate now
    Dim gateobj As objcor = gate.UserData
    If gateobj.exitnow Then
        If player.getLinearVelocityFromWorldPoint(player.WorldCenter).x = 0 And player.getLinearVelocityFromWorldPoint(player.WorldCenter).y = 0 Then
            If exitCD < 0 Then Return
            Batch.SetColorRGBA(1,1,1,mapping(exitCD,120,0,1,0))
            Batch.DrawTex2(playervictory,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)
            Batch.SetColorRGBA(1,1,1,1)
            Return          
        End If  
    End If
   
    If ontrain Then
        If Abs(player.getLinearVelocityFromWorldPoint(player.WorldCenter).x) - Abs(trainbody.getLinearVelocityFromWorldPoint(trainbody.WorldCenter).x) > 1 Then
            If drawleft Then
                Batch.DrawRegion2(player_framesflip(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
            Else
                Batch.DrawRegion2(player_frames(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
            End If  
        Else
            If drawleft Then
                Batch.DrawRegion2(playeridle_framesflip(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
            Else
                Batch.DrawRegion2(playeridle_frames(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)
            End If  
        End If
        Return
    End If

    If onlift Then
        If objcordinate.horizontal = 0 Then
            If player.getLinearVelocityFromWorldPoint(player.WorldCenter).x <> liftonBody.getLinearVelocityFromWorldPoint(liftonBody.WorldCenter).x Then
                If drawleft Then
                    Batch.DrawRegion2(player_framesflip(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
                Else
                    Batch.DrawRegion2(player_frames(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
                End If  
            Else
                If drawleft Then
                    Batch.DrawRegion2(playeridle_framesflip(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
                Else
                    Batch.DrawRegion2(playeridle_frames(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)
                End If  
            End If
        Else
            If Abs(player.getLinearVelocityFromWorldPoint(player.WorldCenter).x) > 0.2 Then
                If drawleft Then
                    Batch.DrawRegion2(player_framesflip(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
                Else
                    Batch.DrawRegion2(player_frames(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
                End If  
            Else
                If drawleft Then
                    Batch.DrawRegion2(playeridle_framesflip(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
                Else
                    Batch.DrawRegion2(playeridle_frames(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)
                End If  
            End If              
        End If      
        Return
    End If
       
    If Abs(player.getLinearVelocityFromWorldPoint(player.WorldCenter).y) < 0.2 And Abs(player.getLinearVelocityFromWorldPoint(player.WorldCenter).x) < 0.2 Then
        'IDLE
        If drawleft Then
            Batch.DrawRegion2(playeridle_framesflip(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
        Else
            Batch.DrawRegion2(playeridle_frames(0,playerindex Mod 5),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)
        End If      
    Else
        If player.getLinearVelocityFromWorldPoint(player.WorldCenter).y > 1 Then 'JUMP
            If drawleft Then
                Batch.DrawTex2(playerjumpflip,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)              
            Else
                Batch.DrawTex2(playerjump,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
            End If  
        else if player.getLinearVelocityFromWorldPoint(player.WorldCenter).y < -0.2 Then 'FALL
            If drawleft Then
                Batch.DrawTex2(playerfallflip,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)      
            Else
                Batch.DrawTex2(playerfall,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)      
            End If  
        Else 'RUN
            If flynow Then
                If drawleft Then
                    Batch.DrawTex2(playerjumpflip,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)              
                Else
                    Batch.DrawTex2(playerjump,vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
                End If  
            Else
                If drawleft Then
                    Batch.DrawRegion2(player_framesflip(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
                Else
                    Batch.DrawRegion2(player_frames(0,playerindex Mod 8),vec2.x-objcordinate.width*1.1,vec2.y-objcordinate.height/1.85,objcordinate.width*2.1,objcordinate.height*1.8)  
                End If                  
            End If  
        End If      
    End If
End Sub


so again the idea is checking the player body velocity to understand how your player is moving: RIGHT, LEFT, UP, DOWN

and draw the correct sprite but in special scenario act different like on lift even if player y velocity is > 0 dont draw jumping sprite else draw correct sprite after endcontact between lift and char act with the default drawing scenario.

i hope it is not too complicated what i wrote in this post :rolleyes:
Hello Ilan. I appreciate this information. I was testing like I tell you in my last answer, and works fine, when the character is in air the variable in_air change to TRUE and when the character es touching any else body the variable in_air change FALSE.

Do now I'm in testing with the sprites, so I don't know yet if will appear any drawbaks, so I'm going to check your last comments carefully to put in practice.
 

ilan

Expert
Licensed User
Longtime User
when the character es touching any else body the variable in_air change FALSE.
as i said, this is a wrong behavior.
if the character touches any body (like wall, enemy, bullet, obstacles) except of the ground while being in the air then changing to in_air = false is wrong.
 

developer_123

Active Member
Licensed User
Longtime User
as i said, this is a wrong behavior.
if the character touches any body (like wall, enemy, bullet, obstacles) except of the ground while being in the air then changing to in_air = false is wrong.
You're right. I had not noticed since my game does not contain bullets and some other elements I configured intentionally with mask and category of bits so that they did not make contact, however with the ceiling and walls what you said happened. I will carefully review your answer where you relate a code example to implement the tests in mine.
 
Top