Докуметация Cтарт Статьи Форум Лента Вход
Не официальное русскоязычное сообщество

Слушатели Физики

Опубликованно: 13.06.2017, 0:10
Последняя редакция, Andry: 13.06.2017 9:06

Вы можете управлять объектами с физикой (толкать их), применяя к ним физические силы. Как правило, вы также хотите реагировать на возникающие столкновения, например. Путем вычитания очков здоровья или воспроизведения звука. Чтобы задать, как игра реагирует на такие события физики, вы используете «Слушатели физики(Physics Listeners)».

Примеры кода

PhysicsGhostObjects

Прикрепите com.jme3.bullet.control.GhostControl к любому Spatial, чтобы превратить его в объект PhysicsGhostObject. Объекты Ghost автоматически следуют за их Spatial и обнаруживают столкновения. Прикрепленный ghost сам невидим и не тверд (!) И не мешает вашей игре, он только пассивно сообщает о столкновениях.

Вы можете оставить GhostControl не твердым и невидимым и прикрепить его к (невидимому) узлу в сцене, чтобы создать нечто вроде детектора движения. Но GhostControl также отлично работает при добавлении к Spatial объектам, которые являются твердыми (с RigidBodyControl) и видимыми (с помощью Geometry). Одним из вариантов использования GhostControls является проверка столкновений между CharacterControls, когда персонажи идут.

Фигура ghost зависит от CollisionShape, которую вы дали GhostControl. Это означает, что фигура GhostControl может отличаться от фигуры RigidBodyControl. Например, не твердая фигура ghost может быть больше, чем сплошная фигура Spatial (так что вы можете «чувствовать себя впереди»).

GhostControl ghost = new GhostControl(
  new BoxCollisionShape(new Vector3f(1,1,1)));  // фигура куб ghost
Node node = new Node("a ghost-controlled thing");
node.addControl(ghost);                         // ghost следует за этим node
// Необязательно: добавить к Geometry, или другому control, node если вам нужно
...
// прикрепить все для активации
rootNode.attachChild(node);
getPhysicsSpace().add(ghost);
Методы Ghost  Применение
getOverlappingObjects()  Возвращает список объектов, которые в настоящее время сталкиваются (перекрываются) с ghost.
getOverlappingCount()  Возвращает количество текущих сталкивающихся объектов.
getOverlapping(i)  Получите номер i PhysicsCollisionObject.

Слушатель Тактов(Tick) Физики

Реализация jBullet Physics выполняется с постоянной частотой 60 тактов физики или кадров в секунду. Применение сил или проверка наложений влияет только на цикл обновления физики, который не является каждым кадром. Если вы выполняете физические взаимодействия в произвольных точках в цикле simpleUpdate(), вызовы будут отбрасываться с нерегулярными интервалами, поскольку они происходят из цикла.

Когда (не) использовать Слушатель тактов?

Когда вы пишете игровую механику, применяющие силы, необходимо реализовать для неё слушателя тактов (com.jme3.bullet.PhysicsTickListener). Слушатель тактов делает некоторые силы не отпускаемыми, но применяемыми во время следующего такта физики.

Кроме того, когда вы проверяете наложение двух физических объектов с помощью GhostControl, вы не можете просто применять ghost.getOverLappingObjects() где-то вне цикла обновления. Перед тем, как список накладывающихся объектов будет заполнен данными, вам необходимо сделать один физический такт. Опять же, PhysicsTickListener делает выбор времени для вас.

Однако, когда ваша игровая механика просто проверяет текущее состояние (например, getPhysicsLocation()) объектов с физикой, или если вы используете GhostControl как триггер сферы в цикле обновления, вам не нужен дополнительный PhysicsTickListener.

Как слушать такты физики

Вот объявление примерного Physics Control, который слушает такты. (В примере показан RigidBodyControl, но он также может быть GhostControl.)

public class MyCustomControl
    extends RigidBodyControl implements PhysicsTickListener { ... }

Когда вы реализуете интерфейс, вы должны реализовать методы physicsTick() и preTick().

  • prePhysicsTick(PhysicsSpace space, float tpf) вызывается перед каждым шагом, здесь вы применяете силы (изменяете состояние).
  • physicsTick(PhysicsSpace space, float tpf) вызывается после каждого шага, здесь вы опросите результаты (получите текущее состояние).

Значение tpf — это время за кадр в секундах. Вы можете использовать его как фактор для действий времени, чтобы они работали одинаково на медленных и быстрых машинах.

