code كود لعبة الافعى الكلاسيكيه جاهز

codeNET

Administrative
طاقم الإدارة
ادارة فورارنت
إنضم
06/04/2026
المشاركات
72
🎮 استعد للذكريات: لعبة "الأفعى" الكلاسيكية بنسخة برمجية حديثة!

من منا لا يتذكر لعبة الأفعى الشهيرة؟ تلك اللعبة التي قضى الكثير منا ساعات في محاولة كسر أرقامه القياسية فيها. اليوم، نعود بهذه اللعبة الأسطورية لكن برؤية برمجية بسيطة، تمنحكم التسلية والمتعة مباشرة في متصفحكم.



🕹️ لمحة عن اللعبة:
تعتبر لعبة الأفعى (Snake Game) من أبسط الألعاب وأكثرها إثارة في عالم البرمجة. قمنا بتطوير كود كامل يتسم بالخفة والسرعة، يهدف إلى:
  • التسلية الفورية: لعبة سريعة لا تحتاج إلى تحميل أو تنصيب.
  • التعلم البرمجي: كود نظيف يوضح كيف يتم التعامل مع منطق الحركة والاصطدام.
  • تحدي النفس: حاول الحصول على أكبر طول ممكن للأفعى دون الاصطدام بالحائط!



🚀 مميزات الكود الذي نقدمه:
الكود تم بناؤه باستخدام تقنيات الويب الحديثة، وهو يتميز بـ:
  1. استجابة كاملة: يعمل بسلاسة على أجهزة الكمبيوتر والهواتف.
  2. ألوان مريحة: تصميم متناسق تماماً مع الوضع الداكن لضمان راحة العين أثناء اللعب.
  3. سهولة التعديل: يمكنك تغيير سرعة الأفعى أو ألوانها بلمسة بسيطة في الكود.



📥 كيفية التشغيل؟
كل ما عليك فعله هو نسخ الكود الذي سنشاركه معكم، ووضعه في ملف بصيغة HTML وتشغيله على أي متصفح. استمتع بالتحدي وشاركنا بأعلى سكور وصلت إليه في الردود!

نصيحة المطور: السر في الفوز هو الهدوء وعدم الاستعجال في حركات الالتفاف الضيقة!



________________________________
نتمنى لكم وقتاً ممتعاً في مجتمع 4rNET التقني
إعداد: مهدي حميد


