|
2 | 2 | <html lang="zh">
|
3 | 3 | <head>
|
4 | 4 | <meta charset="UTF-8" />
|
5 |
| - <title>可以射击的3D直升机</title> |
| 5 | + <title>直升机射击小游戏</title> |
6 | 6 | <style>
|
7 | 7 | .cuboid {
|
8 | 8 | width: 100%;
|
|
793 | 793 | --alpha: 1;
|
794 | 794 | }
|
795 | 795 | }
|
| 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 | + } |
796 | 834 | </style>
|
797 | 835 | </head>
|
798 | 836 | <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 | + |
799 | 845 | <div class="scene">
|
800 | 846 | <div class="helicopter__tilter">
|
801 | 847 | <div class="helicopter__wrapper">
|
|
999 | 1045 | <script type="module">
|
1000 | 1046 | import gsap from 'https://cdn.skypack.dev/gsap@3.11.0';
|
1001 | 1047 | let FIRING = false;
|
| 1048 | + |
| 1049 | + let score = 0; |
| 1050 | + let timeLeft = 60; |
| 1051 | + let gameInterval; |
| 1052 | + |
1002 | 1053 | 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 | + |
1003 | 1060 | document.addEventListener('pointermove', ({ x, y }) => {
|
1004 | 1061 | const newX = gsap.utils.mapRange(
|
1005 | 1062 | 0,
|
|
1062 | 1119 | FIRING = false;
|
1063 | 1120 | });
|
1064 | 1121 |
|
| 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 | + |
1065 | 1223 | // Purely for debugging purposes
|
1066 | 1224 | // import { GUI } from 'https://cdn.skypack.dev/dat.gui'
|
1067 | 1225 |
|
|
0 commit comments