关于vue检测多元素碰撞的问题?

从度娘出得出如下代码:

<template>
  <div id="wrap"></div>
</template>

<script>
export default {
  data () {
    return {
      //获得wrapDiv
      wrapDiv: null,
      //定义数组存储所有的小球
      balls: [],
      title: ['11', '22', '33', '44', '55', '66', '77', '88']
    }
  },
  created () {
    this.$nextTick(function () {
      this.wrapDiv = document.getElementById("wrap");
      this.init()
    })
  },
  methods: {
    init () {
      this.createBalls();
      for (var i = 0; i < this.balls.length; i++) {
        //将所有的小球传到函数中,来实现对小球的移动
        this.moveBalls(this.balls[i]);
      }
    },
    randomNum (m, n) {
      return Math.floor(Math.random() * (n - m + 1) + m);
    },
    /**
     * 生成一个随机颜色,并返回rgb字符串值
     */
    randomColor () {
      var r = this.randomNum(0, 255);
      var g = this.randomNum(0, 255);
      var b = this.randomNum(0, 255);
      return "rgb(" + r + "," + g + "," + b + ")";
    },
    //生成小球函数
    createBalls () {
      for (var i = 0; i < this.title.length; i++) {
        var ball = document.createElement("p");
        //随机小球起始的X坐标和小球的Y坐标
        ball.x = this.randomNum(0, 700);
        ball.y = this.randomNum(0, 500);
        //随机小球的移动速度
        // ball.speed = this.randomNum(2, 5);
        ball.speed = 0.4;
        //随机小球移动的方向
        if (Math.random() - 0.5 > 0) {
          ball.xflag = true;
        } else {
          ball.xflag = false;
        }
        if (Math.random() - 0.5 > 0) {
          ball.yflag = true;
        } else {
          ball.yflag = false;
        }
        //随机小球的背景颜色
        ball.style.backgroundColor = this.randomColor();
        // ball.innerHTML = i + 1;
        ball.innerHTML = this.title[i];
        //将小球插入当wrapDiv中
        this.wrapDiv.appendChild(ball);
        //将所有的小球存储到数组中
        this.balls.push(ball);
      }
    },
    moveBalls (ballObj) {
      var _this = this
      setInterval(function () {
        ballObj.style.top = ballObj.y + "px";
        ballObj.style.left = ballObj.x + "px";
        //判断小球的标志量,对小球作出相应操作
        if (ballObj.yflag) {
          //小球向下移动 下边界
          ballObj.y += ballObj.speed;
          if (ballObj.y >= 500 - ballObj.offsetWidth) {
            ballObj.y = 500 - ballObj.offsetWidth;
            ballObj.yflag = false;
          }
        } else {
          //小球向上移动
          ballObj.y -= ballObj.speed;
          if (ballObj.y <= 0) {
            ballObj.y = 0;
            ballObj.yflag = true;
          }
        }
        if (ballObj.xflag) {
          //小球向右移动 右边界
          ballObj.x += ballObj.speed;
          if (ballObj.x >= 700 - ballObj.offsetHeight) {
            ballObj.x = 700 - ballObj.offsetHeight;
            ballObj.xflag = false;
          }
        } else {
          //小球向左移动
          ballObj.x -= ballObj.speed;
          if (ballObj.x <= 0) {
            ballObj.x = 0;
            ballObj.xflag = true;
          }
        }
        _this.crash(ballObj);
      }, 10);
    },
    crash (ballObj) {
      var x1, y1, x2, y2;
      //通过传过来的小球对象来获取小球的X坐标和Y坐标
      x1 = ballObj.x;
      y1 = ballObj.y;
      for (var i = 0; i < this.balls.length; i++) {
        //确保不和自己对比
        if (ballObj != this.balls[i]) {
          x2 = this.balls[i].x;
          y2 = this.balls[i].y;
          //判断位置的平方和小球的圆心坐标的关系 相距多长时触碰反弹
          if (Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) + 500 <= Math.pow(ballObj.offsetWidth + this.balls[i].offsetWidth, 2)) {
            //判断传过来的小球对象,相对于碰撞小球的哪个方位
            if (ballObj.x < this.balls[i].x) {
              if (ballObj.y < this.balls[i].y) {
                //小球对象在被碰小球的左上角
                ballObj.yflag = false;
                ballObj.xflag = false;
              } else if (ballObj.y > this.balls[i].y) {
                //小球对象在被碰小球的左下角
                ballObj.xflag = false;
                ballObj.yflag = true;
              } else {
                //小球对象在被撞小球的正左方
                ballObj.xflag = false;
              }
            } else if (ballObj.x > this.balls[i].x) {
              if (ballObj.y < this.balls[i].y) {
                //小球对象在被碰撞小球的右上方
                ballObj.yflag = false;
                ballObj.xflag = true;
              } else if (ballObj.y > this.balls[i].y) {
                //小球对象在被碰撞小球的右下方
                ballObj.xflag = true;
                ballObj.yflag = true;
              } else {
                //小球对象在被撞小球的正右方
                ballObj.xflag = true;
              }
            } else if (ballObj.y > this.balls[i].y) {
              //小球对象在被撞小球的正下方
              ballObj.yflag = true;
            } else if (ballObj.y < this.balls[i].y) {
              //小球对象在被撞小球的正上方
              ballObj.yflag = false;
            }
          }
        }
      }
    }
  }
}
</script>

但经测试元素得碰撞区域比元素本身要大很多,如图

1673259898913.png

我感觉问题出在这一句,不知道对不对,因为 Math.pow 算的是平方