كود:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Monochrome Custom Snake</title>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;700&display=swap');

        * { box-sizing: border-box; margin: 0; padding: 0; }

        body {
            background: #050505;
            color: #ffffff;
            font-family: 'Space Grotesk', sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            overflow: hidden;
            touch-action: none;
        }

        .game-wrapper {
            position: relative;
            padding: 20px;
            background: #0a0a0a;
            border-radius: 16px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.9), 0 0 0 1px #222;
            z-index: 10;
        }

        .stats {
            display: flex;
            justify-content: space-between;
            width: 100%;
            margin-bottom: 15px;
            padding: 0 5px;
        }

        .stat-box { display: flex; flex-direction: column; }
        
        .stat-label {
            font-size: 11px;
            color: #666;
            text-transform: uppercase;
            letter-spacing: 3px;
        }

        .stat-value {
            font-size: 28px;
            font-weight: 700;
            color: #fff;
            text-shadow: 0 0 15px rgba(255, 255, 255, 0.4);
        }

        #best .stat-value {
            color: #aaa;
            text-shadow: none;
        }

        canvas#g {
            background: #000;
            border-radius: 8px;
            box-shadow: inset 0 0 50px rgba(0,0,0,1);
            display: block;
            border: 1px solid #333;
            position: relative;
        }

        .overlay {
            position: absolute;
            top: 0; left: 0; width: 100%; height: 100%;
            background: rgba(0, 0, 0, 0.95);
            backdrop-filter: blur(8px);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            border-radius: 16px;
            z-index: 30;
            transition: opacity 0.3s;
        }

        h1 {
            font-size: 34px;
            color: #fff;
            margin-bottom: 5px;
            text-transform: uppercase;
            letter-spacing: 6px;
            text-shadow: 0 0 20px rgba(255, 255, 255, 0.5);
            text-align: center;
        }

        h2 {
            font-size: 22px;
            letter-spacing: 3px;
            margin-bottom: 5px;
        }

        .subtitle {
            font-size: 13px;
            color: #888;
            margin-bottom: 20px;
            text-transform: uppercase;
            letter-spacing: 2px;
        }

        button {
            background: #fff;
            color: #000;
            border: none;
            padding: 12px 30px;
            margin: 5px;
            font-size: 14px;
            font-weight: 700;
            border-radius: 4px;
            cursor: pointer;
            box-shadow: 0 0 20px rgba(255, 255, 255, 0.2);
            font-family: inherit;
            text-transform: uppercase;
            letter-spacing: 2px;
            transition: all 0.2s;
        }

        button:active {
            transform: scale(0.95);
            background: #ccc;
        }

        .btn-outline {
            background: transparent;
            color: #fff;
            border: 1px solid #fff;
            box-shadow: none;
        }

        #drawCanvas {
            border: 2px dashed #555;
            border-radius: 8px;
            background: rgba(255, 255, 255, 0.05);
            width: 150px;
            height: 150px;
            touch-action: none;
            margin-bottom: 15px;
            cursor: crosshair;
        }

        .tools {
            display: flex;
            gap: 10px;
            margin-bottom: 15px;
            align-items: center;
        }

        input[type="color"] {
            -webkit-appearance: none;
            border: none;
            width: 40px;
            height: 40px;
            border-radius: 50%;
            cursor: pointer;
            background: transparent;
        }
        input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
        input[type="color"]::-webkit-color-swatch { border: 2px solid #fff; border-radius: 50%; }


        #playerName {
            background: transparent;
            border: 1px solid #555;
            color: #fff;
            padding: 10px;
            font-family: inherit;
            text-align: center;
            width: 180px;
            margin-bottom: 10px;
            text-transform: uppercase;
            border-radius: 4px;
            outline: none;
        }
        #playerName:focus {
            border-color: #fff;
        }
        #leaderboardBox {
            margin: 5px 0 20px 0;
            text-align: left;
            width: 80%;
            max-width: 250px;
            border-top: 1px dashed #333;
            border-bottom: 1px dashed #333;
            padding: 10px 0;
        }
        #leaderboardBox h3 {
            font-size: 12px;
            text-align: center;
            letter-spacing: 4px;
            margin-bottom: 10px;
            color: #aaa;
        }
        #leaderboardList {
            list-style: none;
            padding: 0;
            font-size: 13px;
            letter-spacing: 1px;
        }
        #leaderboardList li {
            display: flex;
            justify-content: space-between;
            margin-bottom: 5px;
            color: #888;
        }
        #leaderboardList li span.lb-score {
            color: #fff;
            font-weight: bold;
        }
        #leaderboardList li.highlight {
            color: #fff;
            text-shadow: 0 0 10px rgba(255,255,255,0.5);
        }

        .hidden { display: none !important; }
    </style>
