今天遇到了一个比较复杂的问题,准备用canvas实现一下这个效果
<!--/**
* @author: liuk
* @date: 2023/4/9
* @describe: 小球位置
*/-->
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=10">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="generator" content="editplus@">
<meta name="author" content="作者">
<meta name="keywords" content="关键字">
<meta name="description" content="描述">
<title>小球位置</title>
<link rel="shortcut icon" href=""/><!-- 网页图标 -->
<link rel="stylesheet" type="javascript" href="">
<style type="text/css">
canvas {
background-color: #ccc;
}
</style>
</head>
<body>
<canvas></canvas>
<script type="text/javascript">
const canvas = document.getElementsByTagName('canvas')[0],
ctx = canvas.getContext('2d');
class Ball {
constructor(startPos, direction, box, obstacle, r = 5) {
const [startX, startY] = startPos;//小球运动起点
this.x = this.limitPos(startX, r, 100);
this.y = this.limitPos(startY, r, 100);
const [direction1, direction2] = direction // 小球初始方向
this.dx = (direction2[0] - direction1[0]) / 10;
this.dy = (direction2[1] - direction1[1]) / 10;
const [box1, box2, box3, box4] = box // 外围框(暂定为长方形)
canvas.width = box3[0] - box1[0];
canvas.height = box3[1] - box1[1];
this.boxStartpos = box1;// 盒子左上点坐标
this.obstacleArr = obstacle;// 障碍物位置,求出 y = kx +b
this.k = null;
this.b = null;
this.xx = null;
this.color = 'blue';
this.r = r;
this.timer = null
}
init() {
//定时器
return new Promise((resolve, reject) => {
this.lineFn()
const self = this
this.timer = setInterval(function () {
ctx.clearRect(0, 0, canvas.width, canvas.height)
self.update();
self.renderLine()
self.renderBall();
self.isLineInner([self.x, self.y], (val) => {
resolve(val)
})
}, 10);
})
}
update() {//小球运动
this.x += this.dx;
this.y += this.dy;
if (this.x < this.r || this.x > canvas.width - this.r) {
this.dx = -this.dx;
}
if (this.y < this.r || this.y > canvas.height - this.r) {
this.dy = -this.dy;
}
}
renderBall() { // 小球渲染
ctx.beginPath();
ctx.globalAlpha = '1';
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
renderLine() {// 障碍物渲染
ctx.beginPath();
ctx.moveTo(this.obstacleArr[0][0], this.obstacleArr[0][1]);
ctx.lineTo(this.obstacleArr[1][0], this.obstacleArr[1][1]);
ctx.lineWidth = 1;
ctx.strokeStyle = 'red';
ctx.stroke()
}
limitPos(count, r, boxL) {// 限制球在盒子内
return count < r || count > boxL - r ? r : count;
}
lineFn() {//求出 障碍物的线性方程 y = kx + b
// 斜率
const k = ((this.obstacleArr[1][1] - this.obstacleArr[0][1]) / (this.obstacleArr[1][0] - this.obstacleArr[0][0]))
this.k = k
if (Math.abs(k) === Infinity) {
this.xx = this.obstacleArr[0][0]; // x = 常数
} else if (k === 0) {
this.b = this.obstacleArr[0][1]; // y = 常数}
} else {
this.b = this.obstacleArr[0][1] - (k * this.obstacleArr[0][0])
}
}
isLineInner(pos, callback) { // 判断点是否在线上
const [x, y] = pos
if (x < Math.min(this.obstacleArr[0][0], this.obstacleArr[1][0]) ||
x > Math.max(this.obstacleArr[0][0], this.obstacleArr[1][0]) ||
y < Math.min(this.obstacleArr[0][1], this.obstacleArr[1][1]) ||
y > Math.max(this.obstacleArr[0][1], this.obstacleArr[1][1])) {
return
} else if (this.xx && this.xx === x) {//情况1
callback([this.boxStartpos[0] + x, this.boxStartpos[1] + y]);
window.clearInterval(this.timer)
return [this.boxStartpos[0] + x, this.boxStartpos[1] + y]
} else if (this.k === 0 && y === this.b) {//情况2
callback([this.boxStartpos[0] + x, this.boxStartpos[1] + y]);
window.clearInterval(this.timer)
return [this.boxStartpos[0] + x, this.boxStartpos[1] + y]
} else if (this.y.toFixed() === (this.k * x + this.b).toFixed()) {//情况3
callback([this.boxStartpos[0] + x, this.boxStartpos[1] + y]);
window.clearInterval(this.timer)
return [this.boxStartpos[0] + x, this.boxStartpos[1] + y]
}
}
}
function getEndPos(startPos, direction, box, obstacle) {
const ball = new Ball(startPos, direction, box, obstacle);
ball.init().then((val) => {
alert('当前小球位置为 ' + JSON.stringify(val))
})
}
getEndPos([5, 10], [[0, 0], [5, 5]], [[0, 0], [500, 0], [500, 500], [0, 500]], [[300, 200], [300, 500]])
</script>
</body>
</html>
小球障碍物碰撞题目实现