<template>
<div class="about">
<div class="chart" ref="main">
<div class="circle1 circle" ref="circle2">
<span>球1<br /><span style="top: 20px;position: relative;">30分</span></span>
</div>
<div class="circle2 circle" ref="circle2">
<span>球2<br /><span style="top: 20px;position: relative;">20分</span></span>
</div>
<div class="circle3 circle" ref="circle3">
<span>球3<br /><span style="top: 20px;position: relative;margin-left: 1.5rem">25分</span></span>
</div>
<div class="circle4 circle" ref="circle4">
<span>球4<br /><span style="top: 20px;position: relative;margin-left: 2.5rem">10分</span></span>
</div>
<div class="circle5 circle" ref="circle5">
<span>球5<br /><span style="top: 20px;position: relative;margin-left: 2rem">14分</span></span>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
main: "",
//获取五个小球的div
circlesL: "",
//用来存放小球div每个的具体信息,包括坐标,速度等值
container: [],
arr: {},
//初始化运动的最大宽高,初始定义为0
maxW: [],
maxH: [],
//获取小球的直径
cwidth: [],
};
},
mounted() {
this.main = this.$refs.main;
this.circles = this.main.getElementsByClassName('circle');
// 为了让小球不卡在盒子边缘,所以要减去自身宽高
for (let index = 0; index < this.circles.length; index++) {
this.maxW.push(this.main.offsetWidth - this.circles[index].clientWidth);
this.maxH.push(this.main.offsetHeight - this.circles[index].clientHeight);
this.cwidth.push(this.circles[index].offsetWidth);
}
this.initializeCircle();
// 对每一个小球绑定计时器,让小球动起来
for (let i = 0; i < this.container.length; i++) {
this.cricleMove(this.container[i]);
}
},
methods: {
//初始化球体信息
initializeCircle() {
// 数组对象初始化
for (let i = 0; i < this.circles.length; i++) {
this.arr = {};
// 初始x坐标
this.arr.x = Math.floor(Math.random() * (this.maxW[i] + 3));
// 初始y坐标
this.arr.y = Math.floor(Math.random() * (this.maxH[i] + 5));
// 圆心x坐标
this.arr.cx = this.arr.x + this.circles[i].offsetWidth / 2;
// 圆心y坐标
this.arr.cy = this.arr.y + this.circles[i].offsetHeight / 2;
// x轴移动方向
this.arr.movex = Math.floor(Math.random() * 3);
// y轴移动方向
this.arr.movey = Math.floor(Math.random() * 3);
// 随机速度
this.arr.speed = 1 + Math.floor(Math.random() * 2);
// 计数器
this.arr.timer = null;
// 索引值
this.arr.index = i;
// 存放所有属性值
this.container.push(this.arr);
// 初始化小球位置
this.circles[i].style.left = `${this.arr.x}px`;
this.circles[i].style.top = `${this.arr.y}px`;
}
},
// 球体碰撞函数
circleCrash(index) {
const currentBall = this.container[index];
for (let i = 0; i < this.container.length; i++) {
if (i !== index) {
const otherBall = this.container[i];
// 计算两个球心的距离
const dx = otherBall.cx - currentBall.cx;
const dy = otherBall.cy - currentBall.cy;
const distance = Math.sqrt(dx * dx + dy * dy);
// 碰撞阈值,这里应该是两个球的半径之和
const collisionThreshold = (this.cwidth[currentBall.index] / 2) + (this.cwidth[otherBall.index] / 2);
if (distance < collisionThreshold) {
// 简单的互斥逻辑,像弹簧一样把球推开
// 计算重合部分的长度
const overlap = collisionThreshold - distance;
// 计算互斥方向上的单位向量
const unitX = dx / distance;
const unitY = dy / distance;
// 将球体移开使其不重叠
// 移动当前球
currentBall.x -= overlap * unitX * 0.5;
currentBall.y -= overlap * unitY * 0.5;
// 同时移动另一个球
otherBall.x += overlap * unitX * 0.5;
otherBall.y += overlap * unitY * 0.5;
// 更新球的圆心位置
currentBall.cx = currentBall.x + this.cwidth[currentBall.index] / 2;
currentBall.cy = currentBall.y + this.cwidth[currentBall.index] / 2;
otherBall.cx = otherBall.x + this.cwidth[otherBall.index] / 2;
otherBall.cy = otherBall.y + this.cwidth[otherBall.index] / 2;
// 简单地反转当前球的运动方向来模拟碰撞的响应
currentBall.movex = -unitX > 0 ? 1 : 0;
currentBall.movey = -unitY > 0 ? 1 : 0;
// 反转另一个球的运动方向
otherBall.movex = unitX > 0 ? 1 : 0;
otherBall.movey = unitY > 0 ? 1 : 0;
}
}
}
},
//球体移动函数
cricleMove(balls) {
// 每个球都有单独的定时器
balls.timer = setInterval(() => {
if (balls.movex === 1) {
// 如果向右跑,则一直加速度,碰到边界,改为反方向运动
balls.x += balls.speed;
if (balls.x + balls.speed >= this.maxW[balls.index]) {
// 防止小球移动出界限
balls.x = this.maxW[balls.index];
balls.movex = 0;
}
} else {
balls.x -= balls.speed;
if (balls.x - balls.speed <= 0) {
balls.x = 0;
balls.movex = 1;
}
}
if (balls.movey === 1) {
balls.y += balls.speed;
if (balls.y + balls.speed >= this.maxH[balls.index]) {
balls.y = this.maxH[balls.index];
balls.movey = 0;
}
} else {
balls.y -= balls.speed;
if (balls.y - balls.speed <= 0) {
balls.y = 0;
balls.movey = 1;
}
}
balls.cx = balls.x + this.circles[0].offsetWidth / 2; // 小球圆心等于:运动中x的值加上自身的半径
balls.cy = balls.y + this.circles[0].offsetHeight / 2;
this.circles[balls.index].style.left = balls.x + 'px'; // 小球相对于屏幕的位置
this.circles[balls.index].style.top = balls.y + 'px';
this.circleCrash(balls.index); // 每个小球进行碰撞检测
}, 25);
}
}
};
</script>
<style lang="scss" scoped>
@mixin lineHeight($height) {
height: $height;
line-height: $height;
}
.about {
.chart {
height: 50rem;
margin: 0 auto;
// border: 0.1rem solid rgba(6, 143, 106, 1);
position: relative;
.font_style {
text-align: center;
color: #FFFFFF;
font-size: 1.3rem;
}
.circle1 {
position: absolute;
top: 1rem;
left: 5rem;
width: 12rem;
height: 12rem;
// @include lineHeight(12rem);
border-radius: 50%;
box-shadow: inset 0px 0px 2rem 0.3rem #8F8915;
font-size: 1.5rem;
// text-align: center;
align-items: center;
display: flex;
justify-content: center;
flex-direction: row;
// display: flex;
}
.circle2 {
position: absolute;
top: 16rem;
left: 10rem;
width: 10rem;
height: 10rem;
// @include lineHeight(10rem);
border-radius: 50%;
box-shadow: inset 0px 0px 3.3rem 1.1rem #14C424;
font-size: 1.1rem;
align-items: center;
display: flex;
justify-content: center;
flex-direction: row;
}
.circle3 {
position: absolute;
top: 28rem;
left: 15rem;
width: 8rem;
height: 8rem;
// @include lineHeight(8rem);
border-radius: 50%;
box-shadow: inset 0px 0px 4rem 1.1rem #0C5EB9;
font-size: 1rem;
align-items: center;
display: flex;
justify-content: center;
flex-direction: row;
}
.circle4 {
position: absolute;
top: 25rem;
left: 2rem;
width: 10rem;
height: 10rem;
border-radius: 50%;
box-shadow: inset 0px 0px 4rem 1.1rem #5C15BD;
font-size: 1.3rem;
align-items: center;
display: flex;
justify-content: center;
flex-direction: row;
}
.circle5 {
position: absolute;
top: 38rem;
left: 5rem;
width: 8rem;
height: 8rem;
// @include lineHeight(8rem);
border-radius: 50%;
box-shadow: inset 0rem 0rem 4rem 1.1rem #256BD1;
font-size: 1rem;
align-items: center;
display: flex;
justify-content: center;
flex-direction: row;
}
}
}</style>
vue中多个小球运动 碰撞之后弹开效果
最新推荐文章于 2024-08-16 19:02:09 发布