</head>
<body>

    <div class="game-wrapper">
        <div class="stats">
            <div class="stat-box" id="score">
                <span class="stat-label">Score</span>
                <span class="stat-value" id="s">0</span>
            </div>
            <div class="stat-box" id="best" style="text-align: right;">
                <span class="stat-label">Best</span>
                <span class="stat-value" id="b">0</span>
            </div>
        </div>

        <canvas id="g" width="300" height="420"></canvas>

        <div id="draw-menu" class="overlay">
            <h2>snake 🐍 game</h2>
            <div class="subtitle">Draw face of snake pointing UP &uarr; </div>
            
            <canvas id="drawCanvas" width="60" height="60"></canvas>
            
            <div class="tools">
                <input type="color" id="colorPicker" value="#ffffff">
                <button class="btn-outline" onclick="clearCanvas()">CLEAR</button>
            </div>
            <button onclick="saveAndStart()">START MISSION</button>
            <button class="btn-outline" style="font-size: 10px; padding: 8px 20px;" onclick="skipAndStart()">SKIP (DEFAULT)</button>
        </div>

        <div id="menu" class="overlay hidden">
            <h1 id="title">orhan~ codes</h1>
            <div class="subtitle" id="sub" style="margin-bottom: 10px;">Final Score: 0</div>
            
            <div id="newHighScoreSection" class="hidden" style="display:flex; flex-direction:column; align-items:center;">
                <div class="subtitle" style="color: #fff; margin-bottom: 10px;">TOP TIER REACHED</div>
                <input type="text" id="playerName" placeholder="ENTER ALIAS" maxlength="6">
                <button onclick="saveScore()" class="btn-outline" style="margin-bottom: 15px;">SUBMIT DATA</button>
            </div>

            <div id="leaderboardBox">
                <h3>orhan~</h3>
                <ol id="leaderboardList"></ol>
            </div>

            <div id="actionButtons" style="display: flex; gap: 5px;">
                <button onclick="startGame()" id="btn">RETRY</button>
                <button class="btn-outline" onclick="openDrawMenu()">REDRAW</button>
            </div>
        </div>
    </div>

    <script>
        const canvas = document.getElementById("g");
        const ctx = canvas.getContext("2d");
        const scoreDisplay = document.getElementById("s");
        const bestDisplay = document.getElementById("b");
        const menu = document.getElementById("menu");
        const drawMenu = document.getElementById("draw-menu");
        const title = document.getElementById("title");
        const sub = document.getElementById("sub");
        
        // Drawing Variables
        const drawCanvas = document.getElementById("drawCanvas");
        const drawCtx = drawCanvas.getContext("2d");
        const colorPicker = document.getElementById("colorPicker");
        let isDrawing = false;
        let customHeadImg = new Image();
        let useCustomHead = false;

        // Leaderboard Variables
        let leaderboard = [];
        try {
            leaderboard = JSON.parse(localStorage.getItem("monoSnakeLeaderboard")) || [];
        } catch(e) {}

        // --- DRAWING LOGIC ---
        function getDrawPos(e) {
            const rect = drawCanvas.getBoundingClientRect();
            const clientX = e.touches ? e.touches[0].clientX : e.clientX;
            const clientY = e.touches ? e.touches[0].clientY : e.clientY;
            return {
                x: (clientX - rect.left) * (drawCanvas.width / rect.width),
                y: (clientY - rect.top) * (drawCanvas.height / rect.height)
            };
        }

        function startDraw(e) {
            e.preventDefault();
            isDrawing = true;
            const pos = getDrawPos(e);
            drawCtx.beginPath();
            drawCtx.moveTo(pos.x, pos.y);
        }

        function draw(e) {
            e.preventDefault();
            if (!isDrawing) return;
            const pos = getDrawPos(e);
            drawCtx.lineTo(pos.x, pos.y);
            drawCtx.strokeStyle = colorPicker.value;
            drawCtx.lineWidth = 4;
            drawCtx.lineCap = "round";
            drawCtx.lineJoin = "round";
            drawCtx.stroke();
        }

        function stopDraw(e) {
            e.preventDefault();
            isDrawing = false;
        }

        drawCanvas.addEventListener("mousedown", startDraw);
        drawCanvas.addEventListener("mousemove", draw);
        drawCanvas.addEventListener("mouseup", stopDraw);
        drawCanvas.addEventListener("mouseout", stopDraw);
        drawCanvas.addEventListener("touchstart", startDraw, {passive: false});
        drawCanvas.addEventListener("touchmove", draw, {passive: false});
        drawCanvas.addEventListener("touchend", stopDraw);

        function clearCanvas() {
            drawCtx.clearRect(0, 0, drawCanvas.width, drawCanvas.height);
        }

        function saveAndStart() {
            customHeadImg.src = drawCanvas.toDataURL();
            useCustomHead = true;
            drawMenu.classList.add("hidden");
            startGame();
        }

        function skipAndStart() {
            useCustomHead = false;
            drawMenu.classList.add("hidden");
            startGame();
        }

        function openDrawMenu() {
            menu.classList.add("hidden");
            drawMenu.classList.remove("hidden");
        }



        const box = 15;
        const gridCols = canvas.width / box;
        const gridRows = canvas.height / box;
        
        let snake, food, d, score, gameSpeed;
        let gameTimer;
        let pulseTime = 0;
        let particles = [];
        
        let highScore = 0;
        try { highScore = localStorage.getItem("monoSnakeBest") || 0; } catch(e) {}
        bestDisplay.innerHTML = highScore;

        
        let touchStartX = 0, touchStartY = 0;
        document.addEventListener('touchstart', e => {
            if(!drawMenu.classList.contains('hidden') || !menu.classList.contains('hidden')) return;
            touchStartX = e.changedTouches[0].screenX;
            touchStartY = e.changedTouches[0].screenY;
        }, {passive: false});

        document.addEventListener('touchend', e => {
            if(!drawMenu.classList.contains('hidden') || !menu.classList.contains('hidden')) return;
            let touchEndX = e.changedTouches[0].screenX;
            let touchEndY = e.changedTouches[0].screenY;
            handleInput(touchStartX, touchStartY, touchEndX, touchEndY);
        }, {passive: false});

        function handleInput(startX, startY, endX, endY) {
            let dx = endX - startX, dy = endY - startY;
            if (Math.abs(dx) > Math.abs(dy)) {
                if (dx > 30 && d !== "LEFT") d = "RIGHT";
                else if (dx < -30 && d !== "RIGHT") d = "LEFT";
            } else {
                if (dy > 30 && d !== "UP") d = "DOWN";
                else if (dy < -30 && d !== "DOWN") d = "UP";
            }
        }

        document.addEventListener("keydown", e => {
        
            if(document.activeElement.tagName === "INPUT") return;
            if(!drawMenu.classList.contains('hidden') || !menu.classList.contains('hidden')) return;
            
            if(e.keyCode == 37 && d !== "RIGHT") d = "LEFT";
            else if(e.keyCode == 38 && d !== "DOWN") d = "UP";
            else if(e.keyCode == 39 && d !== "LEFT") d = "RIGHT";
            else if(e.keyCode == 40 && d !== "UP") d = "DOWN";
        });

        function startGame() {
            menu.classList.add("hidden");
            score = 0; gameSpeed = 120;
            scoreDisplay.innerHTML = score;
            particles = []; d = "RIGHT";
            snake = [ {x: 5, y: 10}, {x: 4, y: 10}, {x: 3, y: 10} ];
            spawnFood();
            if(gameTimer) clearTimeout(gameTimer);
            gameLoop(); requestAnimationFrame(render);
        }

        function spawnFood() {
            let valid = false;
            while(!valid) {
                food = {
                    x: Math.floor(Math.random() * gridCols),
                    y: Math.floor(Math.random() * gridRows)
                };
                valid = !snake.some(seg => seg.x === food.x && seg.y === food.y);
            }
        }

        function createParticles(x, y) {
            for(let i = 0; i < 15; i++) {
                particles.push({
                    x: x, y: y,
                    vx: (Math.random() - 0.5) * 8, vy: (Math.random() - 0.5) * 8,
                    life: 1,
                    color: Math.random() > 0.5 ? "#ffffff" : "#888888"
                });
            }
        }

        function gameLoop() {
            let headX = snake[0].x, headY = snake[0].y;
            if(d == "LEFT") headX--; if(d == "UP") headY--;
            if(d == "RIGHT") headX++; if(d == "DOWN") headY++;

        
            if(headX < 0) headX = gridCols - 1; if(headX >= gridCols) headX = 0;
            if(headY < 0) headY = gridRows - 1; if(headY >= gridRows) headY = 0;

            if(headX == food.x && headY == food.y) {
                score++; scoreDisplay.innerHTML = score;
                createParticles(food.x * box + box/2, food.y * box + box/2);
                spawnFood();
                if(gameSpeed > 50) gameSpeed -= 2;
            } else {
                snake.pop();
            }

            let newHead = { x: headX, y: headY };
            if(collision(newHead, snake)) { gameOver(); return; }

            snake.unshift(newHead);
            gameTimer = setTimeout(gameLoop, gameSpeed);
        }

        function collision(head, array) {
            return array.some(seg => head.x === seg.x && head.y === seg.y);
        }


        function updateLeaderboardUI(highlightName = null) {
            const list = document.getElementById("leaderboardList");
            list.innerHTML = "";
            if (leaderboard.length === 0) {
                list.innerHTML = "<li style='justify-content:center'>NO DATA AVAILABLE</li>";
                return;
            }
            leaderboard.forEach((entry, index) => {
                let li = document.createElement("li");
                if (entry.name === highlightName) li.classList.add("highlight");
                li.innerHTML = `<span>${index + 1}. ${entry.name}</span> <span class="lb-score">${entry.score}</span>`;
                list.appendChild(li);
            });
        }

        function saveScore() {
            const input = document.getElementById("playerName");
            let name = input.value.trim().toUpperCase() || "ANON";
            
            leaderboard.push({ name: name, score: score });
            leaderboard.sort((a, b) => b.score - a.score);
            leaderboard = leaderboard.slice(0, 5);
            
            try { localStorage.setItem("monoSnakeLeaderboard", JSON.stringify(leaderboard)); } catch(e) {}

            document.getElementById("newHighScoreSection").classList.add("hidden");
            document.getElementById("actionButtons").classList.remove("hidden");
            input.value = "";
            updateLeaderboardUI(name);
        }

        function gameOver() {
            if(score > highScore) {
                highScore = score;
                try { localStorage.setItem("monoSnakeBest", highScore); } catch(e) {}
                bestDisplay.innerHTML = highScore;
            }
            
            title.innerHTML = "TERMINATED";
            title.style.color = "#fff";
            sub.innerHTML = `Final Score: ${score}`;

    
            const isTopFive = leaderboard.length < 5 || score > (leaderboard[leaderboard.length - 1]?.score || 0);

            if (score > 0 && isTopFive) {
                document.getElementById("newHighScoreSection").classList.remove("hidden");
                document.getElementById("actionButtons").classList.add("hidden");
            } else {
                document.getElementById("newHighScoreSection").classList.add("hidden");
                document.getElementById("actionButtons").classList.remove("hidden");
            }

            updateLeaderboardUI();
            menu.classList.remove("hidden");
        }

        function render() {
            if(!menu.classList.contains("hidden") || !drawMenu.classList.contains("hidden")) return;

            
            ctx.fillStyle = "#000000";
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            
            ctx.fillStyle = "#1a1a1a";
            for(let x = 0; x < canvas.width; x += box) {
                for(let y = 0; y < canvas.height; y += box) {
                    ctx.fillRect(x + box/2 - 1, y + box/2 - 1, 2, 2);
                }
            }

            pulseTime += 0.15; let pulse = Math.sin(pulseTime) * 1.5;
            
    
            ctx.fillStyle = "#ffffff";
            ctx.shadowBlur = 15;
            ctx.shadowColor = "#ffffff";
            ctx.beginPath();
            let bx = food.x * box + box/2, by = food.y * box + box/2;
            let size = (box/2 - 3) + pulse;
            ctx.moveTo(bx, by - size);
            ctx.lineTo(bx + size, by);
            ctx.lineTo(bx, by + size);
            ctx.lineTo(bx - size, by);
            ctx.closePath();
            ctx.fill();

    
            ctx.shadowBlur = 10;
            ctx.shadowColor = "rgba(255, 255, 255, 0.6)";
            ctx.strokeStyle = "#ffffff";
            ctx.lineWidth = box * 0.7;
            ctx.lineCap = "round";
            ctx.lineJoin = "round";
            
            ctx.beginPath();
            ctx.moveTo(snake[0].x * box + box/2, snake[0].y * box + box/2);
            for(let i = 1; i < snake.length; i++) {
                if (Math.abs(snake[i].x - snake[i-1].x) > 1 || Math.abs(snake[i].y - snake[i-1].y) > 1) {
                    ctx.moveTo(snake[i].x * box + box/2, snake[i].y * box + box/2);
                } else {
                    ctx.lineTo(snake[i].x * box + box/2, snake[i].y * box + box/2);
                }
            }
            ctx.stroke();

            
            ctx.shadowBlur = 0;
            let hx = snake[0].x * box + box/2, hy = snake[0].y * box + box/2;
            
            if (useCustomHead) {
        
                ctx.save();
                ctx.translate(hx, hy);
                let angle = 0;
                if (d === "RIGHT") angle = Math.PI / 2;
                else if (d === "DOWN") angle = Math.PI;
                else if (d === "LEFT") angle = -Math.PI / 2;
                else if (d === "UP") angle = 0;
                ctx.rotate(angle);
                
            
                let headSize = box * 1.5;
                ctx.drawImage(customHeadImg, -headSize/2, -headSize/2, headSize, headSize);
                ctx.restore();
            } else {
        
                ctx.fillStyle = "#ffffff";
                ctx.beginPath(); ctx.arc(hx, hy, box/2.2, 0, Math.PI * 2); ctx.fill();

                let e1x = hx, e1y = hy, e2x = hx, e2y = hy, tx = hx, ty = hy, offset = box/3.5;
                if(d === "RIGHT") { e1x += 2; e1y -= offset; e2x += 2; e2y += offset; tx += box; }
                else if(d === "LEFT") { e1x -= 2; e1y -= offset; e2x -= 2; e2y += offset; tx -= box; }
                else if(d === "UP") { e1x -= offset; e1y -= 2; e2x += offset; e2y -= 2; ty -= box; }
                else if(d === "DOWN") { e1x -= offset; e1y += 2; e2x += offset; e2y += 2; ty += box; }

                ctx.strokeStyle = "#aaaaaa"; ctx.lineWidth = 1.5;
                ctx.beginPath(); ctx.moveTo(hx, hy); ctx.lineTo(tx, ty);
                if(d==="RIGHT" || d==="LEFT") {
                    ctx.lineTo(tx + (d==="RIGHT"?2:-2), ty - 2); ctx.moveTo(tx, ty); ctx.lineTo(tx + (d==="RIGHT"?2:-2), ty + 2);
                } else {
                    ctx.lineTo(tx - 2, ty + (d==="DOWN"?2:-2)); ctx.moveTo(tx, ty); ctx.lineTo(tx + 2, ty + (d==="DOWN"?2:-2));
                }
                ctx.stroke();

                ctx.fillStyle = "#000000";
                ctx.beginPath(); ctx.arc(e1x, e1y, 2.5, 0, Math.PI*2); ctx.fill();
                ctx.beginPath(); ctx.arc(e2x, e2y, 2.5, 0, Math.PI*2); ctx.fill();
                
                ctx.fillStyle = "#ffffff";
                let pxOffset = (d==="RIGHT"?1:d==="LEFT"?-1:0), pyOffset = (d==="DOWN"?1:d==="UP"?-1:0);
                ctx.beginPath(); ctx.arc(e1x + pxOffset, e1y + pyOffset, 1, 0, Math.PI*2); ctx.fill();
                ctx.beginPath(); ctx.arc(e2x + pxOffset, e2y + pyOffset, 1, 0, Math.PI*2); ctx.fill();
            }

            
            for(let i = particles.length - 1; i >= 0; i--) {
                let p = particles[i];
                p.x += p.vx; p.y += p.vy;
                p.vx *= 0.92; p.vy *= 0.92;
                p.life -= 0.03;
                if(p.life <= 0) { particles.splice(i, 1); continue; }
                
                ctx.globalAlpha = p.life;
                ctx.fillStyle = p.color;
                ctx.beginPath(); ctx.arc(p.x, p.y, 2 * p.life, 0, Math.PI*2); ctx.fill();
            }
            
            ctx.globalAlpha = 1;
            requestAnimationFrame(render);
        }
    </script>
</body>
</html>
 
عودة
أعلى أسفل