<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>打地鼠游戏</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Comic Sans MS', cursive;
background: linear-gradient(45deg, #87CEEB, #98FB98);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
.game-container {
background: rgba(255, 255, 255, 0.9);
border-radius: 20px;
padding: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
text-align: center;
backdrop-filter: blur(10px);
}
.game-header {
margin-bottom: 20px;
}
.game-title {
font-size: 2.5em;
color: #2c3e50;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
margin-bottom: 10px;
animation: bounce 2s infinite;
}
@keyframes bounce {
0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
40% { transform: translateY(-10px); }
60% { transform: translateY(-5px); }
}
.game-stats {
display: flex;
justify-content: space-around;
margin-bottom: 20px;
font-size: 1.2em;
font-weight: bold;
}
.stat {
background: linear-gradient(45deg, #FF6B6B, #4ECDC4);
color: white;
padding: 10px 20px;
border-radius: 15px;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
.game-board {
display: grid;
grid-template-columns: repeat(3, 120px);
grid-template-rows: repeat(3, 120px);
gap: 15px;
justify-content: center;
margin: 20px 0;
}
.hole {
position: relative;
width: 120px;
height: 120px;
background: radial-gradient(circle, #8B4513 0%, #654321 70%, #3c2415 100%);
border-radius: 50%;
overflow: hidden;
cursor: pointer;
box-shadow: inset 0 5px 15px rgba(0,0,0,0.5);
transition: transform 0.1s;
}
.hole:active {
transform: scale(0.95);
}
.mole {
position: absolute;
bottom: -80px;
left: 50%;
transform: translateX(-50%);
width: 80px;
height: 80px;
background: linear-gradient(45deg, #D2691E, #CD853F);
border-radius: 50% 50% 40% 40%;
transition: bottom 0.3s ease-in-out;
cursor: pointer;
}
.mole::before {
content: '';
position: absolute;
top: 15px;
left: 20px;
width: 12px;
height: 12px;
background: #000;
border-radius: 50%;
box-shadow: 25px 0 0 #000;
}
.mole::after {
content: '';
position: absolute;
top: 35px;
left: 35px;
width: 10px;
height: 8px;
background: #FF69B4;
border-radius: 50%;
}
.mole.up {
bottom: 20px;
animation: wiggle 0.5s ease-in-out infinite;
}
.mole.hit {
animation: hit 0.3s ease-out;
}
@keyframes wiggle {
0%, 100% { transform: translateX(-50%) rotate(-5deg); }
50% { transform: translateX(-50%) rotate(5deg); }
}
@keyframes hit {
0% { transform: translateX(-50%) scale(1); }
50% { transform: translateX(-50%) scale(1.2) rotate(15deg); }
100% { transform: translateX(-50%) scale(0.8); bottom: -80px; }
}
.controls {
margin-top: 20px;
}
.btn {
background: linear-gradient(45deg, #FF6B6B, #4ECDC4);
color: white;
border: none;
padding: 15px 30px;
border-radius: 25px;
font-size: 1.1em;
font-weight: bold;
cursor: pointer;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
transition: all 0.3s;
margin: 0 10px;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0,0,0,0.3);
}
.btn:active {
transform: translateY(0);
}
.btn:disabled {
background: #ccc;
cursor: not-allowed;
transform: none;
}
.game-over {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.8);
display: none;
justify-content: center;
align-items: center;
z-index: 1000;
}
.game-over-content {
background: white;
padding: 40px;
border-radius: 20px;
text-align: center;
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
.game-over h2 {
color: #2c3e50;
font-size: 2em;
margin-bottom: 20px;
}
.final-score {
font-size: 1.5em;
color: #e74c3c;
margin-bottom: 20px;
}
.score-popup {
position: absolute;
color: #e74c3c;
font-size: 2em;
font-weight: bold;
pointer-events: none;
animation: scoreFloat 1s ease-out forwards;
}
@keyframes scoreFloat {
0% { transform: translateY(0) scale(1); opacity: 1; }
100% { transform: translateY(-50px) scale(1.2); opacity: 0; }
}
.miss-popup {
position: absolute;
color: #3498db;
font-size: 1.5em;
font-weight: bold;
pointer-events: none;
animation: scoreFloat 1s ease-out forwards;
}
.clouds {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: -1;
}
.cloud {
position: absolute;
background: rgba(255, 255, 255, 0.8);
border-radius: 50px;
animation: float 20s infinite linear;
}
.cloud::before,
.cloud::after {
content: '';
position: absolute;
background: rgba(255, 255, 255, 0.8);
border-radius: 50px;
}
.cloud1 {
width: 100px;
height: 40px;
top: 20%;
animation-duration: 25s;
}
.cloud1::before {
width: 50px;
height: 40px;
top: -20px;
left: 10px;
}
.cloud1::after {
width: 60px;
height: 20px;
top: -10px;
right: 10px;
}
.cloud2 {
width: 80px;
height: 30px;
top: 60%;
animation-duration: 30s;
animation-delay: -10s;
}
.cloud2::before {
width: 40px;
height: 30px;
top: -15px;
left: 15px;
}
.cloud2::after {
width: 50px;
height: 15px;
top: -8px;
right: 15px;
}
@keyframes float {
0% { left: -120px; }
100% { left: 100%; }
}
</style>
</head>
<body>
<div class="clouds">
<div class="cloud cloud1"></div>
<div class="cloud cloud2"></div>
</div>
<div class="game-container">
<div class="game-header">
<h1 class="game-title">🔨 打地鼠大作战 🐹</h1>
<div class="game-stats">
<div class="stat">得分: <span id="score">0</span></div>
<div class="stat">时间: <span id="time">60</span>s</div>
<div class="stat">连击: <span id="combo">0</span></div>
</div>
</div>
<div class="game-board" id="gameBoard">
<!-- 9个洞口 -->
</div>
<div class="controls">
<button class="btn" id="startBtn">开始游戏</button>
<button class="btn" id="pauseBtn" disabled>暂停</button>
<button class="btn" id="resetBtn">重置</button>
</div>
</div>
<div class="game-over" id="gameOver">
<div class="game-over-content">
<h2>🎉 游戏结束 🎉</h2>
<div class="final-score">最终得分: <span id="finalScore">0</span></div>
<div>最高连击: <span id="maxCombo">0</span></div>
<br>
<button class="btn" onclick="restartGame()">再来一局</button>
</div>
</div>
<script>
class WhackAMoleGame {
constructor() {
this.score = 0;
this.timeLeft = 60;
this.combo = 0;
this.maxCombo = 0;
this.isPlaying = false;
this.isPaused = false;
this.gameTimer = null;
this.moleTimer = null;
this.difficulty = 1;
this.holes = [];
this.initGame();
this.bindEvents();
}
initGame() {
const gameBoard = document.getElementById('gameBoard');
gameBoard.innerHTML = '';
// 创建9个洞口
for (let i = 0; i < 9; i++) {
const hole = document.createElement('div');
hole.className = 'hole';
hole.innerHTML = '<div class="mole" data-hole="' + i + '"></div>';
gameBoard.appendChild(hole);
this.holes.push(hole);
}
}
bindEvents() {
document.getElementById('startBtn').addEventListener('click', () => this.startGame());
document.getElementById('pauseBtn').addEventListener('click', () => this.pauseGame());
document.getElementById('resetBtn').addEventListener('click', () => this.resetGame());
// 绑定地鼠点击事件
document.addEventListener('click', (e) => {
if (e.target.classList.contains('mole') && e.target.classList.contains('up')) {
this.hitMole(e.target);
} else if (this.isPlaying && !this.isPaused) {
this.miss(e);
}
});
}
startGame() {
this.isPlaying = true;
this.isPaused = false;
this.score = 0;
this.timeLeft = 60;
this.combo = 0;
this.maxCombo = 0;
this.difficulty = 1;
this.updateDisplay();
document.getElementById('startBtn').disabled = true;
document.getElementById('pauseBtn').disabled = false;
this.startTimer();
this.spawnMole();
}
pauseGame() {
if (this.isPaused) {
this.isPaused = false;
document.getElementById('pauseBtn').textContent = '暂停';
this.startTimer();
this.spawnMole();
} else {
this.isPaused = true;
document.getElementById('pauseBtn').textContent = '继续';
clearInterval(this.gameTimer);
clearTimeout(this.moleTimer);
}
}
resetGame() {
this.isPlaying = false;
this.isPaused = false;
clearInterval(this.gameTimer);
clearTimeout(this.moleTimer);
this.score = 0;
this.timeLeft = 60;
this.combo = 0;
this.maxCombo = 0;
this.updateDisplay();
this.hideAllMoles();
document.getElementById('startBtn').disabled = false;
document.getElementById('pauseBtn').disabled = true;
document.getElementById('pauseBtn').textContent = '暂停';
document.getElementById('gameOver').style.display = 'none';
}
startTimer() {
this.gameTimer = setInterval(() => {
this.timeLeft--;
this.updateDisplay();
if (this.timeLeft <= 0) {
this.endGame();
}
// 随着时间推移增加难度
if (this.timeLeft % 15 === 0 && this.timeLeft > 0) {
this.difficulty += 0.2;
}
}, 1000);
}
spawnMole() {
if (!this.isPlaying || this.isPaused) return;
const randomHole = Math.floor(Math.random() * 9);
const mole = this.holes[randomHole].querySelector('.mole');
if (!mole.classList.contains('up')) {
mole.classList.add('up');
// 地鼠停留时间随难度降低
const stayTime = Math.max(800 - (this.difficulty * 100), 400);
setTimeout(() => {
if (mole.classList.contains('up')) {
mole.classList.remove('up');
this.combo = 0; // 地鼠自动消失时重置连击
this.updateDisplay();
}
}, stayTime);
}
// 下次地鼠出现时间随难度降低
const nextSpawn = Math.max(1200 - (this.difficulty * 150), 600);
this.moleTimer = setTimeout(() => this.spawnMole(), nextSpawn);
}
hitMole(mole) {
if (!this.isPlaying || this.isPaused) return;
mole.classList.remove('up');
mole.classList.add('hit');
this.combo++;
this.maxCombo = Math.max(this.maxCombo, this.combo);
// 连击加分
const baseScore = 10;
const comboBonus = Math.floor(this.combo / 3) * 5;
const scoreGain = baseScore + comboBonus;
this.score += scoreGain;
this.updateDisplay();
// 显示得分动画
this.showScorePopup(mole.parentElement, '+' + scoreGain);
setTimeout(() => {
mole.classList.remove('hit');
}, 300);
}
miss(e) {
// 点击空白处,连击归零
if (this.combo > 0) {
this.combo = 0;
this.updateDisplay();
this.showMissPopup(e, '连击断了!');
}
}
showScorePopup(element, text) {
const popup = document.createElement('div');
popup.className = 'score-popup';
popup.textContent = text;
popup.style.left = '50%';
popup.style.top = '50%';
popup.style.transform = 'translate(-50%, -50%)';
element.style.position = 'relative';
element.appendChild(popup);
setTimeout(() => {
if (popup.parentElement) {
popup.parentElement.removeChild(popup);
}
}, 1000);
}
showMissPopup(e, text) {
const popup = document.createElement('div');
popup.className = 'miss-popup';
popup.textContent = text;
popup.style.left = e.clientX + 'px';
popup.style.top = e.clientY + 'px';
popup.style.position = 'fixed';
document.body.appendChild(popup);
setTimeout(() => {
if (popup.parentElement) {
popup.parentElement.removeChild(popup);
}
}, 1000);
}
hideAllMoles() {
this.holes.forEach(hole => {
const mole = hole.querySelector('.mole');
mole.classList.remove('up', 'hit');
});
}
updateDisplay() {
document.getElementById('score').textContent = this.score;
document.getElementById('time').textContent = this.timeLeft;
document.getElementById('combo').textContent = this.combo;
}
endGame() {
this.isPlaying = false;
clearInterval(this.gameTimer);
clearTimeout(this.moleTimer);
this.hideAllMoles();
document.getElementById('finalScore').textContent = this.score;
document.getElementById('maxCombo').textContent = this.maxCombo;
document.getElementById('gameOver').style.display = 'flex';
document.getElementById('startBtn').disabled = false;
document.getElementById('pauseBtn').disabled = true;
}
}
// 初始化游戏
const game = new WhackAMoleGame();
function restartGame() {
document.getElementById('gameOver').style.display = 'none';
game.startGame();
}
</script>
</body>
</html>
THE END