Skip to content

Commit 4e0e959

Browse files
committed
shooting game
1 parent edb5167 commit 4e0e959

File tree

1 file changed

+159
-1
lines changed

1 file changed

+159
-1
lines changed

33-helicopter-game/index.html

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<html lang="zh">
33
<head>
44
<meta charset="UTF-8" />
5-
<title>可以射击的3D直升机</title>
5+
<title>直升机射击小游戏</title>
66
<style>
77
.cuboid {
88
width: 100%;
@@ -793,9 +793,55 @@
793793
--alpha: 1;
794794
}
795795
}
796+
.target {
797+
position: absolute;
798+
width: 40px;
799+
height: 40px;
800+
background-color: red;
801+
border-radius: 50%;
802+
transform: translate3d(0, 0, 100vmin);
803+
}
804+
805+
#score, #timer {
806+
position: fixed;
807+
top: 20px;
808+
font-size: 24px;
809+
color: white;
810+
z-index: 1000;
811+
}
812+
813+
#score {
814+
left: 20px;
815+
}
816+
817+
#timer {
818+
right: 20px;
819+
}
820+
821+
#gameOver {
822+
position: fixed;
823+
top: 50%;
824+
left: 50%;
825+
transform: translate(-50%, -50%);
826+
background-color: rgba(0, 0, 0, 0.8);
827+
color: white;
828+
padding: 20px;
829+
border-radius: 10px;
830+
text-align: center;
831+
display: none;
832+
z-index: 2000;
833+
}
796834
</style>
797835
</head>
798836
<body>
837+
<div id="score">得分: <span id="scoreValue">0</span></div>
838+
<div id="timer">时间: <span id="timeLeft">60</span>s</div>
839+
<div id="gameOver" onclick="restartGame()">
840+
<h2>游戏结束</h2>
841+
<p>你的得分: <span id="finalScore"></span></p>
842+
<p>点击任意处重新开始</p>
843+
</div>
844+
799845
<div class="scene">
800846
<div class="helicopter__tilter">
801847
<div class="helicopter__wrapper">
@@ -999,7 +1045,18 @@
9991045
<script type="module">
10001046
import gsap from 'https://cdn.skypack.dev/gsap@3.11.0';
10011047
let FIRING = false;
1048+
1049+
let score = 0;
1050+
let timeLeft = 60;
1051+
let gameInterval;
1052+
10021053
const BOUNDS = 50;
1054+
1055+
const scoreElement = document.getElementById('scoreValue');
1056+
const timerElement = document.getElementById('timeLeft');
1057+
const gameOverElement = document.getElementById('gameOver');
1058+
const finalScoreElement = document.getElementById('finalScore');
1059+
10031060
document.addEventListener('pointermove', ({ x, y }) => {
10041061
const newX = gsap.utils.mapRange(
10051062
0,
@@ -1062,6 +1119,107 @@
10621119
FIRING = false;
10631120
});
10641121

1122+
function createTarget() {
1123+
const target = document.createElement('div');
1124+
target.className = 'target';
1125+
target.style.left = `${Math.random() * window.innerWidth}px`;
1126+
target.style.top = `${Math.random() * window.innerHeight}px`;
1127+
document.body.appendChild(target);
1128+
1129+
gsap.to(target, {
1130+
x: gsap.utils.random(-500, 500),
1131+
y: gsap.utils.random(-300, 300),
1132+
duration: 2,
1133+
ease: "none",
1134+
repeat: -1,
1135+
yoyo: true
1136+
});
1137+
1138+
target.addEventListener('click', () => {
1139+
score += 10;
1140+
scoreElement.textContent = score;
1141+
target.remove();
1142+
createTarget();
1143+
});
1144+
}
1145+
1146+
function startGame() {
1147+
score = 0;
1148+
timeLeft = 60;
1149+
scoreElement.textContent = score;
1150+
timerElement.textContent = timeLeft;
1151+
gameOverElement.style.display = 'none';
1152+
1153+
createTarget();
1154+
createTarget();
1155+
1156+
gameInterval = setInterval(() => {
1157+
timeLeft--;
1158+
timerElement.textContent = timeLeft;
1159+
if (timeLeft <= 0) {
1160+
endGame();
1161+
}
1162+
}, 1000);
1163+
}
1164+
1165+
function endGame() {
1166+
clearInterval(gameInterval);
1167+
gameOverElement.style.display = 'block';
1168+
finalScoreElement.textContent = score;
1169+
document.querySelectorAll('.target').forEach(target => target.remove());
1170+
}
1171+
1172+
window.restartGame = startGame;
1173+
1174+
startGame();
1175+
1176+
// 修改射击逻辑
1177+
gsap.ticker.add((time, deltaTime, frame) => {
1178+
if (FIRING) {
1179+
const AMMO = document.createElement('div');
1180+
AMMO.innerHTML = `
1181+
<div class="cuboid cuboid--ammo">
1182+
<div class="cuboid__side"></div>
1183+
<div class="cuboid__side"></div>
1184+
<div class="cuboid__side"></div>
1185+
<div class="cuboid__side"></div>
1186+
<div class="cuboid__side"></div>
1187+
<div class="cuboid__side"></div>
1188+
</div>
1189+
`;
1190+
AMMO.className = 'helicopter__ammo';
1191+
AMMO.style.setProperty('--hue', Math.random() * 360);
1192+
1193+
const launcher = frame % 2 === 0 ? document.querySelector('.helicopter__launcher--left') : document.querySelector('.helicopter__launcher--right');
1194+
launcher.appendChild(AMMO);
1195+
1196+
gsap.to(AMMO, {
1197+
xPercent: () => gsap.utils.random(-3000, -2000),
1198+
onComplete: () => {
1199+
const targets = document.querySelectorAll('.target');
1200+
targets.forEach(target => {
1201+
if (isColliding(AMMO, target)) {
1202+
score += 5;
1203+
scoreElement.textContent = score;
1204+
target.remove();
1205+
createTarget();
1206+
}
1207+
});
1208+
AMMO.remove();
1209+
}
1210+
});
1211+
}
1212+
});
1213+
1214+
function isColliding(elem1, elem2) {
1215+
const rect1 = elem1.getBoundingClientRect();
1216+
const rect2 = elem2.getBoundingClientRect();
1217+
return !(rect1.right < rect2.left ||
1218+
rect1.left > rect2.right ||
1219+
rect1.bottom < rect2.top ||
1220+
rect1.top > rect2.bottom);
1221+
}
1222+
10651223
// Purely for debugging purposes
10661224
// import { GUI } from 'https://cdn.skypack.dev/dat.gui'
10671225

0 commit comments

Comments
 (0)