Meta Description" name="description" />
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>PİKSEL YOL</title>
<style>
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; user-select: none; }
html, body {
margin: 0; padding: 0; height: 100%;
background: #070502;
display: flex; align-items: center; justify-content: center;
font-family: 'Courier New', monospace;
overflow: hidden;
}
#wrap {
position: relative;
width: min(96vw, 520px);
padding: 14px;
background: #0f0a04;
border: 3px solid #4a3410;
box-shadow: 0 0 0 2px #070502, 0 0 40px rgba(255,176,0,0.08) inset, 0 0 24px rgba(255,176,0,0.06);
}
/* scanline / crt overlay */
#wrap::after {
content: "";
position: absolute; inset: 0;
background: repeating-linear-gradient(
to bottom,
rgba(255,176,0,0.035) 0px,
rgba(255,176,0,0.035) 1px,
transparent 2px,
transparent 3px
);
pointer-events: none;
mix-blend-mode: overlay;
}
h1 {
margin: 0 0 10px 0;
font-size: 22px;
letter-spacing: 4px;
color: #ffb000;
text-shadow: 0 0 6px rgba(255,176,0,0.6), 0 0 14px rgba(255,176,0,0.25);
text-align: center;
font-weight: 700;
}
#stats {
display: flex;
justify-content: space-between;
color: #d99a2b;
font-size: 12px;
letter-spacing: 1px;
margin-bottom: 8px;
padding: 0 2px;
}
#stats b { color: #ffce5c; font-size: 14px; display: block; }
#stats div { text-align: center; flex: 1; }
#canvasHolder {
display: flex;
justify-content: center;
align-items: center;
background: #0a0600;
border: 2px solid #3a2708;
box-shadow: inset 0 0 20px rgba(0,0,0,0.8);
padding: 8px;
}
canvas {
display: block;
image-rendering: pixelated;
touch-action: none;
cursor: crosshair;
}
#msg {
min-height: 18px;
text-align: center;
color: #ff6a3a;
font-size: 12px;
letter-spacing: 1px;
margin-top: 8px;
text-shadow: 0 0 6px rgba(255,106,58,0.5);
}
#controls {
display: flex;
gap: 8px;
margin-top: 10px;
}
button {
flex: 1;
font-family: 'Courier New', monospace;
font-weight: 700;
letter-spacing: 2px;
font-size: 13px;
padding: 10px 6px;
background: #1a1206;
color: #ffb000;
border: 2px solid #5c4014;
cursor: pointer;
transition: all 0.08s ease;
}
button:active { transform: translateY(1px); }
button:disabled {
color: #4a3a1c;
border-color: #2a2010;
cursor: default;
}
#playBtn:not(:disabled) {
background: #2a1c04;
color: #7cff8a;
border-color: #3d6b1f;
box-shadow: 0 0 10px rgba(124,255,138,0.25);
}
#hint {
text-align: center;
color: #6b5326;
font-size: 10px;
letter-spacing: 1px;
margin-top: 8px;
}
</style>
</head>
<body>
<div id="wrap">
<h1>PİKSEL YOL</h1>
<div id="stats">
<div>SKOR<b id="scoreEl">0</b></div>
<div>SEVİYE<b id="levelEl">1</b></div>
<div>EN YÜKSEK<b id="bestEl">0</b></div>
</div>
<div id="canvasHolder">
<canvas id="cv"></canvas>
</div>
<div id="msg">Başlangıçtan (yeşil) bitişe (kırmızı) yol çiz.</div>
<div id="controls">
<button id="clearBtn">TEMİZLE</button>
<button id="playBtn" disabled>OYNAT ▶</button>
</div>
<div id="hint">sürükleyerek ya da hücrelere dokunarak yol çiz</div>
</div>
<script>
(function(){
const canvas = document.getElementById('cv');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('scoreEl');
const levelEl = document.getElementById('levelEl');
const bestEl = document.getElementById('bestEl');
const msgEl = document.getElementById('msg');
const clearBtn = document.getElementById('clearBtn');
const playBtn = document.getElementById('playBtn');
let score = 0, best = 0, level = 1;
let n, cellSize, rooms, path, playing = false;
const CANVAS_MAX = 460;
function rand(a) { return Math.floor(Math.random() * a); }
function shuffle(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = rand(i + 1);
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
function generateMaze(size) {
const grid = Array.from({length: size}, () =>
Array.from({length: size}, () => ({top:true,right:true,bottom:true,left:true,visited:false}))
);
const stack = [[0,0]];
grid[0][0].visited = true;
while (stack.length) {
const [x,y] = stack[stack.length-1];
const dirs = shuffle([
[0,-1,'top','bottom'],
[1,0,'right','left'],
[0,1,'bottom','top'],
[-1,0,'left','right']
]);
let moved = false;
for (const [dx,dy,wall,opp] of dirs) {
const nx = x+dx, ny = y+dy;
if (nx>=0 && nx<size && ny>=0 && ny<size && !grid[ny][nx].visited) {
grid[y][x][wall] = false;
grid[ny][nx][opp] = false;
grid[ny][nx].visited = true;
stack.push([nx,ny]);
moved = true;
break;
}
}
if (!moved) stack.pop();
}
return grid;
}
function connected(x1,y1,x2,y2) {
const dx = x2-x1, dy = y2-y1;
if (dx===1 && dy===0) return !rooms[y1][x1].right;
if (dx===-1 && dy===0) return !rooms[y1][x1].left;
if (dx===0 && dy===1) return !rooms[y1][x1].bottom;
if (dx===0 && dy===-1) return !rooms[y1][x1].top;
return false;
}
function setupLevel() {
n = Math.min(4 + level, 12);
cellSize = Math.floor(CANVAS_MAX / n);
const size = cellSize * n;
canvas.width = size;
canvas.height = size;
rooms = generateMaze(n);
path = [{x:0,y:0}];
playing = false;
playBtn.disabled = true;
msgEl.textContent = 'Başlangıçtan (yeşil) bitişe (kırmızı) yol çiz.';
msgEl.style.color = '#d99a2b';
draw();
}
function draw(spritePos) {
ctx.fillStyle = '#0a0600';
ctx.fillRect(0,0,canvas.width,canvas.height);
// rooms
for (let y=0;y<n;y++) {
for (let x=0;x<n;x++) {
const px = x*cellSize, py = y*cellSize;
ctx.fillStyle = '#150e04';
ctx.fillRect(px+2, py+2, cellSize-4, cellSize-4);
}
}
// start / end markers
ctx.fillStyle = '#2fbf4f';
ctx.fillRect(2, 2, cellSize-4, cellSize-4);
ctx.fillStyle = '#e33a2e';
ctx.fillRect((n-1)*cellSize+2, (n-1)*cellSize+2, cellSize-4, cellSize-4);
// walls
ctx.strokeStyle = '#5c4014';
ctx.lineWidth = 3;
ctx.beginPath();
for (let y=0;y<n;y++) {
for (let x=0;x<n;x++) {
const px = x*cellSize, py = y*cellSize;
const r = rooms[y][x];
if (r.top) { ctx.moveTo(px,py); ctx.lineTo(px+cellSize,py); }
if (r.left) { ctx.moveTo(px,py); ctx.lineTo(px,py+cellSize); }
if (r.right) { ctx.moveTo(px+cellSize,py); ctx.lineTo(px+cellSize,py+cellSize); }
if (r.bottom) { ctx.moveTo(px,py+cellSize); ctx.lineTo(px+cellSize,py+cellSize); }
}
}
ctx.stroke();
// outer border glow
ctx.strokeStyle = '#3a2708';
ctx.lineWidth = 4;
ctx.strokeRect(0,0,canvas.width,canvas.height);
// drawn path
if (path.length > 1) {
ctx.strokeStyle = '#ffb000';
ctx.lineWidth = Math.max(4, cellSize*0.18);
ctx.lineCap = 'square';
ctx.lineJoin = 'miter';
ctx.shadowColor = 'rgba(255,176,0,0.7)';
ctx.shadowBlur = 6;
ctx.beginPath();
path.forEach((c,i) => {
const cx = c.x*cellSize + cellSize/2;
const cy = c.y*cellSize + cellSize/2;
if (i===0) ctx.moveTo(cx,cy); else ctx.lineTo(cx,cy);
});
ctx.stroke();
ctx.shadowBlur = 0;
}
// path node dots
ctx.fillStyle = '#ffce5c';
path.forEach(c => {
const cx = c.x*cellSize + cellSize/2;
const cy = c.y*cellSize + cellSize/2;
ctx.fillRect(cx-3, cy-3, 6, 6);
});
// sprite (during play animation)
if (spritePos) {
const cx = spritePos.x*cellSize + cellSize/2;
const cy = spritePos.y*cellSize + cellSize/2;
const s = cellSize*0.5;
ctx.fillStyle = '#7cff8a';
ctx.shadowColor = 'rgba(124,255,138,0.8)';
ctx.shadowBlur = 10;
ctx.fillRect(cx-s/2, cy-s/2, s, s);
ctx.shadowBlur = 0;
ctx.fillStyle = '#0a0600';
ctx.fillRect(cx-s/4, cy-s/6, 3, 3);
ctx.fillRect(cx+s/4-3, cy-s/6, 3, 3);
}
}
function cellFromEvent(evt) {
const rect = canvas.getBoundingClientRect();
const clientX = evt.touches ? evt.touches[0].clientX : evt.clientX;
const clientY = evt.touches ? evt.touches[0].clientY : evt.clientY;
const scaleX = canvas.width / rect.width;
const scaleY = canvas.height / rect.height;
const x = Math.floor((clientX - rect.left) * scaleX / cellSize);
const y = Math.floor((clientY - rect.top) * scaleY / cellSize);
if (x<0||x>=n||y<0||y>=n) return null;
return {x,y};
}
let dragging = false;
let lastProcessed = null;
function tryAppend(cell) {
if (playing) return;
const last = path[path.length-1];
if (cell.x===last.x && cell.y===last.y) return;
// undo: tapped second-to-last cell
if (path.length > 1) {
const prev = path[path.length-2];
if (cell.x===prev.x && cell.y===prev.y) {
path.pop();
updatePlayState();
draw();
return;
}
}
const dx = Math.abs(cell.x-last.x), dy = Math.abs(cell.y-last.y);
if (dx+dy !== 1) return; // must be orthogonal neighbor
if (!connected(last.x,last.y,cell.x,cell.y)) return; // must not cross a wall
path.push(cell);
updatePlayState();
draw();
}
function updatePlayState() {
const last = path[path.length-1];
const complete = last.x===n-1 && last.y===n-1;
playBtn.disabled = !complete;
if (complete) {
msgEl.textContent = 'Yol tamam! OYNAT\'a bas.';
msgEl.style.color = '#7cff8a';
} else {
msgEl.textContent = 'Başlangıçtan (yeşil) bitişe (kırmızı) yol çiz.';
msgEl.style.color = '#d99a2b';
}
}
function pointerDown(evt) {
evt.preventDefault();
if (playing) return;
const cell = cellFromEvent(evt);
if (!cell) return;
dragging = true;
lastProcessed = null;
if (cell.x===0 && cell.y===0 && path.length===1) return;
tryAppend(cell);
lastProcessed = cell;
}
function pointerMove(evt) {
if (!dragging || playing) return;
evt.preventDefault();
const cell = cellFromEvent(evt);
if (!cell) return;
if (lastProcessed && lastProcessed.x===cell.x && lastProcessed.y===cell.y) return;
tryAppend(cell);
lastProcessed = cell;
}
function pointerUp() { dragging = false; lastProcessed = null; }
canvas.addEventListener('mousedown', pointerDown);
canvas.addEventListener('mousemove', pointerMove);
window.addEventListener('mouseup', pointerUp);
canvas.addEventListener('touchstart', pointerDown, {passive:false});
canvas.addEventListener('touchmove', pointerMove, {passive:false});
window.addEventListener('touchend', pointerUp);
clearBtn.addEventListener('click', () => {
if (playing) return;
path = [{x:0,y:0}];
updatePlayState();
draw();
});
playBtn.addEventListener('click', () => {
if (playing || playBtn.disabled) return;
playing = true;
playBtn.disabled = true;
clearBtn.disabled = true;
msgEl.textContent = 'Koşuluyor...';
msgEl.style.color = '#ffce5c';
let i = 0;
const stepMs = Math.max(30, 120 - level*8);
const timer = setInterval(() => {
draw(path[i]);
i++;
if (i >= path.length) {
clearInterval(timer);
onLevelComplete();
}
}, stepMs);
});
function onLevelComplete() {
const gained = 100 * level;
score += gained;
if (score > best) best = score;
scoreEl.textContent = score;
bestEl.textContent = best;
msgEl.textContent = '+' + gained + ' puan! Sonraki labirent...';
msgEl.style.color = '#7cff8a';
level++;
levelEl.textContent = level;
clearBtn.disabled = false;
setTimeout(setupLevel, 950);
}
setupLevel();
})();
</script>
</body>
</html>
1
1
13KB
13KB
101.0ms
292.0ms
102.0ms