vue 俄罗斯方块

本文介绍了使用Vue技术难点,主要在于旋转处理。通过标定方块初始点,转换为相对坐标,实现方块的旋转。在消除行时进行二次判定,并将操作函数化以简化代码和模块调试。移动方块时,根据移动方向从相应侧开始判断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文链接: vue 俄罗斯方块

上一篇: tf 文字识别 多个文字 data 数据流

下一篇: opencv 二值化的素描

技术难点主要在于旋转的处理

标定一个不变的点设为方块初始点

将方块坐标变为一个相对坐标

向下x正, 向右y正

原始方块坐标为[x, y] 旋转后的坐标为 [y, -x]

记录方块的初始点移动, 加上旋转后的坐标完成变换

判断消除时, 如果消除了一行后, 还需要在进行一次判定, 判定落下来的行是否需要消除

将相关操作设计为函数, 简化代码开发, 和模块调试

移动的时候, 向右移动时从从右边开始判断, 向左移动时, 由左边开始判断

<template>
  <div class="main">
    <div class="cells">
      <div v-for="(row, index) in game" :key="index">
        <div class="row">
          <div
            v-for="(cell, key) in row"
            :key="key"
            :class="classes[cell]"
            class="cell"
          ></div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
// 向下x正 向右y正
const H = 25;
const W = 11;
const MID_W = 5;
// 初始砖块,以中心为原点的相对坐标偏移列表
const BLOCKS = [
  [[0, 0], [0, 1], [1, 0], [1, 1]], //田
  [[0, -1], [0, 0], [1, 0], [1, 1]],
  [[0, 0], [0, -1], [0, 1], [0, 2]],
  [[0, 0], [0, 1], [1, 1], [1, 0]], // z
  [[0, 0], [0, -1], [-1, 0], [-1, 1]],
  [[0, 0], [0, 1], [-1, -1], [-1, 0]],
  [[0, 0], [0, 1], [1, 0], [0, -1]],
  [[0, 0], [1, 0], [-1, 0], [1, -1]],
  [[0, 0], [1, 0], [-1, 0], [1, 1]]
];

