Я использую MatterJs для игры, основанной на физике, и не нашел решения проблемы предотвращения принудительного перетаскивания тел мышкой через другие тела. Если вы перетаскиваете тело в другое тело, перетаскиваемое тело может заставить себя проникнуть в другое тело и пройти через него. Я ищу надежный способ предотвратить их пересечение. Вы можете наблюдать этот эффект в любой демонстрации MatterJS, выделив тело мышью и попытавшись протолкнуть его через другое тело. Вот типичный пример:
https://brm.io/matter-js/demo/#staticFriction
К сожалению, это нарушает любые игры или симуляции в зависимости от перетаскивания. Я пробовал многочисленные решения, такие как нарушение ограничения мыши при столкновении или уменьшение жесткости ограничения, но ничего, что работало бы надежно.
Любые предложения приветствуются!
Ответы:
Я думаю, что лучшим ответом здесь будет значительный пересмотр
Matter.Resolver
модуля для реализации прогностического предотвращения физических конфликтов между любыми телами. Все, кроме этого, гарантированно потерпит неудачу при определенных обстоятельствах. При этом здесь говорится о двух «решениях», которые на самом деле являются лишь частичными решениями. Они изложены ниже.Решение 1 (обновление)
Это решение имеет несколько преимуществ:
Идея этого подхода состоит в том, чтобы разрешить парадокс того, что происходит, « когда непреодолимая сила встречает неподвижный объект », делая силу остановить. Это обеспечивается функцией
Matter.Event
beforeUpdate
, которая позволяетpositionImpulse
ограничить абсолютную скорость и импульс (или, точнее , не являющийся физическим импульсом) в каждом направлении в пределах определенных пользователем границ.В примере я ограничивая
velocity
иpositionImpulse
вx
иy
до максимальной величины25.0
. Результат показан нижеКак вы можете видеть, можно перетаскивать тела, и они не будут проходить друг через друга. Это то, что отличает этот подход от других: большинство других потенциальных решений терпят неудачу, когда пользователь достаточно жесток с их перетаскиванием.
Единственный недостаток, с которым я столкнулся при использовании этого метода, заключается в том, что можно использовать нестатическое тело, чтобы ударить другое нестатическое тело достаточно сильно, чтобы дать ему достаточную скорость до точки, где
Resolver
модуль не сможет обнаружить столкновение и позволить второе тело, чтобы пройти через другие тела. (В примере со статическим трением требуемая скорость равна примерно50.0
, мне удалось сделать это успешно только один раз, и, следовательно, у меня нет анимации, изображающей это).Решение 2
Это дополнительное решение, хотя справедливое предупреждение: оно не простое.
В общих чертах, способ, которым это работает, состоит в том, чтобы проверить
dragBody
, столкнулось ли тело с статическим телом, и с тех пор ли мышь зашла слишком далеко безdragBody
следования. Если он обнаруживает , что разделение между мышью иdragBody
становится слишком большим , что снимает слушатель событий от и заменяет его на другую функцию MouseMove, . Эта функция проверяет, вернулась ли мышь в заданную близость к центру тела. К сожалению, я не мог заставить встроенный метод работать должным образом, поэтому мне пришлось включить его напрямую (кто-то, более опытный, чем я, в Javascript должен будет это выяснить). Наконец, если событие обнаружено, оно переключается обратно к обычному слушателю.Matter.js
mouse.mousemove
mouse.element
mousemove()
Matter.Mouse._getRelativeMousePosition()
mouseup
mousemove
После применения схемы переключения слушателя событий тела теперь ведут себя примерно так
Я проверил это довольно тщательно, но я не могу гарантировать, что это будет работать в каждом случае. Следует также отметить, что
mouseup
событие не обнаружено, если только мышь не находится внутри холста, когда это происходит, но это верно для любого Matter.jsmouseup
обнаружения поэтому я не пытался это исправить.Если скорость достаточно велика,
Resolver
не удастся обнаружить какое-либо столкновение, и поскольку ей не хватает прогностического предотвращения этой разновидности физического конфликта, это позволит телу пройти, как показано здесь.Это может быть решено путем объединения с решением 1 .
Последнее замечание: возможно применить это только к определенным взаимодействиям (например, между статическим и нестатическим телом). Это достигается путем изменения
(например, для статических тел)
Неудачные решения
В случае, если какие-либо будущие пользователи столкнутся с этим вопросом и сочтут оба решения недостаточными для своего варианта использования, вот некоторые из решений, которые я пробовал, которые не работали. Путеводитель по тому, что не надо делать.
mouse.mouseup
напрямую: объект удален немедленно.mouse.mouseup
черезEvent.trigger(mouseConstraint, 'mouseup', {mouse: mouse})
: переопределеноEngine.update
, поведение без изменений.Matter.Body.setStatic(body, false)
илиbody.isStatic = false
).(0,0)
viasetForce
при приближении к конфликту: объект по-прежнему может проходить, необходимо реализовать вResolver
для фактической работы.mouse.element
на другой холст с помощьюsetElement()
или путемmouse.element
прямого изменения: объект немедленно удаляется.collisionStart
: противоречивое обнаружение столкновений по-прежнему разрешает проход с помощью этого методаисточник
Я бы справился с этой функцией по-другому:
источник
matter.js
обрабатывать тела? от сюда «... как виртуальные пружины , которая крепится к мыши При перемещении ... пружина присоединенная [к телу] и вытягивается в направлении мышей ...».Resolver
решит, что делать со сталкивающимися телами - если вы внимательно изучите этот код, я ожидаю, что он все равно решит разрешить перетаскивание при многих обстоятельствах ..... может сработать, если вы также реализован свою собственную версиюsolveVelocity
и ,solvePosition
но в этот момент вы все еще вручную делать то , что вы хотите MatterJS непосредственно обрабатывать ....Для контроля столкновения при перетаскивании необходимо использовать фильтр столкновений и события .
Создание тел с маской фильтра столкновений по умолчанию
0x0001
. Добавьте уловstartdrag
иenddrag
события и установите другую категорию фильтра столкновений тела, чтобы временно избежать столкновений.источник
Похоже, что это связано с проблемой 672 на их странице GitHub, которая, по-видимому, предполагает, что это происходит из-за отсутствия непрерывного обнаружения столкновений (CCD).
Была предпринята попытка исправить это, и код для этого можно найти здесь, но проблема все еще остается открытой, так что, похоже, вам, возможно, потребуется отредактировать движок, чтобы встроить в него CCD.
источник