{"id":363,"date":"2025-10-13T04:36:16","date_gmt":"2025-10-13T04:36:16","guid":{"rendered":"https:\/\/insaatsirketleri.com.tr\/en\/?p=363"},"modified":"2025-10-13T04:39:09","modified_gmt":"2025-10-13T04:39:09","slug":"space-game","status":"publish","type":"post","link":"https:\/\/insaatsirketleri.com.tr\/en\/space-game\/","title":{"rendered":"Space Game"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<!DOCTYPE html>\n<html lang=\"tr\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Uzay Ka\u00e7\u0131\u015f\u00e7\u0131s\u0131 (Space Dodger) H5 Oyunu<\/title>\n    <style>\n        @import url('https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;700&display=swap');\n        \n        body {\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            min-height: 100vh;\n            margin: 0;\n            background-color: #0d1117; \/* Dark space background *\/\n            color: #e6f6ff;\n            font-family: 'Inter', sans-serif;\n            padding: 20px;\n            box-sizing: border-box;\n            overflow: hidden;\n        }\n\n        #game-container {\n            position: relative;\n            width: 100%;\n            max-width: 500px; \/* Max width for game area *\/\n            aspect-ratio: 1 \/ 1.5; \/* Vertical game aspect ratio *\/\n            box-shadow: 0 0 30px rgba(0, 180, 255, 0.5);\n            border-radius: 12px;\n            overflow: hidden;\n        }\n\n        #game-canvas {\n            background-color: #010409;\n            display: block;\n            width: 100%;\n            height: 100%;\n            border: 2px solid #00b4ff;\n            border-radius: 10px;\n        }\n\n        #ui-overlay {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            background-color: rgba(0, 0, 0, 0.7);\n            z-index: 10;\n            border-radius: 10px;\n            transition: opacity 0.3s ease;\n        }\n\n        #score-board {\n            display: flex;\n            justify-content: space-between;\n            width: 100%;\n            max-width: 500px;\n            margin-bottom: 10px;\n            padding: 10px;\n            background-color: #161b22;\n            border-radius: 8px;\n            font-size: 1.1rem;\n        }\n        \n        #current-score, #high-score {\n            font-weight: bold;\n            color: #00ffaa;\n            text-shadow: 0 0 5px #00ffaa60;\n        }\n\n        h1 {\n            color: #00b4ff;\n            font-size: 2.5rem;\n            margin-bottom: 20px;\n            text-shadow: 0 0 10px rgba(0, 180, 255, 0.8);\n        }\n\n        .message {\n            text-align: center;\n            margin-bottom: 30px;\n        }\n\n        .message h2 {\n            font-size: 2.2rem;\n            color: #ff4d4d;\n            margin-bottom: 10px;\n            text-shadow: 0 0 8px rgba(255, 77, 77, 0.7);\n        }\n\n        .message p {\n            font-size: 1.1rem;\n            color: #b3ccff;\n        }\n\n        #start-button {\n            padding: 15px 30px;\n            font-size: 1.2rem;\n            font-weight: 700;\n            color: #0d1117;\n            background-color: #00ffaa;\n            border: none;\n            border-radius: 50px;\n            cursor: pointer;\n            box-shadow: 0 5px 20px rgba(0, 255, 170, 0.4);\n            transition: all 0.2s ease;\n            text-transform: uppercase;\n        }\n\n        #start-button:hover {\n            background-color: #33ffbb;\n            box-shadow: 0 8px 25px rgba(0, 255, 170, 0.6);\n            transform: translateY(-2px);\n        }\n\n        \/* Responsive adjustments for smaller screens *\/\n        @media (max-width: 600px) {\n            h1 {\n                font-size: 1.8rem;\n                margin-bottom: 15px;\n            }\n            #score-board {\n                font-size: 0.9rem;\n                padding: 8px;\n            }\n            #start-button {\n                padding: 12px 25px;\n                font-size: 1rem;\n            }\n            .message h2 {\n                font-size: 1.8rem;\n            }\n        }\n    <\/style>\n<\/head>\n<body>\n\n    <h1>\ud83d\ude80 Uzay Ka\u00e7\u0131\u015f\u00e7\u0131s\u0131<\/h1>\n\n    <div id=\"score-board\">\n        <div id=\"current-score\">Puan: 0<\/div>\n        <div id=\"high-score\">En Y\u00fcksek Puan: 0<\/div>\n    <\/div>\n\n    <div id=\"game-container\">\n        <canvas id=\"game-canvas\"><\/canvas>\n        <div id=\"ui-overlay\">\n            <div class=\"message\" id=\"overlay-message\">\n                <h2>Oyuna Haz\u0131r M\u0131s\u0131n?<\/h2>\n                <p>Uzay Gemisini **Sol (\u2190)** ve **Sa\u011f (\u2192)** ok tu\u015flar\u0131<br>veya **ekran\u0131n kenarlar\u0131na dokunarak** hareket ettir.<\/p>\n            <\/div>\n            <button id=\"start-button\">Oyuna Ba\u015fla<\/button>\n        <\/div>\n    <\/div>\n\n    <script>\n        \/\/ Global variables for Firebase setup (MANDATORY)\n        const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';\n        const firebaseConfig = typeof __firebase_config !== 'undefined' ? JSON.parse(__firebase_config) : null;\n        const initialAuthToken = typeof __initial_auth_token !== 'undefined' ? __initial_auth_token : null;\n\n        \/\/ Game Constants\n        const CANVAS_WIDTH_RATIO = 500; \/\/ Reference width for scaling\n        const CANVAS_HEIGHT_RATIO = 750; \/\/ Reference height for scaling\n\n        \/\/ Game State\n        let gameState = 'START'; \/\/ 'START', 'PLAYING', 'GAME_OVER'\n        let currentScore = 0;\n        let highScore = 0;\n\n        \/\/ Canvas Setup\n        const canvas = document.getElementById('game-canvas');\n        const ctx = canvas.getContext('2d');\n        const uiOverlay = document.getElementById('ui-overlay');\n        const startButton = document.getElementById('start-button');\n        const currentScoreEl = document.getElementById('current-score');\n        const highScoreEl = document.getElementById('high-score');\n        const overlayMessage = document.getElementById('overlay-message');\n\n        \/\/ Scaling factor\n        let scaleFactor = 1;\n\n        \/\/ Player (Ship) Object\n        let player = {\n            x: CANVAS_WIDTH_RATIO \/ 2,\n            y: CANVAS_HEIGHT_RATIO - 50,\n            width: 30,\n            height: 30,\n            speed: 5,\n            direction: 0, \/\/ -1: left, 1: right, 0: stop\n            \/\/ Draw the ship as a triangle\n            draw: function() {\n                ctx.save();\n                ctx.translate(this.x, this.y);\n                ctx.fillStyle = '#00ffaa';\n                ctx.beginPath();\n                \/\/ Tip of the ship\n                ctx.moveTo(0, -this.height \/ 2); \n                \/\/ Bottom right corner\n                ctx.lineTo(this.width \/ 2, this.height \/ 2);\n                \/\/ Bottom left corner\n                ctx.lineTo(-this.width \/ 2, this.height \/ 2);\n                ctx.closePath();\n                ctx.fill();\n\n                \/\/ Add a glowing effect at the bottom (thrusters)\n                ctx.fillStyle = 'rgba(255, 165, 0, 0.8)'; \/\/ Orange\/Yellow\n                ctx.shadowColor = '#ffa500';\n                ctx.shadowBlur = 10;\n                ctx.fillRect(-this.width \/ 4, this.height \/ 2 - 5, this.width \/ 2, 8);\n                ctx.shadowBlur = 0; \/\/ Reset shadow\n                \n                ctx.restore();\n            },\n            update: function() {\n                this.x += this.direction * this.speed;\n\n                \/\/ Boundary checking\n                if (this.x - this.width \/ 2 < 0) {\n                    this.x = this.width \/ 2;\n                }\n                if (this.x + this.width \/ 2 > CANVAS_WIDTH_RATIO) {\n                    this.x = CANVAS_WIDTH_RATIO - this.width \/ 2;\n                }\n            }\n        };\n\n        \/\/ Obstacles (Meteors) Array\n        let obstacles = [];\n        let obstacleSpawnRate = 60; \/\/ Frames between spawns\n        let frameCount = 0;\n        let scoreMultiplier = 1; \/\/ Used to increase difficulty\n\n        \/\/ Obstacle Constructor\n        function Obstacle() {\n            this.size = 10 + Math.random() * 20 * scoreMultiplier;\n            this.x = Math.random() * (CANVAS_WIDTH_RATIO - this.size * 2) + this.size;\n            this.y = -this.size;\n            this.speed = 2 + Math.random() * 2 * scoreMultiplier;\n            this.color = `hsl(${Math.random() * 360}, 70%, 50%)`;\n\n            this.draw = function() {\n                ctx.fillStyle = this.color;\n                ctx.shadowColor = this.color;\n                ctx.shadowBlur = 5;\n                ctx.fillRect(this.x - this.size \/ 2, this.y - this.size \/ 2, this.size, this.size);\n                ctx.shadowBlur = 0;\n            };\n\n            this.update = function() {\n                this.y += this.speed;\n            };\n        }\n\n        \/\/ --- Core Game Functions ---\n\n        function resizeCanvas() {\n            \/\/ Calculate scale factor based on container width\n            const container = document.getElementById('game-container');\n            const containerRect = container.getBoundingClientRect();\n            \n            \/\/ Set canvas size to match the container\n            canvas.width = containerRect.width;\n            canvas.height = containerRect.height;\n\n            \/\/ Calculate the new scale factor relative to the reference width\n            scaleFactor = canvas.width \/ CANVAS_WIDTH_RATIO;\n            \n            \/\/ Set up context transformation for easy drawing (optional but helps keep coordinates consistent)\n            ctx.setTransform(scaleFactor, 0, 0, scaleFactor, 0, 0);\n\n            \/\/ Re-render the game elements after resize if necessary (especially important for Game Over screen)\n            if (gameState !== 'PLAYING') {\n                draw();\n            }\n        }\n\n        function spawnObstacle() {\n            obstacles.push(new Obstacle());\n            \/\/ Increase difficulty: faster spawn and higher speed\/size\n            if (frameCount % 600 === 0 && scoreMultiplier < 5) {\n                scoreMultiplier += 0.2;\n                obstacleSpawnRate = Math.max(20, 60 - scoreMultiplier * 5); \/\/ Minimum spawn rate is 20 frames\n            }\n        }\n\n        function checkCollision() {\n            for (let i = 0; i < obstacles.length; i++) {\n                const obs = obstacles[i];\n                \/\/ Simple AABB collision detection\n                const dx = player.x - obs.x;\n                const dy = player.y - obs.y;\n                const distance = Math.sqrt(dx * dx + dy * dy);\n                \n                \/\/ Collision if the distance between centers is less than the sum of half widths\/heights (approximate)\n                const safeDistance = (player.width + obs.size) \/ 2;\n\n                if (distance < safeDistance * 0.8) { \/\/ Added a buffer (0.8) for slightly more forgiving collision\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        function updateScore() {\n            currentScore += 1;\n            currentScoreEl.textContent = `Puan: ${currentScore}`;\n        }\n\n        \/\/ --- Game Loop and Drawing ---\n\n        function draw() {\n            \/\/ Clear the canvas, scaled to the reference size\n            ctx.clearRect(0, 0, CANVAS_WIDTH_RATIO, CANVAS_HEIGHT_RATIO);\n            \n            \/\/ Draw Player\n            player.draw();\n\n            \/\/ Draw Obstacles\n            for (let i = 0; i < obstacles.length; i++) {\n                obstacles[i].draw();\n            }\n        }\n\n        function update() {\n            \/\/ Update Player position\n            player.update();\n\n            \/\/ Update Obstacles\n            for (let i = obstacles.length - 1; i >= 0; i--) {\n                obstacles[i].update();\n\n                \/\/ Remove obstacles that go off screen\n                if (obstacles[i].y > CANVAS_HEIGHT_RATIO + obstacles[i].size) {\n                    obstacles.splice(i, 1);\n                    updateScore(); \/\/ Score increases when an obstacle is successfully passed\n                }\n            }\n\n            \/\/ Spawn new Obstacles\n            frameCount++;\n            if (frameCount % Math.floor(obstacleSpawnRate) === 0) {\n                spawnObstacle();\n            }\n\n            \/\/ Check for Collision\n            if (checkCollision()) {\n                endGame();\n            }\n        }\n\n        function gameLoop() {\n            if (gameState !== 'PLAYING') return;\n\n            update();\n            draw();\n            \n            requestAnimationFrame(gameLoop);\n        }\n\n        \/\/ --- Game State Management ---\n        \n        function startGame() {\n            if (gameState === 'PLAYING') return;\n\n            \/\/ Reset state\n            gameState = 'PLAYING';\n            currentScore = 0;\n            currentScoreEl.textContent = 'Puan: 0';\n            player.x = CANVAS_WIDTH_RATIO \/ 2;\n            player.y = CANVAS_HEIGHT_RATIO - 50;\n            obstacles = [];\n            frameCount = 0;\n            scoreMultiplier = 1;\n            \n            uiOverlay.style.opacity = '0';\n            uiOverlay.style.pointerEvents = 'none';\n\n            gameLoop();\n        }\n\n        function endGame() {\n            gameState = 'GAME_OVER';\n            \n            \/\/ Update High Score\n            if (currentScore > highScore) {\n                highScore = currentScore;\n                highScoreEl.textContent = `En Y\u00fcksek Puan: ${highScore}`;\n                \/\/ Save new high score to Firestore (if available)\n                saveHighScore(highScore);\n            }\n\n            \/\/ Show Game Over overlay\n            overlayMessage.innerHTML = `\n                <h2>Oyun Bitti!<\/h2>\n                <p>Puan\u0131n\u0131z: ${currentScore}<\/p>\n                <p>\u00c7arpt\u0131n\u0131z! Tekrar denemeye haz\u0131r m\u0131s\u0131n\u0131z?<\/p>\n            `;\n            startButton.textContent = 'Tekrar Oyna';\n            \n            uiOverlay.style.opacity = '1';\n            uiOverlay.style.pointerEvents = 'auto';\n        }\n\n        \/\/ --- Input Handling (Keyboard and Touch) ---\n\n        function handleKeyDown(e) {\n            if (gameState !== 'PLAYING') return;\n            if (e.key === 'ArrowLeft' || e.key === 'a' || e.key === 'A') {\n                player.direction = -1;\n            } else if (e.key === 'ArrowRight' || e.key === 'd' || e.key === 'D') {\n                player.direction = 1;\n            }\n        }\n\n        function handleKeyUp(e) {\n            if (gameState !== 'PLAYING') return;\n            if (e.key === 'ArrowLeft' || e.key === 'ArrowRight' || e.key === 'a' || e.key === 'd' || e.key === 'A' || e.key === 'D') {\n                player.direction = 0;\n            }\n        }\n\n        \/\/ Touch\/Click Handling for mobile and desktop\n        function handleTouchStart(e) {\n            if (gameState !== 'PLAYING') return;\n            e.preventDefault();\n            const rect = canvas.getBoundingClientRect();\n            const touchX = (e.touches ? e.touches[0].clientX : e.clientX) - rect.left;\n\n            \/\/ Determine direction based on where the touch occurred on the canvas\n            if (touchX < rect.width \/ 2) {\n                player.direction = -1; \/\/ Left half\n            } else {\n                player.direction = 1; \/\/ Right half\n            }\n        }\n\n        function handleTouchEnd(e) {\n            if (gameState !== 'PLAYING') return;\n            player.direction = 0;\n        }\n\n        \/\/ Attach event listeners\n        window.addEventListener('keydown', handleKeyDown);\n        window.addEventListener('keyup', handleKeyUp);\n        \n        canvas.addEventListener('mousedown', handleTouchStart);\n        canvas.addEventListener('mouseup', handleTouchEnd);\n        canvas.addEventListener('touchstart', handleTouchStart);\n        canvas.addEventListener('touchend', handleTouchEnd);\n        \n        startButton.addEventListener('click', startGame);\n\n        window.addEventListener('resize', resizeCanvas);\n        \n        \/\/ --- Firebase\/Firestore Integration for High Score ---\n        \n        let db, auth, userId = null;\n        let isAuthReady = false;\n\n        \/\/ Firestore fonksiyonlar\u0131n\u0131 genel kapsamda tan\u0131ml\u0131yoruz, b\u00f6ylece di\u011fer fonksiyonlar eri\u015febilir.\n        let doc, setDoc, getDoc, collection, query, limit, getDocs;\n\n\n        async function initializeFirebase() {\n            try {\n                \/\/ Check if Firebase config is available\n                if (!firebaseConfig) {\n                    console.error(\"Firebase config missing. High score will not be saved.\");\n                    isAuthReady = true;\n                    return;\n                }\n\n                \/\/ Dynamic imports for Firebase (MANDATORY for single-file HTML)\n                const { initializeApp } = await import(\"https:\/\/www.gstatic.com\/firebasejs\/11.6.1\/firebase-app.js\");\n                const authImports = await import(\"https:\/\/www.gstatic.com\/firebasejs\/11.6.1\/firebase-auth.js\");\n                const firestoreImports = await import(\"https:\/\/www.gstatic.com\/firebasejs\/11.6.1\/firebase-firestore.js\");\n                \n                firestoreImports.setLogLevel('Debug');\n\n\n                const app = initializeApp(firebaseConfig);\n                auth = authImports.getAuth(app);\n                db = firestoreImports.getFirestore(app);\n\n                \/\/ \u0130\u00e7e aktar\u0131lan Firestore fonksiyonlar\u0131n\u0131 global de\u011fi\u015fkenlere at\u0131yoruz\n                doc = firestoreImports.doc;\n                setDoc = firestoreImports.setDoc;\n                getDoc = firestoreImports.getDoc;\n                collection = firestoreImports.collection;\n                query = firestoreImports.query;\n                limit = firestoreImports.limit;\n                getDocs = firestoreImports.getDocs;\n\n\n                \/\/ Sign in with custom token or anonymously\n                if (initialAuthToken) {\n                    await authImports.signInWithCustomToken(auth, initialAuthToken);\n                } else {\n                    await authImports.signInAnonymously(auth);\n                }\n\n                authImports.onAuthStateChanged(auth, (user) => {\n                    if (user) {\n                        userId = user.uid;\n                        isAuthReady = true;\n                        console.log(\"User signed in with ID:\", userId);\n                        loadHighScore();\n                    } else {\n                        \/\/ If auth fails, use a random ID but disable saving high scores\n                        userId = crypto.randomUUID();\n                        isAuthReady = true;\n                        console.warn(\"Authentication failed, using anonymous ID.\");\n                        loadHighScore();\n                    }\n                });\n\n            } catch (error) {\n                console.error(\"Firebase initialization failed:\", error);\n                isAuthReady = true;\n            }\n        }\n\n        const HIGH_SCORE_COLLECTION = `artifacts\/${appId}\/public\/data\/space_dodger_scores`;\n\n        async function loadHighScore() {\n            if (!db || !isAuthReady) return;\n            \n            try {\n                \/\/ Load the highest score globally\n                \/\/ 'query', 'collection', 'limit' now refer to the globally defined variables\n                const q = query(collection(db, HIGH_SCORE_COLLECTION), limit(1));\n                const querySnapshot = await getDocs(q);\n\n                let globalMaxScore = 0;\n                querySnapshot.forEach((doc) => {\n                    const data = doc.data();\n                    if (data && data.score > globalMaxScore) {\n                        globalMaxScore = data.score;\n                    }\n                });\n                \n                \/\/ Also load the current user's personal high score\n                const userDocRef = doc(db, HIGH_SCORE_COLLECTION, userId);\n                const userDocSnap = await getDoc(userDocRef);\n\n                if (userDocSnap.exists()) {\n                    const userScore = userDocSnap.data().score;\n                    highScore = Math.max(globalMaxScore, userScore || 0);\n                } else {\n                    highScore = globalMaxScore;\n                }\n\n                highScoreEl.textContent = `En Y\u00fcksek Puan: ${highScore}`;\n\n            } catch (error) {\n                console.error(\"Error loading high score:\", error);\n            }\n        }\n\n        async function saveHighScore(score) {\n            if (!db || !userId || !isAuthReady || !auth.currentUser || auth.currentUser.isAnonymous) {\n                console.warn(\"Cannot save high score: Firestore not ready or user is anonymous.\");\n                return;\n            }\n\n            try {\n                \/\/ 'doc' and 'setDoc' now refer to the globally defined variables\n                const docRef = doc(db, HIGH_SCORE_COLLECTION, userId);\n                await setDoc(docRef, {\n                    userId: userId,\n                    score: score,\n                    timestamp: new Date().toISOString(),\n                    \/\/ Optionally store username if available\n                }, { merge: true });\n                console.log(\"High score saved successfully:\", score);\n            } catch (error) {\n                console.error(\"Error saving high score:\", error);\n            }\n        }\n\n        \/\/ --- Initial Setup ---\n        window.onload = function() {\n            resizeCanvas();\n            draw(); \/\/ Draw initial state\n            initializeFirebase(); \/\/ Initialize Firebase and load scores\n        };\n    <\/script>\n<\/body>\n<\/html>\n\n","protected":false},"excerpt":{"rendered":"<p>Uzay Ka\u00e7\u0131\u015f\u00e7\u0131s\u0131 (Space Dodger) H5 Oyunu \ud83d\ude80 Uzay Ka\u00e7\u0131\u015f\u00e7\u0131s\u0131 Puan: 0 En Y\u00fcksek Puan: 0 Oyuna Haz\u0131r M\u0131s\u0131n? Uzay Gemisini **Sol (\u2190)** ve **Sa\u011f (\u2192)** ok tu\u015flar\u0131veya **ekran\u0131n [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-363","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/posts\/363","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/comments?post=363"}],"version-history":[{"count":2,"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/posts\/363\/revisions"}],"predecessor-version":[{"id":365,"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/posts\/363\/revisions\/365"}],"wp:attachment":[{"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/media?parent=363"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/categories?post=363"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/insaatsirketleri.com.tr\/en\/wp-json\/wp\/v2\/tags?post=363"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}