Spaces:
Running
Running
Update index.html
Browse files- index.html +401 -19
index.html
CHANGED
@@ -1,19 +1,401 @@
|
|
1 |
-
<!
|
2 |
-
<html>
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Pro Penalty Shootout</title>
|
7 |
+
<style>
|
8 |
+
body {
|
9 |
+
margin: 0;
|
10 |
+
overflow: hidden;
|
11 |
+
font-family: 'Arial', sans-serif;
|
12 |
+
background: #000;
|
13 |
+
}
|
14 |
+
#container { position: relative; }
|
15 |
+
#ui {
|
16 |
+
position: absolute;
|
17 |
+
top: 20px;
|
18 |
+
width: 100%;
|
19 |
+
text-align: center;
|
20 |
+
color: white;
|
21 |
+
font-size: 24px;
|
22 |
+
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
|
23 |
+
}
|
24 |
+
#message {
|
25 |
+
position: absolute;
|
26 |
+
top: 50%;
|
27 |
+
left: 50%;
|
28 |
+
transform: translate(-50%, -50%);
|
29 |
+
color: white;
|
30 |
+
font-size: 72px;
|
31 |
+
font-weight: bold;
|
32 |
+
text-shadow: 0 0 20px #000;
|
33 |
+
opacity: 0;
|
34 |
+
transition: opacity 0.3s;
|
35 |
+
pointer-events: none;
|
36 |
+
}
|
37 |
+
#controls {
|
38 |
+
position: absolute;
|
39 |
+
bottom: 20px;
|
40 |
+
left: 20px;
|
41 |
+
color: white;
|
42 |
+
background: rgba(0,0,0,0.7);
|
43 |
+
padding: 15px;
|
44 |
+
border-radius: 10px;
|
45 |
+
font-size: 18px;
|
46 |
+
line-height: 1.6;
|
47 |
+
}
|
48 |
+
#start-screen {
|
49 |
+
position: absolute;
|
50 |
+
top: 0;
|
51 |
+
left: 0;
|
52 |
+
width: 100%;
|
53 |
+
height: 100%;
|
54 |
+
background: rgba(0,0,0,0.9);
|
55 |
+
display: flex;
|
56 |
+
flex-direction: column;
|
57 |
+
justify-content: center;
|
58 |
+
align-items: center;
|
59 |
+
color: white;
|
60 |
+
z-index: 100;
|
61 |
+
}
|
62 |
+
#start-screen h1 {
|
63 |
+
font-size: 48px;
|
64 |
+
color: #FFD700;
|
65 |
+
margin-bottom: 30px;
|
66 |
+
text-shadow: 0 0 10px #FFD700;
|
67 |
+
}
|
68 |
+
button {
|
69 |
+
padding: 15px 30px;
|
70 |
+
font-size: 18px;
|
71 |
+
background: #4CAF50;
|
72 |
+
color: white;
|
73 |
+
border: none;
|
74 |
+
border-radius: 5px;
|
75 |
+
cursor: pointer;
|
76 |
+
margin: 10px;
|
77 |
+
transition: all 0.3s;
|
78 |
+
}
|
79 |
+
button:hover {
|
80 |
+
background: #45a049;
|
81 |
+
transform: scale(1.05);
|
82 |
+
}
|
83 |
+
#power-bar {
|
84 |
+
position: absolute;
|
85 |
+
bottom: 100px;
|
86 |
+
left: 50%;
|
87 |
+
transform: translateX(-50%);
|
88 |
+
width: 200px;
|
89 |
+
height: 20px;
|
90 |
+
background: rgba(255,255,255,0.2);
|
91 |
+
border-radius: 10px;
|
92 |
+
overflow: hidden;
|
93 |
+
display: none;
|
94 |
+
}
|
95 |
+
#power-level {
|
96 |
+
height: 100%;
|
97 |
+
width: 0%;
|
98 |
+
background: linear-gradient(to right, #4CAF50, #FFD700, #FF5722);
|
99 |
+
}
|
100 |
+
</style>
|
101 |
+
</head>
|
102 |
+
<body>
|
103 |
+
<div id="container">
|
104 |
+
<div id="ui">
|
105 |
+
<span id="goals">0</span> / <span id="shots">0</span>
|
106 |
+
</div>
|
107 |
+
<div id="message"></div>
|
108 |
+
<div id="power-bar"><div id="power-level"></div></div>
|
109 |
+
<div id="controls">
|
110 |
+
<strong>CONTROLS:</strong><br>
|
111 |
+
SPACE - Power up shot<br>
|
112 |
+
LEFT/RIGHT - Aim<br>
|
113 |
+
Release SPACE - Shoot
|
114 |
+
</div>
|
115 |
+
<div id="start-screen">
|
116 |
+
<h1>PRO PENALTY SHOOTOUT</h1>
|
117 |
+
<button id="start-btn">START GAME</button>
|
118 |
+
</div>
|
119 |
+
</div>
|
120 |
+
|
121 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
|
122 |
+
<script>
|
123 |
+
// Setup
|
124 |
+
const scene = new THREE.Scene();
|
125 |
+
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
|
126 |
+
camera.position.set(0, 4, 12);
|
127 |
+
camera.lookAt(0, 1, 0);
|
128 |
+
|
129 |
+
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
130 |
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
131 |
+
renderer.shadowMap.enabled = true;
|
132 |
+
document.getElementById('container').appendChild(renderer.domElement);
|
133 |
+
|
134 |
+
// Lighting
|
135 |
+
const ambientLight = new THREE.AmbientLight(0x404040);
|
136 |
+
scene.add(ambientLight);
|
137 |
+
|
138 |
+
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
139 |
+
directionalLight.position.set(5, 10, 7);
|
140 |
+
directionalLight.castShadow = true;
|
141 |
+
scene.add(directionalLight);
|
142 |
+
|
143 |
+
// Field
|
144 |
+
const field = new THREE.Mesh(
|
145 |
+
new THREE.PlaneGeometry(40, 60),
|
146 |
+
new THREE.MeshStandardMaterial({ color: 0x3CB371 })
|
147 |
+
);
|
148 |
+
field.rotation.x = -Math.PI/2;
|
149 |
+
field.receiveShadow = true;
|
150 |
+
scene.add(field);
|
151 |
+
|
152 |
+
// Goal (more visible)
|
153 |
+
const goalWidth = 7.32;
|
154 |
+
const goalHeight = 2.44;
|
155 |
+
const postMaterial = new THREE.MeshStandardMaterial({
|
156 |
+
color: 0xffffff,
|
157 |
+
metalness: 0.5
|
158 |
+
});
|
159 |
+
|
160 |
+
// Posts
|
161 |
+
const leftPost = new THREE.Mesh(
|
162 |
+
new THREE.BoxGeometry(0.5, goalHeight, 0.5),
|
163 |
+
postMaterial
|
164 |
+
);
|
165 |
+
leftPost.position.set(-goalWidth/2, goalHeight/2, -30);
|
166 |
+
leftPost.castShadow = true;
|
167 |
+
scene.add(leftPost);
|
168 |
+
|
169 |
+
const rightPost = new THREE.Mesh(
|
170 |
+
new THREE.BoxGeometry(0.5, goalHeight, 0.5),
|
171 |
+
postMaterial
|
172 |
+
);
|
173 |
+
rightPost.position.set(goalWidth/2, goalHeight/2, -30);
|
174 |
+
rightPost.castShadow = true;
|
175 |
+
scene.add(rightPost);
|
176 |
+
|
177 |
+
const crossbar = new THREE.Mesh(
|
178 |
+
new THREE.BoxGeometry(goalWidth, 0.5, 0.5),
|
179 |
+
postMaterial
|
180 |
+
);
|
181 |
+
crossbar.position.set(0, goalHeight, -30);
|
182 |
+
crossbar.castShadow = true;
|
183 |
+
scene.add(crossbar);
|
184 |
+
|
185 |
+
// Net
|
186 |
+
const net = new THREE.Mesh(
|
187 |
+
new THREE.BoxGeometry(goalWidth, goalHeight, 2),
|
188 |
+
new THREE.MeshBasicMaterial({
|
189 |
+
wireframe: true,
|
190 |
+
color: 0xffffff,
|
191 |
+
transparent: true,
|
192 |
+
opacity: 0.7
|
193 |
+
})
|
194 |
+
);
|
195 |
+
net.position.set(0, goalHeight/2, -31);
|
196 |
+
scene.add(net);
|
197 |
+
|
198 |
+
// Ball
|
199 |
+
const ballGeometry = new THREE.SphereGeometry(0.4, 32, 32);
|
200 |
+
const ballMaterial = new THREE.MeshStandardMaterial({
|
201 |
+
color: 0xffffff,
|
202 |
+
roughness: 0.2,
|
203 |
+
metalness: 0.5
|
204 |
+
});
|
205 |
+
const ball = new THREE.Mesh(ballGeometry, ballMaterial);
|
206 |
+
ball.position.set(0, 0.4, 0);
|
207 |
+
ball.castShadow = true;
|
208 |
+
scene.add(ball);
|
209 |
+
|
210 |
+
// Goalkeeper (more visible)
|
211 |
+
function createGoalkeeper() {
|
212 |
+
const group = new THREE.Group();
|
213 |
+
|
214 |
+
// Blue jersey
|
215 |
+
const body = new THREE.Mesh(
|
216 |
+
new THREE.BoxGeometry(1, 1.8, 0.4),
|
217 |
+
new THREE.MeshStandardMaterial({ color: 0x1E90FF })
|
218 |
+
);
|
219 |
+
body.position.y = 0.9;
|
220 |
+
group.add(body);
|
221 |
+
|
222 |
+
// Yellow head
|
223 |
+
const head = new THREE.Mesh(
|
224 |
+
new THREE.SphereGeometry(0.3),
|
225 |
+
new THREE.MeshStandardMaterial({ color: 0xFFD700 })
|
226 |
+
);
|
227 |
+
head.position.y = 1.6;
|
228 |
+
group.add(head);
|
229 |
+
|
230 |
+
// Arms (in save position)
|
231 |
+
const leftArm = new THREE.Mesh(
|
232 |
+
new THREE.BoxGeometry(0.2, 0.8, 0.2),
|
233 |
+
body.material
|
234 |
+
);
|
235 |
+
leftArm.position.set(-0.7, 1.3, 0);
|
236 |
+
leftArm.rotation.z = Math.PI/3;
|
237 |
+
group.add(leftArm);
|
238 |
+
|
239 |
+
const rightArm = new THREE.Mesh(
|
240 |
+
new THREE.BoxGeometry(0.2, 0.8, 0.2),
|
241 |
+
body.material
|
242 |
+
);
|
243 |
+
rightArm.position.set(0.7, 1.3, 0);
|
244 |
+
rightArm.rotation.z = -Math.PI/3;
|
245 |
+
group.add(rightArm);
|
246 |
+
|
247 |
+
group.position.z = -29;
|
248 |
+
return group;
|
249 |
+
}
|
250 |
+
|
251 |
+
const goalkeeper = createGoalkeeper();
|
252 |
+
scene.add(goalkeeper);
|
253 |
+
|
254 |
+
// Game state
|
255 |
+
let shots = 0, goals = 0;
|
256 |
+
const maxShots = 5;
|
257 |
+
let power = 0;
|
258 |
+
let isPowering = false;
|
259 |
+
let isShooting = false;
|
260 |
+
let aimDirection = 0;
|
261 |
+
const clock = new THREE.Clock();
|
262 |
+
|
263 |
+
// Controls
|
264 |
+
const keys = {
|
265 |
+
Space: false,
|
266 |
+
ArrowLeft: false,
|
267 |
+
ArrowRight: false
|
268 |
+
};
|
269 |
+
|
270 |
+
window.addEventListener('keydown', (e) => {
|
271 |
+
if (e.code in keys) {
|
272 |
+
keys[e.code] = true;
|
273 |
+
if (e.code === 'Space' && !isPowering && !isShooting && shots < maxShots) {
|
274 |
+
isPowering = true;
|
275 |
+
document.getElementById('power-bar').style.display = 'block';
|
276 |
+
}
|
277 |
+
}
|
278 |
+
});
|
279 |
+
|
280 |
+
window.addEventListener('keyup', (e) => {
|
281 |
+
if (e.code in keys) {
|
282 |
+
keys[e.code] = false;
|
283 |
+
if (e.code === 'Space' && isPowering && !isShooting) {
|
284 |
+
shootBall();
|
285 |
+
}
|
286 |
+
}
|
287 |
+
});
|
288 |
+
|
289 |
+
// Start game
|
290 |
+
document.getElementById('start-btn').addEventListener('click', () => {
|
291 |
+
document.getElementById('start-screen').style.display = 'none';
|
292 |
+
});
|
293 |
+
|
294 |
+
// Power meter
|
295 |
+
function updatePower() {
|
296 |
+
if (isPowering) {
|
297 |
+
power = Math.min(power + 2, 100);
|
298 |
+
document.getElementById('power-level').style.width = `${power}%`;
|
299 |
+
}
|
300 |
+
}
|
301 |
+
|
302 |
+
// Shooting
|
303 |
+
function shootBall() {
|
304 |
+
isPowering = false;
|
305 |
+
isShooting = true;
|
306 |
+
shots++;
|
307 |
+
document.getElementById('shots').textContent = shots;
|
308 |
+
document.getElementById('power-bar').style.display = 'none';
|
309 |
+
|
310 |
+
// Determine target based on aim
|
311 |
+
const targetX = aimDirection * 4;
|
312 |
+
const targetY = goalHeight/2;
|
313 |
+
const speed = 0.5 + (power/100) * 1.5; // Faster ball movement
|
314 |
+
|
315 |
+
let lastTime = performance.now();
|
316 |
+
function animateBall() {
|
317 |
+
const now = performance.now();
|
318 |
+
const delta = (now - lastTime) / 16; // Normalize to ~60fps
|
319 |
+
lastTime = now;
|
320 |
+
|
321 |
+
// Move ball forward and adjust curve
|
322 |
+
ball.position.z -= speed * delta;
|
323 |
+
ball.position.x += (targetX - ball.position.x) * 0.03 * delta;
|
324 |
+
ball.position.y = 0.4 + Math.sin(ball.position.z * 0.2) * 3 * (power/100);
|
325 |
+
|
326 |
+
// Collision with goalkeeper
|
327 |
+
const keeperX = goalkeeper.position.x;
|
328 |
+
if (Math.abs(ball.position.x - keeperX) < 1.2 && ball.position.z < -27) {
|
329 |
+
endShot(false);
|
330 |
+
return;
|
331 |
+
}
|
332 |
+
|
333 |
+
// Goal check
|
334 |
+
if (ball.position.z <= -30) {
|
335 |
+
const isGoal = Math.abs(ball.position.x) < goalWidth/2 && ball.position.y < goalHeight;
|
336 |
+
if (isGoal) {
|
337 |
+
goals++;
|
338 |
+
document.getElementById('goals').textContent = goals;
|
339 |
+
showMessage("GOAL!");
|
340 |
+
} else {
|
341 |
+
showMessage("MISSED!");
|
342 |
+
}
|
343 |
+
endShot(isGoal);
|
344 |
+
return;
|
345 |
+
}
|
346 |
+
|
347 |
+
requestAnimationFrame(animateBall);
|
348 |
+
}
|
349 |
+
|
350 |
+
animateBall();
|
351 |
+
power = 0;
|
352 |
+
}
|
353 |
+
|
354 |
+
function endShot(scored) {
|
355 |
+
isShooting = false;
|
356 |
+
setTimeout(() => {
|
357 |
+
ball.position.set(0, 0.4, 0);
|
358 |
+
if (shots >= maxShots) {
|
359 |
+
setTimeout(() => {
|
360 |
+
showMessage(`FINAL SCORE: ${goals}/${maxShots}`);
|
361 |
+
}, 500);
|
362 |
+
}
|
363 |
+
}, 1000);
|
364 |
+
}
|
365 |
+
|
366 |
+
function showMessage(text) {
|
367 |
+
const message = document.getElementById('message');
|
368 |
+
message.textContent = text;
|
369 |
+
message.style.opacity = 1;
|
370 |
+
setTimeout(() => message.style.opacity = 0, 1500);
|
371 |
+
}
|
372 |
+
|
373 |
+
// Animation loop
|
374 |
+
function animate() {
|
375 |
+
requestAnimationFrame(animate);
|
376 |
+
|
377 |
+
// Goalkeeper movement
|
378 |
+
const time = clock.getElapsedTime();
|
379 |
+
goalkeeper.position.x = Math.sin(time * 1.5) * 3;
|
380 |
+
|
381 |
+
// Handle aim input
|
382 |
+
if (isPowering) {
|
383 |
+
if (keys.ArrowLeft) aimDirection = Math.max(aimDirection - 0.05, -1);
|
384 |
+
if (keys.ArrowRight) aimDirection = Math.min(aimDirection + 0.05, 1);
|
385 |
+
updatePower();
|
386 |
+
}
|
387 |
+
|
388 |
+
renderer.render(scene, camera);
|
389 |
+
}
|
390 |
+
|
391 |
+
// Window resize
|
392 |
+
window.addEventListener('resize', () => {
|
393 |
+
camera.aspect = window.innerWidth / window.innerHeight;
|
394 |
+
camera.updateProjectionMatrix();
|
395 |
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
396 |
+
});
|
397 |
+
|
398 |
+
animate();
|
399 |
+
</script>
|
400 |
+
</body>
|
401 |
+
</html>
|