js通过面向对象编程思想实现小球碰撞的小练习

一开始想着是通过构造函数来定义小球类,但是发现ES6的class关键字更高级和简便,但这只是简单的运用,如果有什么需要改进的地方或者不足,欢迎大家指出扶正。

首先,我们先定义一个父容器。

<div id="box"></div>

其次,就是给父容器设置定位及其它样式

#box {
				width: 700px;
				height: 500px;
				margin: 100px auto 0;
				border: 1px solid #FF0000;
				position: relative;
			}

最后就是js部分了,这里分为几块,因为是小练习,所以我并没有模块化。

首先,我们定义两个方法,生成随机数和随机色。

//随机数
		function randomNum(x, y) {
			let num = Math.floor(Math.random() * (y - x + 1) + x)
			if (Math.abs(num) > 2) {
				return num
			} else {
				return randomNum(x, y)
			}
		}
		//随机色
		function randomColor() {
			let r = randomNum(0, 255)
			let g = randomNum(0, 255)
			let b = randomNum(0, 255)
			return `rgb(${r},${g},${b})`
		}

其次,定义小球类。

//共同属性:大小,颜色、位置、圆球、速度
		//共同行为:移动、碰撞(collision)
		class Ball {
			constructor(size, color, ballLeft, ballTop, speedX, speedY) {
				this.size = size
				this.color = color
				this.ballLeft = ballLeft
				this.ballTop = ballTop
				this.speedX = speedX
				this.speedY = speedY
				this.r = size / 2
			}
			ck = () => {
				this.domBox = document.createElement("div")
				this.domBox.style.width = this.size + "px"
				this.domBox.style.height = this.size + "px"
				this.domBox.style.borderRadius = "100%"
				this.domBox.style.backgroundColor = this.color
				this.domBox.style.position = "absolute"
				box.appendChild(this.domBox)
			}
			move = () => {
				let timer = setInterval(() => {
					this.domBox.style.left = this.ballLeft + "px"
					this.domBox.style.top = this.ballTop + "px"
					this.ballLeft += this.speedX
					this.ballTop += this.speedY
					if (this.ballLeft >= 700 - this.size) {
						this.speedX = -Math.abs(this.speedX)
					}
					if (this.ballLeft <= 0) {
						this.speedX = Math.abs(this.speedX)
					}
					if (this.ballTop >= 500 - this.size) {
						this.speedY = -Math.abs(this.speedY)
					}
					if (this.ballTop <= 0) {
						this.speedY = Math.abs(this.speedY)
					}
				}, 10);
			}
			go = function() {
				this.ck()
				this.move()
			}
		}

然后就是让小球动起来了。

let ballArr = [],
			coordArr = []
		Array(5).fill(1).forEach(() => {
			let ballSize = randomNum(40, 60),
				ballLeft = randomNum(0, 640),
				ballTop = randomNum(0, 440),
				radius = ballSize / 2,
				axiosX = ballLeft + radius,
				axiosY = ballTop + radius,
				judgeCoord = () => {
					// 判断小球生成位置是否重叠
					coordArr.forEach(item => {
						if (Math.abs(item[0] - ballLeft) <= item[2] + radius) {
							ballSize = randomNum(40, 60)
							ballLeft = randomNum(0, 640)
							judgeCoord()
						}
						if (Math.abs(item[1] - ballTop) <= item[2] + radius) {
							ballSize = randomNum(40, 60)
							ballTop = randomNum(0, 440)
							judgeCoord()
						}
					})
				}
			judgeCoord()
			// 记录球的坐标及半径
			coordArr.push([axiosX, axiosY, radius])
			let ball = new Ball(ballSize, randomColor(), ballLeft, ballTop, randomNum(-6, 6), randomNum(-6, 6))
			ball.go()
			ballArr.push(ball)
		})

上面只是实现了小球与父容器的边缘碰撞检测,正常情况下,小球之间的相互碰撞也是需要判断的,所以我们在加个计时器判断每个小球是否碰撞

let isCrash = (obj1, obj2, ballArr) => {
			let mainR = obj1.r + obj2.r
			let distance = Math.sqrt(Math.pow((obj1.left + obj1.r - obj2.left - obj2.r), 2) + Math.pow((
				obj1.top + obj1.r - obj2.top - obj2.r), 2))
			if (mainR >= distance) {
				let vx = obj1.speedX
				let vy = obj1.speedY
				ballArr[obj1.index].speedX = obj2.speedX
				ballArr[obj2.index].speedX = vx
				ballArr[obj1.index].speedY = obj2.speedY
				ballArr[obj2.index].speedY = vy
			}
			return
		}
		this.setInterval(() => {
			let ballProArr = ballArr.map((item, index) => {
				return {
					index,
					left: item.ballLeft,
					top: item.ballTop,
					r: item.r,
					speedX: item.speedX,
					speedY: item.speedY
				}
			})
			ballProArr.forEach((item, index) => {
				let i = 1
				let judgeBalls = () => {
					if (index < ballProArr.length - i) {
						isCrash(item, ballProArr[index + i], ballArr)
						i++
						judgeBalls()
					}
					return
				}
				judgeBalls()
			})
		}, 10)

