<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Prison Escape - 牢獄からの脱出</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Special+Elite&display=swap');
body {
background-color: #0a0a0a;
color: #d1d1d1;
font-family: 'Special+Elite', cursive, serif;
margin: 0;
overflow: hidden;
height: 100vh;
display: flex;
flex-direction: column;
}
#game-container {
position: relative;
width: 100%;
max-width: 800px;
height: 500px;
margin: auto;
background: #1a1a1a;
border: 4px solid #333;
overflow: hidden;
box-shadow: 0 0 50px rgba(0,0,0,0.8);
}
.scene {
position: absolute;
width: 100%;
height: 100%;
display: none;
background-size: cover;
background-position: center;
}
.scene.active {
display: block;
}
.clickable {
position: absolute;
cursor: pointer;
transition: background 0.3s;
}
.clickable:hover {
background: rgba(255, 255, 255, 0.1);
border: 1px dashed rgba(255, 255, 255, 0.3);
}
#inventory {
width: 100%;
max-width: 800px;
height: 80px;
margin: 10px auto;
background: #222;
border: 2px solid #444;
display: flex;
align-items: center;
padding: 0 10px;
gap: 10px;
}
.inv-slot {
width: 60px;
height: 60px;
background: #333;
border: 1px solid #555;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
cursor: pointer;
}
.inv-slot.selected {
border-color: #eab308;
box-shadow: inset 0 0 10px rgba(234, 179, 8, 0.5);
}
#message-box {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
width: 90%;
background: rgba(0, 0, 0, 0.8);
border: 1px solid #eab308;
padding: 15px;
text-align: center;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s;
z-index: 100;
}
#message-box.active {
opacity: 1;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.85);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 200;
display: none;
}
/* Textures & Effects */
.wall-texture {
background-color: #1a1a1a;
background-image: linear-gradient(315deg, #111 25%, transparent 25%), linear-gradient(45deg, #111 25%, transparent 25%);
background-size: 40px 40px;
}
.hallway-texture { background: linear-gradient(to bottom, #222, #000); }
.outdoor-texture { background: linear-gradient(to top, #050505, #1a1a2e); }
.iron-bars { background: repeating-linear-gradient(90deg, #333, #333 10px, transparent 10px, transparent 40px); }
.laser {
position: absolute;
background: rgba(255, 0, 0, 0.6);
box-shadow: 0 0 10px red;
pointer-events: none;
}
/* Icons */
.key-icon::after { content: '🔑'; }
.hammer-icon::after { content: '🔨'; }
.paper-icon::after { content: '📜'; }
.screwdriver-icon::after { content: '🪛'; }
.pliers-icon::after { content: '✂️'; }
.stage-indicator {
position: absolute;
top: 10px;
right: 10px;
color: #666;
font-size: 0.8rem;
}
</style>
</head>
<body>
<div class="p-4 text-center">
<h1 class="text-3xl font-bold text-gray-500 uppercase tracking-widest">Prison Escape</h1>
<p id="sub-title" class="text-sm text-gray-600 mt-1">Stage 1: The Dark Cell</p>
</div>
<div id="game-container">
<!-- Stage 1: The Cell -->
<div id="scene-1" class="scene active wall-texture">
<div class="stage-indicator">Stage 1</div>
<div id="obj-door-1" class="clickable iron-bars" style="top: 50px; left: 350px; width: 100px; height: 350px;" onclick="interact('door1')"></div>
<div id="obj-bed" class="clickable bg-yellow-900/20" style="bottom: 20px; left: 50px; width: 200px; height: 100px; border-radius: 50px 50px 0 0;" onclick="interact('bed')">
<div class="text-center mt-8 text-xs text-yellow-800">藁の山</div>
</div>
<div id="obj-brick" class="clickable bg-gray-800" style="top: 200px; right: 100px; width: 60px; height: 30px; border: 1px solid #444;" onclick="interact('brick')"></div>
<div id="obj-wall" class="clickable" style="top: 80px; left: 100px; width: 120px; height: 80px;" onclick="interact('wall')">
<span class="text-gray-700 text-[10px] select-none">|||| |||| ||</span>
</div>
</div>
<!-- Stage 2: The Hallway -->
<div id="scene-2" class="scene hallway-texture">
<div class="stage-indicator">Stage 2</div>
<div id="obj-exit-2" class="clickable bg-gray-900 border-l-4 border-gray-700" style="top: 50px; right: 0; width: 80px; height: 400px;" onclick="interact('exit2')">
<div class="text-red-900 text-xs rotate-90 mt-20">LOCKED</div>
</div>
<div id="obj-toolbox" class="clickable bg-blue-900/20" style="bottom: 50px; left: 150px; width: 100px; height: 60px; border: 2px solid #334;" onclick="interact('toolbox')">
<div class="text-center text-[10px] text-blue-800">工具箱</div>
</div>
<div id="obj-panel" class="clickable bg-gray-700" style="top: 150px; left: 400px; width: 80px; height: 100px; border: 2px solid #222;" onclick="interact('panel')">
<div class="flex flex-col items-center justify-center h-full gap-2">
<div id="panel-light" class="w-4 h-4 rounded-full bg-red-600 animate-pulse"></div>
<div class="w-10 h-1 bg-black"></div>
</div>
</div>
</div>
<!-- Stage 3: The Perimeter -->
<div id="scene-3" class="scene outdoor-texture">
<div class="stage-indicator">Stage 3</div>
<!-- Laser Security -->
<div id="laser-1" class="laser" style="top: 100px; left: 0; width: 100%; height: 2px;"></div>
<div id="laser-2" class="laser" style="top: 250px; left: 0; width: 100%; height: 2px;"></div>
<div id="laser-3" class="laser" style="top: 400px; left: 0; width: 100%; height: 2px;"></div>
<!-- Guard Box -->
<div id="obj-guardbox" class="clickable bg-gray-800" style="bottom: 20px; right: 50px; width: 120px; height: 150px; border: 2px solid #555;" onclick="interact('guardbox')">
<div class="text-center text-[10px] text-gray-400 mt-2">警備用電源</div>
</div>
<!-- Wire Box -->
<div id="obj-wirebox" class="clickable" style="top: 300px; left: 50px; width: 60px; height: 60px; border: 1px dashed #444;" onclick="interact('wirebox')">
<div class="text-[8px] text-red-800 text-center">高電圧注意</div>
</div>
<!-- Final Gate -->
<div id="obj-gate" class="clickable bg-black/40 border-4 border-gray-600" style="top: 50px; left: 300px; width: 200px; height: 400px;" onclick="interact('gate')">
<div class="flex items-center justify-center h-full">
<div class="w-12 h-12 rounded-full border-4 border-red-900 flex items-center justify-center">
<div id="gate-button" class="w-8 h-8 rounded-full bg-red-900"></div>
</div>
</div>
</div>
</div>
<div id="message-box"></div>
<!-- Result Overlay -->
<div id="overlay-end" class="overlay">
<h2 class="text-4xl text-yellow-500 mb-4 font-bold">完全脱出!</h2>
<p class="mb-2 text-xl">あなたはついに自由を手に入れた...</p>
<p class="mb-8 text-gray-500 italic text-sm">Freedom is yours. End of Chapter 1.</p>
<button onclick="location.reload()" class="bg-yellow-900/40 hover:bg-yellow-800/60 text-yellow-200 px-8 py-3 border border-yellow-600 transition-all">最初からやり直す</button>
</div>
</div>
<div id="inventory">
<div class="text-xs text-gray-500 mr-2 uppercase">道具箱</div>
<div id="slot-1" class="inv-slot" onclick="selectItem(0)"></div>
<div id="slot-2" class="inv-slot" onclick="selectItem(1)"></div>
<div id="slot-3" class="inv-slot" onclick="selectItem(2)"></div>
<div id="slot-4" class="inv-slot" onclick="selectItem(3)"></div>
</div>
<script>
const state = {
currentStage: 1,
inventory: [],
selectedItem: null,
flags: {
// Stage 1
bedSearched: false,
brickBroken: false,
hasCode: false,
// Stage 2
keyFound2: false,
toolboxOpened: false,
panelFixed: false,
doorPowerOn: false,
// Stage 3
pliersFound: false,
lasersOff: false,
gateUnlocked: false
}
};
const messages = {
// Stage 1
bed_find: "藁の中から「鍵」と「ハンマー」を見つけた!",
brick_need_tool: "レンガが浮いている。叩けば壊せそうだ。",
brick_break: "ハンマーで叩き壊した。中に「メモ」がある。",
wall_clue: "メモをかざすと数字が読める...『3 8 2 1』",
door_locked: "頑丈な扉だ。鍵と4桁の番号が必要らしい。",
door_unlock: "ガチャリ! 牢獄の扉が開いた。外へ出よう。",
// Stage 2
hallway_intro: "廊下に出た。出口の電子ロックが赤く光っている。",
toolbox_locked: "工具箱に鍵がかかっている。",
toolbox_key_hint: "工具箱の裏を調べると、予備の「鍵」を見つけた!",
toolbox_open: "鍵が合った!中から「ドライバー」を手に入れた。",
panel_fixed: "ドライバーで配電盤を修理した。電子ロックの電力が回復した!",
exit2_locked: "電子ロックがまだ赤色だ。電力を通さなければ。",
exit2_success: "電子ロック解除。さらに先へ進む...",
// Stage 3
stage3_intro: "外だ!だがレーザーセキュリティが作動している。触れると警報が鳴るだろう。",
guardbox_find: "警備ボックスの隙間に「ペンチ」が挟まっているのを見つけた!",
wirebox_danger: "ここがレーザーの制御盤か。素手では危ない。",
wirebox_cut: "ペンチで赤い配線を切断した!レーザーが消えた。",
gate_locked: "門のボタンが反応しない。レーザーを先に止める必要がある。",
gate_final: "門がゆっくりと開いていく... 自由だ!"
};
function showMessage(text) {
const box = document.getElementById('message-box');
box.innerText = text;
box.classList.add('active');
setTimeout(() => {
box.classList.remove('active');
}, 3000);
}
function switchScene(stage) {
document.querySelectorAll('.scene').forEach(s => s.classList.remove('active'));
const nextScene = document.getElementById(`scene-${stage}`);
if (nextScene) {
nextScene.classList.add('active');
state.currentStage = stage;
if (stage === 2) {
document.getElementById('sub-title').innerText = "Stage 2: The Silent Hallway";
showMessage(messages.hallway_intro);
} else if (stage === 3) {
document.getElementById('sub-title').innerText = "Stage 3: The Final Gate";
showMessage(messages.stage3_intro);
}
}
}
function updateInventoryUI() {
for (let i = 0; i < 4; i++) {
const slot = document.getElementById(`slot-${i+1}`);
if (!slot) continue;
slot.innerHTML = '';
slot.className = 'inv-slot';
if (state.inventory[i]) {
const item = state.inventory[i];
const icon = document.createElement('span');
if (item === 'key') icon.className = 'key-icon';
if (item === 'hammer') icon.className = 'hammer-icon';
if (item === 'paper') icon.className = 'paper-icon';
if (item === 'screwdriver') icon.className = 'screwdriver-icon';
if (item === 'pliers') icon.className = 'pliers-icon';
slot.appendChild(icon);
if (state.selectedItem === i) {
slot.classList.add('selected');
}
}
}
}
function addItem(item) {
if (!state.inventory.includes(item)) {
state.inventory.push(item);
updateInventoryUI();
}
}
function removeItem(item) {
state.inventory = state.inventory.filter(i => i !== item);
state.selectedItem = null;
updateInventoryUI();
}
function selectItem(index) {
if (state.inventory[index]) {
state.selectedItem = state.selectedItem === index ? null : index;
updateInventoryUI();
}
}
function interact(obj) {
const selected = state.inventory[state.selectedItem];
// --- STAGE 1 ---
if (state.currentStage === 1) {
switch(obj) {
case 'bed':
if (!state.flags.bedSearched) {
addItem('key'); addItem('hammer');
state.flags.bedSearched = true;
showMessage(messages.bed_find);
} else showMessage("もう何もない。");
break;
case 'brick':
if (selected === 'hammer') {
addItem('paper'); state.flags.brickBroken = true;
showMessage(messages.brick_break);
} else showMessage(messages.brick_need_tool);
break;
case 'wall':
if (selected === 'paper') {
state.flags.hasCode = true;
showMessage(messages.wall_clue);
} else showMessage("暗くて読めない。");
break;
case 'door1':
if (selected === 'key' && state.flags.hasCode) {
showMessage(messages.door_unlock);
setTimeout(() => { removeItem('key'); switchScene(2); }, 1500);
} else showMessage(messages.door_locked);
break;
}
}
// --- STAGE 2 ---
else if (state.currentStage === 2) {
switch(obj) {
case 'toolbox':
if (state.flags.toolboxOpened) {
showMessage("工具箱は空だ。");
} else if (selected === 'key') {
showMessage(messages.toolbox_open);
addItem('screwdriver'); state.flags.toolboxOpened = true;
removeItem('key');
} else {
if (!state.flags.keyFound2) {
showMessage(messages.toolbox_key_hint);
addItem('key'); state.flags.keyFound2 = true;
} else showMessage(messages.toolbox_locked);
}
break;
case 'panel':
if (selected === 'screwdriver') {
state.flags.panelFixed = true;
state.flags.doorPowerOn = true;
showMessage(messages.panel_fixed);
document.getElementById('panel-light').classList.replace('bg-red-600', 'bg-green-500');
} else showMessage(messages.panel_broken);
break;
case 'exit2':
if (state.flags.doorPowerOn) {
showMessage(messages.exit2_success);
setTimeout(() => { switchScene(3); }, 1500);
} else showMessage(messages.exit2_locked);
break;
}
}
// --- STAGE 3 ---
else if (state.currentStage === 3) {
switch(obj) {
case 'guardbox':
if (!state.flags.pliersFound) {
addItem('pliers');
state.flags.pliersFound = true;
showMessage(messages.guardbox_find);
} else showMessage("空の警備ボックスだ。");
break;
case 'wirebox':
if (state.flags.lasersOff) {
showMessage("配線はすでに切断されている。");
} else if (selected === 'pliers') {
state.flags.lasersOff = true;
showMessage(messages.wirebox_cut);
document.querySelectorAll('.laser').forEach(l => l.style.display = 'none');
document.getElementById('gate-button').classList.replace('bg-red-900', 'bg-green-600');
} else {
showMessage(messages.wirebox_danger);
}
break;
case 'gate':
if (state.flags.lasersOff) {
showMessage(messages.gate_final);
setTimeout(() => {
document.getElementById('overlay-end').style.display = 'flex';
}, 1500);
} else {
showMessage(messages.gate_locked);
}
break;
}
}
}
window.onload = () => {
showMessage("ここから出なければ... 部屋の中を調べてみよう。");
};
</script>
</body>
</html>
脱出するゲーム