Vue2模拟俄罗斯方块小游戏

这篇具有很好参考价值的文章主要介绍了Vue2模拟俄罗斯方块小游戏。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、效果展示

二、代码分享

三、原理分析

3.1、界面搭建

3.2、方块创建

3.3、方块旋转

3.4、方块移动

3.5、移动判断

3.6、下落判断与清除

3.7、得分计算

一、效果展示

Vue2模拟俄罗斯方块小游戏

二、代码分享

<template>
  <div class="game">
    <div class="game-div">
      <div class="game-min">
        <div class="row" v-for="(row, i) in frame" :key="i">
          <p
            class="element"
            v-for="(col, j) in row"
            :key="j"
            :style="{ background: col.bg }"
          ></p>
        </div>
      </div>
      <!-- 小屏幕 -->
      <div class="right-div">
        <div class="ass">
          <div class="row" v-for="(row, i) in ass" :key="i">
            <p
              class="element"
              v-for="(col, j) in row"
              :key="j"
              :style="{ background: col.bg }"
            ></p>
          </div>
        </div>
        <!-- 分数计算 -->
        <div class="score-div">
          <div>
            <p>
              <span>得分:</span>&emsp;<span style="color: red">{{
                score
              }}</span>
            </p>
          </div>
          <div>
            <p>
              <span>等级:</span>&emsp;<span style="color: red">{{
                level
              }}</span>
            </p>
          </div>
          <div>
            <p>
              <span>消除:</span>&emsp;<span style="color: red">{{
                times
              }}</span>
            </p>
          </div>
          <div class="ztks" @click="stopGame">暂停/开始</div>
        </div>
      </div>
    </div>
    <!-- 控制台 -->
    <div class="control">
      <p @click="change1">变换</p>
      <div class="control-center">
        <div @click="moveLeft">向左</div>
        <div @click="moveRight">向右</div>
      </div>
      <p @click="moveDown">向下</p>
    </div>
  </div>
</template>

