给定 2 个圆嵌套在另一个中:有必要实现内部圆与光标的排斥,而它不应超出外部圆的边界。
class Circle {
constructor(node) {
this.DOMElement = node;
this.ctx = this.DOMElement.getContext('2d');
this.dx = 0;
this.dy = 0;
this.x = this.DOMElement.width / 2,
this.y = this.DOMElement.height / 2,
this.ballRadius = 39;
this.cirleRadius = this.DOMElement.width / 2 - 50
}
drawCircle(x, y, radius, fill) {
this.ctx.beginPath();
this.ctx[`${fill.fill}Style`] = fill.color;
this.ctx.lineWidth = 3;
this.ctx.arc(x, y, radius, 0, Math.PI*2, true);
this.ctx[fill.fill]();
this.ctx.closePath();
}
render() {
this.ctx.clearRect(0, 0, this.DOMElement.width, this.DOMElement.height);
this.drawCircle(
this.DOMElement.width / 2,
this.DOMElement.height / 2,
this.cirleRadius,
{fill: 'stroke', color: '#34648e'}
);
this.drawCircle(
this.x,
this.y,
this.ballRadius,
{fill: 'fill', color: '#0294bf'}
);
if(Math.pow(this.x - this.DOMElement.width / 2, 2) + Math.pow(this.y - this.DOMElement.height / 2, 2) >= Math.pow(this.cirleRadius - this.ballRadius, 2) ) {
// ????
}
const frame = requestAnimationFrame(this.render.bind(this))
}
init() {
let currentX = 0;
let currentY = 0;
let distance = 0;
let speed = 10;
this.DOMElement.onmousemove = (event) => {
let mouseX = event.clientX - this.DOMElement.offsetLeft - 10;
let mouseY = event.clientY - this.DOMElement.offsetTop - this.DOMElement.scrollTop + window.pageYOffset - 14;
let xResult = mouseX - currentX;
let yResult = mouseY - currentY;
distance = Math.sqrt(xResult * xResult + yResult * yResult);
if(Math.pow(mouseX - this.x, 2) + Math.pow(mouseY - this.y, 2) <= Math.pow(this.ballRadius + 5, 2) ) {
this.x += xResult / distance * speed;
this.y += yResult / distance * speed;
}
currentX = mouseX;
currentY = mouseY;
}
this.render();
}
}
const circle = new Circle(document.querySelector('#canvas'));
circle.init();
.canvas {
border: 15px solid #ebebeb;
margin: auto;
background-color: #f8f8f8;
}
<canvas id="canvas" class="canvas" width="590" height="600">
告诉我如何通过在一定距离处用光标接触球来实现有计划的“反弹”,同时在碰撞期间从外圆的边界进行同样的平滑“反弹”。
为了使运动没有抖动,有必要根据帧之间的速度和时间来计算位置。
那些。知道物体在最后一帧中的位置、它的方向、移动速度以及自上一帧以来经过了多少秒,我们计算出新的位置。
我整理了一个小例子:
我启动了一个描述球状态的对象。
挂起一个监听器,它通过以下方式更新全局鼠标位置
mousemove
编写了一个绘制循环(通过递归调用
requestAnimationFrame
),它从状态对象中获取球的位置值并绘制它+绘制外圆。启动了一个独立于绘图的循环(
setInterval
),它改变了球的状态。它做了 3 件事:处理鼠标相对于球的位置,当发生碰撞时,设置球的速度和运动矢量。
根据球的当前位置、运动矢量和速度计算球的新位置。逐渐降低移动速度。
通过计算新的反射运动矢量来处理与外圆的碰撞
反射矢量等于原始矢量减去法向矢量乘以撞击点处的法向矢量与原始矢量的双标量积。
r = i−2(i⋅n)n
这是一个工作示例:
该算法存在不准确之处,或者更确切地说是缺陷,但在此示例中它们无关紧要。
在计算球的碰撞的那一刻,当与外圆的碰撞检查成功通过时,球已经在圆外,我定义的法线正好在球的中心点,而不是在碰撞点。可以计算这一点,但这会使示例复杂化。
考虑到撞击点的运动矢量的变化,当它已经在边界之外时,没有足够的将球转移回外圈区域。这表现在这样一个事实中,即使有时您也可以直观地看到球是如何稍微超出边界的。