Matter.js 光标 – 如何在悬停主体时更改光标?

问题描述 投票:0回答:1

在我的网站上,我创建了一个 Matter.js 世界,其中有一堆可拖动的物体。关于如何在将鼠标悬停在我的身体上时创建抓取光标的任何简单想法都失败了。如果没有它,就没有迹象表明元素是交互式的。你知道如何改变matter.js中的光标吗?

我已经将 html 元素作为主体添加到 Matter.js 中,所以我尝试在它们上强制使用 CSS 光标设置。然后我尝试改变 mouseenter 上的光标,然后我尝试使用 Matter.js 鼠标约束来做到这一点,但都没有效果

mConstraint = MouseConstraint.create(engine, {
  mouse: mouse,
  constraint: {
    stiffness: 0.2,
    render: {
      visible: true,
    },
  },
});

 World.add(world, mConstraint);

Events.on(mConstraint, "mousemove", function (event) {
  var foundBodies = Query.point(bodies, event.mouse.position);
  if (foundBodies.length > 0) {
    console.log("foundBodies", foundBodies);
    foundBodies.forEach(function (body) {
      body.render.cursor = "grab"; 
    });
  }
});
javascript mouseevent matter.js
1个回答
0
投票

MJS 的渲染器主要用于原型设计,因此您的用例可能会突破内部渲染器的限制。根据更广泛的应用程序上下文,使用自定义渲染器可能有意义。如果您使用 DOM 作为渲染器,CSS 样式(例如光标)就会变得自然。请参阅此示例

对于使用原型渲染器,您的移动代码应该或多或少可以工作,但添加:

render.canvas.style.cursor = "default";

使用默认光标,并且

render.canvas.style.cursor = "grab";

使用抓取光标。由于只有一个光标,因此您无需在每个主体上都设置它。

这是一个更复杂的示例,使用“抓取”并处理拖动:

const engine = Matter.Engine.create();
engine.gravity.y = 0; // enable top-down
const map = {width: 300, height: 300};
const render = Matter.Render.create({
  element: document.body,
  engine,
  options: {...map, wireframes: false},
});
const player = Matter.Bodies.rectangle(
  // x y w h
  map.width / 2, map.height / 2, 35, 35,
  {frictionAir: 1}
);
const mouseConstraint = Matter.MouseConstraint.create(engine, {
  element: document.body
});
Matter.Composite.add(engine.world, [
  mouseConstraint,
  player,
]);

const touchingMouse = () =>
  Matter.Query.point(
    engine.world.bodies, // or just [player]
    mouseConstraint.mouse.position
  ).length > 0;

Matter.Events.on(engine, "beforeUpdate", event => {
  if (!mouseDown && !touchingMouse()) {
    render.canvas.style.cursor = "default";
  }
  else if (touchingMouse()) {
    render.canvas.style.cursor = mouseDown ? "grabbing" : "grab";
  }
});
let mouseDown = false;
render.canvas.addEventListener("mousedown", event => {
  mouseDown = true;

  if (touchingMouse()) {
    render.canvas.style.cursor = "grabbing";
  } else {
    render.canvas.style.cursor = "default";
  }
});
render.canvas.addEventListener("mouseup", event => {
  mouseDown = false;

  if (touchingMouse()) {
    render.canvas.style.cursor = "grab";
  } else {
    render.canvas.style.cursor = "default";
  }
});
Matter.Render.run(render);
Matter.Runner.run(Matter.Runner.create(), engine);
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>

另一种需要更多提升但可能在某些用例中派上用场的方法是在每个帧的鼠标下方放置一个不可见的传感器主体,用于检测移动时的交互:

const engine = Matter.Engine.create();
engine.gravity.y = 0; // enable top-down
const map = {width: 300, height: 300};
const render = Matter.Render.create({
  element: document.body,
  engine,
  options: {...map, wireframes: false},
});
const player = Matter.Bodies.rectangle(
  // x y w h
  map.width / 2, map.height / 2, 35, 35,
  {frictionAir: 1}
);
const mouseBody = Matter.Bodies.rectangle(
  // x y w h
  map.width / 2, map.height / 2, 1, 1, {
    isStatic: true,
    collisionFilter: {mask: 0b01},
    isSensor: true,
    render: {fillStyle: "transparent"},
  }
);
const mouseConstraint = Matter.MouseConstraint.create(engine, {
  element: document.body,
  collisionFilter: {category: 0b10},
});
Matter.Composite.add(engine.world, [
  mouseConstraint,
  player,
  mouseBody,
]);
Matter.Events.on(engine, "beforeUpdate", event => {
  Matter.Body.setPosition(
    mouseBody,
    mouseConstraint.mouse.position
  );
});
let mouseDown = false;
Matter.Events.on(engine, "collisionEnd", event => {
  if (
    !mouseDown &&
    !Matter.Collision.collides(mouseBody, player)
  ) {
    render.canvas.style.cursor = "default";
  }
});
Matter.Events.on(engine, "collisionStart", event => {
  if (
    Matter.Collision.collides(mouseBody, player)
  ) {
    render.canvas.style.cursor = mouseDown ? "grabbing" : "grab";
  }
});
render.canvas.addEventListener("mousedown", event => {
  mouseDown = true;

  if (Matter.Collision.collides(mouseBody, player)) {
    render.canvas.style.cursor = "grabbing";
  } else {
    render.canvas.style.cursor = "default";
  }
});
render.canvas.addEventListener("mouseup", event => {
  mouseDown = false;

  if (Matter.Collision.collides(mouseBody, player)) {
    render.canvas.style.cursor = "grab";
  } else {
    render.canvas.style.cursor = "default";
  }
});
Matter.Render.run(render);
Matter.Runner.run(Matter.Runner.create(), engine);
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>

© www.soinside.com 2019 - 2024. All rights reserved.