AdhamYasser2025 commited on
Commit
3fa2a5f
·
verified ·
1 Parent(s): 078a19d

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +603 -874
index.html CHANGED
@@ -1,1072 +1,801 @@
1
  <!DOCTYPE html>
2
  <html lang="ar" dir="rtl">
3
-
4
  <head>
5
  <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
7
- <title>EATER HOLE 3D ULTRA - حفرة الآكلة ثلاثية الأبعاد</title>
8
-
9
- <!-- استيراد مكتبة Three.js -->
10
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
11
-
12
  <style>
13
  * {
14
  margin: 0;
15
  padding: 0;
16
  box-sizing: border-box;
 
17
  }
18
-
19
  body {
20
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
21
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
22
  overflow: hidden;
 
 
 
23
  touch-action: none;
24
- user-select: none;
25
  }
26
-
27
  #gameContainer {
28
  position: relative;
29
- width: 100vw;
30
  height: 100vh;
31
  }
32
-
33
  #gameCanvas {
34
- display: none;
 
 
35
  width: 100%;
36
  height: 100%;
 
37
  }
38
-
39
- /* Main Menu Styles */
40
- #mainMenu {
41
  position: absolute;
42
  top: 0;
43
  left: 0;
44
  width: 100%;
45
  height: 100%;
46
- background: linear-gradient(135deg, #0a0e27 0%, #1a0033 100%);
47
  display: flex;
48
  flex-direction: column;
49
  justify-content: center;
50
  align-items: center;
51
- z-index: 1000;
52
- animation: neonPulse 2s ease-in-out infinite alternate;
 
53
  }
