CTO at Unnyhog, Backend/Game-dev (Java/C#/Nodejs)
0,2
рейтинг
10 декабря 2012 в 23:56

Разработка → Работа с ContactListener из Box2d в Libgdx tutorial

В продолжение прошлой статьи про использование Box2d в Libgdx решил рассмотреть работу с классом ContactListener.

Из наименования класса очевидно, что использовать его следует для обработки коллизий. Рассмотрим пару практических примеров.

image


ContactListener — интерфейс, который можно реализовать в своём классе для дальнейшего использования в игровом мире.

Необходимо реализовать 4 метода: beginContact, endContact, preSolve, postSolve.

Наш класс будет иметь примерно такой вид:
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){
    	  
      }

}


Чтобы использовать его, необходимо назначить его игровому миру.
world.setContactListener(new MyContactListener());


beginContact

Срабатывает, когда два объекта начинают накладываться. Прокает только в рамках шага.

endContact

Срабатывает, когда два объекта прекращают соприкасаться. Может быть вызван, когда тело разрушено, таким образом, это событие может иметь место вне временного шага.

preSolve

Срабатывает после обнаружения столкновения, но перед его обработкой. Это позволяет нам как-то изменить контакт до его обработки. Например, можно сделать контакт неактивным. Возьмём пример из прошлой статьи. Мы использовали движущуюся платформу. Допустим, вы хотите сделать так, чтобы персонаж проходил сквозь неё. Тогда preSolve будет выглядеть так:
     @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") используется для идентификации объекта. Напомню, что при создании платформы используется метод platform.getFixtureList().get(0).setUserData("p").


postSolve

Метод позволяет осуществить логику игры, которая изменяет физику после контакта. Например, деформировать или уничтожить объект после контакта. Однако, Box2D не позволяет вам изменять физику в методе, потому что вы могли бы разрушить объекты, которые Box2D в настоящее время обрабатывает, приводя к ошибке.

Есть тут одна тонкость — нельзя просто удалить объект, так как он может обрабатываться где-то в данный момент, и в итоге вы получите ошибку:
java.lang.NullPointerException
at com.badlogic.gdx.physics.box2d.World.contactFilter


И так, в методе будем удалять блоки, с которыми столкнулись.

@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); 		  
    	  }
      }


Теперь, при столкновении блоки, для которых задано getFixtureList().get(0).setUserData("b") будут уничтожены. Я писал сверху, что при обычном удалении будет ошибка. Но, если перед удалением сделать объект неактивным body.setActive(false), то ошибки не будет.


Исходники

Можете скачать исходники с блога. Они довольно сыроваты, правда. Но понять принципы работы помогут.
CTO at Unnyhog, Backend/Game-dev (Java/C#/Nodejs)
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (5)

  • 0
    Срабатывает после обнаружения столкновения, но перед его обработкой. Это позволяет нам как-то изменить контакт до его обработки. Например, можно сделать контакт неактивным.


    Для этого есть группы коллизий и фильтры в Box2D.
    • 0
      contactFilter?

      Одно и то же в LibGDX можно реализовать по разному. Я лишь один из вариантов предложил.
      • 0
        А причем тут LibGDX? Box2D он и в африке Box2D, это физический движок. И я подметил то, что для фильтров столкновений — нужно использовать contactFilter или группы столкновений. Эти два варианта не ищут данные для контакта.
        • 0
          Может вы и правы. Как я уже говорил, Box2D я не так давно начал изучать и с contactFilter пока не работал.
        • 0
          Я достал свою лопату и решил все таки прокомментировать.

          Одно из применений PostSolve — возможность реализации «частичной» фильтрации коллизий. Например, платформа, на которую можно запрыгнуть снизу вверх (коллизии нет), и стоять на ней, спрыгнув на нее сверху вниз (коллизия есть).

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.