Meta Description" name="description" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Night Escape</title>
<style>
*{box-sizing:border-box}
body{margin:0;background:#050505;color:white;font-family:Arial;overflow:hidden}
canvas{display:block;margin:auto;background:#111}
#ui{
position:fixed;top:10px;left:10px;z-index:5;
font-size:18px;text-shadow:0 0 5px #000
}
#msg{
position:fixed;bottom:20px;left:50%;transform:translateX(-50%);
text-align:center;font-size:18px
}
#controls{
position:fixed;bottom:15px;left:15px;right:15px;
display:flex;justify-content:space-between;pointer-events:none
}
.pad{pointer-events:auto;display:grid;grid-template-columns:55px 55px 55px;gap:5px}
button{
width:55px;height:55px;border:1px solid #777;border-radius:12px;
background:#222;color:white;font-size:22px;opacity:.85
}
.empty{visibility:hidden}
#action{pointer-events:auto}
</style>
</head>
<body>
<div id="ui">
π Keys: <span id="keys">0</span>/2<br>
β€οΈ Health: <span id="hp">100</span><br>
πͺ Find the exit!
</div>
<div id="msg">Find both keys and escape...</div>
<canvas id="game" width="900" height="600"></canvas>
<div id="controls">
<div class="pad">
<button class="empty"></button>
<button onclick="move(0,-1)">β¬οΈ</button>
<button class="empty"></button>
<button onclick="move(-1,0)">β¬
οΈ</button>
<button onclick="move(0,1)">β¬οΈ</button>
<button onclick="move(1,0)">β‘οΈ</button>
</div>
<button id="action" onclick="interact()">β</button>
</div>
<script>
const canvas=document.getElementById("game");
const ctx=canvas.getContext("2d");
const TILE=50;
const map=[
"##################",
"#P.....#..........#",
"#.####.#.######...#",
"#....#.#......#...#",
"###..#.#.####.#.###",
"#....#.#....#.#...#",
"#.####.####.#.###.#",
"#......#....#.....#",
"#.######.########.#",
"#.................#",
"#.###############.#",
"#.................E",
"##################"
];
let player={x:1,y:1,hp:100};
let monster={x:15,y:9};
let keys=[];
let collected=0;
let gameOver=false;
for(let y=0;y<map.length;y++){
for(let x=0;x<map[y].length;x++){
if(map[y][x]=="P") player={x,y,hp:100};
}
}
// Keys placed in the house
keys=[
{x:6,y:3,got:false},
{x:14,y:7,got:false}
];
function wall(x,y){
return y<0||y>=map.length||x<0||x>=map[y].length||map[y][x]=="#";
}
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
// House
for(let y=0;y<map.length;y++){
for(let x=0;x<map[y].length;x++){
let px=x*TILE,py=y*TILE;
if(map[y][x]=="#"){
ctx.fillStyle="#292929";
ctx.fillRect(px,py,TILE,TILE);
ctx.strokeStyle="#111";
ctx.strokeRect(px,py,TILE,TILE);
}else{
ctx.fillStyle="#151515";
ctx.fillRect(px,py,TILE,TILE);
}
}
}
// Exit
ctx.fillStyle="#183f25";
ctx.fillRect(17*TILE,11*TILE,TILE,TILE);
ctx.fillStyle="white";
ctx.font="25px Arial";
ctx.fillText("πͺ",17*TILE+10,11*TILE+33);
// Keys
keys.forEach(k=>{
if(!k.got){
ctx.fillStyle="gold";
ctx.beginPath();
ctx.arc(k.x*TILE+25,k.y*TILE+25,9,0,Math.PI*2);
ctx.fill();
ctx.fillRect(k.x*TILE+32,k.y*TILE+22,12,6);
}
});
// Monster
ctx.fillStyle="#7b0000";
ctx.beginPath();
ctx.arc(monster.x*TILE+25,monster.y*TILE+25,19,0,Math.PI*2);
ctx.fill();
ctx.fillStyle="white";
ctx.font="18px Arial";
ctx.fillText("π",monster.x*TILE+13,monster.y*TILE+31);
// Player
ctx.fillStyle="#4da6ff";
ctx.beginPath();
ctx.arc(player.x*TILE+25,player.y*TILE+25,17,0,Math.PI*2);
ctx.fill();
// darkness / flashlight effect
let grad=ctx.createRadialGradient(
player.x*TILE+25,player.y*TILE+25,60,
player.x*TILE+25,player.y*TILE+25,260
);
grad.addColorStop(0,"rgba(0,0,0,0)");
grad.addColorStop(1,"rgba(0,0,0,.82)");
ctx.fillStyle=grad;
ctx.fillRect(0,0,canvas.width,canvas.height);
}
function move(dx,dy){
if(gameOver)return;
let nx=player.x+dx, ny=player.y+dy;
if(!wall(nx,ny)){
player.x=nx;
player.y=ny;
// Pick up keys
keys.forEach(k=>{
if(!k.got && k.x==player.x && k.y==player.y){
k.got=true;
collected++;
document.getElementById("keys").textContent=collected;
msg("π Key found!");
}
});
// Exit
if(player.x==17 && player.y==11){
if(collected==2){
win();
}else{
msg("π Door locked! You need both keys.");
}
}
}
}
function monsterMove(){
if(gameOver)return;
let dx=player.x-monster.x;
let dy=player.y-monster.y;
// Monster follows player
let mx=0,my=0;
if(Math.abs(dx)>Math.abs(dy))
mx=Math.sign(dx);
else
my=Math.sign(dy);
if(!wall(monster.x+mx,monster.y+my)){
monster.x+=mx;
monster.y+=my;
}
// Attack
if(monster.x==player.x && monster.y==player.y){
player.hp-=20;
document.getElementById("hp").textContent=player.hp;
msg("πΉ RUN! The creature found you!");
// push player away
if(!wall(player.x-dx,player.y-dy)){
player.x-=Math.sign(dx);
player.y-=Math.sign(dy);
}
if(player.hp<=0) lose();
}
}
function interact(){
if(gameOver)return;
let distance=Math.abs(player.x-monster.x)+Math.abs(player.y-monster.y);
if(distance<=1)
msg("πΉ Something is VERY close...");
else
msg("Nothing useful here...");
}
function msg(text){
document.getElementById("msg").textContent=text;
}
function win(){
gameOver=true;
msg("π YOU ESCAPED! You survived the night!");
}
function lose(){
gameOver=true;
msg("π GAME OVER β The house got you!");
}
// Keyboard
document.addEventListener("keydown",e=>{
if(e.key=="ArrowUp"||e.key=="w")move(0,-1);
if(e.key=="ArrowDown"||e.key=="s")move(0,1);
if(e.key=="ArrowLeft"||e.key=="a")move(-1,0);
if(e.key=="ArrowRight"||e.key=="d")move(1,0);
if(e.key=="e"||e.key==" ")interact();
});
// Monster moves every 1 second
setInterval(monsterMove,1000);
function loop(){
draw();
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>1
1
6KB
6KB
170.0ms
184.0ms
170.0ms