Estoy usando MatterJs para un juego basado en la física y no he encontrado una solución para el problema de evitar que los cuerpos sean arrastrados por el mouse a otros cuerpos. Si arrastra un cuerpo hacia otro cuerpo, el cuerpo que está siendo arrastrado puede forzarse dentro del otro cuerpo y atravesarlo. Estoy buscando una forma confiable de evitar que se crucen. Puede observar este efecto en cualquier demostración de MatterJS seleccionando un cuerpo con el mouse e intentando forzarlo a través de otro cuerpo. Aquí está un ejemplo típico:
https://brm.io/matter-js/demo/#staticFriction
Desafortunadamente, esto rompe cualquier juego o simulación dependiendo de arrastrar y soltar. He intentado numerosas soluciones, como romper la restricción del mouse cuando se produce una colisión o reducir la rigidez de la restricción, pero nada que funcione de manera confiable.
Cualquier sugerencia bienvenida!
Respuestas:
Creo que la mejor respuesta aquí sería una revisión importante del
Matter.Resolver
módulo para implementar la prevención predictiva de conflictos físicos entre cualquier cuerpo. Cualquier cosa por debajo de eso está garantizada para fallar bajo ciertas circunstancias. Dicho esto aquí hay dos "soluciones" que, en realidad, son solo soluciones parciales. Se detallan a continuación.Solución 1 (Actualización)
Esta solución tiene varias ventajas:
La idea detrás de este enfoque es resolver la paradoja de lo que sucede " cuando una fuerza imparable se encuentra con un objeto inamovible " haciendo que la fuerza se pueda detener. Esto está habilitado por
Matter.Event
beforeUpdate
, que permite que la velocidad absoluta y el impulso (o más bienpositionImpulse
, que no es realmente un impulso físico) en cada dirección se vean restringidos dentro de los límites definidos por el usuario.En el ejemplo, estoy restringiendo
velocity
ypositionImpulse
enx
yy
a una magnitud máxima de25.0
. El resultado se muestra a continuación.Como puede ver, es posible ser bastante violento al arrastrar los cuerpos y no se atravesarán entre sí. Esto es lo que diferencia a este enfoque de los demás: la mayoría de las otras soluciones potenciales fallan cuando el usuario es lo suficientemente violento con su arrastre.
El único inconveniente que he encontrado con este método es que es posible usar un cuerpo no estático para golpear a otro cuerpo no estático lo suficientemente fuerte como para darle suficiente velocidad al punto donde el
Resolver
módulo no detectará la colisión y permitirá segundo cuerpo para pasar a través de otros cuerpos. (En el ejemplo de fricción estática, la velocidad requerida es de alrededor50.0
, solo he logrado hacer esto con éxito una vez y, en consecuencia, no tengo una animación que lo represente).Solución 2
Sin embargo, esta es una solución adicional, una advertencia justa: no es sencilla.
En términos generales, la forma en que esto funciona es verificar si el cuerpo que se está arrastrando
dragBody
, ha chocado con un cuerpo estático y si el mouse se ha movido demasiado lejos sindragBody
seguirlo. Si detecta que la separación entre el ratón ydragBody
se ha convertido en demasiado grande que elimina el detector de eventos desde y lo reemplaza con una función diferente mousemove, . Esta función verifica si el mouse ha regresado a una proximidad determinada del centro del cuerpo. Desafortunadamente, no pude lograr que el método incorporado funcionara correctamente, así que tuve que incluirlo directamente (alguien con más conocimientos que yo en Javascript tendrá que resolverlo). Finalmente, si se detecta un evento, vuelve al oyente normal .Matter.js
mouse.mousemove
mouse.element
mousemove()
Matter.Mouse._getRelativeMousePosition()
mouseup
mousemove
Después de aplicar el esquema de cambio de escucha de eventos, los cuerpos ahora se comportan más así
He probado esto bastante a fondo, pero no puedo garantizar que funcione en todos los casos. También
mouseup
vale la pena señalar que el evento no se detecta a menos que el mouse esté dentro del lienzo cuando ocurre, pero esto es cierto para cualquiermouseup
detección de Matter.js , por lo que no intenté solucionarlo.Si la velocidad es lo suficientemente grande,
Resolver
no detectará ninguna colisión y, dado que carece de prevención predictiva de este sabor de conflicto físico, permitirá que el cuerpo pase, como se muestra aquí.Esto se puede resolver combinando con la Solución 1 .
Una última nota aquí, es posible aplicar esto solo a ciertas interacciones (por ejemplo, aquellas entre un cuerpo estático y no estático). Hacerlo se logra cambiando
a (por ejemplo, cuerpos estáticos)
Soluciones fallidas
En caso de que algún usuario futuro se encuentre con esta pregunta y encuentre que ambas soluciones son insuficientes para su caso de uso, estas son algunas de las soluciones que intenté que no funcionaron. Una guía de lo que no se debe hacer.
mouse.mouseup
directamente: objeto eliminado de inmediato.mouse.mouseup
través deEvent.trigger(mouseConstraint, 'mouseup', {mouse: mouse})
: anulado porEngine.update
, comportamiento sin cambios.Matter.Body.setStatic(body, false)
obody.isStatic = false
).(0,0)
travéssetForce
cuando se acerca al conflicto: el objeto aún puede pasar, necesitaría implementarseResolver
para que realmente funcione.mouse.element
a un lienzo diferente a travéssetElement()
o mutandomouse.element
directamente: objeto eliminado de inmediato.collisionStart
: la detección de colisión inconsistente todavía permite pasar con este métodofuente
Hubiera gestionado la función de otra manera:
fuente
matter.js
maneja arrastrar cuerpos ya? desde aquí "... como un resorte virtual que se adhiere al mouse. Al arrastrar ... el resorte se une [al cuerpo] y tira en la dirección del mouse ..."Resolver
para decidir qué hacer con los cuerpos en colisión; después de haber examinado ese código un poco, espero que todavía decida permitir el arrastre en muchas circunstancias ... podría funcionar si usted también implementó su propia versión desolveVelocity
y,solvePosition
pero en ese punto todavía está haciendo manualmente lo que desea que MatterJS maneje directamente ...Para controlar la colisión cuando se arrastra, debe utilizar el filtro de colisión y los eventos .
Cree cuerpos con la máscara de filtro de colisión predeterminada
0x0001
. Agregue capturasstartdrag
yenddrag
eventos y establezca diferentes categorías de filtro de colisión corporal para evitar temporalmente colisiones.fuente
Esto parece estar relacionado con el problema 672 en su página de GitHub, que parece sugerir que esto ocurre debido a la falta de detección continua de colisiones (CCD).
Se ha intentado remediar esto y el código se puede encontrar aquí, pero el problema aún está abierto, por lo que parece que necesitará editar el motor para construir CCD en usted mismo.
fuente