diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..30621b7 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,303 @@ +/* General Styles & Themes */ +:root { + --font-retro: 'Courier New', Courier, monospace; + --radius-m: 8px; + --shadow-m: 0 4px 12px rgba(0, 0, 0, 0.2); + --shadow-l: 0 8px 24px rgba(0, 0, 0, 0.3); + --transition-speed: 0.3s; +} + +body { + font-family: var(--font-retro); + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + transition: background-color var(--transition-speed), color var(--transition-speed); +} + +/* --- Theme Definitions --- */ +body.dark-theme { + --bg-color: #1a1a1a; + --surface-color: #2a2a2a; + --text-color: #f0f0f0; + --primary-color: #00ff00; + --accent-color: #ff00ff; + --border-color: #444; + --canvas-bg: #000; +} + +body.light-theme { + --bg-color: #f0f0f0; + --surface-color: #ffffff; + --text-color: #1a1a1a; + --primary-color: #008000; + --accent-color: #d900d9; + --border-color: #ccc; + --canvas-bg: #e0e0e0; +} +/* --- End Theme Definitions --- */ + +body { + background-color: var(--bg-color); + color: var(--text-color); +} + +/* Game Container & Canvas */ +.game-container { + position: relative; + display: flex; + justify-content: center; + align-items: center; + background-color: var(--surface-color); + border-radius: var(--radius-m); + box-shadow: var(--shadow-l); + padding: 24px; /* Increased padding for a larger canvas */ +} + +canvas { + background-color: var(--canvas-bg); + border-radius: 4px; + border: 1px solid var(--border-color); +} + +/* HUD (Heads-Up Display) */ +#hud { + position: absolute; + top: 24px; + left: 24px; + right: 24px; + display: flex; + justify-content: space-between; + align-items: center; + z-index: 10; +} + +#score-container { + font-size: 1.8em; + font-weight: bold; + color: var(--text-color); + background: rgba(0,0,0,0.3); + padding: 8px 16px; + border-radius: var(--radius-m); +} + +body.light-theme #score-container { + background: rgba(255,255,255,0.5); +} + + +#settings-btn { + background: none; + border: none; + cursor: pointer; + padding: 8px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + transition: background-color var(--transition-speed); +} + +#settings-btn svg { + fill: var(--text-color); + transition: transform 0.5s; +} + +#settings-btn:hover { + background-color: rgba(128, 128, 128, 0.2); +} +#settings-btn:hover svg { + transform: rotate(90deg); +} + + +/* Start Screen */ +#start-screen { + position: absolute; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.8); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + z-index: 20; + border-radius: 4px; +} + +body.light-theme #start-screen { + background-color: rgba(255, 255, 255, 0.8); +} + +#start-screen h1 { + font-size: 5em; + color: var(--primary-color); + text-shadow: 0 0 10px var(--primary-color); + margin-bottom: 32px; +} + +/* Buttons */ +#play-btn, .difficulty-btn, #close-settings-btn { + font-family: var(--font-retro); + font-size: 1.2em; + padding: 12px 24px; + border: 2px solid var(--primary-color); + background-color: transparent; + color: var(--primary-color); + cursor: pointer; + border-radius: var(--radius-m); + transition: background-color var(--transition-speed), color var(--transition-speed), box-shadow var(--transition-speed); + text-transform: uppercase; +} + +#play-btn:hover, .difficulty-btn:hover, #close-settings-btn:hover { + background-color: var(--primary-color); + color: var(--surface-color); + box-shadow: 0 0 15px var(--primary-color); +} + +.difficulty-btn.active { + background-color: var(--primary-color); + color: var(--surface-color); + box-shadow: 0 0 15px var(--primary-color); +} + +/* Settings Modal */ +#settings-backdrop { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.6); + display: flex; + justify-content: center; + align-items: center; + z-index: 100; + opacity: 1; + transition: opacity var(--transition-speed); +} + +#settings-backdrop.hidden { + opacity: 0; + pointer-events: none; +} + +#settings-panel { + background-color: var(--surface-color); + padding: 24px 32px; + border-radius: var(--radius-m); + box-shadow: var(--shadow-l); + width: 90%; + max-width: 400px; + border: 1px solid var(--border-color); + display: flex; + flex-direction: column; + gap: 24px; +} + +#settings-panel h2 { + margin: 0; + text-align: center; + font-size: 2em; + color: var(--primary-color); +} + +.settings-group { + display: flex; + justify-content: space-between; + align-items: center; + gap: 16px; +} + +.settings-group label { + font-size: 1.2em; + font-weight: bold; +} + +#difficulty-btns { + display: flex; + gap: 8px; +} + +.difficulty-btn { + font-size: 0.9em; + padding: 8px 12px; +} + +#close-settings-btn { + margin-top: 16px; + border-color: var(--accent-color); + color: var(--accent-color); +} +#close-settings-btn:hover { + background-color: var(--accent-color); + color: var(--surface-color); + box-shadow: 0 0 15px var(--accent-color); +} + + +/* Theme Switch */ +.theme-switch { + position: relative; + display: inline-block; + width: 60px; + height: 34px; +} + +.theme-switch input { + opacity: 0; + width: 0; + height: 0; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #444; + transition: var(--transition-speed); + border-radius: 34px; +} + +.slider:before { + position: absolute; + content: ""; + height: 26px; + width: 26px; + left: 4px; + bottom: 4px; + background-color: white; + transition: var(--transition-speed); + border-radius: 50%; +} + +input:checked + .slider { + background-color: var(--primary-color); +} + +body.light-theme input:checked + .slider { + background-color: #ccc; +} + +body.light-theme .slider { + background-color: #ccc; +} + +body.light-theme input:checked + .slider { + background-color: var(--primary-color); +} + + +input:checked + .slider:before { + transform: translateX(26px); +} + +.hidden { + display: none; +} diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..535f462 --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,242 @@ +document.addEventListener('DOMContentLoaded', () => { + const canvas = document.getElementById('gameCanvas'); + const ctx = canvas.getContext('2d'); + const scoreEl = document.getElementById('score'); + const bestScoreEl = document.getElementById('best-score'); + const playBtn = document.getElementById('play-btn'); + const startScreen = document.getElementById('start-screen'); + + const settingsBtn = document.getElementById('settings-btn'); + const closeSettingsBtn = document.getElementById('close-settings-btn'); + const settingsBackdrop = document.getElementById('settings-backdrop'); + const difficultyBtns = document.getElementById('difficulty-btns'); + const themeToggle = document.getElementById('theme-toggle'); + + const gridSize = 20; + canvas.width = 600; + canvas.height = 600; + + let snake = [{ x: 15, y: 15 }]; + let food = {}; + let direction = 'right'; + let score = 0; + let bestScore = 0; + let speed = 200; + let gameInterval; + let levelThreshold = 5; + let gameRunning = false; + let isGamePausedBySettings = false; + + // --- Settings --- + function openSettings() { + if (gameRunning) { + clearInterval(gameInterval); + isGamePausedBySettings = true; + } + settingsBackdrop.classList.remove('hidden'); + } + + function closeSettings() { + if (isGamePausedBySettings) { + gameInterval = setInterval(update, speed); + isGamePausedBySettings = false; + } + settingsBackdrop.classList.add('hidden'); + } + + function setDifficulty(difficulty) { + switch (difficulty) { + case 'easy': + speed = 250; + break; + case 'normal': + speed = 150; + break; + case 'hard': + speed = 75; + break; + } + document.querySelectorAll('.difficulty-btn').forEach(btn => { + btn.classList.toggle('active', btn.dataset.difficulty === difficulty); + }); + localStorage.setItem('snakeDifficulty', difficulty); + } + + function applyTheme(theme) { + document.body.classList.toggle('light-theme', theme === 'light'); + document.body.classList.toggle('dark-theme', theme === 'dark'); + themeToggle.checked = theme === 'dark'; + localStorage.setItem('snakeTheme', theme); + draw(); + } + + settingsBtn.addEventListener('click', openSettings); + closeSettingsBtn.addEventListener('click', closeSettings); + settingsBackdrop.addEventListener('click', (e) => { + if (e.target === settingsBackdrop) { + closeSettings(); + } + }); + + difficultyBtns.addEventListener('click', (e) => { + if (e.target.classList.contains('difficulty-btn')) { + setDifficulty(e.target.dataset.difficulty); + } + }); + + themeToggle.addEventListener('change', () => { + applyTheme(themeToggle.checked ? 'dark' : 'light'); + }); + + const savedDifficulty = localStorage.getItem('snakeDifficulty') || 'normal'; + setDifficulty(savedDifficulty); + + const savedTheme = localStorage.getItem('snakeTheme') || 'dark'; + applyTheme(savedTheme); + + bestScore = localStorage.getItem('snakeBestScore') || 0; + bestScoreEl.textContent = bestScore; + + + // --- Game Logic --- + function placeFood() { + food = { + x: Math.floor(Math.random() * (canvas.width / gridSize)), + y: Math.floor(Math.random() * (canvas.height / gridSize)) + }; + for (let segment of snake) { + if (segment.x === food.x && segment.y === food.y) { + placeFood(); + return; + } + } + } + + function draw() { + const accentColor = getComputedStyle(document.body).getPropertyValue('--accent-color').trim(); + const canvasBg = getComputedStyle(document.body).getPropertyValue('--canvas-bg').trim(); + + ctx.fillStyle = canvasBg; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + snake.forEach((segment, index) => { + ctx.fillStyle = accentColor; + if (index === 0) { + ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize); + } else { + ctx.fillRect(segment.x * gridSize + 1, segment.y * gridSize + 1, gridSize - 2, gridSize - 2); + } + }); + + const foodX = food.x * gridSize; + const foodY = food.y * gridSize; + const foodRadius = gridSize / 2.5; + + ctx.save(); + + ctx.shadowColor = '#A020F0'; + ctx.shadowBlur = 20; + + const gradient = ctx.createRadialGradient( + foodX + foodRadius, foodY + foodRadius, foodRadius * 0.1, + foodX + foodRadius, foodY + foodRadius, foodRadius + ); + gradient.addColorStop(0, '#E0B0FF'); + gradient.addColorStop(1, '#8A2BE2'); + + ctx.fillStyle = gradient; + ctx.beginPath(); + ctx.arc(foodX + gridSize / 2, foodY + gridSize / 2, foodRadius, 0, 2 * Math.PI); + ctx.fill(); + + ctx.restore(); + } + + function update() { + if (!gameRunning) return; + + const head = { ...snake[0] }; + switch (direction) { + case 'up': head.y--; break; + case 'down': head.y++; break; + case 'left': head.x--; break; + case 'right': head.x++; break; + } + + if (head.x < 0 || head.x >= canvas.width / gridSize || head.y < 0 || head.y >= canvas.height / gridSize) { + return gameOver(); + } + + for (let i = 1; i < snake.length; i++) { + if (head.x === snake[i].x && head.y === snake[i].y) { + return gameOver(); + } + } + + snake.unshift(head); + + if (head.x === food.x && head.y === food.y) { + score++; + scoreEl.textContent = score; + placeFood(); + if (score % levelThreshold === 0) { + increaseSpeed(); + } + } else { + snake.pop(); + } + + draw(); + } + + function increaseSpeed() { + clearInterval(gameInterval); + speed = Math.max(50, speed * 0.9); + gameInterval = setInterval(update, speed); + } + + function gameOver() { + clearInterval(gameInterval); + isGamePausedBySettings = false; + + if (score > bestScore) { + bestScore = score; + localStorage.setItem('snakeBestScore', bestScore); + bestScoreEl.textContent = bestScore; + } + + startScreen.style.display = 'flex'; + startScreen.querySelector('h1').textContent = 'Game Over'; + playBtn.textContent = 'Play Again'; + gameRunning = false; + } + + function startGame() { + snake = [{ x: 15, y: 15 }]; + direction = 'right'; + score = 0; + scoreEl.textContent = score; + gameRunning = true; + isGamePausedBySettings = false; + startScreen.style.display = 'none'; + + const currentDifficulty = localStorage.getItem('snakeDifficulty') || 'normal'; + setDifficulty(currentDifficulty); + + placeFood(); + clearInterval(gameInterval); + gameInterval = setInterval(update, speed); + } + + playBtn.addEventListener('click', startGame); + + document.addEventListener('keydown', e => { + const key = e.key; + if ((key === 'ArrowUp' || key.toLowerCase() === 'w') && direction !== 'down') direction = 'up'; + if ((key === 'ArrowDown' || key.toLowerCase() === 's') && direction !== 'up') direction = 'down'; + if ((key === 'ArrowLeft' || key.toLowerCase() === 'a') && direction !== 'right') direction = 'left'; + if ((key === 'ArrowRight' || key.toLowerCase() === 'd') && direction !== 'left') direction = 'right'; + }); + + draw(); +}); \ No newline at end of file diff --git a/index.php b/index.php index e13ae95..f3842ef 100644 --- a/index.php +++ b/index.php @@ -1,131 +1,56 @@ - - + - - - New Style - - - - + + + Snake Game + - -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

Flatlogic AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

+ + +
+
+
+ Score: 0 + Best: 0 +
+ +
+ + + +
+

SNAKE

+ +
-
- + + + + - + \ No newline at end of file