54
-
55
- @keyframes neonPulse {
56
- 0% {
57
- filter: brightness(1) drop-shadow(0 0 20px #00ffff);
58
- }
59
- 100% {
60
- filter: brightness(1.2) drop-shadow(0 0 40px #ff00ff);
61
- }
62
- }
63
-
64
  .gameTitle {
65
- font-size: clamp(2rem, 6vw, 4rem);
66
- font-weight: bold;
67
- background: linear-gradient(45deg, #00ffff, #ff00ff, #ffff00);
 
68
  -webkit-background-clip: text;
69
- -webkit-text-fill-color: transparent;
70
  background-clip: text;
71
- text-align: center;
72
- margin-bottom: 20px;
73
- animation: glow 2s ease-in-out infinite alternate;
74
- text-shadow: 0 0 30px rgba(0, 255, 255, 0.5);
75
- }
76
-
77
- @keyframes glow {
78
- 0% {
79
- filter: drop-shadow(0 0 20px #00ffff);
80
- }
81
- 100% {
82
- filter: drop-shadow(0 0 40px #ff00ff);
83
- }
84
  }
85
-
86
  .developer {
87
- color: #00ffff;
88
  font-size: 1.2rem;
89
- margin-bottom: 40px;
90
- text-shadow: 0 0 10px rgba(0, 255, 255, 0.8);
91
  }
92
-
93
- .menuButton {
94
- padding: 15px 40px;
95
- margin: 10px;
96
- font-size: 1.2rem;
97
- font-weight: bold;
98
- background: linear-gradient(45deg, #667eea, #764ba2);
99
  color: white;
100
- border: 2px solid #00ffff;
 
 
 
101
  border-radius: 50px;
102
  cursor: pointer;
 
 
103
  transition: all 0.3s;
104
- box-shadow: 0 4px 15px rgba(0, 255, 255, 0.4);
105
- min-width: 200px;
106
- }
107
-
108
- .menuButton:hover {
109
- transform: translateY(-3px) scale(1.05);
110
- box-shadow: 0 8px 25px rgba(255, 0, 255, 0.6);
111
- background: linear-gradient(45deg, #764ba2, #667eea);
112
- }
113
-
114
- /* HUD Styles */
115
- #gameHUD {
116
- position: absolute;
117
- top: 20px;
118
- right: 20px;
119
- color: white;
120
- font-size: 1.2rem;
121
- font-weight: bold;
122
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
123
- z-index: 100;
124
- display: none;
125
  }
126
-
127
- .hudItem {
128
- background: rgba(0, 0, 0, 0.7);
129
- padding: 10px 20px;
130
- margin: 5px 0;
131
- border-radius: 10px;
132
- border: 2px solid #00ffff;
133
- box-shadow: 0 0 20px rgba(0, 255, 255, 0.5);
134
- }
135
-
136
- /* Mobile Controls */
137
- #mobileControls {
138
- position: absolute;
139
- bottom: 20px;
140
- left: 50%;
141
- transform: translateX(-50%);
142
- display: none;
143
- z-index: 100;
144
  }
145
-
146
- .joystick {
147
- width: 150px;
148
- height: 150px;
149
- background: radial-gradient(circle, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.1));
150
- border: 3px solid #00ffff;
151
- border-radius: 50%;
152
- position: relative;
153
- box-shadow: 0 0 30px rgba(0, 255, 255, 0.5);
154
  }
155
-
156
- .joystickKnob {
157
  width: 60px;
158
  height: 60px;
159
- background: radial-gradient(circle, #ff00ff, #667eea);
160
  border-radius: 50%;
161
- position: absolute;
162
- top: 50%;
163
- left: 50%;
164
- transform: translate(-50%, -50%);
165
- box-shadow: 0 0 20px rgba(255, 0, 255, 0.8);
166
  }
167
-
168
- /* WhatsApp Button */
169
- .whatsappBtn {
170
- position: fixed;
171
- bottom: 20px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  left: 20px;
173
- width: 60px;
174
- height: 60px;
175
- background: #25d366;
176
- border-radius: 50%;
 
 
 
 
 
177
  display: flex;
178
- align-items: center;
179
- justify-content: center;
180
- text-decoration: none;
181
- box-shadow: 0 4px 20px rgba(37, 211, 102, 0.5);
182
- z-index: 1001;
183
- transition: transform 0.3s;
184
  }
185
-
186
- .whatsappBtn:hover {
187
- transform: scale(1.1);
188
  }
189
-
190
- .whatsappBtn::before {
191
- content: "💬";
192
- font-size: 30px;
193
  }
194
-
195
- /* Loading Screen */
196
- #loadingScreen {
197
  position: absolute;
198
- top: 0;
199
  left: 0;
200
  width: 100%;
201
- height: 100%;
202
- background: linear-gradient(135deg, #0a0e27, #1a0033);
203
- display: none;
204
- flex-direction: column;
205
- justify-content: center;
206
- align-items: center;
207
- z-index: 2000;
208
  }
209
-
210
- .loader {
211
  width: 80px;
212
  height: 80px;
213
- border: 8px solid rgba(0, 255, 255, 0.3);
214
- border-top: 8px solid #00ffff;
215
  border-radius: 50%;
216
- animation: spin 1s linear infinite;
217
- }
218
-
219
- @keyframes spin {
220
- 0% { transform: rotate(0deg); }
221
- 100% { transform: rotate(360deg); }
222
- }
223
-
224
- /* Pause Menu */
225
- #pauseMenu {
226
- position: absolute;
227
- top: 50%;
228
- left: 50%;
229
- transform: translate(-50%, -50%);
230
- background: rgba(0, 0, 0, 0.9);
231
- padding: 30px;
232
- border-radius: 20px;
233
- border: 2px solid #00ffff;
234
- display: none;
235
- z-index: 500;
236
- }
237
-
238
- .pauseTitle {
239
- color: #00ffff;
240
  font-size: 2rem;
241
- margin-bottom: 20px;
242
- text-align: center;
243
- }
244
-
245
- /* Skin Selection Modal */
246
- #skinModal {
247
- position: absolute;
248
- top: 50%;
249
- left: 50%;
250
- transform: translate(-50%, -50%);
251
- background: rgba(0, 0, 0, 0.95);
252
- padding: 30px;
253
- border-radius: 20px;
254
- border: 2px solid #00ffff;
255
- display: none;
256
- z-index: 600;
257
- max-width: 400px;
258
- width: 90%;
259
- }
260
-
261
- .skinTitle {
262
- color: #00ffff;
263
- font-size: 1.8rem;
264
- margin-bottom: 20px;
265
- text-align: center;
266
- }
267
-
268
- .skinGrid {
269
- display: grid;
270
- grid-template-columns: repeat(2, 1fr);
271
- gap: 15px;
272
- margin-bottom: 20px;
273
- }
274
-
275
- .skinOption {
276
- padding: 15px;
277
- background: linear-gradient(45deg, #667eea, #764ba2);
278
- border: 2px solid transparent;
279
- border-radius: 10px;
280
  color: white;
281
- cursor: pointer;
282
- transition: all 0.3s;
283
- text-align: center;
284
- font-weight: bold;
285
- }
286
-
287
- .skinOption:hover {
288
- border-color: #00ffff;
289
- transform: scale(1.05);
290
- box-shadow: 0 0 20px rgba(0, 255, 255, 0.5);
291
- }
292
-
293
- .skinOption.selected {
294
- border-color: #00ffff;
295
- background: linear-gradient(45deg, #00ffff, #ff00ff);
296
  }
297
-
298
- /* Instructions Modal */
299
- #instructionsModal {
300
  position: absolute;
301
  top: 50%;
302
  left: 50%;
303
  transform: translate(-50%, -50%);
304
- background: rgba(0, 0, 0, 0.95);
305
  padding: 30px;
306
  border-radius: 20px;
307
- border: 2px solid #00ffff;
 
308
  display: none;
309
- z-index: 600;
310
- max-width: 500px;
311
- width: 90%;
312
  }
313
-
314
- .instructionsTitle {
315
- color: #00ffff;
316
- font-size: 1.8rem;
317
  margin-bottom: 20px;
318
- text-align: center;
319
  }
320
-
321
- .instructionsText {
322
- color: white;
323
- line-height: 1.8;
324
- font-size: 1.1rem;
 
 
 
325
  }
326
-
327
- .closeButton {
328
- background: linear-gradient(45deg, #ff00ff, #667eea);
329
- color: white;
330
- border: none;
331
- padding: 10px 20px;
332
- border-radius: 10px;
333
- cursor: pointer;
334
- margin-top: 20px;
335
- font-weight: bold;
336
- width: 100%;
337
  }
338
-
339
- /* Responsive */
340
  @media (max-width: 768px) {
341
  .gameTitle {
342
- font-size: 2rem;
343
  }
344
-
345
- .menuButton {
346
- padding: 12px 30px;
 
347
  font-size: 1rem;
348
  }
349
-
350
- #gameHUD {
351
- font-size: 1rem;
352
- top: 10px;
353
- right: 10px;
354
  }
355
-
356
- .hudItem {
357
- padding: 8px 15px;
 
 
 
358
  }
359
  }
360
-
361
- /* Built with anycoder link */
362
- .anycoderLink {
363
- position: fixed;
364
- top: 10px;
365
- right: 10px;
366
- color: #00ffff;
367
- text-decoration: none;
368
- font-size: 12px;
369
- z-index: 1002;
370
- text-shadow: 0 0 5px rgba(0,255,255,0.5);
371
- transition: all 0.3s;
372
- }
373
-
374
- .anycoderLink:hover {
375
- color: #ff00ff;
376
- transform: scale(1.1);
377
- }
378
  </style>
379
  </head>
380
-
381
  <body>
382
  <div id="gameContainer">
383
- <!-- Main Menu -->
384
- <div id="mainMenu">
 
385
  <h1 class="gameTitle">EATER HOLE 3D ULTRA</h1>
386
- <p class="developer">by: أدهم ياسر محمد</p>
387
- <button class="menuButton" onclick="startGame()">ابدأ اللعب</button>
388
- <button class="menuButton" onclick="showSkins()">اختيار الجلد</button>
389
- <button class="menuButton" onclick="showInstructions()">كيفية اللعب</button>
390
- <button class="menuButton" onclick="toggleSound()">🔊 الصوت</button>
391
- </div>
392
-
393
- <!-- Loading Screen -->
394
- <div id="loadingScreen">
395
- <div class="loader"></div>
396
- <p style="color: #00ffff; margin-top: 20px;">جاري التحميل...</p>
397
- </div>
398
-
399
- <!-- Pause Menu -->
400
- <div id="pauseMenu">
401
- <h2 class="pauseTitle">إيقاف مؤقت</h2>
402
- <button class="menuButton" onclick="resumeGame()">متابعة</button>
403
- <button class="menuButton" onclick="backToMenu()">القائمة الرئيسية</button>
404
- </div>
405
-
406
- <!-- Skin Selection Modal -->
407
- <div id="skinModal">
408
- <h2 class="skinTitle">اختر الجلد</h2>
409
- <div class="skinGrid">
410
- <div class="skinOption" onclick="selectSkin('classic', this)">Classic</div>
411
- <div class="skinOption" onclick="selectSkin('fire', this)">Fire</div>
412
- <div class="skinOption" onclick="selectSkin('disco', this)">Disco</div>
413
- <div class="skinOption" onclick="selectSkin('ice', this)">Ice</div>
414
- <div class="skinOption" onclick="selectSkin('galaxy', this)">Galaxy</div>
415
- <div class="skinOption" onclick="selectSkin('rainbow', this)">Rainbow</div>
416
  </div>
417
- <button class="closeButton" onclick="closeSkinModal()">اختيار</button>
 
 
 
418
  </div>
419
-
420
- <!-- Instructions Modal -->
421
- <div id="instructionsModal">
422
- <h2 class="instructionsTitle">كيفية اللعب</h2>
423
- <div class="instructionsText">
424
- <p>📱 <strong>على الهاتف:</strong> استخدم عصا التحكم في الأسفل</p>
425
- <p>⌨️ <strong>على الكمبيوتر:</strong> استخدم الأسهم أو WASD</p>
426
- <p>🎯 <strong>الهدف:</strong> أكل كل الأشياء الصغرى من حجمك</p>
427
- <p>📈 <strong>النمو:</strong> كلما أكلت أكثر، كلما كبرت</p>
428
- <p>🏆 <strong>المستويات:</strong> أكمل المستويات وزد نقاطك!</p>
429
- <p>🎮 <strong>ESC:</strong> إيقاف مؤقت</p>
430
- <p>🤖 <strong>NPC:</strong> احذر من الحفر الأخرى!</p>
 
 
 
 
 
431
  </div>
432
- <button class="closeButton" onclick="closeInstructions()">فهمت!</button>
433
- </div>
434
-
435
- <!-- Game Canvas -->
436
- <canvas id="gameCanvas"></canvas>
437
-
438
- <!-- Game HUD -->
439
- <div id="gameHUD">
440
- <div class="hudItem">المستوى: <span id="level">1</span></div>
441
- <div class="hudItem">الحجم: <span id="size">5.0</span></div>
442
- <div class="hudItem">الأهداف: <span id="objects">50</span></div>
443
- <div class="hudItem">النقاط: <span id="score">0</span></div>
444
  </div>
445
-
446
- <!-- Mobile Controls -->
447
  <div id="mobileControls">
448
- <div class="joystick" id="joystick">
449
- <div class="joystickKnob" id="joystickKnob"></div>
450
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
451
  </div>
452
-
453
- <!-- WhatsApp Button -->
454
- <a href="https://wa.me/01097399624" class="whatsappBtn" target="_blank"></a>
455
-
456
- <!-- Built with anycoder -->
457
- <a href="https://huggingface.co/spaces/akhaliq/anycoder" class="anycoderLink" target="_blank">Built with anycoder</a>
458
  </div>
459
 
460
  <script>
461
- // Game Variables
462
  let scene, camera, renderer;
463
- let playerHole, ground;
464
- let npcs = [];
465
  let objects = [];
 
466
  let level = 1;
 
467
  let score = 0;
468
- let soundEnabled = true;
469
- let gameRunning = false;
470
  let currentSkin = 'classic';
471
- let audioContext;
472
- let movement = { x: 0, z: 0 };
473
- let joystickActive = false;
474
- let animationId;
475
-
476
- // Initialize Three.js Scene
477
- function initScene() {
478
  scene = new THREE.Scene();
479
- scene.fog = new THREE.Fog(0x404040, 100, 500);
480
-
481
- // Camera Setup
482
- camera = new THREE.PerspectiveCamera(
483
- 75,
484
- window.innerWidth / window.innerHeight,
485
- 0.1,
486
- 1000
487
- );
488
- camera.position.set(0, 50, 50);
489
  camera.lookAt(0, 0, 0);
490
-
491
- // Renderer Setup
492
- const canvas = document.getElementById('gameCanvas');
493
  renderer = new THREE.WebGLRenderer({
494
- canvas: canvas,
495
  antialias: true
496
  });
497
  renderer.setSize(window.innerWidth, window.innerHeight);
498
- renderer.shadowMap.enabled = true;
499
- renderer.shadowMap.type = THREE.PCFSoftShadowMap;
500
-
501
- // Lighting
502
- const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
503
  scene.add(ambientLight);
504
-
505
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
506
- directionalLight.position.set(50, 100, 50);
507
- directionalLight.castShadow = true;
508
- directionalLight.shadow.camera.left = -100;
509
- directionalLight.shadow.camera.right = 100;
510
- directionalLight.shadow.camera.top = 100;
511
- directionalLight.shadow.camera.bottom = -100;
512
  scene.add(directionalLight);
513
-
 
514
  createGround();
515
- createPlayerHole();
516
- createObjects();
 
 
 
517
  createNPCs();
 
 
 
 
 
 
 
 
 
518
  }
519
-
520
- // Create Ground
521
  function createGround() {
522
- const groundGeometry = new THREE.PlaneGeometry(200, 200, 50, 50);
523
- const groundMaterial = new THREE.MeshLambertMaterial({
524
- color: 0xffffff,
525
- wireframe: false
 
526
  });
527
  ground = new THREE.Mesh(groundGeometry, groundMaterial);
528
  ground.rotation.x = -Math.PI / 2;
529
- ground.receiveShadow = true;
530
  scene.add(ground);
 
 
 
 
 
 
531
  }
532
-
533
- // Create Player Hole
534
- function createPlayerHole() {
535
- const holeGeometry = new THREE.CylinderGeometry(5, 5, 2, 32);
536
- const holeMaterial = new THREE.MeshBasicMaterial({
537
  color: 0x000000,
538
- transparent: true,
539
- opacity: 0.8
540
- });
541
- playerHole = new THREE.Mesh(holeGeometry, holeMaterial);
542
- playerHole.position.y = -1;
543
- scene.add(playerHole);
544
-
545
- // Add ring effect
546
- const ringGeometry = new THREE.RingGeometry(5, 5.5, 32);
547
- const ringMaterial = new THREE.MeshBasicMaterial({
548
- color: 0xff00ff,
549
- side: THREE.DoubleSide,
550
- transparent: true,
551
- opacity: 0.6
552
  });
553
- const ring = new THREE.Mesh(ringGeometry, ringMaterial);
554
- ring.rotation.x = -Math.PI / 2;
555
- ring.position.y = 0.01;
556
- playerHole.add(ring);
557
-
558
- applySkin();
559
  }
560
-
561
- // Create Objects
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
562
  function createObjects() {
563
- const objectTypes = [
564
- { size: 1, color: 0x00ff00, height: 2, points: 10 },
565
- { size: 2, color: 0x0000ff, height: 4, points: 20 },
566
- { size: 3, color: 0xff0000, height: 6, points: 30 },
567
- { size: 4, color: 0xffff00, height: 8, points: 40 },
568
- { size: 5, color: 0xff00ff, height: 10, points: 50 },
569
- ];
570
-
571
- for (let i = 0; i < 50; i++) {
572
- const type = objectTypes[Math.floor(Math.random() * objectTypes.length)];
573
- const geometry = new THREE.BoxGeometry(type.size, type.height, type.size);
574
- const material = new THREE.MeshLambertMaterial({ color: type.color });
575
- const object = new THREE.Mesh(geometry, material);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
576
 
577
- object.position.x = (Math.random() - 0.5) * 180;
578
- object.position.z = (Math.random() - 0.5) * 180;
579
- object.position.y = type.height / 2;
580
- object.userData = {
581
- size: type.size,
582
- originalY: type.height / 2,
583
- beingEaten: false,
584
- points: type.points
585
- };
586
 
587
- object.castShadow = true;
588
- object.receiveShadow = true;
589
  scene.add(object);
590
  objects.push(object);
591
  }
592
- }
593
-
594
- // Create NPCs
595
- function createNPCs() {
596
- for (let i = 0; i < 10; i++) {
597
- const holeGeometry = new THREE.CylinderGeometry(3, 3, 2, 32);
598
- const holeMaterial = new THREE.MeshBasicMaterial({
599
- color: new THREE.Color().setHSL(Math.random(), 1, 0.5),
600
- transparent: true,
601
- opacity: 0.7
602
- });
603
- const npc = new THREE.Mesh(holeGeometry, holeMaterial);
604
 
605
- npc.position.x = (Math.random() - 0.5) * 180;
606
- npc.position.z = (Math.random() - 0.5) * 180;
607
- npc.position.y = -1;
608
- npc.userData = {
609
- speed: 0.1 + Math.random() * 0.2,
610
- size: 3,
611
- targetX: npc.position.x,
612
- targetZ: npc.position.z,
613
- lastDirectionChange: Date.now()
614
- };
615
 
616
- scene.add(npc);
617
- npcs.push(npc);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
618
  }
619
  }
620
-
621
- // Sound System
622
- function initSound() {
623
- try {
624
- audioContext = new (window.AudioContext || window.webkitAudioContext)();
625
- } catch(e) {
626
- console.log('Audio not supported');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
627
  }
628
  }
629
-
630
- function playSound(type) {
631
- if (!soundEnabled || !audioContext) return;
632
-
 
 
 
 
 
 
 
633
  try {
 
 
 
 
634
  const oscillator = audioContext.createOscillator();
635
  const gainNode = audioContext.createGain();
636
-
637
  oscillator.connect(gainNode);
638
  gainNode.connect(audioContext.destination);
639
-
640
- switch(type) {
641
- case 'eat':
642
- oscillator.frequency.value = 200;
643
- gainNode.gain.value = 0.1;
644
- oscillator.start();
645
- oscillator.stop(audioContext.currentTime + 0.1);
646
- break;
647
- case 'levelup':
648
- oscillator.frequency.value = 400;
649
- oscillator.frequency.exponentialRampToValueAtTime(800, audioContext.currentTime + 0.5);
650
- gainNode.gain.value = 0.2;
651
- oscillator.start();
652
- oscillator.stop(audioContext.currentTime + 0.5);
653
- break;
654
- }
655
- } catch(e) {
656
- console.log('Error playing sound');
657
  }
658
  }
659
-
660
- // Game Controls
661
- function setupControls() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
662
  // Keyboard controls
663
- document.addEventListener('keydown', (e) => {
664
- if (!gameRunning) return;
665
 
666
  switch(e.key) {
667
  case 'ArrowUp':
668
  case 'w':
669
  case 'W':
670
- movement.z = -1;
671
  break;
672
  case 'ArrowDown':
673
  case 's':
674
  case 'S':
675
- movement.z = 1;
676
  break;
677
  case 'ArrowLeft':
678
  case 'a':
679
  case 'A':
680
- movement.x = -1;
681
  break;
682
  case 'ArrowRight':
683
  case 'd':
684
  case 'D':
685
- movement.x = 1;
686
- break;
687
- case 'Escape':
688
- togglePause();
689
  break;
690
  }
691
  });
692
-
693
- document.addEventListener('keyup', (e) => {
694
  switch(e.key) {
695
  case 'ArrowUp':
696
- case 'ArrowDown':
697
  case 'w':
698
  case 'W':
 
699
  case 's':
700
  case 'S':
701
- movement.z = 0;
702
  break;
703
  case 'ArrowLeft':
704
- case 'ArrowRight':
705
  case 'a':
706
  case 'A':
 
707
  case 'd':
708
  case 'D':
709
- movement.x = 0;
710
  break;
711
  }
712
  });
713
-
714
- // Touch/Joystick controls
715
- setupJoystick();
716
- }
717
-
718
- function setupJoystick() {
719
- const joystick = document.getElementById('joystick');
720
- const knob = document.getElementById('joystickKnob');
721
-
722
- const handleJoystick = (e) => {
723
- if (!joystickActive) return;
724
-
725
- const rect = joystick.getBoundingClientRect();
726
- const centerX = rect.left + rect.width / 2;
727
- const centerY = rect.top + rect.height / 2;
728
-
729
- let clientX, clientY;
730
- if (e.touches) {
731
- clientX = e.touches[0].clientX;
732
- clientY = e.touches[0].clientY;
733
- } else {
734
- clientX = e.clientX;
735
- clientY = e.clientY;
736
- }
737
-
738
- let deltaX = clientX - centerX;
739
- let deltaY = clientY - centerY;
740
-
741
- const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
742
- const maxDistance = rect.width / 2 - 30;
743
-
744
- if (distance > maxDistance) {
745
- deltaX = (deltaX / distance) * maxDistance;
746
- deltaY = (deltaY / distance) * maxDistance;
747
- }
748
-
749
- knob.style.transform = `translate(calc(-50% + ${deltaX}px), calc(-50% + ${deltaY}px))`;
750
-
751
- movement.x = deltaX / maxDistance;
752
- movement.z = deltaY / maxDistance;
753
- };
754
-
755
- const startJoystick = (e) => {
756
- joystickActive = true;
757
- handleJoystick(e);
758
- e.preventDefault();
759
- };
760
-
761
- const endJoystick = () => {
762
- joystickActive = false;
763
- knob.style.transform = 'translate(-50%, -50%)';
764
- movement.x = 0;
765
- movement.z = 0;
766
- };
767
-
768
- // Touch events
769
- joystick.addEventListener('touchstart', startJoystick);
770
- joystick.addEventListener('touchmove', handleJoystick);
771
- joystick.addEventListener('touchend', endJoystick);
772
-
773
- // Mouse events for desktop
774
- joystick.addEventListener('mousedown', startJoystick);
775
- document.addEventListener('mousemove', handleJoystick);
776
- document.addEventListener('mouseup', endJoystick);
777
- }
778
-
779
- // Update Game Logic
780
- function updateGame() {
781
- if (!gameRunning) return;
782
-
783
- // Update player position
784
- if (movement.x !== 0 || movement.z !== 0) {
785
- const speed = 0.5;
786
- playerHole.position.x += movement.x * speed;
787
- playerHole.position.z += movement.z * speed;
788
-
789
- // Keep player in bounds
790
- playerHole.position.x = Math.max(-90, Math.min(90, playerHole.position.x));
791
- playerHole.position.z = Math.max(-90, Math.min(90, playerHole.position.z));
792
-
793
- // Update camera to follow player
794
- camera.position.x = playerHole.position.x;
795
- camera.position.z = playerHole.position.z + 50;
796
- camera.lookAt(playerHole.position.x, 0, playerHole.position.z);
797
- }
798
-
799
- // Check object collisions
800
- const playerRadius = parseFloat(playerHole.geometry.parameters.radius);
801
 
802
- objects.forEach((obj, index) => {
803
- if (obj.userData.beingEaten) {
804
- // Animate object being eaten
805
- obj.position.y -= 0.5;
806
- obj.scale.multiplyScalar(0.95);
807
-
808
- if (obj.scale.x < 0.1) {
809
- scene.remove(obj);
810
- objects.splice(index, 1);
811
- score += obj.userData.points;
812
-
813
- // Grow player hole
814
- playerHole.geometry.dispose();
815
- playerHole.geometry = new THREE.CylinderGeometry(
816
- Math.min(playerRadius + 0.2, 20),
817
- Math.min(playerRadius + 0.2, 20),
818
- 2,
819
- 32
820
- );
821
-
822
- playSound('eat');
823
- updateHUD();
824
- }
825
- return;
826
- }
827
-
828
- const distance = Math.sqrt(
829
- Math.pow(obj.position.x - playerHole.position.x, 2) +
830
- Math.pow(obj.position.z - playerHole.position.z, 2)
831
- );
832
-
833
- if (distance < playerRadius && obj.userData.size < playerRadius) {
834
- obj.userData.beingEaten = true;
835
- }
836
- });
837
-
838
- // Update NPCs
839
- npcs.forEach(npc => {
840
- // Simple AI movement
841
- const now = Date.now();
842
- if (now - npc.userData.lastDirectionChange > 2000) {
843
- npc.userData.targetX = (Math.random() - 0.5) * 180;
844
- npc.userData.targetZ = (Math.random() - 0.5) * 180;
845
- npc.userData.lastDirectionChange = now;
846
- }
847
-
848
- const dx = npc.userData.targetX - npc.position.x;
849
- const dz = npc.userData.targetZ - npc.position.z;
850
- const dist = Math.sqrt(dx * dx + dz * dz);
851
-
852
- if (dist > 1) {
853
- npc.position.x += (dx / dist) * npc.userData.speed;
854
- npc.position.z += (dz / dist) * npc.userData.speed;
855
- }
856
-
857
- // NPCs eat objects too
858
- const npcRadius = npc.userData.size;
859
- objects.forEach((obj, index) => {
860
- if (obj.userData.beingEaten) return;
861
-
862
- const distance = Math.sqrt(
863
- Math.pow(obj.position.x - npc.position.x, 2) +
864
- Math.pow(obj.position.z - npc.position.z, 2)
865
- );
866
-
867
- if (distance < npcRadius && obj.userData.size < npcRadius) {
868
- obj.userData.beingEaten = true;
869
- npc.userData.size = Math.min(npc.userData.size + 0.1, 15);
870
-
871
- npc.geometry.dispose();
872
- npc.geometry = new THREE.CylinderGeometry(
873
- npc.userData.size,
874
- npc.userData.size,
875
- 2,
876
- 32
877
- );
878
- }
879
- });
880
  });
881
-
882
- // Check level completion
883
- if (objects.length === 0) {
884
- nextLevel();
885
- }
886
- }
887
-
888
- // Level Management
889
- function nextLevel() {
890
- level++;
891
- playSound('levelup');
892
-
893
- // Clear existing objects
894
- objects.forEach(obj => scene.remove(obj));
895
- objects = [];
896
-
897
- // Create new objects
898
- createObjects();
899
-
900
- // Change ground color
901
- const colors = [0xffffff, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0xff8800];
902
- ground.material.color.setHex(colors[level % colors.length]);
903
-
904
- // Reset player position
905
- playerHole.position.set(0, -1, 0);
906
-
907
- updateHUD();
908
- }
909
-
910
- // UI Functions
911
- function updateHUD() {
912
- document.getElementById('level').textContent = level;
913
- document.getElementById('size').textContent = playerHole.geometry.parameters.radius.toFixed(1);
914
- document.getElementById('objects').textContent = objects.length;
915
- document.getElementById('score').textContent = score;
916
  }
917
-
918
- function startGame() {
919
- document.getElementById('mainMenu').style.display = 'none';
920
- document.getElementById('gameCanvas').style.display = 'block';
921
- document.getElementById('gameHUD').style.display = 'block';
922
-
923
- if (window.innerWidth <= 768) {
924
- document.getElementById('mobileControls').style.display = 'block';
925
- }
926
 
927
- if (!scene) {
928
- initScene();
929
- setupControls();
930
- initSound();
 
 
 
 
 
 
 
 
 
931
  }
932
 
933
- gameRunning = true;
934
- updateHUD();
935
- animate();
936
- }
937
-
938
- function togglePause() {
939
- if (!gameRunning) return;
940
-
941
- gameRunning = false;
942
- document.getElementById('pauseMenu').style.display = 'block';
943
- cancelAnimationFrame(animationId);
944
- }
945
-
946
- function resumeGame() {
947
- document.getElementById('pauseMenu').style.display = 'none';
948
- gameRunning = true;
949
- animate();
950
- }
951
-
952
- function backToMenu() {
953
- gameRunning = false;
954
- cancelAnimationFrame(animationId);
955
- document.getElementById('pauseMenu').style.display = 'none';
956
- document.getElementById('gameCanvas').style.display = 'none';
957
- document.getElementById('gameHUD').style.display = 'none';
958
- document.getElementById('mobileControls').style.display = 'none';
959
- document.getElementById('mainMenu').style.display = 'flex';
960
- }
961
-
962
- function showSkins() {
963
- document.getElementById('skinModal').style.display = 'block';
964
- }
965
-
966
- function closeSkinModal() {
967
- document.getElementById('skinModal').style.display = 'none';
968
  }
969
-
970
- function selectSkin(skin, element) {
971
- // Remove selected class from all options
972
- document.querySelectorAll('.skinOption').forEach(opt => {
973
- opt.classList.remove('selected');
974
- });
975
-
976
- // Add selected class to clicked option
977
- element.classList.add('selected');
978
  currentSkin = skin;
979
- applySkin();
980
- }
981
-
982
- function applySkin() {
983
- const colors = {
984
- classic: 0x000000,
985
- fire: 0xff4500,
986
- disco: 0xff00ff,
987
- ice: 0x00ffff,
988
- galaxy: 0x4b0082,
989
- rainbow: 0xff00ff
990
- };
991
-
992
- if (playerHole) {
993
- playerHole.material.color.setHex(colors[currentSkin] || 0x000000);
994
-
995
- // Update ring color for special skins
996
- const ring = playerHole.children[0];
997
- if (ring) {
998
- if (currentSkin === 'rainbow') {
999
- ring.material.color.setHSL((Date.now() / 1000) % 1, 1, 0.5);
1000
- } else {
1001
- ring.material.color.setHex(colors[currentSkin] || 0xff00ff);
1002
- }
1003
- }
1004
- }
1005
- }
1006
-
1007
- function showInstructions() {
1008
- document.getElementById('instructionsModal').style.display = 'block';
1009
- }
1010
-
1011
- function closeInstructions() {
1012
- document.getElementById('instructionsModal').style.display = 'none';
1013
- }
1014
-
1015
- function toggleSound() {
1016
- soundEnabled = !soundEnabled;
1017
- const status = soundEnabled ? 'الصوت مفعل 🔊' : 'الصوت معطل 🔇';
1018
 
1019
- // Create toast notification
1020
- const toast = document.createElement('div');
1021
- toast.textContent = status;
1022
- toast.style.cssText = `
1023
- position: fixed;
1024
- top: 50%;
1025
- left: 50%;
1026
- transform: translate(-50%, -50%);
1027
- background: rgba(0, 0, 0, 0.9);
1028
- color: ${soundEnabled ? '#00ff00' : '#ff0000'};
1029
- padding: 20px 40px;
1030
- border-radius: 10px;
1031
- font-size: 1.2rem;
1032
- font-weight: bold;
1033
- z-index: 3000;
1034
- animation: fadeInOut 2s ease-in-out;
1035
- `;
1036
- document.body.appendChild(toast);
1037
 
1038
- setTimeout(() => {
1039
- document.body.removeChild(toast);
1040
- }, 2000);
1041
  }
1042
-
1043
- // Animation Loop
1044
  function animate() {
1045
- if (!gameRunning) return;
1046
 
1047
- animationId = requestAnimationFrame(animate);
1048
- updateGame();
1049
-
1050
- // Animate rainbow skin
1051
- if (currentSkin === 'rainbow' && playerHole && playerHole.children[0]) {
1052
- playerHole.children[0].material.color.setHSL((Date.now() / 1000) % 1, 1, 0.5);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1053
  }
1054
 
1055
  renderer.render(scene, camera);
1056
  }
1057
-
1058
- // Handle Window Resize
1059
- window.addEventListener('resize', () => {
1060
- if (camera && renderer) {
1061
- camera.aspect = window.innerWidth / window.innerHeight;
1062
- camera.updateProjectionMatrix();
1063
- renderer.setSize(window.innerWidth, window.innerHeight);
1064
- }
1065
- });
1066
-
1067
- // Add fade animation
1068
- const style = document.createElement('style');
1069
- style.textContent = `
1070
- @keyframes fadeInOut {
1071
- 0% { opacity: 0; transform: translate(-50%, -50%) scale(0.8); }
1072
- 20% { opacity: 1;
 
1
  <!DOCTYPE html>
2
  <html lang="ar" dir="rtl">
 
3
  <head>
4
  <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
+ <title>EATER HOLE 3D ULTRA - لعبة الحفرة الآكلة</title>
 
 
7
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
 
8
  <style>
9
  * {
10
  margin: 0;
11
  padding: 0;
12
  box-sizing: border-box;
13
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
14
  }
15
+
16
  body {
 
 
17
  overflow: hidden;
18
+ background: linear-gradient(135deg, #0f0c29, #302b63, #24243e);
19
+ height: 100vh;
20
+ color: white;
21
  touch-action: none;
 
22
  }
23
+
24
  #gameContainer {
25
  position: relative;
26
+ width: 100%;
27
  height: 100vh;
28
  }
29
+
30
  #gameCanvas {
31
+ position: absolute;
32
+ top: 0;
33
+ left: 0;
34
  width: 100%;
35
  height: 100%;
36
+ z-index: 1;
37
  }
38
+
39
+ #menuScreen {
 
40
  position: absolute;
41
  top: 0;
42
  left: 0;
43
  width: 100%;
44
  height: 100%;
 
45
  display: flex;
46
  flex-direction: column;
47
  justify-content: center;
48
  align-items: center;
49
+ background: rgba(0, 0, 0, 0.8);
50
+ z-index: 10;
51
+ transition: opacity 0.5s;
52
  }
53
+
 
 
 
 
 
 
 
 
 
54
  .gameTitle {
55
+ font-size: 3.5rem;
56
+ margin-bottom: 1rem;
57
+ text-align: center;
58
+ background: linear-gradient(45deg, #ff00cc, #3333ff);
59
  -webkit-background-clip: text;
 
60
  background-clip: text;
61
+ color: transparent;
62
+ text-shadow: 0 0 10px rgba(255, 0, 204, 0.5);
63
+ font-weight: bold;
64
+ letter-spacing: 2px;
 
 
 
 
 
 
 
 
 
65
  }
66
+
67
  .developer {
 
68
  font-size: 1.2rem;
69
+ margin-bottom: 2rem;
70
+ color: #aaa;
71
  }
72
+
73
+ .btn {
74
+ background: linear-gradient(45deg, #ff00cc, #3333ff);
 
 
 
 
75
  color: white;
76
+ border: none;
77
+ padding: 15px 30px;
78
+ font-size: 1.2rem;
79
+ margin: 10px;
80
  border-radius: 50px;
81
  cursor: pointer;
82
+ width: 250px;
83
+ text-align: center;
84
  transition: all 0.3s;
85
+ box-shadow: 0 0 15px rgba(255, 0, 204, 0.5);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  }
87
+
88
+ .btn:hover {
89
+ transform: scale(1.05);
90
+ box-shadow: 0 0 20px rgba(255, 0, 204, 0.8);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  }
92
+
93
+ .skinSelection {
94
+ display: flex;
95
+ margin: 20px 0;
 
 
 
 
 
96
  }
97
+
98
+ .skinOption {
99
  width: 60px;
100
  height: 60px;
101
+ margin: 0 10px;
102
  border-radius: 50%;
103
+ cursor: pointer;
104
+ border: 2px solid transparent;
105
+ transition: all 0.3s;
 
 
106
  }
107
+
108
+ .skinOption.selected {
109
+ border-color: #ff00cc;
110
+ transform: scale(1.1);
111
+ box-shadow: 0 0 10px #ff00cc;
112
+ }
113
+
114
+ #classicSkin {
115
+ background: linear-gradient(45deg, #000, #333);
116
+ }
117
+
118
+ #fireSkin {
119
+ background: linear-gradient(45deg, #ff0000, #ff9900);
120
+ }
121
+
122
+ #discoSkin {
123
+ background: linear-gradient(45deg, #00ff00, #0000ff);
124
+ }
125
+
126
+ #hud {
127
+ position: absolute;
128
+ top: 20px;
129
  left: 20px;
130
+ z-index: 5;
131
+ background: rgba(0, 0, 0, 0.6);
132
+ padding: 15px;
133
+ border-radius: 15px;
134
+ min-width: 200px;
135
+ }
136
+
137
+ .hudItem {
138
+ margin: 5px 0;
139
  display: flex;
140
+ justify-content: space-between;
 
 
 
 
 
141
  }
142
+
143
+ .hudLabel {
144
+ color: #aaa;
145
  }
146
+
147
+ .hudValue {
148
+ color: #ff00cc;
149
+ font-weight: bold;
150
  }
151
+
152
+ #mobileControls {
 
153
  position: absolute;
154
+ bottom: 30px;
155
  left: 0;
156
  width: 100%;
157
+ display: flex;
158
+ justify-content: space-around;
159
+ z-index: 5;
 
 
 
 
160
  }
161
+
162
+ .controlBtn {
163
  width: 80px;
164
  height: 80px;
165
+ background: rgba(255, 255, 255, 0.2);
 
166
  border-radius: 50%;
167
+ display: flex;
168
+ justify-content: center;
169
+ align-items: center;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  font-size: 2rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  color: white;
172
+ user-select: none;
173
+ touch-action: none;
174
+ backdrop-filter: blur(5px);
175
+ border: 2px solid rgba(255, 0, 204, 0.5);
 
 
 
 
 
 
 
 
 
 
 
176
  }
177
+
178
+ #levelComplete {
 
179
  position: absolute;
180
  top: 50%;
181
  left: 50%;
182
  transform: translate(-50%, -50%);
183
+ background: rgba(0, 0, 0, 0.8);
184
  padding: 30px;
185
  border-radius: 20px;
186
+ text-align: center;
187
+ z-index: 20;
188
  display: none;
 
 
 
189
  }
190
+
191
+ .levelTitle {
192
+ font-size: 2.5rem;
193
+ color: #ff00cc;
194
  margin-bottom: 20px;
 
195
  }
196
+
197
+ .credits {
198
+ position: absolute;
199
+ bottom: 20px;
200
+ right: 20px;
201
+ color: #aaa;
202
+ font-size: 0.9rem;
203
+ z-index: 5;
204
  }
205
+
206
+ .credits a {
207
+ color: #ff00cc;
208
+ text-decoration: none;
 
 
 
 
 
 
 
209
  }
210
+
 
211
  @media (max-width: 768px) {
212
  .gameTitle {
213
+ font-size: 2.5rem;
214
  }
215
+
216
+ .btn {
217
+ width: 200px;
218
+ padding: 12px 20px;
219
  font-size: 1rem;
220
  }
221
+
222
+ .controlBtn {
223
+ width: 70px;
224
+ height: 70px;
225
+ font-size: 1.5rem;
226
  }
227
+
228
+ #hud {
229
+ top: 10px;
230
+ left: 10px;
231
+ padding: 10px;
232
+ min-width: 160px;
233
  }
234
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  </style>
236
  </head>
 
237
  <body>
238
  <div id="gameContainer">
239
+ <canvas id="gameCanvas"></canvas>
240
+
241
+ <div id="menuScreen">
242
  <h1 class="gameTitle">EATER HOLE 3D ULTRA</h1>
243
+ <p class="developer">تم التطوير بواسطة: أدهم ياسر محمد</p>
244
+
245
+ <div class="skinSelection">
246
+ <div id="classicSkin" class="skinOption selected"></div>
247
+ <div id="fireSkin" class="skinOption"></div>
248
+ <div id="discoSkin" class="skinOption"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  </div>
250
+
251
+ <button id="startBtn" class="btn">بدء اللعبة</button>
252
+ <button id="howToPlayBtn" class="btn">كيفية اللعب</button>
253
+ <button id="contactBtn" class="btn">الاتصال بالمطور</button>
254
  </div>
255
+
256
+ <div id="hud">
257
+ <div class="hudItem">
258
+ <span class="hudLabel">المستوى:</span>
259
+ <span id="levelValue" class="hudValue">1</span>
260
+ </div>
261
+ <div class="hudItem">
262
+ <span class="hudLabel">حجم الحفرة:</span>
263
+ <span id="sizeValue" class="hudValue">1.0</span>
264
+ </div>
265
+ <div class="hudItem">
266
+ <span class="hudLabel"لأجسام المتبقية:</span>
267
+ <span id="objectsValue" class="hudValue">50</span>
268
+ </div>
269
+ <div class="hudItem">
270
+ <span class="hudLabel">النقاط:</span>
271
+ <span id="scoreValue" class="hudValue">0</span>
272
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
273
  </div>
274
+
 
275
  <div id="mobileControls">
276
+ <div class="controlBtn" id="upBtn">↑</div>
277
+ <div class="controlBtn" id="leftBtn"></div>
278
+ <div class="controlBtn" id="downBtn">↓</div>
279
+ <div class="controlBtn" id="rightBtn">→</div>
280
+ </div>
281
+
282
+ <div id="levelComplete">
283
+ <h2 class="levelTitle">تهانينا! أكملت المستوى</h2>
284
+ <p>تم التهام <span id="eatenCount">0</span> جسم</p>
285
+ <p>حصلت على <span id="pointsEarned">0</span> نقطة</p>
286
+ <button id="nextLevelBtn" class="btn">المستوى التالي</button>
287
+ </div>
288
+
289
+ <div class="credits">
290
+ Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a>
291
  </div>
 
 
 
 
 
 
292
  </div>
293
 
294
  <script>
295
+ // Game variables
296
  let scene, camera, renderer;
297
+ let player, npcs = [];
 
298
  let objects = [];
299
+ let ground;
300
  let level = 1;
301
+ let playerSize = 1;
302
  let score = 0;
303
+ let objectsToEat = 50;
 
304
  let currentSkin = 'classic';
305
+ let gameStarted = false;
306
+ let playerVelocity = { x: 0, z: 0 };
307
+ const playerSpeed = 0.1;
308
+
309
+ // Initialize the game
310
+ function init() {
311
+ // Create scene
312
  scene = new THREE.Scene();
313
+ scene.background = new THREE.Color(0x0a0a2a);
314
+ scene.fog = new THREE.Fog(0x0a0a2a, 20, 100);
315
+
316
+ // Create camera
317
+ camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
318
+ camera.position.set(0, 20, 0);
 
 
 
 
319
  camera.lookAt(0, 0, 0);
320
+
321
+ // Create renderer
 
322
  renderer = new THREE.WebGLRenderer({
323
+ canvas: document.getElementById('gameCanvas'),
324
  antialias: true
325
  });
326
  renderer.setSize(window.innerWidth, window.innerHeight);
327
+ renderer.setPixelRatio(window.devicePixelRatio);
328
+
329
+ // Add lighting
330
+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
 
331
  scene.add(ambientLight);
332
+
333
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
334
+ directionalLight.position.set(10, 20, 10);
 
 
 
 
 
335
  scene.add(directionalLight);
336
+
337
+ // Create ground
338
  createGround();
339
+
340
+ // Create player
341
+ createPlayer();
342
+
343
+ // Create NPCs
344
  createNPCs();
345
+
346
+ // Create objects
347
+ createObjects();
348
+
349
+ // Event listeners
350
+ setupEventListeners();
351
+
352
+ // Start game loop
353
+ animate();
354
  }
355
+
356
+ // Create ground
357
  function createGround() {
358
+ const groundGeometry = new THREE.PlaneGeometry(100, 100);
359
+ const groundMaterial = new THREE.MeshStandardMaterial({
360
+ color: level === 1 ? 0xffffff : 0xdddddd,
361
+ roughness: 0.8,
362
+ metalness: 0.2
363
  });
364
  ground = new THREE.Mesh(groundGeometry, groundMaterial);
365
  ground.rotation.x = -Math.PI / 2;
 
366
  scene.add(ground);
367
+
368
+ // Add grid helper for level 1
369
+ if (level === 1) {
370
+ const gridHelper = new THREE.GridHelper(100, 20, 0x444444, 0x222222);
371
+ scene.add(gridHelper);
372
+ }
373
  }
374
+
375
+ // Create player
376
+ function createPlayer() {
377
+ const geometry = new THREE.CylinderGeometry(1, 1, 0.5, 32);
378
+ const material = new THREE.MeshStandardMaterial({
379
  color: 0x000000,
380
+ emissive: 0x111111,
381
+ roughness: 0.7,
382
+ metalness: 0.3
 
 
 
 
 
 
 
 
 
 
 
383
  });
384
+ player = new THREE.Mesh(geometry, material);
385
+ player.position.y = 0.25;
386
+ scene.add(player);
 
 
 
387
  }
388
+
389
+ // Create NPCs
390
+ function createNPCs() {
391
+ for (let i = 0; i < 20; i++) {
392
+ const geometry = new THREE.CylinderGeometry(0.5, 0.5, 0.4, 32);
393
+ const material = new THREE.MeshStandardMaterial({
394
+ color: 0xff0000,
395
+ emissive: 0x220000,
396
+ roughness: 0.7,
397
+ metalness: 0.3
398
+ });
399
+ const npc = new THREE.Mesh(geometry, material);
400
+
401
+ // Random position
402
+ npc.position.x = (Math.random() - 0.5) * 80;
403
+ npc.position.z = (Math.random() - 0.5) * 80;
404
+ npc.position.y = 0.2;
405
+
406
+ // Random direction
407
+ npc.userData.direction = new THREE.Vector3(
408
+ Math.random() - 0.5,
409
+ 0,
410
+ Math.random() - 0.5
411
+ ).normalize();
412
+
413
+ npc.userData.speed = 0.02 + Math.random() * 0.03;
414
+ npc.userData.size = 0.5;
415
+
416
+ scene.add(npc);
417
+ npcs.push(npc);
418
+ }
419
+ }
420
+
421
+ // Create objects to eat
422
  function createObjects() {
423
+ objects = [];
424
+
425
+ for (let i = 0; i < objectsToEat; i++) {
426
+ let object;
427
+
428
+ // Random object type (building, tree, rock)
429
+ const objectType = Math.floor(Math.random() * 3);
430
+
431
+ switch(objectType) {
432
+ case 0: // Building
433
+ const width = 1 + Math.random() * 3;
434
+ const height = 2 + Math.random() * 5;
435
+ const depth = 1 + Math.random() * 3;
436
+ const geometry = new THREE.BoxGeometry(width, height, depth);
437
+ const material = new THREE.MeshStandardMaterial({
438
+ color: 0x3498db,
439
+ roughness: 0.8
440
+ });
441
+ object = new THREE.Mesh(geometry, material);
442
+ object.position.y = height / 2;
443
+ object.userData.size = Math.max(width, depth);
444
+ break;
445
+
446
+ case 1: // Tree
447
+ const trunkGeometry = new THREE.CylinderGeometry(0.3, 0.4, 2, 8);
448
+ const trunkMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513 });
449
+ const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
450
+ trunk.position.y = 1;
451
+
452
+ const leavesGeometry = new THREE.ConeGeometry(1.5, 3, 8);
453
+ const leavesMaterial = new THREE.MeshStandardMaterial({ color: 0x27ae60 });
454
+ const leaves = new THREE.Mesh(leavesGeometry, leavesMaterial);
455
+ leaves.position.y = 3.5;
456
+
457
+ object = new THREE.Group();
458
+ object.add(trunk);
459
+ object.add(leaves);
460
+ object.userData.size = 1.5;
461
+ break;
462
+
463
+ case 2: // Rock
464
+ const rockGeometry = new THREE.DodecahedronGeometry(0.5 + Math.random() * 1, 0);
465
+ const rockMaterial = new THREE.MeshStandardMaterial({
466
+ color: 0x7f8c8d,
467
+ roughness: 0.9
468
+ });
469
+ object = new THREE.Mesh(rockGeometry, rockMaterial);
470
+ object.userData.size = 0.8 + Math.random() * 0.7;
471
+ break;
472
+ }
473
 
474
+ // Random position
475
+ object.position.x = (Math.random() - 0.5) * 80;
476
+ object.position.z = (Math.random() - 0.5) * 80;
477
+
478
+ // Random rotation for variety
479
+ object.rotation.y = Math.random() * Math.PI * 2;
 
 
 
480
 
 
 
481
  scene.add(object);
482
  objects.push(object);
483
  }
484
+
485
+ // Update HUD
486
+ document.getElementById('objectsValue').textContent = objects.length;
487
+ }
488
+
489
+ // Update NPCs
490
+ function updateNPCs() {
491
+ for (const npc of npcs) {
492
+ // Move NPC
493
+ npc.position.x += npc.userData.direction.x * npc.userData.speed;
494
+ npc.position.z += npc.userData.direction.z * npc.userData.speed;
 
495
 
496
+ // Boundary check
497
+ if (Math.abs(npc.position.x) > 45 || Math.abs(npc.position.z) > 45) {
498
+ npc.userData.direction.x = -npc.userData.direction.x;
499
+ npc.userData.direction.z = -npc.userData.direction.z;
500
+ }
 
 
 
 
 
501
 
502
+ // Random direction change
503
+ if (Math.random() < 0.01) {
504
+ npc.userData.direction = new THREE.Vector3(
505
+ Math.random() - 0.5,
506
+ 0,
507
+ Math.random() - 0.5
508
+ ).normalize();
509
+ }
510
+
511
+ // Check if NPC can eat objects
512
+ for (let i = objects.length - 1; i >= 0; i--) {
513
+ const object = objects[i];
514
+ const distance = npc.position.distanceTo(object.position);
515
+
516
+ if (distance < npc.userData.size + 0.5 && object.userData.size < npc.userData.size) {
517
+ // NPC eats the object
518
+ scene.remove(object);
519
+ objects.splice(i, 1);
520
+
521
+ // NPC grows
522
+ npc.userData.size += 0.05;
523
+ npc.scale.set(
524
+ npc.userData.size / 0.5,
525
+ 1,
526
+ npc.userData.size / 0.5
527
+ );
528
+
529
+ // Update HUD
530
+ document.getElementById('objectsValue').textContent = objects.length;
531
+ }
532
+ }
533
  }
534
  }
535
+
536
+ // Check collisions
537
+ function checkCollisions() {
538
+ for (let i = objects.length - 1; i >= 0; i--) {
539
+ const object = objects[i];
540
+ const distance = player.position.distanceTo(object.position);
541
+
542
+ if (distance < playerSize + 1 && object.userData.size < playerSize) {
543
+ // Player eats the object
544
+ scene.remove(object);
545
+ objects.splice(i, 1);
546
+
547
+ // Player grows
548
+ playerSize += 0.1;
549
+ player.scale.set(playerSize, 1, playerSize);
550
+
551
+ // Update score
552
+ score += Math.floor(object.userData.size * 10);
553
+
554
+ // Play sound
555
+ playEatSound();
556
+
557
+ // Update HUD
558
+ document.getElementById('sizeValue').textContent = playerSize.toFixed(1);
559
+ document.getElementById('objectsValue').textContent = objects.length;
560
+ document.getElementById('scoreValue').textContent = score;
561
+
562
+ // Check level completion
563
+ if (objects.length === 0) {
564
+ completeLevel();
565
+ }
566
+ }
567
  }
568
  }
569
+
570
+ // Complete level
571
+ function completeLevel() {
572
+ gameStarted = false;
573
+ document.getElementById('levelComplete').style.display = 'block';
574
+ document.getElementById('eatenCount').textContent = objectsToEat;
575
+ document.getElementById('pointsEarned').textContent = score;
576
+ }
577
+
578
+ // Play sound when eating
579
+ function playEatSound() {
580
  try {
581
+ // Create audio context
582
+ const audioContext = new (window.AudioContext || window.webkitAudioContext)();
583
+
584
+ // Create oscillator
585
  const oscillator = audioContext.createOscillator();
586
  const gainNode = audioContext.createGain();
587
+
588
  oscillator.connect(gainNode);
589
  gainNode.connect(audioContext.destination);
590
+
591
+ // Configure sound
592
+ oscillator.type = 'sine';
593
+ oscillator.frequency.setValueAtTime(300, audioContext.currentTime);
594
+ oscillator.frequency.exponentialRampToValueAtTime(50, audioContext.currentTime + 0.3);
595
+
596
+ gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
597
+ gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);
598
+
599
+ // Play sound
600
+ oscillator.start();
601
+ oscillator.stop(audioContext.currentTime + 0.3);
602
+ } catch (e) {
603
+ console.log("Audio not supported:", e);
 
 
 
 
604
  }
605
  }
606
+
607
+ // Setup event listeners
608
+ function setupEventListeners() {
609
+ // Start button
610
+ document.getElementById('startBtn').addEventListener('click', () => {
611
+ document.getElementById('menuScreen').style.display = 'none';
612
+ gameStarted = true;
613
+ });
614
+
615
+ // Skin selection
616
+ document.getElementById('classicSkin').addEventListener('click', () => {
617
+ selectSkin('classic');
618
+ });
619
+
620
+ document.getElementById('fireSkin').addEventListener('click', () => {
621
+ selectSkin('fire');
622
+ });
623
+
624
+ document.getElementById('discoSkin').addEventListener('click', () => {
625
+ selectSkin('disco');
626
+ });
627
+
628
+ // Contact button
629
+ document.getElementById('contactBtn').addEventListener('click', () => {
630
+ window.location.href = 'https://wa.me/201097399624';
631
+ });
632
+
633
+ // Next level button
634
+ document.getElementById('nextLevelBtn').addEventListener('click', () => {
635
+ level++;
636
+ objectsToEat = 50 + level * 5;
637
+ document.getElementById('levelComplete').style.display = 'none';
638
+ document.getElementById('levelValue').textContent = level;
639
+
640
+ // Reset scene
641
+ while(scene.children.length > 0) {
642
+ scene.remove(scene.children[0]);
643
+ }
644
+
645
+ // Recreate game elements
646
+ createGround();
647
+ createPlayer();
648
+ createNPCs();
649
+ createObjects();
650
+
651
+ // Reset player size
652
+ playerSize = 1;
653
+ player.scale.set(1, 1, 1);
654
+
655
+ // Update HUD
656
+ document.getElementById('sizeValue').textContent = playerSize.toFixed(1);
657
+ document.getElementById('objectsValue').textContent = objects.length;
658
+
659
+ gameStarted = true;
660
+ });
661
+
662
+ // Mobile controls
663
+ const controlBtns = document.querySelectorAll('.controlBtn');
664
+ controlBtns.forEach(btn => {
665
+ btn.addEventListener('touchstart', (e) => {
666
+ e.preventDefault();
667
+ handleControl(btn.id);
668
+ });
669
+ });
670
+
671
  // Keyboard controls
672
+ window.addEventListener('keydown', (e) => {
673
+ if (!gameStarted) return;
674
 
675
  switch(e.key) {
676
  case 'ArrowUp':
677
  case 'w':
678
  case 'W':
679
+ playerVelocity.z = -playerSpeed;
680
  break;
681
  case 'ArrowDown':
682
  case 's':
683
  case 'S':
684
+ playerVelocity.z = playerSpeed;
685
  break;
686
  case 'ArrowLeft':
687
  case 'a':
688
  case 'A':
689
+ playerVelocity.x = -playerSpeed;
690
  break;
691
  case 'ArrowRight':
692
  case 'd':
693
  case 'D':
694
+ playerVelocity.x = playerSpeed;
 
 
 
695
  break;
696
  }
697
  });
698
+
699
+ window.addEventListener('keyup', (e) => {
700
  switch(e.key) {
701
  case 'ArrowUp':
 
702
  case 'w':
703
  case 'W':
704
+ case 'ArrowDown':
705
  case 's':
706
  case 'S':
707
+ playerVelocity.z = 0;
708
  break;
709
  case 'ArrowLeft':
 
710
  case 'a':
711
  case 'A':
712
+ case 'ArrowRight':
713
  case 'd':
714
  case 'D':
715
+ playerVelocity.x = 0;
716
  break;
717
  }
718
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
719
 
720
+ // Window resize
721
+ window.addEventListener('resize', () => {
722
+ camera.aspect = window.innerWidth / window.innerHeight;
723
+ camera.updateProjectionMatrix();
724
+ renderer.setSize(window.innerWidth, window.innerHeight);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
725
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
726
  }
727
+
728
+ // Handle mobile controls
729
+ function handleControl(btnId) {
730
+ if (!gameStarted) return;
 
 
 
 
 
731
 
732
+ switch(btnId) {
733
+ case 'upBtn':
734
+ playerVelocity.z = -playerSpeed;
735
+ break;
736
+ case 'downBtn':
737
+ playerVelocity.z = playerSpeed;
738
+ break;
739
+ case 'leftBtn':
740
+ playerVelocity.x = -playerSpeed;
741
+ break;
742
+ case 'rightBtn':
743
+ playerVelocity.x = playerSpeed;
744
+ break;
745
  }
746
 
747
+ // Reset velocity after a short time
748
+ setTimeout(() => {
749
+ playerVelocity.x = 0;
750
+ playerVelocity.z = 0;
751
+ }, 200);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
752
  }
753
+
754
+ // Select skin
755
+ function selectSkin(skin) {
 
 
 
 
 
 
756
  currentSkin = skin;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
757
 
758
+ // Update UI
759
+ document.querySelectorAll('.skinOption').forEach(option => {
760
+ option.classList.remove('selected');
761
+ });
762
+ document.getElementById(skin + 'Skin').classList.add('selected');
 
 
 
 
 
 
 
 
 
 
 
 
 
763
 
764
+ // Update player material (in a real game, you'd change the player's appearance)
 
 
765
  }
766
+
767
+ // Game loop
768
  function animate() {
769
+ requestAnimationFrame(animate);
770
 
771
+ if (gameStarted) {
772
+ // Update player position
773
+ player.position.x += playerVelocity.x;
774
+ player.position.z += playerVelocity.z;
775
+
776
+ // Boundary check
777
+ if (player.position.x < -45) player.position.x = -45;
778
+ if (player.position.x > 45) player.position.x = 45;
779
+ if (player.position.z < -45) player.position.z = -45;
780
+ if (player.position.z > 45) player.position.z = 45;
781
+
782
+ // Update camera to follow player
783
+ camera.position.x = player.position.x;
784
+ camera.position.z = player.position.z + 10;
785
+ camera.lookAt(player.position.x, 0, player.position.z);
786
+
787
+ // Update NPCs
788
+ updateNPCs();
789
+
790
+ // Check collisions
791
+ checkCollisions();
792
  }
793
 
794
  renderer.render(scene, camera);
795
  }
796
+
797
+ // Start the game when page loads
798
+ window.onload = init;
799
+ </script>
800
+ </body>
801
+ </html>