vue3实现打飞机(雷电)

代码可直接运行直接玩,而且要自己加上一些随机事件都很简单了(例如发射速度变快,子弹变大,敌人变慢等)

html 复制代码
<template>
  <div class="flex items-center justify-center h-100vh w-full">
    <div>
      SCORE: {{ score }}
      <div class="box w-400 h-500 relative p-8" ref="box">
        <div
          class="tank-wrap absolute bottom-6"
          ref="tankWrap"
          :style="{ left: tankLeft + 'px' }"
        >
          <div class="tank" :style="{ width: tankWidth + 'px' }"></div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
const box = ref();
const tankWidth = 40;
const tankWrap = ref();

/**
 * 左右方向键控制坦克
 */
const tankLeft = ref<number>(150);
function mousemove(e: MouseEvent) {
  const boxRect = box.value.getBoundingClientRect();
  if (!boxRect) return;
  const left = e.clientX - boxRect.left;

  if (left < 0) {
    tankLeft.value = 0;
  } else if (left > boxRect.width - tankWidth) {
    tankLeft.value = boxRect.width - tankWidth;
  } else {
    tankLeft.value = left;
  }
}
/**
 * 发射子弹
 */
function start() {
  const tankWrapRect = tankWrap.value.getBoundingClientRect();
  const boxRect = box.value.getBoundingClientRect();

  const bullet = document.createElement("div");
  bullet.className =
    "fixed top-0 left-0 w-6 h-6 bg-red-500 border-rd-50% bullet";
  // 加上一半的坦克宽度,再减去一半的自身宽度
  bullet.style.left = tankWrapRect.left + tankWidth / 2 - 3 + "px";
  bullet.style.top = tankWrapRect.top + "px";
  box.value.appendChild(bullet);
  let top = 0;

  const timer = setInterval(() => {
    top += 5;
    const result = tankWrapRect.top - top;
    bullet.style.top = result + "px";

    if (result < boxRect.top) {
      clearInterval(timer);
      bullet.remove();
    }
  }, 16);
}
const score = ref(0);
/**
 * 生成敌人
 */
const enemyCreator = () => {
  const boxRect = box.value.getBoundingClientRect();
  const enemy = document.createElement("div");
  //  宽度10-75px随机
  const enemyWidth = Math.floor(Math.random() * 66) + 10;
  const enemyHeight = Math.floor(Math.random() * 25) + 5;
  enemy.style.width = enemyWidth + "px";
  enemy.style.height = enemyHeight + "px";
  // 0% 到 50%随机
  enemy.style.borderRadius = Math.floor(Math.random() * 51) + "%";
  enemy.style.backgroundColor = `rgb(${Math.floor(
    Math.random() * 256
  )},${Math.floor(Math.random() * 256)},${Math.floor(Math.random() * 256)})`;
  enemy.className = "fixed enemy";
  //boxRect.left 到 (boxRect.left + boxRect.width) 之间的随机数
  enemy.style.left =
    Math.floor(Math.random() * (boxRect.width - enemyWidth)) +
    boxRect.left +
    "px";
  enemy.style.top = boxRect.top + "px";
  box.value.appendChild(enemy);
  let top = 0;
  const speed = Math.floor(Math.random() * 7) + 2;
  let timer: any = setInterval(() => {
    top += speed;
    enemy.style.top = boxRect.top + top + "px";

    /**
     * 检测碰撞敌人
     */
    const enemies = document.querySelectorAll(".fixed.enemy");
    const bullets = document.querySelectorAll(".fixed.bullet");
    for (let i = 0; i < bullets.length; i++) {
      const bulletRect = bullets[i].getBoundingClientRect();
      if (
        bulletRect.left < enemy.getBoundingClientRect().right &&
        bulletRect.right > enemy.getBoundingClientRect().left &&
        bulletRect.top < enemy.getBoundingClientRect().bottom &&
        bulletRect.bottom > enemy.getBoundingClientRect().top
      ) {
        clearInterval(timer);
        score.value ++;
        bullets[i].remove();
        enemy.remove();
      }
    }

    if (enemy && boxRect.top + top + enemyHeight > boxRect.bottom) {
      alert("你已经输了");
      clearInterval(timer);
      window.location.reload();
    }
  }, 30);
};

let fireTimer: any = null;
let enemyTimer: any = null;
onMounted(() => {
  document.addEventListener("mousemove", mousemove);
  fireTimer = setInterval(() => {
    start();
  }, 260);
  enemyTimer = setInterval(() => {
    enemyCreator();
  }, 750);
});
const clear = () => {
  document.removeEventListener("mousemove", mousemove);
  clearInterval(fireTimer);
  clearInterval(enemyTimer);
};
onUnmounted(() => {
  clear();
});
</script>
<style>
.enemy {
  box-shadow: 0 2px 4px #0000006e;
}
</style>
<style lang="scss" scoped>
.box {
  border-radius: 4px;
  border: 1px solid #adadad;
  background: #ccc;
  overflow: hidden;
}
// tank-head-percentage
$t-h: 40%;
.tank-wrap {
  filter: drop-shadow(0 4px 2px #1c0099cc);
  .tank {
    height: 40px;
    border-radius: 8px;
    background-image: linear-gradient(90deg, #0b33b6 0%, #aaf2ff 100%);
    clip-path: polygon(
      0 58%,
      36% $t-h,
      36% 20%,
      50% 0%,
      64% 20%,
      64% $t-h,
      100% 58%,
      100% 100%,
      0 100%
    );
  }
}
</style>
相关推荐
满怀10153 分钟前
【Django全栈开发实战】从零构建企业级Web应用
前端·python·django·orm·web开发·前后端分离
Darling02zjh43 分钟前
GUI图形化演示
前端
Channing Lewis1 小时前
如何判断一个网站后端是用什么语言写的
前端·数据库·python
互联网搬砖老肖1 小时前
Web 架构之状态码全解
前端·架构
showmethetime1 小时前
matlab提取脑电数据的五种频域特征指标数值
前端·人工智能·matlab
码农捻旧1 小时前
解决Mongoose “Cannot overwrite model once compiled“ 错误的完整指南
javascript·数据库·mongodb·node.js·express
淡笑沐白2 小时前
探索Turn.js:打造惊艳的3D翻页效果
javascript·html5·turn.js
海上彼尚2 小时前
秒删node_modules[无废话版]
vue.js·react.js
sunxunyong2 小时前
yarn任务筛选spark任务,判断内存/CPU使用超过限制任务
javascript·ajax·spark
Ynov2 小时前
详细解释api
javascript·visual studio code