if (Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) + 500 <= Math.pow(ballObj.offsetWidth + this.balls[i].offsetWidth, 2))

经尝试后效果仍然无法达到触碰元素本身边缘弹开得效果,还望指点迷津,谢谢!

阅读 1.8k
2 个回答
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      html,
      body {
        height: 100%;
      }
      body {
        margin: 0;
      }
      * {
        box-sizing: border-box;
      }
      #wrap {
        position: relative;
        height: 100%;
      }
      #wrap p {
        width: 100px;
        height: 100px;
        margin: 0;
        position: absolute;
        display: flex;
        justify-content: center;
        align-items: center;
      }
    </style>
  </head>
  <body>
    <div id="wrap"></div>
    <script>
      let wrapDiv = null;
      //定义数组存储所有的小球
      const balls = [];
      const title = ['11', '22', '33', '44', '55', '66', '77', '88'];
      wrapDiv = document.getElementById('wrap');
      const { width, height } = wrapDiv.getBoundingClientRect();
      init();
      function init() {
        createBalls();
        for (var i = 0; i < balls.length; i++) {
          //将所有的小球传到函数中,来实现对小球的移动
          moveBalls(balls[i]);
        }
      }
      function randomNum(m, n) {
        return Math.floor(Math.random() * (n - m + 1) + m);
      }
      /**
       * 生成一个随机颜色,并返回rgb字符串值
       */
      function randomColor() {
        var r = randomNum(0, 255);
        var g = randomNum(0, 255);
        var b = randomNum(0, 255);
        return 'rgb(' + r + ',' + g + ',' + b + ')';
      }
      //生成小球函数
      function createBalls() {
        const fragment = document.createDocumentFragment();
        for (var i = 0; i < title.length; i++) {
          var ball = document.createElement('p');
          //随机小球起始的X坐标和小球的Y坐标
          ball.x = randomNum(0, width - 100);
          ball.y = randomNum(0, height - 100);
          //随机小球的移动速度
          // ball.speed = this.randomNum(2, 5);
          ball.speed = 0.4;
          //随机小球移动的方向
          if (Math.random() - 0.5 > 0) {
            ball.xflag = true;
          } else {
            ball.xflag = false;
          }
          if (Math.random() - 0.5 > 0) {
            ball.yflag = true;
          } else {
            ball.yflag = false;
          }
          //随机小球的背景颜色
          ball.style.backgroundColor = randomColor();
          // ball.innerHTML = i + 1;
          ball.innerHTML = title[i];
          //将小球插入当wrapDiv中
          fragment.appendChild(ball);
          //将所有的小球存储到数组中
          balls.push(ball);
        }
        wrapDiv.appendChild(fragment);
      }
      function moveBalls(ballObj) {
        setInterval(function () {
          ballObj.style.top = ballObj.y + 'px';
          ballObj.style.left = ballObj.x + 'px';
          //判断小球的标志量,对小球作出相应操作
          if (ballObj.yflag) {
            //小球向下移动 下边界
            ballObj.y += ballObj.speed;
            // 100指的是元素高度
            if (ballObj.y >= height - 100) {
              ballObj.y = height - 100;
              ballObj.yflag = false;
            }
          } else {
            //小球向上移动
            ballObj.y -= ballObj.speed;
            if (ballObj.y <= 0) {
              ballObj.y = 0;
              ballObj.yflag = true;
            }
          }
          if (ballObj.xflag) {
            //小球向右移动 右边界
            ballObj.x += ballObj.speed;
            // 100指的是元素宽度
            if (ballObj.x >= width - 100) {
              ballObj.x = width - 100;
              ballObj.xflag = false;
            }
          } else {
            //小球向左移动
            ballObj.x -= ballObj.speed;
            if (ballObj.x <= 0) {
              ballObj.x = 0;
              ballObj.xflag = true;
            }
          }
          crash(ballObj);
        }, 10);
      }
      function crash(ballObj) {
        var x1, y1, x2, y2;
        //通过传过来的小球对象来获取小球的X坐标和Y坐标
        x1 = ballObj.x;
        y1 = ballObj.y;
        for (var i = 0; i < balls.length; i++) {
          //确保不和自己对比
          if (ballObj != balls[i]) {
            x2 = balls[i].x;
            y2 = balls[i].y;
            // 100分别指的是当前元素宽高,x1 - x2小于宽度并且y1-y2小于高度
            if (Math.abs(x1 - x2) <= 100 && Math.abs(y1 - y2) <= 100) {
              //判断传过来的小球对象,相对于碰撞小球的哪个方位
              if (x1 <= x2) {
                if (y1 <= y2) {
                  //小球对象在被碰小球的左上角
                  ballObj.yflag = false;
                  ballObj.xflag = false;
                } else {
                  //小球对象在被碰小球的左下角
                  ballObj.xflag = false;
                  ballObj.yflag = true;
                }
              } else {
                if (y1 < y2) {
                  //小球对象在被碰撞小球的右上方
                  ballObj.yflag = false;
                  ballObj.xflag = true;
                } else {
                  //小球对象在被碰撞小球的右下方
                  ballObj.xflag = true;
                  ballObj.yflag = true;
                }
              }
            }
          }
        }
      }
    </script>
  </body>
</html>

用原生js写了下,你的判断逻辑写太多了,那些正上方正下方可以看成是左上角右下角的特例子,其实碰撞逻辑就是Math.abs(x1 - x2) <= width && Math.abs(y1 - y2) <= height; width,heigth指的就是当前元素的宽高

把元素p css内置的padding设置为0 padding 0; margin:0 box-sizing:border-box

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题