效果图:

 完整代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			#box {
				width: 700px;
				height: 500px;
				margin: 100px auto 0;
				border: 1px solid #FF0000;
				position: relative;
			}
		</style>
	</head>
	<body>
		<div id="box"></div>
	</body>
	<script type="text/javascript">
		//随机数
		function randomNum(x, y) {
			let num = Math.floor(Math.random() * (y - x + 1) + x)
			if (Math.abs(num) > 2) {
				return num
			} else {
				return randomNum(x, y)
			}
		}
		//随机色
		function randomColor() {
			let r = randomNum(0, 255)
			let g = randomNum(0, 255)
			let b = randomNum(0, 255)
			return `rgb(${r},${g},${b})`
		}
		//共同属性:大小,颜色、位置、圆球、速度
		//共同行为:移动、碰撞(collision)
		class Ball {
			constructor(size, color, ballLeft, ballTop, speedX, speedY) {
				this.size = size
				this.color = color
				this.ballLeft = ballLeft
				this.ballTop = ballTop
				this.speedX = speedX
				this.speedY = speedY
				this.r = size / 2
			}
			ck = () => {
				this.domBox = document.createElement("div")
				this.domBox.style.width = this.size + "px"
				this.domBox.style.height = this.size + "px"
				this.domBox.style.borderRadius = "100%"
				this.domBox.style.backgroundColor = this.color
				this.domBox.style.position = "absolute"
				box.appendChild(this.domBox)
			}
			move = () => {
				let timer = setInterval(() => {
					this.domBox.style.left = this.ballLeft + "px"
					this.domBox.style.top = this.ballTop + "px"
					this.ballLeft += this.speedX
					this.ballTop += this.speedY
					if (this.ballLeft >= 700 - this.size) {
						this.speedX = -Math.abs(this.speedX)
					}
					if (this.ballLeft <= 0) {
						this.speedX = Math.abs(this.speedX)
					}
					if (this.ballTop >= 500 - this.size) {
						this.speedY = -Math.abs(this.speedY)
					}
					if (this.ballTop <= 0) {
						this.speedY = Math.abs(this.speedY)
					}
				}, 10);
			}
			go = function() {
				this.ck()
				this.move()
			}
		}
		let ballArr = [],
			coordArr = []
		Array(5).fill(1).forEach(() => {
			let ballSize = randomNum(40, 60),
				ballLeft = randomNum(0, 640),
				ballTop = randomNum(0, 440),
				radius = ballSize / 2,
				axiosX = ballLeft + radius,
				axiosY = ballTop + radius,
				judgeCoord = () => {
					// 判断小球生成位置是否重叠
					coordArr.forEach(item => {
						if (Math.abs(item[0] - ballLeft) <= item[2] + radius) {
							ballSize = randomNum(40, 60)
							ballLeft = randomNum(0, 640)
							judgeCoord()
						}
						if (Math.abs(item[1] - ballTop) <= item[2] + radius) {
							ballSize = randomNum(40, 60)
							ballTop = randomNum(0, 440)
							judgeCoord()
						}
					})
				}
			judgeCoord()
			// 记录球的坐标及半径
			coordArr.push([axiosX, axiosY, radius])
			let ball = new Ball(ballSize, randomColor(), ballLeft, ballTop, randomNum(-6, 6), randomNum(-6, 6))
			ball.go()
			ballArr.push(ball)
		})

		let isCrash = (obj1, obj2, ballArr) => {
			let mainR = obj1.r + obj2.r
			let distance = Math.sqrt(Math.pow((obj1.left + obj1.r - obj2.left - obj2.r), 2) + Math.pow((
				obj1.top + obj1.r - obj2.top - obj2.r), 2))
			if (mainR >= distance) {
				let vx = obj1.speedX
				let vy = obj1.speedY
				ballArr[obj1.index].speedX = obj2.speedX
				ballArr[obj2.index].speedX = vx
				ballArr[obj1.index].speedY = obj2.speedY
				ballArr[obj2.index].speedY = vy
			}
			return
		}
		this.setInterval(() => {
			let ballProArr = ballArr.map((item, index) => {
				return {
					index,
					left: item.ballLeft,
					top: item.ballTop,
					r: item.r,
					speedX: item.speedX,
					speedY: item.speedY
				}
			})
			ballProArr.forEach((item, index) => {
				let i = 1
				let judgeBalls = () => {
					if (index < ballProArr.length - i) {
						isCrash(item, ballProArr[index + i], ballArr)
						i++
						judgeBalls()
					}
					return
				}
				judgeBalls()
			})
		}, 10)
	</script>
</html>

 父容器和某些条件是写死的,需要的同学可以自行改进。

扫描二维码关注公众号,回复: 16960637 查看本文章

细心的同学会发现我并没有把小球之间的碰撞行为封装在小球类中,因为我暂时还没有找到解决思路,如果你有更好的思路,欢迎与我交流,一起进步!

猜你喜欢

转载自blog.csdn.net/qq_55874738/article/details/128285771