目录

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>
本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
喜樂的CC1 小时前
[react]Next.js之自适应布局和高清屏幕适配解决方案
javascript·react.js·postcss
天天扭码1 小时前
零基础 | 入门前端必备技巧——使用 DOM 操作插入 HTML 元素
前端·javascript·dom
咖啡虫2 小时前
css中的3d使用:深入理解 CSS Perspective 与 Transform-Style
前端·css·3d
烛阴2 小时前
手把手教你搭建 Express 日志系统,告别线上事故!
javascript·后端·express
拉不动的猪2 小时前
设计模式之------策略模式
前端·javascript·面试
旭久2 小时前
react+Tesseract.js实现前端拍照获取/选择文件等文字识别OCR
前端·javascript·react.js
独行soc2 小时前
2025年常见渗透测试面试题-红队面试宝典下(题目+回答)
linux·运维·服务器·前端·面试·职场和发展·csrf
uhakadotcom3 小时前
Google Earth Engine 机器学习入门:基础知识与实用示例详解
前端·javascript·面试
麓殇⊙3 小时前
Vue--组件练习案例
前端·javascript·vue.js
outstanding木槿3 小时前
React中 点击事件写法 的注意(this、箭头函数)
前端·javascript·react.js