🎮ArcadeLab

لعبة جمع المكعبات 3D - الجوال

by FrozenRider22
476 lines16.6 KB🛠️ Three.js (3D graphics)
▶ Play
<!DOCTYPE html>
<html lang="ar">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>لعبة جمع المكعبات 3D - الجوال</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
        body { 
            overflow: hidden; 
            font-family: Arial, sans-serif; 
            background: #000;
            touch-action: none;
            user-select: none;
            -webkit-user-select: none;
        }
        
        #score {
            position: fixed; top: 15px; right: 15px;
            color: white; font-size: 20px; font-weight: bold;
            text-shadow: 2px 2px 6px black;
            background: rgba(0,0,0,0.4);
            padding: 8px 16px;
            border-radius: 20px;
            z-index: 10;
        }
        
        #timer {
            position: fixed; top: 15px; left: 15px;
            color: white; font-size: 20px; font-weight: bold;
            text-shadow: 2px 2px 6px black;
            background: rgba(0,0,0,0.4);
            padding: 8px 16px;
            border-radius: 20px;
            z-index: 10;
        }
        
        /* عصا التحكم */
        #joystick {
            position: fixed; bottom: 40px; left: 30px;
            width: 130px; height: 130px;
            background: rgba(255,255,255,0.15);
            border: 2px solid rgba(255,255,255,0.4);
            border-radius: 50%;
            z-index: 20;
            touch-action: none;
        }
        
        #stick {
            position: absolute;
            width: 60px; height: 60px;
            background: rgba(255,255,255,0.7);
            border: 2px solid white;
            border-radius: 50%;
            top: 33px; left: 33px;
            transition: transform 0.05s ease-out;
            box-shadow: 0 4px 10px rgba(0,0,0,0.4);
            pointer-events: none;
        }
        
        /* شاشة النهاية */
        #gameOver {
            position: fixed; top: 0; left: 0; width: 100%; height: 100%;
            background: rgba(0,0,0,0.85);
            display: none;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            color: white;
            z-index: 100;
            text-align: center;
            padding: 20px;
        }
        
        #gameOver h1 {
            font-size: 42px;
            margin-bottom: 20px;
            color: #ff5722;
            text-shadow: 2px 2px 10px black;
        }
        
        #gameOver p {
            font-size: 24px;
            margin-bottom: 15px;
        }
        
        #gameOver .finalScore {
            font-size: 60px;
            font-weight: bold;
            color: #ffeb3b;
            margin-bottom: 30px;
            text-shadow: 3px 3px 10px black;
        }
        
        #restartBtn {
            padding: 18px 50px;
            font-size: 22px;
            font-weight: bold;
            background: #4CAF50;
            color: white;
            border: none;
            border-radius: 50px;
            box-shadow: 0 6px 20px rgba(76,175,80,0.5);
            cursor: pointer;
            touch-action: manipulation;
        }
        
        #restartBtn:active {
            transform: scale(0.95);
            background: #388E3C;
        }
        
        /* شاشة البداية */
        #startScreen {
            position: fixed; top: 0; left: 0; width: 100%; height: 100%;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            color: white;
            z-index: 200;
            text-align: center;
            padding: 20px;
        }
        
        #startScreen h1 {
            font-size: 38px;
            margin-bottom: 15px;
            text-shadow: 2px 2px 10px rgba(0,0,0,0.5);
        }
        
        #startScreen p {
            font-size: 18px;
            margin-bottom: 30px;
            opacity: 0.9;
            line-height: 1.6;
        }
        
        #startBtn {
            padding: 20px 60px;
            font-size: 24px;
            font-weight: bold;
            background: #ff5722;
            color: white;
            border: none;
            border-radius: 50px;
            box-shadow: 0 8px 25px rgba(255,87,34,0.5);
            cursor: pointer;
            touch-action: manipulation;
        }
        
        #startBtn:active {
            transform: scale(0.95);
        }
    </style>
