📜 ⬆️ ⬇️

Working with ContactListener from Box2d to Libgdx

In continuation of the last article about using Box2d in Libgdx decided to consider working with the class ContactListener .

It is obvious from the class name that it should be used for handling collisions. Consider a couple of practical examples.

image

')
ContactListener is an interface that can be implemented in its class for future use in the game world.

It is necessary to implement 4 methods: beginContact , endContact , preSolve , postSolve .

Our class will look something like this:
 public class MyContactListener implements ContactListener{ @Override public void endContact(Contact contact) { } @Override public void beginContact(Contact contact) { } @Override public void preSolve (Contact contact, Manifold oldManifold){ } @Override public void postSolve (Contact contact, ContactImpulse impulse){ } } 


To use it, you must assign it to the game world.
 world.setContactListener(new MyContactListener()); 


beginContact

It works when two objects start to overlap. Prokat only in the framework of the step.

endContact

It is triggered when two objects stop touching. It can be triggered when the body is destroyed, so this event can take place outside the time step.

preSolve

It works after a collision is detected, but before it is processed. This allows us to somehow change the contact before it is processed. For example, you can make the contact inactive. Take an example from a previous article. We used a moving platform. Suppose you want to make a character pass through it. Then preSolve will look like this:
  @Override public void preSolve (Contact contact, Manifold oldManifold){ WorldManifold manifold = contact.getWorldManifold(); for(int j = 0; j < manifold.getNumberOfContactPoints(); j++){ if(contact.getFixtureA().getUserData() != null && contact.getFixtureA().getUserData().equals("p")) contact.setEnabled(false); if(contact.getFixtureB().getUserData() != null && contact.getFixtureB().getUserData().equals("p")) contact.setEnabled(false); } } 


contact.getFixtureA().getUserData().equals("p") used to identify an object. I recall that when creating a platform, the platform.getFixtureList().get(0).setUserData("p") method is used.


postSolve

The method allows you to implement the logic of the game, which changes the physics after contact. For example, deform or destroy an object after contact. However, Box2D does not allow you to change the physics in the method, because you could destroy objects that Box2D is currently processing, leading to an error.

There is one subtlety here - you cannot just delete an object, since it can be processed somewhere at the moment, and in the end you will get an error:
java.lang.NullPointerException
at com.badlogic.gdx.physics.box2d.World.contactFilter


And so, in the method we will delete the blocks that we encountered.

 @Override public void postSolve (Contact contact, ContactImpulse impulse){ Body body = null; if(contact.getFixtureA() != null &amp;&amp; contact.getFixtureA().getUserData() != null &amp;&amp; contact.getFixtureA().getUserData().equals("b")) body = contact.getFixtureA().getBody(); if(contact.getFixtureB() != null &amp;&amp; contact.getFixtureB().getUserData() != null &amp;&amp; contact.getFixtureB().getUserData().equals("b")) body = contact.getFixtureB().getBody(); if(body != null){ body.setActive(false); world.destroyBody(body); } } 


Now, in a collision, the blocks for which getFixtureList().get(0).setUserData("b") is specified will be destroyed. I wrote above that during a normal deletion there would be an error. But, if you make the object inactive body.setActive(false) before deletion, there will be no error.


Sources

You can download the source from the blog . They are pretty damp, really. But to understand the principles of work will help.

Source: https://habr.com/ru/post/162079/


All Articles