J'utilise MatterJs pour un jeu basé sur la physique et je n'ai pas trouvé de solution au problème d'empêcher les corps d'être traînés de force par la souris à travers d'autres corps. Si vous faites glisser un corps vers un autre corps, le corps que vous faites glisser peut se forcer dans et à travers l'autre corps. Je cherche un moyen fiable de les empêcher de se croiser. Vous pouvez observer cet effet dans n'importe quelle démonstration de MatterJS en sélectionnant un corps avec la souris et en essayant de le forcer à travers un autre corps. Voici un exemple typique:
https://brm.io/matter-js/demo/#staticFriction
Malheureusement, cela interrompt tous les jeux ou simulations en fonction du glisser-déposer. J'ai tenté de nombreuses solutions, comme briser la contrainte de la souris lors d'une collision ou réduire la rigidité de la contrainte, mais rien qui fonctionne de manière fiable.
Toutes les suggestions sont les bienvenues!
Réponses:
Je pense que la meilleure réponse ici serait une refonte significative du
Matter.Resolver
module pour implémenter l'évitement prédictif des conflits physiques entre tous les corps. Tout ce qui est en deçà est garanti d'échouer dans certaines circonstances. Cela étant dit, ce sont deux "solutions" qui, en réalité, ne sont que des solutions partielles. Ils sont décrits ci-dessous.Solution 1 (mise à jour)
Cette solution présente plusieurs avantages:
L'idée derrière cette approche est de résoudre le paradoxe de ce qui se passe « lorsqu'une force imparable rencontre un objet inamovible » en rendant la force imparable. Ceci est activé par le
Matter.Event
beforeUpdate
, qui permet depositionImpulse
contraindre la vitesse absolue et l'impulsion (ou plutôt , ce qui n'est pas vraiment une impulsion physique) dans chaque direction à l'intérieur de limites définies par l'utilisateur.Dans l'exemple, je limite le
velocity
etpositionImpulse
dansx
ety
à une amplitude maximale de25.0
. Le résultat est montré ci-dessousComme vous pouvez le voir, il est possible d'être assez violent en traînant les corps et ils ne passeront pas entre eux. C'est ce qui distingue cette approche des autres: la plupart des autres solutions potentielles échouent lorsque l'utilisateur est suffisamment violent avec son glissement.
Le seul inconvénient que j'ai rencontré avec cette méthode est qu'il est possible d'utiliser un corps non statique pour frapper un autre corps non statique suffisamment fort pour lui donner une vitesse suffisante au point où le
Resolver
module ne parviendra pas à détecter la collision et à permettre la deuxième corps à traverser d'autres corps. (Dans l'exemple de friction statique, la vitesse requise est d'environ50.0
, je n'ai réussi à le faire qu'une fois avec succès, et par conséquent je n'ai pas d'animation le représentant).Solution 2
Il s'agit d'une solution supplémentaire, avertissement juste: ce n'est pas simple.
En termes généraux, la façon dont cela fonctionne consiste à vérifier si le corps en train d'être glissé,
dragBody
est entré en collision avec un corps statique et si la souris s'est depuis déplacée trop loin sansdragBody
suivre. Si elle détecte que la séparation entre la souris etdragBody
est devenu trop grand , il supprime l' écouteur d'événement de et la remplace par une fonction mousemove différente, . Cette fonction vérifie si la souris est revenue à une certaine proximité du centre du corps. Malheureusement, je n'ai pas pu faire fonctionner correctement la méthode intégrée , j'ai donc dû l'inclure directement (quelqu'un de plus compétent que moi en Javascript devra le comprendre). Enfin, si un événement est détecté, il revient à l' écouteur normal .Matter.js
mouse.mousemove
mouse.element
mousemove()
Matter.Mouse._getRelativeMousePosition()
mouseup
mousemove
Après avoir appliqué le schéma de commutation de l'écouteur d'événements, les corps se comportent maintenant comme ceci
J'ai testé cela assez minutieusement, mais je ne peux pas garantir que cela fonctionnera dans tous les cas. Il convient également de noter que l'
mouseup
événement n'est détecté que si la souris se trouve dans le canevas lorsqu'il se produit - mais cela est vrai pour toutemouseup
détection de Matter.js, donc je n'ai pas essayé de résoudre ce problème.Si la vitesse est suffisamment grande,
Resolver
elle ne détectera aucune collision et, comme elle n'a pas de prévention prédictive de cette saveur de conflit physique, elle permettra au corps de passer, comme illustré ici.Cela peut être résolu en combinant avec la solution 1 .
Une dernière remarque ici, il est possible de ne l'appliquer qu'à certaines interactions (par exemple celles entre un corps statique et un corps non statique). Pour ce faire, il faut changer
(par exemple pour les corps statiques)
Solutions échouées
Au cas où de futurs utilisateurs rencontreraient cette question et trouveraient les deux solutions insuffisantes pour leur cas d'utilisation, voici quelques-unes des solutions que j'ai essayées qui n'ont pas fonctionné. Un guide en quelque sorte pour ne pas faire.
mouse.mouseup
direct: objet supprimé immédiatement.mouse.mouseup
viaEvent.trigger(mouseConstraint, 'mouseup', {mouse: mouse})
: remplacé parEngine.update
, comportement inchangé.Matter.Body.setStatic(body, false)
oubody.isStatic = false
).(0,0)
viasetForce
à l'approche d'un conflit: l'objet peut toujours passer, devrait être implémenté dansResolver
pour fonctionner réellement.mouse.element
à une autre toile viasetElement()
ou par mutationmouse.element
directement: objet supprimé immédiatement.collisionStart
: la détection de collision incohérente permet toujours de passer avec cette méthodela source
J'aurais géré la fonctionnalité d'une autre manière:
la source
matter.js
les corps glissent déjà? d' ici "... comme un ressort virtuel qui s'attache à la souris. Lorsque vous faites glisser ... le ressort est attaché [au corps] et tire dans le sens de la souris ..."Resolver
pour décider quoi faire à propos des corps en collision - après avoir parcouru ce code un peu, je m'attends à ce qu'il décide toujours d'autoriser le drag-through dans de nombreuses circonstances ..... pourrait fonctionner si vous a également implémenté votre propre version desolveVelocity
etsolvePosition
mais à ce stade, vous faites toujours manuellement ce que vous voulez que MatterJS gère directement ....Pour contrôler les collisions lorsque vous les faites glisser, vous devez utiliser le filtre de collision et les événements .
Créez des corps avec le masque de filtre de collision par défaut
0x0001
. Ajoutez des capturesstartdrag
et desenddrag
événements et définissez une catégorie de filtre de collision corporelle différente pour éviter temporairement les collisions.la source
Cela semble être lié au problème 672 sur leur page GitHub qui semble suggérer que cela se produit en raison d'un manque de détection de collision continue (CCD).
Une tentative de remédier à cela a été faite et le code pour cela peut être trouvé ici, mais le problème est toujours ouvert, il semble que vous devrez peut-être modifier le moteur pour y intégrer vous-même CCD.
la source