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