DevForML commited on
Commit
2371998
·
verified ·
1 Parent(s): 867ba79

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +716 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: 3d Game
3
- emoji: 🏢
4
- colorFrom: red
5
  colorTo: gray
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: 3d-game
3
+ emoji: 🐳
4
+ colorFrom: yellow
5
  colorTo: gray
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,716 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Pixel Quest 3D: Find Your Friend</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
9
+ <style>
10
+ body {
11
+ margin: 0;
12
+ overflow: hidden;
13
+ font-family: 'Press Start 2P', cursive;
14
+ image-rendering: pixelated;
15
+ }
16
+
17
+ canvas {
18
+ display: block;
19
+ image-rendering: pixelated;
20
+ }
21
+
22
+ @font-face {
23
+ font-family: 'Press Start 2P';
24
+ src: url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
25
+ }
26
+
27
+ .pixel-border {
28
+ border: 4px solid #fff;
29
+ box-shadow: 0 0 0 4px #000, inset 0 0 0 4px #000;
30
+ }
31
+
32
+ .quiz-option {
33
+ transition: all 0.1s;
34
+ border: 3px solid #fff;
35
+ box-shadow: 0 0 0 3px #000;
36
+ }
37
+
38
+ .quiz-option:hover {
39
+ background-color: #4a5568;
40
+ transform: translateY(-2px);
41
+ }
42
+
43
+ .quiz-option.correct {
44
+ background-color: #48bb78;
45
+ }
46
+
47
+ .quiz-option.wrong {
48
+ background-color: #f56565;
49
+ }
50
+
51
+ .pixel-text {
52
+ text-shadow: 3px 3px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
53
+ }
54
+
55
+ .health-bar {
56
+ height: 10px;
57
+ background-color: #4a5568;
58
+ border: 2px solid #000;
59
+ }
60
+
61
+ .health-fill {
62
+ height: 100%;
63
+ background-color: #48bb78;
64
+ transition: width 0.3s;
65
+ }
66
+
67
+ /* New styles for better camera controls */
68
+ .controls-info {
69
+ position: absolute;
70
+ bottom: 20px;
71
+ left: 50%;
72
+ transform: translateX(-50%);
73
+ background-color: rgba(0, 0, 0, 0.7);
74
+ padding: 10px;
75
+ border-radius: 5px;
76
+ color: white;
77
+ text-align: center;
78
+ font-size: 12px;
79
+ }
80
+ </style>
81
+ </head>
82
+ <body class="bg-gray-900">
83
+ <div id="game-container" class="relative w-full h-screen">
84
+ <!-- Start Screen -->
85
+ <div id="start-screen" class="absolute inset-0 flex flex-col items-center justify-center bg-gray-900 z-10">
86
+ <h1 class="text-4xl md:text-6xl text-green-400 mb-8 pixel-text">PIXEL QUEST 3D</h1>
87
+ <p class="text-xl text-white mb-12 pixel-text">Find Your Lost Friend!</p>
88
+ <div class="flex mb-8">
89
+ <div class="w-16 h-16 bg-red-500 pixel-border mr-4"></div>
90
+ <div class="w-16 h-16 bg-blue-500 pixel-border"></div>
91
+ </div>
92
+ <button id="start-btn" class="px-8 py-4 bg-green-500 hover:bg-green-600 text-white font-bold pixel-border transition-all transform hover:scale-105">
93
+ START ADVENTURE
94
+ </button>
95
+ <div class="mt-8 text-white text-sm pixel-text">
96
+ Controls: WASD to move, Space to jump, F to attack
97
+ </div>
98
+ </div>
99
+
100
+ <!-- Quiz Modal -->
101
+ <div id="quiz-modal" class="hidden absolute inset-0 flex items-center justify-center z-20 bg-black bg-opacity-70">
102
+ <div class="bg-gray-800 p-6 rounded-lg w-11/12 max-w-md pixel-border">
103
+ <h2 id="quiz-question" class="text-xl text-white mb-6 pixel-text"></h2>
104
+ <div id="quiz-options" class="space-y-3"></div>
105
+ <div id="quiz-feedback" class="mt-4 text-yellow-300 hidden pixel-text"></div>
106
+ </div>
107
+ </div>
108
+
109
+ <!-- End Screen -->
110
+ <div id="end-screen" class="hidden absolute inset-0 flex flex-col items-center justify-center bg-gray-900 z-10">
111
+ <h1 id="end-title" class="text-4xl md:text-6xl text-green-400 mb-8 pixel-text">FRIEND FOUND!</h1>
112
+ <div class="flex items-center mb-8">
113
+ <div class="w-32 h-32 bg-red-500 pixel-border mr-4"></div>
114
+ <div class="w-32 h-32 bg-blue-500 pixel-border"></div>
115
+ </div>
116
+ <p id="final-score" class="text-xl text-white mb-12 pixel-text"></p>
117
+ <button id="restart-btn" class="px-8 py-4 bg-green-500 hover:bg-green-600 text-white font-bold pixel-border transition-all transform hover:scale-105">
118
+ PLAY AGAIN
119
+ </button>
120
+ </div>
121
+
122
+ <!-- Game Over Screen -->
123
+ <div id="game-over-screen" class="hidden absolute inset-0 flex flex-col items-center justify-center bg-gray-900 z-10">
124
+ <h1 class="text-4xl md:text-6xl text-red-500 mb-8 pixel-text">GAME OVER</h1>
125
+ <p id="game-over-score" class="text-xl text-white mb-12 pixel-text"></p>
126
+ <button id="game-over-restart-btn" class="px-8 py-4 bg-green-500 hover:bg-green-600 text-white font-bold pixel-border transition-all transform hover:scale-105">
127
+ TRY AGAIN
128
+ </button>
129
+ </div>
130
+
131
+ <!-- UI Elements -->
132
+ <div id="ui-container" class="absolute top-4 left-4 z-10 hidden">
133
+ <div class="bg-gray-800 bg-opacity-70 p-3 rounded pixel-border">
134
+ <p class="text-white pixel-text">Score: <span id="score-display">0</span></p>
135
+ <p class="text-white pixel-text">Quizzes: <span id="quiz-count">0</span>/4</p>
136
+ <div class="mt-2">
137
+ <p class="text-white pixel-text mb-1">Health:</p>
138
+ <div class="health-bar">
139
+ <div id="health-fill" class="health-fill" style="width: 100%"></div>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </div>
144
+
145
+ <!-- Controls Info -->
146
+ <div id="controls-info" class="controls-info hidden text-white pixel-text">
147
+ WASD: Move | SPACE: Jump | F: Attack Obstacles
148
+ </div>
149
+ </div>
150
+
151
+ <script>
152
+ // Game variables
153
+ let scene, camera, renderer;
154
+ let player, platforms = [], checkpoints = [], coins = [], obstacles = [];
155
+ let playerVelocity = { x: 0, y: 0, z: 0 };
156
+ let playerSpeed = 0.2;
157
+ let jumpForce = 0.4;
158
+ let gravity = 0.02;
159
+ let isJumping = false;
160
+ let gamePaused = false;
161
+ let score = 0;
162
+ let quizzesCompleted = 0;
163
+ let currentCheckpoint = null;
164
+ let friendFound = false;
165
+ let keys = {};
166
+ let worldWidth = 100;
167
+ let worldDepth = 20;
168
+ let friend;
169
+ let playerHealth = 100;
170
+ let lastObstacleHitTime = 0;
171
+ let obstacleHitCooldown = 1000; // 1 second cooldown
172
+ let playerDirection = new THREE.Vector3();
173
+ let cameraOffset = new THREE.Vector3(0, 3, -5);
174
+
175
+ // Quiz questions
176
+ const quizQuestions = [
177
+ {
178
+ question: "What is your friend's favorite color?",
179
+ options: ["Blue", "Green", "Red", "Yellow"],
180
+ correct: 0
181
+ },
182
+ {
183
+ question: "Where did you first meet your friend?",
184
+ options: ["At school", "At the park", "At a party", "Online"],
185
+ correct: 1
186
+ },
187
+ {
188
+ question: "What's your friend's favorite food?",
189
+ options: ["Pizza", "Sushi", "Burgers", "Tacos"],
190
+ correct: 2
191
+ },
192
+ {
193
+ question: "What was your last adventure together?",
194
+ options: ["Hiking", "Movie marathon", "Road trip", "Camping"],
195
+ correct: 3
196
+ }
197
+ ];
198
+
199
+ // Initialize game
200
+ function init() {
201
+ // Scene setup
202
+ scene = new THREE.Scene();
203
+ scene.background = new THREE.Color(0x87CEEB); // Sky blue
204
+
205
+ // Camera (perspective for better 3D feel)
206
+ const aspect = window.innerWidth / window.innerHeight;
207
+ camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000);
208
+ camera.position.set(0, 5, 15);
209
+ camera.lookAt(0, 0, 0);
210
+
211
+ // Renderer
212
+ renderer = new THREE.WebGLRenderer({ antialias: false });
213
+ renderer.setPixelRatio(window.devicePixelRatio > 1 ? 2 : 1);
214
+ renderer.setSize(window.innerWidth, window.innerHeight);
215
+ renderer.shadowMap.enabled = true;
216
+ document.getElementById('game-container').appendChild(renderer.domElement);
217
+
218
+ // Lighting
219
+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
220
+ scene.add(ambientLight);
221
+
222
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
223
+ directionalLight.position.set(10, 20, 10);
224
+ directionalLight.castShadow = true;
225
+ directionalLight.shadow.mapSize.width = 1024;
226
+ directionalLight.shadow.mapSize.height = 1024;
227
+ scene.add(directionalLight);
228
+
229
+ // Create world
230
+ createWorld();
231
+
232
+ // Create player
233
+ createPlayer();
234
+
235
+ // Create checkpoints
236
+ createCheckpoints();
237
+
238
+ // Create obstacles
239
+ createObstacles();
240
+
241
+ // Create friend
242
+ createFriend();
243
+
244
+ // Event listeners
245
+ window.addEventListener('resize', onWindowResize);
246
+ document.addEventListener('keydown', onKeyDown);
247
+ document.addEventListener('keyup', onKeyUp);
248
+
249
+ // Start button
250
+ document.getElementById('start-btn').addEventListener('click', startGame);
251
+ document.getElementById('restart-btn').addEventListener('click', restartGame);
252
+ document.getElementById('game-over-restart-btn').addEventListener('click', restartGame);
253
+ }
254
+
255
+ function createWorld() {
256
+ // Ground
257
+ const groundGeometry = new THREE.BoxGeometry(worldWidth, 1, worldDepth);
258
+ const groundMaterial = new THREE.MeshStandardMaterial({
259
+ color: 0x2e8b57,
260
+ roughness: 1.0
261
+ });
262
+ const ground = new THREE.Mesh(groundGeometry, groundMaterial);
263
+ ground.position.y = -0.5;
264
+ ground.receiveShadow = true;
265
+ scene.add(ground);
266
+
267
+ // Platforms
268
+ const platformPositions = [
269
+ { x: 10, y: 2, z: 0, width: 8, depth: 8 },
270
+ { x: 25, y: 3, z: 5, width: 6, depth: 6 },
271
+ { x: 40, y: 4, z: -3, width: 10, depth: 10 },
272
+ { x: 60, y: 2, z: 2, width: 12, depth: 8 },
273
+ { x: 80, y: 5, z: 0, width: 8, depth: 8 }
274
+ ];
275
+
276
+ platformPositions.forEach(pos => {
277
+ const platformGeometry = new THREE.BoxGeometry(pos.width, 1, pos.depth);
278
+ const platformMaterial = new THREE.MeshStandardMaterial({
279
+ color: 0x8b4513,
280
+ roughness: 1.0
281
+ });
282
+ const platform = new THREE.Mesh(platformGeometry, platformMaterial);
283
+ platform.position.set(pos.x, pos.y, pos.z);
284
+ platform.receiveShadow = true;
285
+ scene.add(platform);
286
+ platforms.push(platform);
287
+ });
288
+
289
+ // Coins
290
+ for (let i = 0; i < 20; i++) {
291
+ const coinGeometry = new THREE.CylinderGeometry(0.5, 0.5, 0.2, 16);
292
+ const coinMaterial = new THREE.MeshStandardMaterial({ color: 0xffd700 });
293
+ const coin = new THREE.Mesh(coinGeometry, coinMaterial);
294
+
295
+ // Position coins randomly above platforms or ground
296
+ let x, y, z;
297
+ if (Math.random() > 0.5) {
298
+ // On platforms
299
+ const platform = platforms[Math.floor(Math.random() * platforms.length)];
300
+ x = platform.position.x + (Math.random() - 0.5) * (platform.geometry.parameters.width - 2);
301
+ y = platform.position.y + 1;
302
+ z = platform.position.z + (Math.random() - 0.5) * (platform.geometry.parameters.depth - 2);
303
+ } else {
304
+ // On ground
305
+ x = Math.random() * worldWidth;
306
+ y = 0.5;
307
+ z = (Math.random() - 0.5) * (worldDepth - 4);
308
+ }
309
+
310
+ coin.position.set(x, y, z);
311
+ coin.rotation.x = Math.PI / 2;
312
+ coin.userData.isCoin = true;
313
+ scene.add(coin);
314
+ coins.push(coin);
315
+ }
316
+ }
317
+
318
+ function createPlayer() {
319
+ // Simple pixel-style character
320
+ const playerGeometry = new THREE.BoxGeometry(1, 2, 1);
321
+ const playerMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
322
+ player = new THREE.Mesh(playerGeometry, playerMaterial);
323
+ player.position.set(0, 1, 0);
324
+ player.castShadow = true;
325
+ scene.add(player);
326
+ }
327
+
328
+ function createCheckpoints() {
329
+ // Create 4 checkpoints along the path
330
+ const checkpointPositions = [
331
+ { x: 15, y: 0, z: 0 },
332
+ { x: 30, y: 0, z: 0 },
333
+ { x: 50, y: 0, z: 0 },
334
+ { x: 70, y: 0, z: 0 }
335
+ ];
336
+
337
+ checkpointPositions.forEach((pos, index) => {
338
+ const checkpointGeometry = new THREE.BoxGeometry(2, 2, 2);
339
+ const checkpointMaterial = new THREE.MeshStandardMaterial({
340
+ color: 0xffff00,
341
+ transparent: true,
342
+ opacity: 0.7
343
+ });
344
+ const checkpoint = new THREE.Mesh(checkpointGeometry, checkpointMaterial);
345
+ checkpoint.position.set(pos.x, pos.y + 1, pos.z);
346
+ checkpoint.userData.isCheckpoint = true;
347
+ checkpoint.userData.quizIndex = index;
348
+ scene.add(checkpoint);
349
+ checkpoints.push(checkpoint);
350
+ });
351
+ }
352
+
353
+ function createObstacles() {
354
+ // Create destroyable obstacles
355
+ const obstaclePositions = [
356
+ { x: 5, y: 1, z: 3, width: 1, height: 2, depth: 1 },
357
+ { x: 20, y: 1, z: -2, width: 1, height: 2, depth: 1 },
358
+ { x: 35, y: 1, z: 4, width: 1, height: 2, depth: 1 },
359
+ { x: 45, y: 1, z: -3, width: 1, height: 2, depth: 1 },
360
+ { x: 65, y: 1, z: 2, width: 1, height: 2, depth: 1 }
361
+ ];
362
+
363
+ obstaclePositions.forEach(pos => {
364
+ const obstacleGeometry = new THREE.BoxGeometry(pos.width, pos.height, pos.depth);
365
+ const obstacleMaterial = new THREE.MeshStandardMaterial({
366
+ color: 0x8b0000,
367
+ roughness: 1.0
368
+ });
369
+ const obstacle = new THREE.Mesh(obstacleGeometry, obstacleMaterial);
370
+ obstacle.position.set(pos.x, pos.y + pos.height/2, pos.z);
371
+ obstacle.castShadow = true;
372
+ obstacle.receiveShadow = true;
373
+ obstacle.userData.isObstacle = true;
374
+ obstacle.userData.health = 30; // Obstacle health
375
+ scene.add(obstacle);
376
+ obstacles.push(obstacle);
377
+ });
378
+ }
379
+
380
+ function createFriend() {
381
+ // Create the friend character at the end
382
+ const friendGeometry = new THREE.BoxGeometry(1, 2, 1);
383
+ const friendMaterial = new THREE.MeshStandardMaterial({ color: 0x0000ff });
384
+ friend = new THREE.Mesh(friendGeometry, friendMaterial);
385
+ friend.position.set(worldWidth - 5, 1, 0);
386
+ friend.castShadow = true;
387
+ friend.userData.isFriend = true;
388
+ scene.add(friend);
389
+ }
390
+
391
+ function startGame() {
392
+ document.getElementById('start-screen').classList.add('hidden');
393
+ document.getElementById('ui-container').classList.remove('hidden');
394
+ document.getElementById('controls-info').classList.remove('hidden');
395
+ animate();
396
+ }
397
+
398
+ function restartGame() {
399
+ // Reset game state
400
+ score = 0;
401
+ quizzesCompleted = 0;
402
+ friendFound = false;
403
+ gamePaused = false;
404
+ playerHealth = 100;
405
+
406
+ // Reset player position
407
+ player.position.set(0, 1, 0);
408
+ playerVelocity = { x: 0, y: 0, z: 0 };
409
+
410
+ // Reset UI
411
+ document.getElementById('score-display').textContent = '0';
412
+ document.getElementById('quiz-count').textContent = '0/4';
413
+ document.getElementById('health-fill').style.width = '100%';
414
+ document.getElementById('end-screen').classList.add('hidden');
415
+ document.getElementById('game-over-screen').classList.add('hidden');
416
+ document.getElementById('ui-container').classList.remove('hidden');
417
+ document.getElementById('controls-info').classList.remove('hidden');
418
+
419
+ // Clear and recreate all game objects
420
+ clearScene();
421
+ createWorld();
422
+ createPlayer();
423
+ createCheckpoints();
424
+ createObstacles();
425
+ createFriend();
426
+
427
+ // Restart animation
428
+ animate();
429
+ }
430
+
431
+ function clearScene() {
432
+ // Remove all objects from scene except lights and camera
433
+ while(scene.children.length > 0) {
434
+ const obj = scene.children[0];
435
+ if (!(obj instanceof THREE.Light) && !(obj instanceof THREE.Camera)) {
436
+ scene.remove(obj);
437
+ }
438
+ }
439
+
440
+ // Clear arrays
441
+ platforms = [];
442
+ checkpoints = [];
443
+ coins = [];
444
+ obstacles = [];
445
+ }
446
+
447
+ function showQuiz(quizIndex) {
448
+ gamePaused = true;
449
+ currentCheckpoint = quizIndex;
450
+
451
+ const quiz = quizQuestions[quizIndex];
452
+ document.getElementById('quiz-question').textContent = quiz.question;
453
+
454
+ const optionsContainer = document.getElementById('quiz-options');
455
+ optionsContainer.innerHTML = '';
456
+
457
+ quiz.options.forEach((option, i) => {
458
+ const optionBtn = document.createElement('button');
459
+ optionBtn.className = 'w-full p-3 bg-gray-700 text-white quiz-option pixel-text';
460
+ optionBtn.textContent = option;
461
+ optionBtn.addEventListener('click', () => checkAnswer(i));
462
+ optionsContainer.appendChild(optionBtn);
463
+ });
464
+
465
+ document.getElementById('quiz-feedback').classList.add('hidden');
466
+ document.getElementById('quiz-modal').classList.remove('hidden');
467
+ }
468
+
469
+ function checkAnswer(answerIndex) {
470
+ const quiz = quizQuestions[currentCheckpoint];
471
+ const options = document.querySelectorAll('.quiz-option');
472
+
473
+ if (answerIndex === quiz.correct) {
474
+ // Correct answer
475
+ options[answerIndex].classList.add('correct');
476
+ document.getElementById('quiz-feedback').textContent = 'Correct!';
477
+ document.getElementById('quiz-feedback').classList.remove('hidden');
478
+
479
+ setTimeout(() => {
480
+ quizzesCompleted++;
481
+ document.getElementById('quiz-count').textContent = `${quizzesCompleted}/4`;
482
+ document.getElementById('quiz-modal').classList.add('hidden');
483
+ gamePaused = false;
484
+
485
+ // Remove the checkpoint
486
+ const checkpoint = checkpoints[currentCheckpoint];
487
+ scene.remove(checkpoint);
488
+ checkpoints[currentCheckpoint] = null;
489
+
490
+ // Add score
491
+ score += 100;
492
+ document.getElementById('score-display').textContent = score;
493
+
494
+ // Reset player velocity to prevent getting stuck
495
+ playerVelocity.x = 0;
496
+ playerVelocity.z = 0;
497
+ }, 1000);
498
+ } else {
499
+ // Wrong answer
500
+ options[answerIndex].classList.add('wrong');
501
+ options[quiz.correct].classList.add('correct');
502
+ document.getElementById('quiz-feedback').textContent = 'Try again!';
503
+ document.getElementById('quiz-feedback').classList.remove('hidden');
504
+ }
505
+ }
506
+
507
+ function onWindowResize() {
508
+ const aspect = window.innerWidth / window.innerHeight;
509
+ camera.aspect = aspect;
510
+ camera.updateProjectionMatrix();
511
+ renderer.setSize(window.innerWidth, window.innerHeight);
512
+ }
513
+
514
+ function onKeyDown(event) {
515
+ keys[event.code] = true;
516
+
517
+ // Jump
518
+ if (event.code === 'Space' && !isJumping && !gamePaused) {
519
+ playerVelocity.y = jumpForce;
520
+ isJumping = true;
521
+ }
522
+
523
+ // Attack (destroy obstacles)
524
+ if (event.code === 'KeyF' && !gamePaused) {
525
+ attackObstacle();
526
+ }
527
+ }
528
+
529
+ function onKeyUp(event) {
530
+ keys[event.code] = false;
531
+ }
532
+
533
+ function attackObstacle() {
534
+ const playerBox = new THREE.Box3().setFromObject(player);
535
+
536
+ obstacles.forEach((obstacle, index) => {
537
+ if (obstacle && new THREE.Box3().setFromObject(player).intersectsBox(new THREE.Box3().setFromObject(obstacle))) {
538
+ // Reduce obstacle health
539
+ obstacle.userData.health -= 10;
540
+
541
+ // If obstacle is destroyed
542
+ if (obstacle.userData.health <= 0) {
543
+ scene.remove(obstacle);
544
+ obstacles[index] = null;
545
+ score += 50;
546
+ document.getElementById('score-display').textContent = score;
547
+ }
548
+ }
549
+ });
550
+ }
551
+
552
+ function checkCollisions() {
553
+ // Check platform collisions
554
+ let onGround = false;
555
+ const playerBox = new THREE.Box3().setFromObject(player);
556
+
557
+ platforms.forEach(platform => {
558
+ const platformBox = new THREE.Box3().setFromObject(platform);
559
+ if (playerBox.intersectsBox(platformBox)) {
560
+ // Check if player is on top of platform
561
+ if (player.position.y > platform.position.y + 0.9) {
562
+ player.position.y = platform.position.y + 1 + player.geometry.parameters.height / 2;
563
+ playerVelocity.y = 0;
564
+ isJumping = false;
565
+ onGround = true;
566
+ }
567
+ }
568
+ });
569
+
570
+ // Ground collision
571
+ if (player.position.y <= 0) {
572
+ player.position.y = 0;
573
+ playerVelocity.y = 0;
574
+ isJumping = false;
575
+ onGround = true;
576
+ }
577
+
578
+ // Check coin collisions
579
+ coins.forEach((coin, index) => {
580
+ if (coin && new THREE.Box3().setFromObject(player).intersectsBox(new THREE.Box3().setFromObject(coin))) {
581
+ scene.remove(coin);
582
+ coins[index] = null;
583
+ score += 10;
584
+ document.getElementById('score-display').textContent = score;
585
+ }
586
+ });
587
+
588
+ // Check checkpoint collisions
589
+ checkpoints.forEach((checkpoint, index) => {
590
+ if (checkpoint && new THREE.Box3().setFromObject(player).intersectsBox(new THREE.Box3().setFromObject(checkpoint))) {
591
+ showQuiz(index);
592
+ }
593
+ });
594
+
595
+ // Check obstacle collisions (damage player)
596
+ const currentTime = Date.now();
597
+ obstacles.forEach(obstacle => {
598
+ if (obstacle && new THREE.Box3().setFromObject(player).intersectsBox(new THREE.Box3().setFromObject(obstacle))) {
599
+ if (currentTime - lastObstacleHitTime > obstacleHitCooldown) {
600
+ playerHealth -= 10;
601
+ lastObstacleHitTime = currentTime;
602
+ document.getElementById('health-fill').style.width = `${playerHealth}%`;
603
+
604
+ // Flash player red when hit
605
+ player.material.color.setHex(0xff0000);
606
+ setTimeout(() => {
607
+ player.material.color.setHex(0xff0000);
608
+ }, 200);
609
+
610
+ // Check if player died
611
+ if (playerHealth <= 0) {
612
+ gameOver();
613
+ }
614
+ }
615
+ }
616
+ });
617
+
618
+ // Check friend collision
619
+ if (!friendFound && new THREE.Box3().setFromObject(player).intersectsBox(new THREE.Box3().setFromObject(friend)) && quizzesCompleted === 4) {
620
+ friendFound = true;
621
+ gamePaused = true;
622
+
623
+ // Show end screen
624
+ document.getElementById('final-score').textContent = `Final Score: ${score}`;
625
+ document.getElementById('end-screen').classList.remove('hidden');
626
+ document.getElementById('ui-container').classList.add('hidden');
627
+ document.getElementById('controls-info').classList.add('hidden');
628
+ }
629
+
630
+ return onGround;
631
+ }
632
+
633
+ function gameOver() {
634
+ gamePaused = true;
635
+ document.getElementById('game-over-score').textContent = `Score: ${score}`;
636
+ document.getElementById('game-over-screen').classList.remove('hidden');
637
+ document.getElementById('ui-container').classList.add('hidden');
638
+ document.getElementById('controls-info').classList.add('hidden');
639
+ }
640
+
641
+ function updateCamera() {
642
+ // Calculate camera position based on player position and direction
643
+ const targetPosition = new THREE.Vector3();
644
+ targetPosition.copy(player.position);
645
+
646
+ // Apply offset relative to player's direction
647
+ const offset = cameraOffset.clone();
648
+
649
+ // Apply the offset to the target position
650
+ targetPosition.add(offset);
651
+
652
+ // Smooth camera movement
653
+ camera.position.lerp(targetPosition, 0.1);
654
+
655
+ // Make camera look at player
656
+ camera.lookAt(player.position);
657
+ }
658
+
659
+ function animate() {
660
+ if (gamePaused) return;
661
+
662
+ requestAnimationFrame(animate);
663
+
664
+ // Player movement - now using WASD for full 3D movement
665
+ const moveSpeed = playerSpeed;
666
+ const moveVector = new THREE.Vector3(0, 0, 0);
667
+
668
+ if (keys['KeyW'] || keys['ArrowUp']) {
669
+ moveVector.z -= moveSpeed;
670
+ }
671
+ if (keys['KeyS'] || keys['ArrowDown']) {
672
+ moveVector.z += moveSpeed;
673
+ }
674
+ if (keys['KeyA'] || keys['ArrowLeft']) {
675
+ moveVector.x -= moveSpeed;
676
+ }
677
+ if (keys['KeyD'] || keys['ArrowRight']) {
678
+ moveVector.x += moveSpeed;
679
+ }
680
+
681
+ // Normalize the vector to prevent faster diagonal movement
682
+ if (moveVector.length() > 0) {
683
+ moveVector.normalize().multiplyScalar(moveSpeed);
684
+
685
+ // Rotate player to face movement direction
686
+ if (moveVector.x !== 0 || moveVector.z !== 0) {
687
+ player.rotation.y = Math.atan2(moveVector.x, moveVector.z);
688
+ }
689
+ }
690
+
691
+ // Apply movement to velocity
692
+ playerVelocity.x = moveVector.x;
693
+ playerVelocity.z = moveVector.z;
694
+
695
+ // Apply gravity
696
+ playerVelocity.y -= gravity;
697
+
698
+ // Update player position
699
+ player.position.x += playerVelocity.x;
700
+ player.position.y += playerVelocity.y;
701
+ player.position.z += playerVelocity.z;
702
+
703
+ // Check collisions
704
+ checkCollisions();
705
+
706
+ // Update camera
707
+ updateCamera();
708
+
709
+ renderer.render(scene, camera);
710
+ }
711
+
712
+ // Start the game
713
+ init();
714
+ </script>
715
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=DevForML/3d-game" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
716
+ </html>