Материя js: столкновение для тела, управляемого мышью - PullRequest
0 голосов
/ 13 января 2020

Я использую библиотеку javascript вещество js, чтобы заменить курсор на холсте HTML веществом js - тело .

Тело (форма круга) следует за курсором, используя ограничение с жесткостью 0,1 и затуханием 1.

Проблема, с которой я столкнулся, заключается в том, что столкновение воспринимается странным образом. Если я сожму достаточно, я смогу заставить объект-курсор проходить через пятна, которые закрыты другими (stati c) объектами.

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

Я также нашел эту связанную проблему:
Предотвращение силового перемещения тел через другие тела с помощью Matter JS
Однако первое решение, похоже, не дало результата. Я мог бы заморозить тело курсора, если курсор находится слишком далеко, но это может создать для пользователя ситуацию с потерянным курсором ...

Это был лучший подход, который я мог найти:

// create engine
var engine = Matter.Engine.create(),
  world = engine.world;

world.gravity.y = 0;

// create renderer
var render = Matter.Render.create({
  element: document.body,
  engine: engine,
  options: {
    width: 400,
    height: 400,
    background: "#00FFFF",
    wireframes: false,
    showAngleIndicator: true,
  }
});

Matter.Render.run(render);

// create runner
var runner = Matter.Runner.create();
Matter.Runner.run(runner, engine);

for (var i = 0; i < (new Date()).getMilliseconds(); ++i) Matter.Common.random(10, 30); //randomize random()

var ran = 0;
Matter.World.add(world, Matter.Composites.stack(10, 10, 5, 2, 20, 20, function(x, y) {
  ran = Matter.Common.random(10, 30);
  return Matter.Bodies.circle(x, y, ran, {
    isStatic: true,
    restitution: 1,
    friction: 1,
    frictionAir: 1,
    frictionStatic: 1,
    inertia: Infinity,
    render: {
      fillStyle: "#" + Math.floor(Math.random() * 16777215).toString(16)
    },
    label: "target",
    radius: ran,
  });
}));

var paddle = Matter.Bodies.circle(0, 0, 30, {
  mass: 1,
  isStatic: false,
  restitution: 1,
  friction: 0,
  inertia: Infinity,
  render: {
    fillStyle: "#000000"
  },
  label: "paddle",
  radius: 30,
});
Matter.World.add(world, paddle);


function posDif(a, b, f = 1) {
  return {
    x: f * (a.position.x - b.position.x),
    y: f * (a.position.y - b.position.y)
  };
}

Matter.Events.on(engine, "collisionActive", (event) => {
  for (var o of event.pairs) {
    if (o.bodyA == paddle && o.bodyB.label == "target") {
      var TgtDist = o.bodyB.radius + paddle.radius;
      var diff = posDif(o.bodyB, paddle);
      var ang = Math.atan2(diff.x, diff.y);

      Matter.Body.setPosition(paddle, {
        x: o.bodyB.position.x - TgtDist * Math.sin(ang),
        y: o.bodyB.position.y - TgtDist * Math.cos(ang)
      });
      con.stiffness = 0.01;
    }
    if (o.bodyB == paddle && o.bodyA.label == "target") { //same with bodyA for bodyB
      var TgtDist = o.bodyA.radius + paddle.radius;
      var diff = posDif(o.bodyA, paddle);
      var ang = Math.atan2(diff.x, diff.y);

      Matter.Body.setPosition(paddle, {
        x: o.bodyA.position.x - TgtDist * Math.sin(ang),
        y: o.bodyA.position.y - TgtDist * Math.cos(ang)
      });
      con.stiffness = 0.01;
    }
  }
});
Matter.Events.on(engine, "collisionEnd", (event) => {
  for (var o of event.pairs) {
    if (o.bodyA == paddle || o.bodyB == paddle)
      con.stiffness = 0.1;
  }
});

var mouse = Matter.Mouse.create(render.canvas),
  mouseConstraint = Matter.MouseConstraint.create(engine, {
    mouse: mouse,
    constraint: {
      angularStiffness: 0.1,
      render: {
        visible: false
      }
    }
  });

var con = Matter.Constraint.create({
  pointA: mouse.position,
  bodyB: mouseConstraint.body = paddle,
  pointB: {
    x: mouse.position.x - paddle.position.x,
    y: mouse.position.y - paddle.position.y
  },
  stiffness: 0.1,
  damping: 1,
  render: {
    visible: false
  },
});
Matter.World.add(world, con);

Matter.World.add(world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.14.2/matter.min.js"></script>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <script src="matter.min.js"></script>
  <style>
    body {
      cursor: none;
    }
  </style>
  <title>Document</title>

</head>

<body></body>

</html>

Есть ли способ получить естественное поведение курсора при столкновении, как я описал выше? Или это потребовало бы непрерывного обнаружения столкновений (CCD), которое еще не полностью поддерживается материей js?

...