<script>
import { color, blockMod, transition } from "@/utils/ykdata.js";
export default {
  data() {
    return {
      row: 20, //行
      col: 10, //列
      frame: [], //界面
      ass: [], //副屏幕
      bg: "#eee",
      block: [], //基本方块集合
      now: { b: 0, c: 0 }, //当前方块以及其旋转角度
      next: { b: 0, c: 0 }, //下一个方块以及其旋转角度
      nowBlock: [], //当前形状数据
      nextBlock: [], //下一个形状数据
      xz: 0, //当前旋转角度
      timer: "", //自动下落
      speed: 800, //速度
      score: 0, //得分
      level: 1, //等级
      times: 0, //消除次数
      stop: true, //是否停止
      removeRow: [], //消除的行记录
    };
  },
  mounted() {
    this.gameFrame();
    this.getBlock(0);
    this.getNext();
    this.init();
  },
  methods: {
    // 游戏框架
    gameFrame() {
      //主屏幕
      for (let i = 0; i < this.row; i++) {
        let a = [];
        for (let j = 0; j < this.col; j++) {
          let b = {
            data: 0,
            bg: this.bg,
          };
          a.push(b);
        }
        this.frame.push(a);
      }
      //副屏幕
      for (let i = 0; i < 4; i++) {
        let a = [];
        for (let j = 0; j < 4; j++) {
          let b = {
            data: 0,
            bg: this.bg,
          };
          a.push(b);
        }
        this.ass.push(a);
      }
      // 模拟格子被占用
      // this.frame[4][4].bg = "#00aaee";
      // this.frame[4][4].data = 1;
    },
    // 渲染方块
    getBlock(e) {
      this.block = blockMod(color[e]);
    },
    // 下一个形状
    async getNext() {
      // 随机获取形状
      this.next.b = Math.floor(Math.random() * this.block.length);
      this.next.c = Math.floor(Math.random() * 4);
    },
    // 渲染当前形状
    init() {
      // 获取到下一个形状数据
      this.now = JSON.parse(JSON.stringify(this.next));
      this.xz = this.now.c;
      // 当前形状数据
      this.nowBlock = JSON.parse(JSON.stringify(this.block[this.now.b]));
      //   渲染形状数据
      //   let c = this.nowBlock.site;
      //   for (let i = 0; i < c.length; i += 2) {
      //     this.frame[c[i]][c[i + 1]].bg = this.nowBlock.color;
      //   }
      this.renderBlock(this.nowBlock, this.frame, 1);
      // 旋转
      if (this.now.c > 0) {
        for (let i = 0; i < this.now.c; i++) {
          this.change(this.nowBlock, this.frame, this.now, i);
        }
      }
      this.getNext().then(() => {
        if (this.nextBlock.site) {
          this.renderBlock(this.nextBlock, this.ass, 0);
        }
        //   下一个形状
        this.nextBlock = JSON.parse(JSON.stringify(this.block[this.next.b]));
        this.renderBlock(this.nextBlock, this.ass, 1);
        // 旋转
        if (this.next.c > 0) {
          for (let i = 0; i < this.next.c; i++) {
            this.change(this.nextBlock, this.ass, this.next, i);
          }
        }
      });
    },
    // 渲染形状
    // b:方块,d:位置,n:0擦除,1生成,2确定落到最下层
    renderBlock(b, d, n) {
      let c = b.site;
      if (n == 0) {
        for (let i = 0; i < c.length; i += 2) {
          d[c[i]][c[i + 1]].bg = this.bg; //0擦除
        }
      } else if (n == 1) {
        for (let i = 0; i < c.length; i += 2) {
          d[c[i]][c[i + 1]].bg = b.color; //1生成
        }
      } else if (n == 2) {
        for (let i = 0; i < c.length; i += 2) {
          d[c[i]][c[i + 1]].data = 1; //2确定落到最下层
        }
      }
    },
    // 旋转 b:当前方块   d:渲染的位置   z:渲染的对象现在还是下一个  xz:当前旋转角度
    change(b, d, z, xz) {
      this.renderBlock(b, d, 0); //先清空再旋转
      // 记录第一块位置
      const x = b.site[0];
      const y = b.site[1];
      for (let i = 0; i < b.site.length; i += 2) {
        let a = b.site[i];
        b.site[i] = b.site[i + 1] - y + x + transition[z.b][xz].x;
        b.site[i + 1] = -(a - x) + y + transition[z.b][xz].y;
      }
      xz++;
      if (xz == 4) {
        xz = 0;
      }
      this.renderBlock(b, d, 1);
    },
    // 向下移动
    moveDown() {
      if (this.canMove(3)) {
        // 先清空
        this.renderBlock(this.nowBlock, this.frame, 0);
        for (let i = 0; i < this.nowBlock.site.length; i += 2) {
          // 向下移动一位
          this.nowBlock.site[i]++;
        }
        this.renderBlock(this.nowBlock, this.frame, 1); //再渲染数据
      } else {
        // 已经不能下落了
        this.renderBlock(this.nowBlock, this.frame, 2);
        // 判断是否可以消除
        this.removeBlock();
      }
    },
    // 向左移动
    moveLeft() {
      if (this.canMove(2)) {
        // 先清空
        this.renderBlock(this.nowBlock, this.frame, 0);
        for (let i = 0; i < this.nowBlock.site.length; i += 2) {
          // 向左移动一位
          this.nowBlock.site[i + 1]--;
        }
        this.renderBlock(this.nowBlock, this.frame, 1); //再渲染数据
      }
    },
    // 向右移动
    moveRight() {
      if (this.canMove(1)) {
        this.renderBlock(this.nowBlock, this.frame, 0);
        for (let i = 0; i < this.nowBlock.site.length; i += 2) {
          this.nowBlock.site[i + 1]++;
        }
        this.renderBlock(this.nowBlock, this.frame, 1); //再渲染数据
      }
    },
    // 是否可移动判断
    // 预判能否移动或变化   e:1右移  2左移  3下移  4变化
    canMove(e) {
      let c = this.nowBlock.site;
      let d = 0;
      switch (e) {
        case 1:
          for (let i = 0; i < c.length; i += 2) {
            if (c[i + 1] >= this.col - 1) {
              return false;
            }
            // 判断下一个位置是否被占用
            d += this.frame[c[i]][c[i + 1] + 1].data;
          }
          if (d > 0) {
            return false;
          }
          break;
        case 2:
          for (let i = 0; i < c.length; i += 2) {
            if (c[i + 1] <= 0) {
              return false;
            }
            // 判断下一个位置是否被占用
            d += this.frame[c[i]][c[i + 1] - 1].data;
          }
          if (d > 0) {
            return false;
          }
          break;
        case 3:
          for (let i = 0; i < c.length; i += 2) {
            if (c[i] >= this.row - 1) {
              return false;
            }
            // 判断下一个位置是否被占用(防穿透)
            d += this.frame[c[i] + 1][c[i + 1]].data;
          }
          if (d > 0) {
            return false;
          }
          break;
        // case 4:
        //   for (let i = 0; i < c.length; i += 2) {
        //     if (c[i + 1] >= this.col - 1) {
        //       return false;
        //     }
        //   }
        //   break;
      }
      return true;
    },
    // 下落时旋转
    // 旋转 b:当前方块  xz:当前旋转角度
    change1() {
      const b = JSON.parse(JSON.stringify(this.nowBlock));
      // 记录第一块位置
      const x = b.site[0];
      const y = b.site[1];
      let n = true;
      for (let i = 0; i < b.site.length; i += 2) {
        let a = b.site[i];
        b.site[i] = b.site[i + 1] - y + x + transition[this.now.b][this.xz].x;
        b.site[i + 1] = -(a - x) + y + transition[this.now.b][this.xz].y;
        // 判断旋转后该点是否合理
        if (
          b.site[i + 1] < 0 ||
          b.site[i + 1] >= this.col ||
          b.site[i] >= this.row ||
          this.frame[b.site[i]][b.site[i + 1]].data > 0
        ) {
          n = false;
        }
      }
      // 符合条件
      if (n) {
        this.renderBlock(this.nowBlock, this.frame, 0); //先清空
        this.xz++;
        if (this.xz == 4) {
          this.xz = 0;
        }
        this.nowBlock = b;
        this.renderBlock(this.nowBlock, this.frame, 1); //再旋转
      }
    },
    // 到底部:确定位置不能再动,保证上面其他方块下落时不会将它穿透
    // 自动下落
    autoMoveDown() {
      this.timer = setInterval(() => {
        this.moveDown();
      }, this.speed);
    },
    // 开始与暂停
    stopGame() {
      this.stop = !this.stop;
      if (this.stop) {
        clearInterval(this.timer);
      } else {
        this.autoMoveDown();
      }
    },
    // 判断是否可以消除
    removeBlock() {
      // 遍历整个界面
      for (let i = 0; i < this.row; i++) {
        let a = 0;
        for (let j = 0; j < this.col; j++) {
          if (this.frame[i][j].data == 1) {
            a++;
          }
        }
        if (a == this.col) {
          // 说明该行已经占满可以消除
          this.removeRow.push(i);
        }
      }
      // 获取是否可以消除行
      if (this.removeRow.length > 0) {
        let l = this.removeRow;
        for (let i = 0; i < l.length; i++) {
          let j = 0;
          let timer = setInterval(() => {
            this.frame[l[i]][j] = { bg: this.bg, data: 0 };
            j++;
            if (j == this.col) {
              clearInterval(timer);
            }
          }, 20);
        }
        setTimeout(() => {
          // 上面方块下移,从下往上判断
          for (let i = this.row - 1; i >= 0; i--) {
            let a = 0;
            for (let j = 0; j < l.length; j++) {
              if (l[j] > i) {
                a++;
              }
            }
            if (a > 0) {
              for (let k = 0; k < this.col; k++) {
                if (this.frame[i][k].data == 1) {
                  // 先向下移动
                  this.frame[i + a][k] = this.frame[i][k];
                  // 再清除当前
                  this.frame[i][k] = { bg: this.bg, data: 0 };
                }
              }
            }
          }
          this.removeRow = []; //清除行记录
          // 生成下一个
          this.init();
        }, 20 * this.col);
        // 数据处理
        // 消除次数+1
        this.times++;
        // 等级向下取整+1
        let lev =  Math.floor(this.times / 10) + 1;
        if (lev > this.level) {
          this.level = lev;
          // 速度
          if (this.level < 21) {
            // 20级以内做减法
            this.speed = 800 - (this.level - 1) * 40;
          } else {
            this.speed = 30;
          }
          // 清除当前下落
          clearInterval(this.timer);
          // 加速
          this.autoMoveDown();
        }
        this.level = this.times;
        // 分数消除一行100,两行300,三行600,四行1000
        this.score += ((l.length * (l.length + 1)) / 2) * 100 * this.level;
      } else {
        this.init();
      }
    },
  },
};
</script>

