在固定区域随机生成元素

作者: MJ 分类: javascript 发布时间: 2020-01-01 21:27

2020-01-02更新

以下方法可以参考,但是在我的需求中有点不太适用,主要是重叠几率太高了,可控性不太好,今天尝试了另一种思路:假如我们每次显示的球不会超过6个,我们其实可以预先设置10个(最好大于我们要显示的个数,方便随机显示)已经定位好的坐标点,然后随机从这10个坐标点中随机抽取6个,每抽取一个就删除掉,防止下次又取重复,这样我们就可以很好的控制球的显示位置,全部在我们已经预设好的点位上了。

核心代码就是从现有数组中随机取值:

<script>
    const arrs = [
      {
        name: "test1"
      },
      {
        name: "test2"
      },
      {
        name: "test3"
      },
      {
        name: "test4"
      },
      {
        name: "test5"
      }
    ];

    //方法1
    function getArrayItems(arr = [], num = 0) {
      let delNum, delArr, res = [];
      if (num >= arr.length) {
        res = arr.splice(0, arr.length);
      } else {
        for (let i = 0; i < num; i++) {
          delNum = Math.floor(Math.random() * arr.length);
          delArr = arr.splice(delNum, 1);
          console.log(delArr);
          res = res.concat(delArr);
        }
      }
      return res;
    }

    const arr = [1, 2];
    const res = getArrayItems(arrs, arr.length);
    console.dir(res);


    // 方法2
    function getRandomArrayElements(arr, count) {
      var shuffled = arr.slice(0), i = arr.length, min = i - count, temp, index;
      while (i-- > min) {
        index = Math.floor((i + 1) * Math.random());
        temp = shuffled[index];
        shuffled[index] = shuffled[i];
        shuffled[i] = temp;
      }
      return shuffled.slice(min);
    }

    var items = ['1', '2', '4', '5', '6', '7', '8', '9', '10'];
    console.log(getRandomArrayElements(items, 4));
  </script>

在固定区域随机生成元素,仿蚂蚁森林的能量球效果,非原创,动画部分没做,回头补一下完整版的, 在前人的基础上优化了一下,分享出来供大家参考,遗留问题还是会几率有一点重叠,如图:

完整代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>仿蚂蚁森林能量球</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .demo {
      height: 250px;
      background: #f5f5f5;
      position: relative;
      overflow: hidden;
    }

    .demo .item {
      width: 40px;
      height: 40px;
      background: #f00;
      position: absolute;
      top: 0;
      left: 0;
      border-radius: 50%;
      line-height: 40px;
      text-align: center;
      color: #fff;
    }

    .button {
      width: 100px;
      height: 100px;
      border-radius: 50%;
      position: absolute;
      bottom: 0;
      left: 0;
      right: 0;
      background: #ff0;
      margin: 0 auto;
    }
  </style>
</head>

<body>
  <div class="demo">
    <div class="item-list"></div>
    <div class="button"></div>
  </div>

  <script>
    let data = [1, 2, 3]; // 能量值
    let cWidth = document.querySelector('.demo').offsetWidth; // 能量球出现区域宽度
    let cHeight = document.querySelector('.demo').offsetHeight; // 能量球出现区域高度
    let circlePadding = 40; // 能量球宽度
    let treeHeight = 100; // 按钮高度
    let circleArr = []; // 存能量球left和top值
    let xArr = []; // 能量球top值,判断是否太近
    let r = 20; // 能量球半径

    // 生成能量球top和left
    function createList(count) {
      data.forEach(() => {
        // 随机获取能量球top和left值,防止出现超出,加上能量球自身的宽和高
        let x = randomNum(circlePadding, cWidth - circlePadding);
        let y = randomNum(circlePadding, cHeight - treeHeight - circlePadding);

        // 判断是否与已有的点太近,如果太近随机给top和left加减值
        if (!isNear(x)) {
          circleArr.push({
            x,
            y
          })
        } else {
          circleArr.push({
            x: x < circlePadding ? x + randomNum(19, circlePadding) : x - randomNum(0, circlePadding),
            y: y < circlePadding ? y + randomNum(38, circlePadding) : y - randomNum(22, circlePadding)
          });
        }

        // xArr用于判断两个能量球是否太近
        xArr.push(x);
      })
    }
    // }
    // 判断两个能量球是否太近
    function isNear(x) {
      let near = false;
      xArr.forEach(val => {
        // 本来为至少要小于2倍半径,但如果其余的点把屏幕均分了,下一个点就永远满足不了条件,故改为小于1.5倍半径,即有多于4/3个圆的部分重叠,则判断为太近
        // 这里可以根据需要更改判断条件
        if (Math.abs(x - val) < (r * 3) / 2) {
          near = true;
        }
      })
      return near;
    }
    // 生成随机数
    function randomNum(from, to) {
      return Math.floor(Math.random() * (to - from + 1) + from);
    }
    // 生成能量球
    createList(3);
    // 渲染页面
    let html = data.map((v, i) => {
      return `<div class="item" style="top:${circleArr[i].y}px;left:${circleArr[i].x}px">${v}</div>`;
    }).join('');
    document.querySelector('.item-list').innerHTML = html;
  </script>
</body>

</html>

其他的一些思路:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .demo {
      height: 300px;
      position: relative;
    }

    .item {
      width: 60px;
      height: 60px;
      background: #f00;
      position: absolute;
      top: 0;
      left: 0;
    }
  </style>
</head>

<body>
  <div class="demo">

  </div>
  <script>
    let targetWidth = document.querySelector('.demo').offsetWidth;
    let targetHeight = document.querySelector('.demo').offsetHeight;
    // console.log(targetWidth, targetHeight);
    let widthNum = parseInt(targetWidth / 60);
    let heightNum = parseInt(targetHeight / 60);
    // console.log(widthNum, heightNum);
    let allNum = widthNum * heightNum;
    // console.log(allNum);
    let arr1 = [];
    for (let i = 0; i < widthNum; i++) {
      arr1.push(i * 60);
    }
    // console.log(arr1);
    let arr2 = [];
    for (let i = 0; i < heightNum; i++) {
      arr2.push(i * 60);
    }
    // console.log(arr2);
    let arr3 = [];
    for (let i = 0; i < allNum; i++) {
      arr3.push({
        left: arr1[Math.floor(Math.random() * arr1.length)],
        top: arr2[Math.floor(Math.random() * arr2.length)]
      });
    }
    // console.log(arr3);
    let data = [1, 2, 3];
    let html = '';
    data.forEach((v, i) => {
      let res = arr3[Math.floor(Math.random() * arr3.length)];
      html += `<div class="item" style="top:${res.top}px;left:${res.left}px;">${v}</div>`;
    })
    document.querySelector('.demo').innerHTML = html;
  </script>
</body>

</html>

参考:

https://github.com/Xiangfs/ant-collect-energy

https://www.jianshu.com/p/d3de46af06ad

https://juejin.im/entry/5d088209e51d4555e372a604

https://www.cnblogs.com/tnnyang/p/9089051.html

https://bbs.csdn.net/topics/390906538?locationNum=9&fps=1

https://www.cnblogs.com/doseoer/p/5728955.html

欢迎关注小程序,感谢您的支持!

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

电子邮件地址不会被公开。 必填项已用*标注