6×6 地宫打地鼠 · 吱吱声
by PrismBuilder59491 lines14.4 KB
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>6×6 地宫打地鼠 · 吱吱声</title>
<style>
* {
box-sizing: border-box;
user-select: none;
}
body {
min-height: 100vh;
margin: 0;
background: linear-gradient(145deg, #1e3c2c, #2a5a3a);
display: flex;
justify-content: center;
align-items: center;
font-family: 'Segoe UI', Roboto, system-ui, sans-serif;
}
.game-container {
background: #3d2e1b;
padding: 1.8rem 2rem 2.5rem;
border-radius: 4rem 4rem 3rem 3rem;
box-shadow: 0 20px 30px rgba(0,0,0,0.7), inset 0 -4px 8px #1f140a;
border-bottom: 6px solid #5b3f24;
}
.board {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 12px;
background: #5a4029;
padding: 20px;
border-radius: 32px;
box-shadow: inset 0 0 0 3px #2f1f10, inset 0 8px 12px rgba(0,0,0,0.5);
margin-bottom: 20px;
}
.cell {
width: 70px;
height: 70px;
background: #7d5d3c;
border-radius: 30% 30% 40% 40%;
box-shadow: inset 0 -8px 0 #3d2a17, inset 0 4px 8px #b48b5a, 0 6px 10px rgba(0,0,0,0.4);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: 0.08s linear;
position: relative;
}
.cell:active {
transform: scale(0.92);
box-shadow: inset 0 -2px 0 #3d2a17, inset 0 4px 6px #b48b5a;
}
/* 地鼠洞 */
.mole {
width: 90%;
height: 90%;
background: #c97d3d;
border-radius: 50% 50% 45% 45%;
box-shadow: inset 0 -4px 0 #5e3a1c, inset 0 6px 10px #f5c48a, 0 4px 6px rgba(0,0,0,0.3);
transform: translateY(6px);
transition: 0.1s ease;
display: flex;
align-items: center;
justify-content: center;
font-size: 2.8rem;
color: #2d1d0c;
text-shadow: 0 2px 4px #eeb576;
line-height: 1;
font-weight: bold;
position: relative;
}
.mole::after {
content: "🐭";
filter: drop-shadow(0 3px 2px rgba(0,0,0,0.3));
font-size: 2.6rem;
}
/* 空坑 */
.empty-hole {
width: 70%;
height: 30%;
background: #3b2819;
border-radius: 50%;
box-shadow: inset 0 4px 6px #1f130a, 0 2px 4px #664a2b;
transform: translateY(10px);
}
.status-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 12px;
color: #f7e9c3;
text-shadow: 0 3px 0 #1f140a;
font-weight: 600;
font-size: 1.2rem;
letter-spacing: 1px;
}
.score-box {
background: #281e12;
padding: 8px 22px;
border-radius: 60px;
box-shadow: inset 0 3px 6px #0f0a05, 0 6px 0 #3d2a17;
color: #f7d98c;
font-size: 1.8rem;
font-weight: 700;
line-height: 1.4;
}
.reset-btn {
background: #b17d4b;
border: none;
color: #21170c;
font-size: 1.4rem;
font-weight: bold;
padding: 6px 20px;
border-radius: 40px;
cursor: pointer;
box-shadow: inset 0 -6px 0 #5f401f, 0 6px 0 #2d1d0c;
transition: 0.06s linear;
display: flex;
align-items: center;
gap: 6px;
font-family: inherit;
letter-spacing: 1px;
}
.reset-btn:active {
transform: translateY(4px);
box-shadow: inset 0 -2px 0 #5f401f, 0 2px 0 #2d1d0c;
}
.hint {
color: #d4c09d;
font-size: 0.9rem;
margin-top: 8px;
text-align: center;
letter-spacing: 1px;
opacity: 0.8;
}
@media (max-width: 580px) {
.game-container { padding: 1.2rem; border-radius: 2.5rem; }
.board { gap: 8px; padding: 12px; }
.cell { width: 54px; height: 54px; }
.mole { font-size: 2rem; }
.mole::after { font-size: 2rem; }
.score-box { font-size: 1.4rem; padding: 4px 14px; }
.reset-btn { font-size: 1rem; padding: 4px 14px; }
}
@media (max-width: 430px) {
.cell { width: 44px; height: 44px; }
.board { gap: 6px; padding: 8px; }
.mole::after { font-size: 1.6rem; }
}
</style>
</head>
<body>
<div class="game-container">
<div class="board" id="board"></div>
<div class="status-bar">
<span>🏆 地宫</span>
<span class="score-box" id="scoreDisplay">0</span>
<button class="reset-btn" id="resetBtn">🔄 重来</button>
</div>
<div class="hint">👆 点击地鼠 · 吱吱作响</div>
</div>
<script>
(function() {
const BOARD_SIZE = 6;
const TOTAL_CELLS = BOARD_SIZE * BOARD_SIZE;
// 游戏状态
let score = 0;
let activeMoleIndex = -1; // -1 表示没有地鼠
let gameInterval = null;
let timeoutId = null; // 额外延迟控制
const boardEl = document.getElementById('board');
const scoreDisplay = document.getElementById('scoreDisplay');
// 音效上下文 (Web Audio)
let audioCtx = null;
// 确保 AudioContext 在用户手势后初始化
function getAudioContext() {
if (!audioCtx) {
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
}
if (audioCtx.state === 'suspended') {
audioCtx.resume();
}
return audioCtx;
}
// 播放 "吱吱" 声 (使用合成音效, 像老鼠叫)
function playSqueak() {
try {
const ctx = getAudioContext();
// 创建一个短促的、音调较高的吱吱声
const oscillator = ctx.createOscillator();
const gainNode = ctx.createGain();
oscillator.type = 'sawtooth'; // 锯齿波带点毛刺感
oscillator.frequency.setValueAtTime(1800, ctx.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(800, ctx.currentTime + 0.08);
gainNode.gain.setValueAtTime(0.25, ctx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.12);
oscillator.connect(gainNode);
gainNode.connect(ctx.destination);
oscillator.start(ctx.currentTime);
oscillator.stop(ctx.currentTime + 0.13);
// 再加一个小“吱”的泛音 让声音更丰富
const osc2 = ctx.createOscillator();
const gain2 = ctx.createGain();
osc2.type = 'square';
osc2.frequency.setValueAtTime(2400, ctx.currentTime);
osc2.frequency.exponentialRampToValueAtTime(1200, ctx.currentTime + 0.06);
gain2.gain.setValueAtTime(0.12, ctx.currentTime);
gain2.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.09);
osc2.connect(gain2);
gain2.connect(ctx.destination);
osc2.start(ctx.currentTime);
osc2.stop(ctx.currentTime + 0.1);
// 快速衰减的噪声 (模拟“吱”的摩擦感)
const bufferSize = ctx.sampleRate * 0.04;
const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
const data = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
data[i] = (Math.random() * 2 - 1) * Math.exp(-i / (bufferSize * 0.3));
}
const noise = ctx.createBufferSource();
noise.buffer = buffer;
const gainNoise = ctx.createGain();
gainNoise.gain.setValueAtTime(0.15, ctx.currentTime);
gainNoise.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.04);
noise.connect(gainNoise);
gainNoise.connect(ctx.destination);
noise.start(ctx.currentTime);
noise.stop(ctx.currentTime + 0.05);
} catch (e) {
// 某些浏览器可能不支持,静默降级
console.warn('吱吱声播放失败:', e);
}
}
// 重置游戏 (清空地鼠, 重置分数)
function resetGame() {
// 清除所有定时器
if (gameInterval) {
clearInterval(gameInterval);
gameInterval = null;
}
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}
// 重置状态
score = 0;
updateScore();
// 移除当前地鼠
if (activeMoleIndex !== -1) {
const prevCell = document.querySelector(`[data-index="${activeMoleIndex}"]`);
if (prevCell) {
const hole = prevCell.querySelector('.empty-hole');
const mole = prevCell.querySelector('.mole');
if (mole) {
mole.remove();
prevCell.appendChild(hole || createEmptyHole());
}
}
activeMoleIndex = -1;
}
// 重新开始循环 (延迟一点点让重置更干净)
startMoleCycle();
}
// 创建空洞元素 (复用)
function createEmptyHole() {
const hole = document.createElement('div');
hole.className = 'empty-hole';
return hole;
}
// 更新分数显示
function updateScore() {
scoreDisplay.textContent = score;
}
// 在地洞中生成地鼠 (指定索引)
function showMole(index) {
// 边界检查
if (index < 0 || index >= TOTAL_CELLS) return false;
// 如果当前已经有地鼠,先移除
if (activeMoleIndex !== -1) {
const oldCell = document.querySelector(`[data-index="${activeMoleIndex}"]`);
if (oldCell) {
const oldMole = oldCell.querySelector('.mole');
if (oldMole) {
oldMole.remove();
oldCell.appendChild(createEmptyHole());
}
}
activeMoleIndex = -1;
}
const cell = document.querySelector(`[data-index="${index}"]`);
if (!cell) return false;
// 移除现有空洞 (如果有)
const hole = cell.querySelector('.empty-hole');
if (hole) hole.remove();
// 创建地鼠
const mole = document.createElement('div');
mole.className = 'mole';
cell.appendChild(mole);
activeMoleIndex = index;
return true;
}
// 隐藏地鼠 (不播放声音)
function hideMole() {
if (activeMoleIndex !== -1) {
const cell = document.querySelector(`[data-index="${activeMoleIndex}"]`);
if (cell) {
const mole = cell.querySelector('.mole');
if (mole) {
mole.remove();
cell.appendChild(createEmptyHole());
}
}
activeMoleIndex = -1;
}
}
// 处理打地鼠 (点击事件)
function handleCellClick(e) {
const cell = e.currentTarget;
const index = parseInt(cell.dataset.index, 10);
// 如果当前地鼠存在且点击的是地鼠所在格子
if (activeMoleIndex === index) {
// 加分
score += 1;
updateScore();
// 播放吱吱声
playSqueak();
// 移除地鼠 (并更新洞)
const mole = cell.querySelector('.mole');
if (mole) {
mole.remove();
cell.appendChild(createEmptyHole());
}
activeMoleIndex = -1;
// 重置计时器:打中后立刻重新安排下一次地鼠出现 (避免同一只停留)
if (gameInterval) {
clearInterval(gameInterval);
gameInterval = null;
}
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}
// 快速启动下一轮 (延迟0.2s 让画面不突兀)
timeoutId = setTimeout(() => {
timeoutId = null;
startMoleCycle();
}, 180);
} else {
// 点空处轻微反馈 (但无音效, 保持干净)
// 可以加一点触感: 只是纯反馈
}
}
// 开始地鼠出现循环 (使用setInterval随机出现)
function startMoleCycle() {
// 清除旧循环
if (gameInterval) {
clearInterval(gameInterval);
gameInterval = null;
}
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}
// 立即生成一只地鼠 (延迟一点点让初始化同步)
timeoutId = setTimeout(() => {
timeoutId = null;
// 如果有地鼠先隐藏 (安全)
if (activeMoleIndex !== -1) {
hideMole();
}
// 随机选一个洞
const randomIndex = Math.floor(Math.random() * TOTAL_CELLS);
showMole(randomIndex);
// 设置定时器,每隔1.8~2.6秒移动地鼠(换位置)
gameInterval = setInterval(() => {
// 如果当前有地鼠,先隐藏
if (activeMoleIndex !== -1) {
hideMole();
}
// 随机生成新地鼠 (不与上次相同? 但无所谓,概率低)
let newIndex;
do {
newIndex = Math.floor(Math.random() * TOTAL_CELLS);
} while (newIndex === activeMoleIndex && TOTAL_CELLS > 1); // 避免完全重复,但无伤大雅
showMole(newIndex);
}, 1900 + Math.random() * 900); // 1.9~2.8秒变化
}, 300);
}
// 初始化棋盘 (6x6)
function buildBoard() {
boardEl.innerHTML = '';
for (let i = 0; i < TOTAL_CELLS; i++) {
const cell = document.createElement('div');
cell.className = 'cell';
cell.dataset.index = i;
// 初始为空洞
const hole = createEmptyHole();
cell.appendChild(hole);
cell.addEventListener('click', handleCellClick);
boardEl.appendChild(cell);
}
}
// 重新启动 (重置 + 构建)
function initGame() {
// 如果已有循环清除
if (gameInterval) {
clearInterval(gameInterval);
gameInterval = null;
}
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}
// 重置地鼠
activeMoleIndex = -1;
score = 0;
updateScore();
// 重建棋盘 (保证干净)
buildBoard();
// 开始循环
startMoleCycle();
}
// 绑定重置按钮
document.getElementById('resetBtn').addEventListener('click', function() {
// 重置并重新开始
initGame();
// 轻触反馈 (并尝试恢复音频上下文)
try {
getAudioContext();
} catch (e) {}
});
// 页面加载启动
window.addEventListener('load', () => {
initGame();
// 预创建音频上下文(在用户第一次点击时自动激活)
document.addEventListener('click', function wakeAudio() {
try {
getAudioContext();
} catch (e) {}
document.removeEventListener('click', wakeAudio);
}, { once: true });
});
// 在页面关闭前清除定时器
window.addEventListener('beforeunload', function() {
if (gameInterval) clearInterval(gameInterval);
if (timeoutId) clearTimeout(timeoutId);
});
})();
</script>
</body>
</html>Game Source: 6×6 地宫打地鼠 · 吱吱声
Creator: PrismBuilder59
Libraries: none
Complexity: complex (491 lines, 14.4 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: 6-6-prismbuilder59" to link back to the original. Then publish at arcadelab.ai/publish.