<style lang='less' scoped>
.game {
  .game-div {
    display: flex;
    .game-min {
      .row {
        display: flex;
        padding-top: 2px;
        .element {
          width: 20px;
          height: 20px;
          padding: 0;
          margin: 0 2px 0 0;
        }
      }
    }
    .right-div {
      padding-left: 20px;
      .ass {
        .row {
          display: flex;
          padding-top: 2px;
          .element {
            width: 20px;
            height: 20px;
            padding: 0;
            margin: 0 2px 0 0;
          }
        }
      }
      .score-div {
        div {
          height: 20px;
          line-height: 20px;
        }
        .ztks {
          width: 100px;
          height: 40px;
          margin-bottom: 10px;
          background-color: palevioletred;
          text-align: center;
          line-height: 40px;
        }
      }
    }
  }
  .control {
    width: 220px;
    p {
      width: 220px;
      height: 40px;
      text-align: center;
      line-height: 40px;
      background-color: #B940EF;
      margin-bottom: 20px;
    }
    .control-center {
      align-items: center;
      display: flex;
      justify-content: space-between;
      margin-bottom: 20px;
      div {
        width: 90px;
        height: 40px;
        text-align: center;
        line-height: 40px;
        background-color: #B940EF;
      }
    }
  }
}
</style>

 工具函数:

//渐变色
export const color = [
  [
    'linear-gradient(180deg, #FFA7EB 0%, #F026A8 100%)',
    'linear-gradient(180deg, #DFA1FF 0%, #9A36F0 100%)',
    'linear-gradient(180deg, #9EAAFF 0%, #3846F4 100%)',
    'linear-gradient(180deg, #7BE7FF 2%, #1E85E2 100%)',
    'linear-gradient(180deg, #89FED8 0%, #18C997 100%)',
    'linear-gradient(180deg, #FFED48 0%, #FD9E16 100%)',
    'linear-gradient(180deg, #FFBA8D 1%, #EB6423 100%)',
  ],
  [
    '#2B7AF5','#2B9DF5','#79CFFF','#1B67DD','#4F94FF','#2180F2','#3FD0FF',
  ],
];

//7种方块元素
export const blockMod = (color) => {
  let a = {
    site: [0, 1, 0, 2, 1, 2, 2, 2],
    color: color[0],
  };
  let b = {
    site: [0, 1, 1, 1, 1, 2, 2, 2],
    color: color[1],
  };
  let c = {
    site: [1, 1, 1, 2, 2, 1, 2, 2],
    color: color[2],
  };
  let d = {
    site: [1, 0, 1, 1, 1, 2, 1, 3],
    color: color[3],
  };
  let e = {
    site: [0, 2, 1, 1, 1, 2, 2, 1],
    color: color[4],
  };
  let f = {
    site: [0, 1, 0, 2, 1, 1, 2, 1],
    color: color[5],
  };
  let g = {
    site: [1, 1, 2, 0, 2, 1, 2, 2],
    color: color[6],
  };
  return ([a, b, c, d, e, f, g]);
};