// 0 表示背景 白色
// 1 表示已经下落的砖块 浅灰
// 2 表示正在下落的砖块 浅蓝
export default {
  name: "Game",
  data() {
    return {
      classes: ["bg", "box", "move"],
      game: Array.from(Array(H)).map(() => Array(W).fill(0)),
      blockIndex: 0,
      block: BLOCKS[this.blockIndex],
      dx: 3,
      dy: MID_W
    };
  },
  methods: {
    left() {
      //   左移
      console.log("左移");
      this.dy--;
      let canMove = true;
      for (let x = 0; x < H; x++) {
        for (let y = 0; y < W; y++) {
          if (this.game[x][y] === 2) {
            if (y === 0 || this.game[x][y - 1] === 1) {
              canMove = false;
              // console.log(x, y);
            }
          }
        }
      }
      if (canMove) {
        for (let x = 0; x < H; x++) {
          for (let y = 0; y < W; y++) {
            if (this.game[x][y] === 2 && y > 0) {
              this.change(x, y, 0);
              this.change(x, y - 1, 2);
            }
          }
        }
      }
    },
    down() {
      console.log("向下");
      this.dx++;
      let pos = [];
      for (let x = 0; x < H; x++) {
        for (let y = 0; y < W; y++) {
          if (this.game[x][y] === 2) pos.push([x, y]);
        }
      }

      let new_pos = [];
      for (let i = 0; i < pos.length; i++) {
        let [x, y] = pos[i];
        new_pos.push([x + 1, y]);
      }

      let canMove = new_pos.every(([x, y]) => {
        if (x < 0 || y < 0 || x >= H || y >= W) {
          //  越界
          return false;
        }

        if (this.game[x][y] === 1) {
          // 已经有了方块
          return false;
        }

        return true;
      });

      if (canMove) {
        for (let [x, y] of pos) this.change(x, y, 0);
        for (let [x, y] of new_pos) this.change(x, y, 2);
      } else {
        for (let [x, y] of pos) this.change(x, y, 1);
        this.init();
        //   判断是否需要消除
        for (let i = H - 1; i > 0; i--) {
          //   从下到上
          let isDel = this.game[i].every(x => x === 1);
          console.log(i, isDel);
          if (isDel) {
            for (let j = i; j > 0; j--) {
              this.game[j] = this.game[j - 1];
            }
            this.game[0] = Array(W).fill(0);
            i++;
          }
          // 删除之后,判断落下来的行是否需要删除
        }
      }
    },
    transfer() {
      console.log("变形");
      let block = this.block;
      let new_block = block.map(([x, y]) => {
        let nx = y;
        let ny = -x;
        return [nx, ny];
      });
      let pos = [];
      for (let x = 0; x < H; x++) {
        for (let y = 0; y < W; y++) {
          if (this.game[x][y] === 2) pos.push([x, y]);
        }
      }

      let new_pos = [];
      console.log("block", block);
      console.log("dx,dy", this.dx, this.dy);
      console.log("diff", new_block);
      for (let i = 0; i < new_block.length; i++) {
        let [x, y] = new_block[i];
        let nx = x + this.dx;
        let ny = y + this.dy;
        new_pos.push([nx, ny]);
      }
      console.log("pos", pos);
      console.log("new_pos", new_pos);

      let canChange = new_pos.every(([x, y]) => {
        if (x < 0 || y < 0 || x >= H || y >= W) {
          //  越界
          return false;
        }

        if (this.game[x][y] === 1) {
          // 已经有了方块
          return false;
        }

        return true;
      });

      console.log("canChange", canChange);

      if (canChange) {
        for (let [x, y] of pos) this.change(x, y, 0);
        for (let [x, y] of new_pos) this.change(x, y, 2);
        this.block = new_block;
      }
    },
    right() {
      console.log("右移");
      let canMove = true;
      this.dy++;
      for (let x = 0; x < H; x++) {
        for (let y = 0; y < W; y++) {
          if (this.game[x][y] === 2) {
            if (y === W - 1 || this.game[x][y + 1] === 1) {
              canMove = false;
              // console.log(x, y);
            }
          }
        }
      }

      // 向哪边移动, 则由哪边遍历
      if (canMove) {
        for (let x = 0; x < H; x++) {
          for (let y = W - 1; y >= 0; y--) {
            if (this.game[x][y] === 2 && y < W - 1) {
              // console.log("move", x, y);
              this.change(x, y, 0);
              this.change(x, y + 1, 2);
            }
          }
        }
      }
    },
    change(x, y, v) {
      this.$set(this.game[x], `${y}`, v);
    },
    keyDown(e) {
      console.log(e);
      if (e.key === "a") {
        this.left();
      } else if (e.key === "w") {
        this.transfer();
      } else if (e.key === "s") {
        this.down();
      } else if (e.key === "d") {
        this.right();
      }
    },
    init() {
      //   随机选择一个block, 放在正上方
      this.dx = 2;
      this.dy = MID_W;
      this.blockIndex = parseInt(Math.random() * BLOCKS.length);
      // console.log(this.blockIndex);
      this.block = Array.from(BLOCKS[this.blockIndex]);

      // 是否为0 表示可以放置初始物块
      let canPut = this.block.every(([x, y]) => {
        console.log("x,y", x, y);
        x = x + this.dx;
        y = y + this.dy;
        return this.game[x][y] === 0;
      });
      if (!canPut) {
        //   游戏结束
      } else {
        this.block.forEach(([x, y]) => {
          x = x + this.dx;
          y = y + this.dy;
          return this.change(x, y, 2);
        });
      }
    }
  },
  mounted() {
    console.log(this.game.length, this.game[0].length);
    this.init();
    document.body.onkeydown = this.keyDown;
    setInterval(() => this.down(), 300);
  }
};
</script>

<style scoped>
.main {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100vw;
  height: 100vh;
  flex-direction: column;
}
.cells {
  display: flex;
  /*justify-content: center;*/
  /*align-items: center;*/
  flex-direction: column;
}

.row {
  display: flex;
  flex-direction: row;
}
.cell {
  width: 25px;
  height: 25px;
  box-sizing: border-box;
  border: 1px solid black;
}
.box {
  background: lightgray;
}

.move {
  background: deepskyblue;
}

.bg {
  background: white;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值