</head>
<body>

    <!-- شاشة البداية -->
    <div id="startScreen">
        <h1>🎮 لعبة جمع المكعبات</h1>
        <p>حرك الكرة البرتقالية بلمس الشاشة<br>واجمع أكبر عدد من المكعبات الملونة<br>لديك 30 ثانية فقط!</p>
        <button id="startBtn">ابدأ اللعب</button>
    </div>

    <!-- واجهة اللعب -->
    <div id="score">النقاط: 0</div>
    <div id="timer">⏱ 30</div>

    <!-- عصا التحكم -->
    <div id="joystick">
        <div id="stick"></div>
    </div>

    <!-- شاشة النهاية -->
    <div id="gameOver">
        <h1>انتهى الوقت!</h1>
        <p>نتيجتك النهائية</p>
        <div class="finalScore" id="finalScore">0</div>
        <button id="restartBtn">العب مرة أخرى</button>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script>
        // ===== الإعداد الأساسي =====
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x87CEEB);
        scene.fog = new THREE.Fog(0x87CEEB, 12, 45);

        const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
        camera.position.set(0, 10, 14);
        camera.lookAt(0, 0, 0);

        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
        document.body.appendChild(renderer.domElement);

        // ===== الإضاءة =====
        const light = new THREE.DirectionalLight(0xffffff, 1);
        light.position.set(5, 10, 5);
        scene.add(light);
        scene.add(new THREE.AmbientLight(0xffffff, 0.6));

        // ===== الأرضية =====
        const floor = new THREE.Mesh(
            new THREE.PlaneGeometry(30, 30),
            new THREE.MeshStandardMaterial({ color: 0x2ecc71 })
        );
        floor.rotation.x = -Math.PI / 2;
        scene.add(floor);

        // ===== اللاعب =====
        const player = new THREE.Mesh(
            new THREE.SphereGeometry(0.6, 32, 32),
            new THREE.MeshStandardMaterial({ color: 0xff5722, emissive: 0x441100 })
        );
        player.position.y = 0.6;
        scene.add(player);

        // ===== المكعبات =====
        const cubes = [];
        const cubeColors = [0xffeb3b, 0xe91e63, 0x9c27b0, 0x00bcd4, 0xff9800, 0x4CAF50];

        function createCube() {
            const cube = new THREE.Mesh(
                new THREE.BoxGeometry(1, 1, 1),
                new THREE.MeshStandardMaterial({ 
                    color: cubeColors[Math.floor(Math.random()*cubeColors.length)]
                })
            );
            cube.position.set(
                (Math.random() - 0.5) * 24,
                0.5,
                (Math.random() - 0.5) * 24
            );
            cube.rotation.y = Math.random() * Math.PI;
            scene.add(cube);
            cubes.push(cube);
        }

        // ===== متغيرات اللعبة =====
        let score = 0;
        let gameActive = false;
        let timeLeft = 30;
        const speed = 0.18;

        // ===== إدخال الحركة (متجهي) =====
        const moveInput = { x: 0, y: 0 }; // من -1 إلى 1

        // كيبورد (للاختبار على الكمبيوتر)
        const keys = {};
        window.addEventListener('keydown', e => keys[e.key] = true);
        window.addEventListener('keyup', e => keys[e.key] = false);

        function updateKeyboardInput() {
            let x = 0, y = 0;
            if (keys['ArrowLeft'] || keys['a'] || keys['A']) x -= 1;
            if (keys['ArrowRight'] || keys['d'] || keys['D']) x += 1;
            if (keys['ArrowUp'] || keys['w'] || keys['W']) y -= 1;
            if (keys['ArrowDown'] || keys['s'] || keys['S']) y += 1;
            if (x !== 0 || y !== 0) {
                moveInput.x = x;
                moveInput.y = y;
            }
        }

        // ===== عصا التحكم =====
        const joystick = document.getElementById('joystick');
        const stick = document.getElementById('stick');
        let joystickActive = false;
        let joystickCenter = { x: 0, y: 0 };
        const maxDist = 45;

        function getJoystickCenter() {
            const rect = joystick.getBoundingClientRect();
            return {
                x: rect.left + rect.width / 2,
                y: rect.top + rect.height / 2
            };
        }

        function handleJoystickStart(e) {
            e.preventDefault();
            joystickActive = true;
            joystickCenter = getJoystickCenter();
            handleJoystickMove(e);
        }

        function handleJoystickMove(e) {
            if (!joystickActive) return;
            e.preventDefault();
            
            const touch = e.touches ? e.touches[0] : e;
            let dx = touch.clientX - joystickCenter.x;
            let dy = touch.clientY - joystickCenter.y;
            
            const dist = Math.sqrt(dx*dx + dy*dy);
            const clampedDist = Math.min(dist, maxDist);
            const angle = Math.atan2(dy, dx);
            
            const stickX = Math.cos(angle) * clampedDist;
            const stickY = Math.sin(angle) * clampedDist;
            stick.style.transform = `translate(${stickX}px, ${stickY}px)`;
            
            // تحويل إلى مدخلات (-1 إلى 1)
            moveInput.x = (dx / maxDist);
            moveInput.y = (dy / maxDist);
            
            // تحديد القيمة القصوى بـ 1
            const mag = Math.sqrt(moveInput.x**2 + moveInput.y**2);
            if (mag > 1) {
                moveInput.x /= mag;
                moveInput.y /= mag;
            }
        }

        function handleJoystickEnd(e) {
            e.preventDefault();
            joystickActive = false;
            stick.style.transform = 'translate(0, 0)';
            moveInput.x = 0;
            moveInput.y = 0;
        }

        joystick.addEventListener('touchstart', handleJoystickStart, { passive: false });
        joystick.addEventListener('touchmove', handleJoystickMove, { passive: false });
        joystick.addEventListener('touchend', handleJoystickEnd, { passive: false });
        joystick.addEventListener('touchcancel', handleJoystickEnd, { passive: false });

        // دعم الماوس (للتجربة على الكمبيوتر)
        joystick.addEventListener('mousedown', handleJoystickStart);
        window.addEventListener('mousemove', handleJoystickMove);
        window.addEventListener('mouseup', handleJoystickEnd);

        // ===== بدء اللعبة =====
        function startGame() {
            // إعادة تعيين
            score = 0;
            timeLeft = 30;
            gameActive = true;
            
            // حذف المكعبات القديمة
            cubes.forEach(c => scene.remove(c));
            cubes.length = 0;
            
            // إنشاء مكعبات جديدة
            for (let i = 0; i < 15; i++) createCube();
            
            // إعادة اللاعب
            player.position.set(0, 0.6, 0);
            
            // تحديث الواجهة
            document.getElementById('score').textContent = 'النقاط: 0';
            document.getElementById('timer').textContent = '⏱ 30';
            document.getElementById('startScreen').style.display = 'none';
            document.getElementById('gameOver').style.display = 'none';
            
            // بدء الحلقة
            lastTime = performance.now();
            animate();
        }

        // ===== حلقة اللعبة =====
        let lastTime = performance.now();

        function animate() {
            if (!gameActive) return;
            requestAnimationFrame(animate);

            const now = performance.now();
            const delta = Math.min((now - lastTime) / 1000, 0.1);
            lastTime = now;

            // تحديث مدخلات الكيبورد إذا لم تكن العصا نشطة
            if (!joystickActive) {
                const prevX = moveInput.x, prevY = moveInput.y;
                updateKeyboardInput();
                // إذا لم تكن هناك ضغطة كيبورد، صفر المدخلات
                if (prevX === moveInput.x && prevY === moveInput.y) {
                    let x = 0, y = 0;
                    if (keys['ArrowLeft'] || keys['a'] || keys['A']) x -= 1;
                    if (keys['ArrowRight'] || keys['d'] || keys['D']) x += 1;
                    if (keys['ArrowUp'] || keys['w'] || keys['W']) y -= 1;
                    if (keys['ArrowDown'] || keys['s'] || keys['S']) y += 1;
                    moveInput.x = x;
                    moveInput.y = y;
                }
            }

            // حركة اللاعب
            player.position.x += moveInput.x * speed * 60 * delta;
            player.position.z += moveInput.y * speed * 60 * delta;

            // حدود الملعب
            player.position.x = Math.max(-14, Math.min(14, player.position.x));
            player.position.z = Math.max(-14, Math.min(14, player.position.z));

            // تدوير اللاعب قليلاً حسب الحركة
            player.rotation.z = -moveInput.x * 0.3;

            // تدوير المكعبات + كشف التصادم
            for (let i = cubes.length - 1; i >= 0; i--) {
                const cube = cubes[i];
                cube.rotation.y += 0.03;
                cube.rotation.x += 0.015;
                cube.position.y = 0.5 + Math.sin(now * 0.003 + i) * 0.15;

                const dx = player.position.x - cube.position.x;
                const dz = player.position.z - cube.position.z;
                const dist = Math.sqrt(dx*dx + dz*dz);

                if (dist < 1.1) {
                    scene.remove(cube);
                    cubes.splice(i, 1);
                    score += 10;
                    document.getElementById('score').textContent = 'النقاط: ' + score;
                    createCube();
                }
            }

            // المؤقت
            timeLeft -= delta;
            const displayTime = Math.max(0, Math.ceil(timeLeft));
            document.getElementById('timer').textContent = '⏱ ' + displayTime;
            
            if (timeLeft <= 0) {
                endGame();
                return;
            }

            // الكاميرا تتبع اللاعب
            camera.position.x = player.position.x * 0.4;
            camera.position.z = player.position.z * 0.4 + 14;
            camera.position.y = 10;
            camera.lookAt(player.position.x * 0.4, 0, player.position.z * 0.4);

            renderer.render(scene, camera);
        }

        // ===== إنهاء اللعبة =====
        function endGame() {
            gameActive = false;
            document.getElementById('finalScore').textContent = score;
            document.getElementById('gameOver').style.display = 'flex';
        }

        // ===== الأزرار =====
        document.getElementById('startBtn').addEventListener('click', startGame);
        document.getElementById('startBtn').addEventListener('touchstart', (e) => {
            e.preventDefault();
            startGame();
        }, { passive: false });

        document.getElementById('restartBtn').addEventListener('click', startGame);
        document.getElementById('restartBtn').addEventListener('touchstart', (e) => {
            e.preventDefault();
            startGame();
        }, { passive: false });

        // ===== تعديل حجم الشاشة =====
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });

        // منع التمرير والسحب على الشاشة
        document.addEventListener('touchmove', (e) => {
            if (e.target.closest('#joystick')) return;
            e.preventDefault();
        }, { passive: false });
    </script>
</body>
</html>

Game Source: لعبة جمع المكعبات 3D - الجوال

Creator: FrozenRider22

Libraries: three

Complexity: complex (476 lines, 16.6 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: 3d-frozenrider22" to link back to the original. Then publish at arcadelab.ai/publish.