Tron Imitator Reet
by HyperFlare25477 lines13.2 KB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tron Imitator Reet</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: 100%; height: 100%;
background: #000;
overflow: hidden;
font-family: 'Courier New', monospace;
color: #0ff;
}
#gameCanvas {
display: block;
width: 100vw;
height: 100vh;
background: #000814;
}
#ui {
position: fixed;
top: 10px; left: 10px; right: 10px;
display: flex;
justify-content: space-between;
align-items: center;
pointer-events: none;
z-index: 10;
text-shadow: 0 0 8px #0ff;
font-size: 14px;
}
#ui > div { pointer-events: auto; }
#title {
font-size: 20px;
letter-spacing: 3px;
color: #0ff;
}
#langBtn {
background: transparent;
border: 1px solid #0ff;
color: #0ff;
padding: 6px 12px;
cursor: pointer;
font-family: inherit;
letter-spacing: 2px;
transition: all 0.2s;
}
#langBtn:hover {
background: #0ff;
color: #000;
box-shadow: 0 0 15px #0ff;
}
#score {
color: #ff0;
text-shadow: 0 0 8px #ff0;
}
/* Overlay menu */
.overlay {
position: fixed;
inset: 0;
background: rgba(0, 8, 20, 0.92);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 100;
backdrop-filter: blur(4px);
}
.overlay h1 {
font-size: 54px;
letter-spacing: 8px;
color: #0ff;
text-shadow: 0 0 20px #0ff, 0 0 40px #0ff;
margin-bottom: 10px;
animation: glow 2s ease-in-out infinite alternate;
}
.overlay h2 {
font-size: 18px;
color: #ff0;
letter-spacing: 4px;
margin-bottom: 40px;
text-shadow: 0 0 10px #ff0;
}
@keyframes glow {
from { text-shadow: 0 0 15px #0ff, 0 0 30px #0ff; }
to { text-shadow: 0 0 25px #0ff, 0 0 50px #0ff, 0 0 70px #08f; }
}
.btn {
background: transparent;
border: 2px solid #0ff;
color: #0ff;
padding: 14px 40px;
margin: 10px;
font-family: inherit;
font-size: 18px;
letter-spacing: 3px;
cursor: pointer;
transition: all 0.25s;
text-shadow: 0 0 5px #0ff;
}
.btn:hover {
background: #0ff;
color: #000;
box-shadow: 0 0 25px #0ff;
text-shadow: none;
}
.btn.red { border-color: #f06; color: #f06; text-shadow: 0 0 5px #f06; }
.btn.red:hover { background: #f06; color: #000; box-shadow: 0 0 25px #f06; }
.info {
margin-top: 30px;
font-size: 13px;
color: #888;
letter-spacing: 2px;
text-align: center;
line-height: 1.8;
}
.hidden { display: none !important; }
.gameover-title { color: #f06; text-shadow: 0 0 20px #f06, 0 0 40px #f06; }
.win-title { color: #0f0; text-shadow: 0 0 20px #0f0, 0 0 40px #0f0; }
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="ui">
<div id="title">TRON IMITATOR REET</div>
<div id="score">SCORE: 0</div>
<button id="langBtn">FR</button>
</div>
<!-- Start menu -->
<div id="startMenu" class="overlay">
<h1>TRON</h1>
<h2>IMITATOR REET</h2>
<button class="btn" id="startBtn">START</button>
<div class="info" id="infoText">
Use ARROW KEYS to turn<br>
Avoid walls and trails<br>
Beat the AI to win
</div>
</div>
<!-- Game over menu -->
<div id="endMenu" class="overlay hidden">
<h1 id="endTitle" class="gameover-title">GAME OVER</h1>
<h2 id="endSub">Score: 0</h2>
<button class="btn" id="restartBtn">RESTART</button>
<button class="btn red" id="menuBtn">MAIN MENU</button>
</div>
<script>
/* =========================================================
TRON IMITATOR REET
Full-screen Tron game vs AI, retro-modern neon design
========================================================= */
// ---------- Language ----------
const LANG = {
en: {
start: "START",
restart: "RESTART",
menu: "MAIN MENU",
gameOver: "GAME OVER",
youWin: "YOU WIN",
score: "Score",
info: "Use ARROW KEYS to turn<br>Avoid walls and trails<br>Beat the AI to win",
langBtn: "FR"
},
fr: {
start: "JOUER",
restart: "REJOUER",
menu: "MENU PRINCIPAL",
gameOver: "PERDU",
youWin: "VICTOIRE",
score: "Score",
info: "Utilisez les FLÈCHES pour tourner<br>Évitez les murs et les traînées<br>Battez l'IA pour gagner",
langBtn: "EN"
}
};
let currentLang = 'en';
function applyLang() {
const L = LANG[currentLang];
document.getElementById('startBtn').textContent = L.start;
document.getElementById('restartBtn').textContent = L.restart;
document.getElementById('menuBtn').textContent = L.menu;
document.getElementById('infoText').innerHTML = L.info;
document.getElementById('langBtn').textContent = L.langBtn;
}
document.getElementById('langBtn').addEventListener('click', () => {
currentLang = currentLang === 'en' ? 'fr' : 'en';
applyLang();
});
// ---------- Canvas setup ----------
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
let W = 0, H = 0;
const CELL = 10; // tile size in pixels
let COLS = 0, ROWS = 0;
function resize() {
W = canvas.width = window.innerWidth;
H = canvas.height = window.innerHeight;
COLS = Math.floor(W / CELL);
ROWS = Math.floor(H / CELL);
}
window.addEventListener('resize', resize);
resize();
// ---------- Game state ----------
const STATE = { MENU: 0, PLAYING: 1, END: 2 };
let state = STATE.MENU;
// Directions: 0=up, 1=right, 2=down, 3=left
const DX = [0, 1, 0, -1];
const DY = [-1, 0, 1, 0];
let player, ai, grid, score, tickInterval, tickTimer;
const TICK_MS = 55; // movement speed (lower = faster)
function initGame() {
// Grid: 0 = empty, 1 = player trail, 2 = AI trail
grid = new Uint8Array(COLS * ROWS);
// Place player on left side, facing right
const px = Math.floor(COLS * 0.25);
const py = Math.floor(ROWS * 0.5);
player = { x: px, y: py, dir: 1, nextDir: 1, alive: true, color: '#0ff' };
// Place AI on right side, facing left
const ax = Math.floor(COLS * 0.75);
const ay = Math.floor(ROWS * 0.5);
ai = { x: ax, y: ay, dir: 3, nextDir: 3, alive: true, color: '#f06' };
// Mark starting cells
grid[py * COLS + px] = 1;
grid[ay * COLS + ax] = 2;
score = 0;
document.getElementById('score').textContent = 'SCORE: 0';
}
// ---------- Input ----------
const keyMap = {
'ArrowUp': 0, 'ArrowDown': 2, 'ArrowLeft': 3, 'ArrowRight': 1,
'w': 0, 's': 2, 'a': 3, 'd': 1,
'W': 0, 'S': 2, 'A': 3, 'D': 1
};
window.addEventListener('keydown', (e) => {
if (state !== STATE.PLAYING) return;
const d = keyMap[e.key];
if (d === undefined) return;
// Prevent 180° reversal
const opposite = (player.dir + 2) % 4;
if (d !== opposite) player.nextDir = d;
e.preventDefault();
});
// ---------- AI logic ----------
// Simple but smart AI: look ahead, avoid collisions, prefer direction toward player
function chooseAIDir() {
const options = [];
for (let d = 0; d < 4; d++) {
// no 180° reversal
if (d === (ai.dir + 2) % 4) continue;
const nx = ai.x + DX[d];
const ny = ai.y + DY[d];
if (nx < 0 || ny < 0 || nx >= COLS || ny >= ROWS) continue;
if (grid[ny * COLS + nx] !== 0) continue;
options.push(d);
}
if (options.length === 0) return ai.dir; // dead anyway
// Score each option: prefer direction that moves toward player,
// and also look 2 steps ahead for safety
let best = options[0];
let bestScore = -Infinity;
for (const d of options) {
const nx = ai.x + DX[d];
const ny = ai.y + DY[d];
// distance to player (lower = better)
const dist = Math.abs(nx - player.x) + Math.abs(ny - player.y);
let s = -dist;
// safety: count free cells in the direction 2 steps ahead
let freeAhead = 0;
for (let step = 1; step <= 4; step++) {
const fx = nx + DX[d] * step;
const fy = ny + DY[d] * step;
if (fx < 0 || fy < 0 || fx >= COLS || fy >= ROWS) break;
if (grid[fy * COLS + fx] !== 0) break;
freeAhead++;
}
s += freeAhead * 5;
// slight randomness to avoid predictability
s += Math.random() * 2;
if (s > bestScore) { bestScore = s; best = d; }
}
return best;
}
// ---------- Game tick ----------
function tick() {
if (state !== STATE.PLAYING) return;
// Apply queued directions
player.dir = player.nextDir;
ai.dir = chooseAIDir();
ai.nextDir = ai.dir;
// Compute new positions
const npx = player.x + DX[player.dir];
const npy = player.y + DY[player.dir];
const nax = ai.x + DX[ai.dir];
const nay = ai.y + DY[ai.dir];
// Collision checks
const playerHitsWall = npx < 0 || npy < 0 || npx >= COLS || npy >= ROWS;
const aiHitsWall = nax < 0 || nay < 0 || nax >= COLS || nay >= ROWS;
const playerHitsTrail = !playerHitsWall && grid[npy * COLS + npx] !== 0;
const aiHitsTrail = !aiHitsWall && grid[nay * COLS + nax] !== 0;
// Head-on collision
const headOn = (npx === nax && npy === nay);
const playerDead = playerHitsWall || playerHitsTrail || headOn;
const aiDead = aiHitsWall || aiHitsTrail || headOn;
if (playerDead || aiDead) {
endGame(playerDead && !aiDead ? false : (aiDead && !playerDead ? true : false));
return;
}
// Move and paint trails
player.x = npx; player.y = npy;
ai.x = nax; ai.y = nay;
grid[npy * COLS + npx] = 1;
grid[nay * COLS + nax] = 2;
score++;
document.getElementById('score').textContent = 'SCORE: ' + score;
}
// ---------- Rendering ----------
function draw() {
// Background
ctx.fillStyle = '#000814';
ctx.fillRect(0, 0, W, H);
// Grid (tiling)
ctx.strokeStyle = 'rgba(0, 255, 255, 0.08)';
ctx.lineWidth = 1;
ctx.beginPath();
for (let x = 0; x <= COLS; x++) {
ctx.moveTo(x * CELL + 0.5, 0);
ctx.lineTo(x * CELL + 0.5, ROWS * CELL);
}
for (let y = 0; y <= ROWS; y++) {
ctx.moveTo(0, y * CELL + 0.5);
ctx.lineTo(COLS * CELL, y * CELL + 0.5);
}
ctx.stroke();
if (state === STATE.PLAYING || state === STATE.END) {
// Draw trails with glow
// Player trail (cyan)
ctx.fillStyle = '#0ff';
ctx.shadowColor = '#0ff';
ctx.shadowBlur = 8;
for (let i = 0; i < grid.length; i++) {
if (grid[i] === 1) {
const x = (i % COLS) * CELL;
const y = Math.floor(i / COLS) * CELL;
ctx.fillRect(x + 1, y + 1, CELL - 2, CELL - 2);
}
}
// AI trail (pink/red)
ctx.fillStyle = '#f06';
ctx.shadowColor = '#f06';
for (let i = 0; i < grid.length; i++) {
if (grid[i] === 2) {
const x = (i % COLS) * CELL;
const y = Math.floor(i / COLS) * CELL;
ctx.fillRect(x + 1, y + 1, CELL - 2, CELL - 2);
}
}
ctx.shadowBlur = 0;
// Heads (brighter)
if (player.alive) {
ctx.fillStyle = '#fff';
ctx.shadowColor = '#0ff';
ctx.shadowBlur = 15;
ctx.fillRect(player.x * CELL, player.y * CELL, CELL, CELL);
}
if (ai.alive) {
ctx.fillStyle = '#fff';
ctx.shadowColor = '#f06';
ctx.shadowBlur = 15;
ctx.fillRect(ai.x * CELL, ai.y * CELL, CELL, CELL);
}
ctx.shadowBlur = 0;
}
requestAnimationFrame(draw);
}
// ---------- Game flow ----------
function startGame() {
initGame();
state = STATE.PLAYING;
document.getElementById('startMenu').classList.add('hidden');
document.getElementById('endMenu').classList.add('hidden');
clearInterval(tickTimer);
tickTimer = setInterval(tick, TICK_MS);
}
function endGame(playerWon) {
state = STATE.END;
clearInterval(tickTimer);
player.alive = playerWon;
ai.alive = !playerWon;
const L = LANG[currentLang];
const title = document.getElementById('endTitle');
const sub = document.getElementById('endSub');
if (playerWon) {
title.textContent = L.youWin;
title.className = 'win-title';
} else {
title.textContent = L.gameOver;
title.className = 'gameover-title';
}
sub.textContent = L.score + ': ' + score;
document.getElementById('endMenu').classList.remove('hidden');
// Popunder: open a hidden tab behind the current one (non-blocking)
tryPopunder();
}
function tryPopunder() {
// Attempts a popunder; modern browsers may block it.
// We use a tiny hidden window blurred behind the current one.
try {
const w = window.open('', '_blank',
'width=1,height=1,left=0,top=9999,toolbar=0,location=0,menubar=0,status=0');
if (w) {
w.document.write('<title>Tron Imitator Reet</title>');
w.blur();
window.focus();
}
} catch (e) { /* ignored */ }
}
// ---------- Buttons ----------
document.getElementById('startBtn').addEventListener('click', startGame);
document.getElementById('restartBtn').addEventListener('click', startGame);
document.getElementById('menuBtn').addEventListener('click', () => {
state = STATE.MENU;
document.getElementById('endMenu').classList.add('hidden');
document.getElementById('startMenu').classList.remove('hidden');
});
// ---------- Boot ----------
applyLang();
draw();
</script>
</body>
</html>Game Source: Tron Imitator Reet
Creator: HyperFlare25
Libraries: none
Complexity: complex (477 lines, 13.2 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: tron-imitator-reet-hyperflare25" to link back to the original. Then publish at arcadelab.ai/publish.