I want to achieve a situation where, when I drag the end of the chain to the object on the right, the end sticks to the object (i.e., both sides are parallel). However, I tried adding constraints to two points, and it had no effect, and even a single point constraint didn’t work.
Now my idea is to create a groove where the end of the chain can be embedded or removed.
How can this be achieved? (Providing a specific method to achieve the effect of the two sides sticking together would also be helpful.)
my codepan demo: https://codepen.io/your-work
window.addEventListener("load", function () {
const {
Engine,
Render,
World,
Bodies,
Composite,
Runner,
Mouse,
MouseConstraint,
Constraint,//约束(类似弹簧等等)
Events,Body,Composites
} = Matter;
var engine = Engine.create();
var render = Render.create({
element: document.body,
engine
});
// 创建插座socket600, 200, 40, 20
const mainRectangle = Bodies.rectangle(600, 200, 40, 20, {
isStatic: true,
render: { fillStyle: "#ff0000" }
});
//580, 200, 20, 15
const notch = Bodies.rectangle(580, 200, 20, 15,{isStatic: true,});
//Body.setPosition(notch, { x: 580, y: 225 });
//Body.setPosition(notch, { x: 180, y: 225 });
const socket = Body.create({
parts: [mainRectangle, notch],
isStatic: true
});
World.add(engine.world, socket);
// 创建链
var group = Body.nextGroup(true);
//12会扭动,10会像鱼一样扭动
var ropeA = Composites.stack(100, 50, 10, 1, 5, 5, function (x, y) {
//创建刚体(链节)
return Bodies.rectangle(x, y, 50, 10, {
collisionFilter: { group: group },
damping:1,
frictionAir: 0.001 //空气阻力
});
});
//将复合主体的所有主体(一系列刚体)链接起来;
Composites.chain(ropeA, 0.5, 0, -0.5, 0, {
stiffness: 0.8,//链接硬度,越大越坚固不易弯曲
length: 2,//每个连接之间的间距
render: { type: "line" } //渲染器设置,这里设置显示出连接的线条
});
//*向一个复合体(Composite)中添加新的元素。
//复合体(链子)上再添加单个或多个主体、约束或复合体[挂点]
Composite.add(
ropeA,//复合体
Constraint.create({ //用于创建一个约束(类似一个虚拟的弹簧或杆),连接两个物体或一个物体的两个点。
bodyB: ropeA.bodies[0],
pointB: { x: -25, y: 0 },
pointA: { x: ropeA.bodies[0].position.x, y: ropeA.bodies[0].position.y },
damping:1,//越大,弹力越弱
stiffness: 0.8//弹性程度,数值越高越不容易拉伸
})
);
// 添加链和地面
Composite.add(engine.world, [
//socket,
ropeA,
Bodies.rectangle(400, 600, 1200, 50.5, { isStatic: true }),
//socket
]);
// 添加鼠标控制
var mouse = Mouse.create(render.canvas);
var mouseConstraint = MouseConstraint.create(engine, {
mouse: mouse,
constraint: {
stiffness: 0.2,
render: {
visible: false
}
}
});
Composite.add(engine.world, mouseConstraint);
// 生成器和渲染器
var runner = Runner.create();
Runner.run(runner, engine);
Render.run(render);
// 变量来跟踪链子的末端是否连接到插座
let isPluggedIn = false;
let endConstraint_top = null,
endConstraint_bottom = null;
// 事件监听器: 在每次刷新时检测链子的末端是否接触到插座
Events.on(engine, "beforeUpdate", function () {
const endBody = ropeA.bodies[ropeA.bodies.length - 1];
//计算两个向量的长度
const distance = Matter.Vector.magnitude(
Matter.Vector.sub(socket.position, endBody.position)
);
if (distance < 46 && !isPluggedIn) {
// 吸附效果:创建约束将链子的末端固定到插座
endConstraint_top = Constraint.create({ //约束
bodyA: endBody,
pointA: { x: 25, y: 2.5 },
bodyB: socket,
pointB: { x: -10, y: 2.5 },
stiffness: 0.6,//0.9
length: 0//0
});
endConstraint_bottom = Constraint.create({ //约束
bodyA: endBody,
pointA: { x: 25, y: -2.5 },
bodyB: socket,
pointB: { x: -10, y: 2.5 },
stiffness: 0.6,//0.9
length: 0//0
});
Composite.add(engine.world, [endConstraint_top,endConstraint_bottom]);//将约束添加入去,世界
isPluggedIn = true;
} else if (isPluggedIn && distance > 46) {
// 拔出效果:移除约束
Composite.remove(engine.world, [endConstraint_top,endConstraint_bottom]);
endConstraint = null;
isPluggedIn = false;
}
});
// 事件监听器: 当鼠标拖动时,检测是否需要解除插座连接
// Events.on(mouseConstraint, "enddrag", function (event) {
// if (event.body === ropeA.bodies[ropeA.bodies.length - 1] && isPluggedIn) {
// const endBody = ropeA.bodies[ropeA.bodies.length - 1];
// const distance = Matter.Vector.magnitude(
// Matter.Vector.sub(socket.position, endBody.position)
// );
// if (distance > 30) {
// // 拔出效果:移除约束
// Composite.remove(engine.world, endConstraint);
// endConstraint = null;
// isPluggedIn = false;
// }
// }
// });
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>文档标题</title>
<script src="https://icdn.fongdan.com/js/matter.min.js"></script>
</head>
<body>
</body>
</html>