//旋转规则
export const transition = [
  [
    {
      x: 1, y: 1,
    }, {
      x: 1, y: 0,
    }, {
      x: 0, y: -2,
    }, {
      x: -2, y: 1,
    }
  ],
  [
    {
      x: 1, y: 1,
    }, {
      x: 1, y: 0,
    }, {
      x: 0, y: -2,
    }, {
      x: -2, y: 1,
    }
  ],
  [
    {
      x: 0, y: 1,
    }, {
      x: 1, y: 0,
    }, {
      x: 0, y: -1,
    }, {
      x: -1, y: 0,
    }
  ],
  [
    {
      x: -1, y: 2,
    }, {
      x: 1, y: 1,
    }, {
      x: 2, y: -1,
    }, {
      x: -2, y: -2,
    }
  ],
  [
    {
      x: 2, y: 0,
    }, {
      x: 0, y: -1,
    }, {
      x: -1, y: -1,
    }, {
      x: -1, y: 2,
    }
  ],
  [
    {
      x: 1, y: 1,
    }, {
      x: 1, y: 0,
    }, {
      x: 0, y: -2,
    }, {
      x: -2, y: 1,
    }
  ],
  [
    {
      x: 0, y: 0,
    }, {
      x: 1, y: 0,
    }, {
      x: -1, y: 0,
    }, {
      x: 0, y: 0,
    }
  ],
]

三、原理分析

3.1、界面搭建

  主界面的20X10,类似贪吃蛇,副界面的随机方块,则是4x4,都是双重for循环。初始化的时候调用gameFrame()即可。

3.2、方块创建

  主要说明一下随机生成的方块,每个都是有4个小方格组成,组成了7种基本样式,在自身基础上进行四个方向的旋转,就是下落的所有可能性。参考坐标如右图所示:

Vue2模拟俄罗斯方块小游戏Vue2模拟俄罗斯方块小游戏

3.3、方块旋转

  旋转 b:当前方块   d:渲染的位置   z:渲染的对象现在还是下一个  xz:当前旋转角度,在change(b, d, z, xz)里进行旋转,这里用到了工具函数里的transition,旋转核心就是找到一个固定的点,看出x和Y坐标的变化,即(x=y,y=-x),加上工具函数里的blockMod,就可以依次生成对应的下落方块。

3.4、方块移动

  在生成一个的同时,要考虑的下一个方块的生成与随机旋转,所以 b:方块,d:位置,n:0擦除,1生成,2确定落到最下层,在renderBlock(b, d, n)方法里进行形状的渲染。

  我们有三个方向:moveDown()、moveLeft()、moveRight(),这里的原理和贪吃蛇基本类似,不过在向下移动时考虑因素较多,下落时旋转要考虑 b:当前方块  xz:当前旋转角度change1()方法,为了保持原来的形状,所以多处用到了深拷贝。

3.5、移动判断

  预判能否移动或变化   e:1右移  2左移  3下移  4变化,在 canMove(e)方法里实现。主要是判断下一个位置是否被占用,到了底部:确定位置不能再动,保证上面其他方块下落时不会将它穿透,是要考虑的问题。

Vue2模拟俄罗斯方块小游戏

3.6、下落判断与清除

  判断是否可以消除:遍历整个界面,当一行被占满,将该行的方块依次删去,并保留上面附着的方块位置不变,形成“被吞噬”的现象。在消掉满了的一行时,要让上面方块下移,从下往上判断,再清除当前方块,避免冲突。

3.7、得分计算


  分数消除一行100,两行300,三行600,四行1000,消掉一行,带分数增加,以此同时,随着等级的增加,速度也会越来越快,难度增加。文章来源地址https://www.toymoban.com/news/detail-482115.html