@override
public void prePhysicsTick(PhysicsSpace space, float tpf){
  // применить изменения состояния ...
}
@override
public void physicsTick(PhysicsSpace space, float tpf){
  // poll game state ...
}

Слушатель Физических Столкновение(Physics Collision Listener)

Когда (не) использовать слушатель столкновений

Если вы не реализуете интерфейс Collision Listener (com.jme3.bullet.collision.PhysicsCollisionListener), столкновения означают, что физические силы между твердыми объектами применяются автоматически. Если вы просто хотите, чтобы «Мячи катились, кирпичи падали, вам не нужен слушатель.

Если вы хотите ответить на событие столкновения (com.jme3.bullet.collision.PhysicsCollisionEvent) с помощью специального действия, вам необходимо реализовать интерфейс PhysicsCollisionListener. Типичные действия, вызванные столкновениями, включают:

  • Увеличение счетчика (например, баллов)
  • Уменьшение счетчика (например, баллов здоровья)
  • Запуск эффекта (например, взрыва)
  • Воспроизведение звука (например, взрыва, ой)
  • … и бесчисленное множество, в зависимости от вашей игры

Как Слушать Столкновения

Вы должны добавить PhysicsCollisionListener в физическое пространство до того, как будут прослушаны столкновения. Вот пример управления физикой, в котором используется слушатель столкновений. (В примере показан RigidBodyControl, но он также может быть GhostControl.)

public class MyCustomControl extends RigidBodyControl
    implements PhysicsCollisionListener {
    public MyCustomControl() {
        bulletAppState.getPhysicsSpace().addCollisionListener(this);
        ...
    }

Чтобы ответить на PhysicsCollisionEvent, теперь вы должны переопределить метод collision() в MyCustomControl. Это дает вам доступ к объекту события. В основном вас будет интересовать идентичность любых двух узлов, которые столкнулись: event.getNodeA() и event.getNodeB().

После того, как вы идентифицируете сталкивающиеся узлы, укажите действие для запуска, когда эта пара столкнется. Обратите внимание, что вы не можете знать, какой из них будет Node A а какой Node B, вам придется иметь дело с любым вариантом.

    public void collision(PhysicsCollisionEvent event) {
        if ( event.getNodeA().getName().equals("player") ) {
            final Node node = event.getNodeA();
            /** ... сделать что-то с node ... */
        } else if ( event.getNodeB().getName().equals("player") ) {
            final Node node = event.getNodeB();
            /** ... сделать что-то с node ... */
        }
    }
Обратите внимание, что после завершения метода collision(), PhysicalCollisionEvent очищается. Вы должны получить все объекты и значения, вам необходимые далее в методе collision().

Чтение деталей из PhysicsCollisionEvent

Событие PhysicsCollisionEvent дает вам доступ к подробной информации о столкновении. Вы уже знаете, что объекты событий могут идентифицировать, какие узлы столкнулись, и даже знает, как сильно они столкнулись:

Методы  Для чего
getObjectA()
getObjectB() 
Два участника столкновений. Вы не можете заранее знать, будет ли какой-либо узел записан как A или B, вам всегда нужно учитывать оба случая.
getAppliedImpulse()  float значение, представляющее собой импульс столкновения
getAppliedImpulseLateral1()  float значение, представляющее импульс бокового столкновения
getAppliedImpulseLateral2()  float значение, представляющее импульс бокового столкновения
getCombinedFriction()  float значение, представляющее трение при столкновении
getCombinedRestitution()  float значение, представляющее собой репликацию столкновения (bounciness)

Обратите внимание, что после вызова метода столкновения объект уже недействителен, поэтому вы должны скопировать любые данные, которые хотите сохранить в локальных переменных.

Группы столкновений(Collision Groups)

Вы можете повысить производительность, переназначив количество тестов, которые необходимо выполнить для обнаружения столкновений. Если у вас есть случай, когда вас интересуют только столкновения между определенными объектами, но не другими, вы можете назначать объекты с физикой разным группам столкновений.

Например, для выбора по щелчку мыши вы только заботитесь, что бы луч выбора сталкивается с несколькими выбираемыми объектами, такими как брошенное оружие или бонусы (одна группа), но не с не выбираемыми элементами, такими как полы или стены (другая группа) ,

myNode.getControl(RigidBodyControl.class).setCollisionGroup(PhysicsCollisionObject.COLLISION_GROUP_02);
myNode.getControl(RigidBodyControl.class).setCollideWithGroups(PhysicsCollisionObject.COLLISION_GROUP_02);

Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

Добавить комментарий

jMonkeyEngine.ru © 2017. Все права сохранены.