到了这里,关于Vue2模拟俄罗斯方块小游戏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【用EXCEL编写俄罗斯方块小游戏(基于VBA)】

    工作属性原因,工作中使用excel办公是常态。前一阵子因工作业务需求,需要用到VBA。研究了一阵子VBA,解决了当时的需求。 后来想想,VBA可以如此彻底的控制excel,那么可不可以编个小游戏呢。 说干就干,先拿与表格最像的俄罗斯方块试试手。 首先,俄罗斯方块游戏需要完

    2023年04月08日
    浏览(39)
  • Java实现俄罗斯方块小游戏。(附完整源代码)

    大家好,我是百思不得小赵。 创作时间:2022 年 5 月 12 日 博客主页: 🔍点此进入博客主页 —— 新时代的农民工 🙊 —— 换一种思维逻辑去看待这个世界 👀 今天是加入CSDN的第1167天。觉得有帮助麻烦👏点赞、🍀评论、❤️收藏 目录 一、游戏背景 二、功能实现 三、效果

    2024年02月03日
    浏览(63)
  • Python课程设计 基于python的俄罗斯方块小游戏

    目录 基于python的俄罗斯方块小游戏 1.概述 1.1 摘要 1.2 开发背景 1.3 开发环境 1.4 实现功能 2.代码描述 2.1 模块导入 2.2 初始化变量 2.3 播放音乐 2.4 创建方块类 2.5 绘制游戏地图 2.6 游戏初始化 2.7 绘制有边框矩形 2.8 绘制我的文字 2.9 游戏主体 2.10 主程序运行 3.运行效果 4.注

    2024年02月22日
    浏览(56)
  • python毕设分享 俄罗斯方块小游戏设计与实现 (源码)

    🔥 Hi,各位同学好呀,这里是L学长! 🥇今天向大家分享一个今年(2022)最新完成的毕业设计项目作品 python小游戏毕设 俄罗斯方块小游戏设计与实现 (源码) 🥇 学长根据实现的难度和等级对项目进行评分(最低0分,满分5分) 难度系数:3分 工作量:3分 创新点:4分 项目获取:

    2024年02月03日
    浏览(55)
  • 基于Python+Pygame实现一个俄罗斯方块小游戏【完整代码】

    俄罗斯方块,一款起源于上世纪80年代的经典电子游戏,凭借简单的规则和独特的魅力,一跃成为全球家喻户晓的经典。你知道其实只需要一些基础的编程知识,就可以自己实现它吗?今天,我们将使用Python的Pygame库,一步步带你构建属于自己的俄罗斯方块小游戏! 游戏初始

    2024年02月04日
    浏览(46)
  • 基于STM32F407的俄罗斯方块小游戏的设计

        本文讲述的是基于STM32F407的俄罗斯方块小游戏的设计思路和测试结果,具体的代码分析见文章 基于STM32F407的俄罗斯方块游戏代码分析_钻仰弥坚的博客-CSDN博客 1.1 可行性分析 可行性分析能够对新系统进行各方面的分析与研究,确定新系统是否具有开发的可行性和必要性

    2024年02月11日
    浏览(48)
  • 基于STM32 LCD屏实现的俄罗斯方块小游戏(20220522完成 第一个综合类项目)

    本项目基于 正点原子mini(stm32f103RCT6) 2.8 寸的 ALIENTEK TFTLCD 模块 二轴摇杆模块 的俄罗斯方块小游戏。(学习过程中的项目自测) 1.随机数生成我是用RTC的时钟自己写的,用srand+rand 只能生成一次。 2.并行程序(有什么更好的方法)。 3.觉得我哪里需要改进或者有什么见解可以评论

    2024年02月08日
    浏览(64)
  • 录有手就行1、吃金币2、打乒乓3、滑雪4、并夕夕版飞机大战5、打地鼠简简单单6、小恐龙7、消消乐8、俄罗斯方块9、贪吃蛇普普通通10、24点小游戏

    1、吃金币 【有手就行系列不介绍玩法了+附源码】 源码分享:   import os import cfg import sys import pygame import random from modules import *     \\\'\\\'\\\'游戏初始化\\\'\\\'\\\' def initGame():     # 初始化pygame, 设置展示窗口     pygame.init()     screen = pygame.display.set_mode(cfg.SCREENSIZE)     pygame.display.set_capt

    2024年03月21日
    浏览(50)
  • 免费分享一套Python俄罗斯方块源码 PyQt5俄罗斯方块源码,太好玩了~

    大家好,我是java1234_小锋老师,看到一个不错的Python俄罗斯方块源码 PyQt5俄罗斯方块源码,分享下哈。 【免费】Python俄罗斯方块源码 PyQt5俄罗斯方块源码 Python小游戏源码_哔哩哔哩_bilibili 【免费】Python俄罗斯方块源码 PyQt5俄罗斯方块源码 Python小游戏源码项目来自互联网,免

    2024年01月25日
    浏览(43)
  • 编写一个俄罗斯方块

    编写俄罗斯方块 思路。 1、创建容器数组,方块, 2、下落,左右移动,旋转,判断结束,消除。  定义一个20行10列的数组表示游戏区。初始这个数组里用0填充,1表示有一个方块,2表示该方块固定了, 然后随机出一个方块,操作左右转,触底变2后,再随机下一个方块,循

    2024年02月12日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包