解压乐园 - 放松小游戏合集
by StormViper161620 lines63.3 KB
<!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: 'Segoe UI', 'Microsoft YaHei', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
overflow-x: hidden;
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
text-align: center;
color: white;
margin-bottom: 30px;
animation: fadeInDown 0.8s ease;
}
h1 {
font-size: 3em;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
letter-spacing: 2px;
}
.subtitle {
font-size: 1.2em;
opacity: 0.9;
}
.menu-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.game-card {
background: white;
border-radius: 20px;
padding: 30px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
position: relative;
overflow: hidden;
}
.game-card:hover {
transform: translateY(-5px) scale(1.02);
box-shadow: 0 15px 40px rgba(0,0,0,0.3);
}
.game-card::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
transition: left 0.5s;
}
.game-card:hover::before {
left: 100%;
}
.game-icon {
font-size: 3em;
margin-bottom: 15px;
}
.game-title {
font-size: 1.5em;
margin-bottom: 10px;
color: #333;
}
.game-desc {
color: #666;
font-size: 0.9em;
}
.game-area {
display: none;
background: white;
border-radius: 20px;
padding: 30px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
animation: fadeIn 0.5s ease;
min-height: 600px;
position: relative;
}
.game-area.active {
display: block;
}
.back-btn {
position: absolute;
top: 20px;
left: 20px;
background: #667eea;
color: white;
border: none;
padding: 10px 20px;
border-radius: 25px;
cursor: pointer;
font-size: 1em;
transition: all 0.3s;
z-index: 100;
}
.back-btn:hover {
background: #764ba2;
transform: scale(1.05);
}
/* 游戏1: 泡泡爆破 */
#bubble-game {
background: linear-gradient(180deg, #87CEEB 0%, #E0F6FF 100%);
border-radius: 15px;
padding: 20px;
height: 500px;
position: relative;
overflow: hidden;
cursor: crosshair;
}
.bubble {
position: absolute;
border-radius: 50%;
background: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.8), rgba(255,255,255,0.2));
box-shadow: inset 0 0 20px rgba(255,255,255,0.5), 0 5px 15px rgba(0,0,0,0.1);
cursor: pointer;
animation: float 3s ease-in-out infinite;
transition: transform 0.1s;
}
.bubble:active {
transform: scale(0.9);
}
.bubble::after {
content: '';
position: absolute;
top: 15%;
left: 20%;
width: 25%;
height: 15%;
background: rgba(255,255,255,0.8);
border-radius: 50%;
transform: rotate(-45deg);
}
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-20px); }
}
.pop-effect {
position: absolute;
pointer-events: none;
animation: pop 0.3s ease-out forwards;
}
@keyframes pop {
0% { transform: scale(1); opacity: 1; }
100% { transform: scale(2); opacity: 0; }
}
/* 游戏2: 无限切水果 */
#fruit-game {
background: linear-gradient(180deg, #FFE5B4 0%, #FFF8DC 100%);
border-radius: 15px;
height: 500px;
position: relative;
overflow: hidden;
cursor: none;
}
.fruit {
position: absolute;
font-size: 3em;
cursor: pointer;
user-select: none;
transition: transform 0.1s;
filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.2));
}
.fruit.sliced {
animation: slice 0.3s ease-out forwards;
}
@keyframes slice {
0% { transform: scale(1) rotate(0deg); opacity: 1; }
100% { transform: scale(0) rotate(180deg); opacity: 0; }
}
.blade {
position: absolute;
width: 60px;
height: 60px;
border-radius: 50%;
background: radial-gradient(circle, rgba(255,255,255,0.9) 0%, rgba(200,200,255,0.5) 100%);
pointer-events: none;
box-shadow: 0 0 20px rgba(100,100,255,0.6);
z-index: 1000;
transition: transform 0.05s;
}
.slash-trail {
position: absolute;
height: 3px;
background: linear-gradient(90deg, transparent, #fff, transparent);
pointer-events: none;
opacity: 0.8;
border-radius: 2px;
}
/* 游戏3: 捏泡泡纸 */
#popit-game {
background: #f0f0f0;
border-radius: 15px;
padding: 40px;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 15px;
max-width: 600px;
margin: 0 auto;
}
.pop-bubble {
width: 80px;
height: 80px;
border-radius: 50%;
background: linear-gradient(145deg, #e6e6e6, #ffffff);
box-shadow: 5px 5px 10px #d1d1d1, -5px -5px 10px #ffffff;
cursor: pointer;
transition: all 0.1s;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5em;
}
.pop-bubble.popped {
background: linear-gradient(145deg, #d1d1d1, #e6e6e6);
box-shadow: inset 5px 5px 10px #b8b8b8, inset -5px -5px 10px #ffffff;
transform: scale(0.95);
}
/* 游戏4: 沙画板 */
#sand-game {
background: #2c3e50;
border-radius: 15px;
padding: 20px;
text-align: center;
}
#sand-canvas {
background: #1a1a2e;
border-radius: 10px;
cursor: crosshair;
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
.color-palette {
margin-top: 15px;
display: flex;
justify-content: center;
gap: 10px;
flex-wrap: wrap;
}
.color-btn {
width: 40px;
height: 40px;
border-radius: 50%;
border: 3px solid white;
cursor: pointer;
transition: transform 0.2s;
box-shadow: 0 3px 10px rgba(0,0,0,0.3);
}
.color-btn:hover {
transform: scale(1.2);
}
.color-btn.active {
transform: scale(1.3);
box-shadow: 0 0 0 3px #667eea;
}
/* 游戏5: 禅意花园 */
#zen-garden {
background: linear-gradient(180deg, #87CEEB 0%, #98D8C8 100%);
border-radius: 15px;
height: 500px;
position: relative;
overflow: hidden;
cursor: grab;
}
#zen-garden:active {
cursor: grabbing;
}
.sand-particle {
position: absolute;
width: 4px;
height: 4px;
background: #F4E4C1;
border-radius: 50%;
pointer-events: none;
}
.rock {
position: absolute;
font-size: 2em;
cursor: move;
user-select: none;
filter: drop-shadow(2px 4px 6px rgba(0,0,0,0.3));
transition: transform 0.2s;
}
.rock:hover {
transform: scale(1.1);
}
.rake-trail {
position: absolute;
height: 2px;
background: rgba(139, 119, 101, 0.6);
pointer-events: none;
}
/* 游戏6: 流体模拟 */
#fluid-game {
background: #000;
border-radius: 15px;
padding: 20px;
text-align: center;
}
#fluid-canvas {
border-radius: 10px;
cursor: crosshair;
box-shadow: 0 0 30px rgba(100, 200, 255, 0.5);
}
.fluid-controls {
margin-top: 15px;
color: white;
}
.fluid-btn {
background: rgba(255,255,255,0.2);
border: 1px solid rgba(255,255,255,0.3);
color: white;
padding: 8px 16px;
margin: 5px;
border-radius: 20px;
cursor: pointer;
transition: all 0.3s;
}
.fluid-btn:hover {
background: rgba(255,255,255,0.3);
transform: translateY(-2px);
}
/* 游戏7: 打击垫 */
#drum-game {
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
border-radius: 15px;
padding: 30px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
max-width: 500px;
margin: 0 auto;
}
.drum-pad {
aspect-ratio: 1;
border-radius: 20px;
background: linear-gradient(145deg, #2a5298, #1e3c72);
box-shadow: 5px 5px 15px rgba(0,0,0,0.3), -5px -5px 15px rgba(255,255,255,0.1);
display: flex;
align-items: center;
justify-content: center;
font-size: 2.5em;
cursor: pointer;
transition: all 0.1s;
user-select: none;
border: 2px solid rgba(255,255,255,0.1);
}
.drum-pad:active, .drum-pad.active {
transform: scale(0.95);
box-shadow: inset 5px 5px 15px rgba(0,0,0,0.3), inset -5px -5px 15px rgba(255,255,255,0.1);
background: linear-gradient(145deg, #1e3c72, #2a5298);
}
.drum-pad span {
pointer-events: none;
}
/* 游戏8: 呼吸练习 */
#breathe-game {
background: linear-gradient(180deg, #a8edea 0%, #fed6e3 100%);
border-radius: 15px;
height: 500px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
.breath-circle {
width: 200px;
height: 200px;
border-radius: 50%;
background: radial-gradient(circle, rgba(255,255,255,0.9) 0%, rgba(200,240,255,0.6) 100%);
box-shadow: 0 0 60px rgba(100,200,255,0.5), inset 0 0 40px rgba(255,255,255,0.8);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2em;
color: #555;
animation: breathe 8s ease-in-out infinite;
cursor: pointer;
transition: transform 0.3s;
}
.breath-circle:hover {
transform: scale(1.05);
}
@keyframes breathe {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.5); }
}
.breath-text {
margin-top: 30px;
font-size: 1.5em;
color: #555;
font-weight: 300;
letter-spacing: 2px;
}
/* 游戏9: 破坏球 */
#smash-game {
background: linear-gradient(180deg, #2c3e50 0%, #34495e 100%);
border-radius: 15px;
height: 500px;
position: relative;
overflow: hidden;
cursor: none;
}
.breakable {
position: absolute;
font-size: 2.5em;
cursor: pointer;
transition: all 0.3s;
filter: drop-shadow(0 4px 6px rgba(0,0,0,0.3));
}
.breakable:hover {
transform: scale(1.1);
}
.breakable.broken {
animation: break 0.5s ease-out forwards;
}
@keyframes break {
0% { transform: scale(1) rotate(0deg); opacity: 1; }
50% { transform: scale(1.3) rotate(10deg); }
100% { transform: scale(0) rotate(20deg); opacity: 0; }
}
.hammer {
position: absolute;
font-size: 3em;
pointer-events: none;
z-index: 1000;
transition: transform 0.05s;
filter: drop-shadow(2px 4px 6px rgba(0,0,0,0.5));
}
.hammer.smashing {
transform: rotate(-45deg);
}
/* 游戏10: 涂鸦板 */
#draw-game {
background: #fafafa;
border-radius: 15px;
padding: 20px;
text-align: center;
}
#draw-canvas {
background: white;
border-radius: 10px;
box-shadow: 0 5px 20px rgba(0,0,0,0.1);
cursor: crosshair;
border: 2px solid #e0e0e0;
}
.draw-tools {
margin-top: 15px;
display: flex;
justify-content: center;
gap: 15px;
align-items: center;
flex-wrap: wrap;
}
.tool-btn {
background: white;
border: 2px solid #ddd;
padding: 8px 16px;
border-radius: 20px;
cursor: pointer;
transition: all 0.3s;
font-size: 0.9em;
}
.tool-btn:hover {
background: #f0f0f0;
transform: translateY(-2px);
box-shadow: 0 3px 10px rgba(0,0,0,0.1);
}
.size-slider {
width: 100px;
}
/* 响应式 */
@media (max-width: 768px) {
h1 { font-size: 2em; }
.menu-grid { grid-template-columns: 1fr; }
.game-area { padding: 15px; min-height: 400px; }
}
@keyframes fadeInDown {
from { opacity: 0; transform: translateY(-30px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.score-board {
position: absolute;
top: 20px;
right: 20px;
background: rgba(255,255,255,0.9);
padding: 10px 20px;
border-radius: 25px;
font-weight: bold;
color: #333;
box-shadow: 0 3px 10px rgba(0,0,0,0.1);
z-index: 50;
}
.particle {
position: absolute;
pointer-events: none;
animation: particle-fall 1s ease-out forwards;
}
@keyframes particle-fall {
0% { transform: translateY(0) rotate(0deg); opacity: 1; }
100% { transform: translateY(100px) rotate(360deg); opacity: 0; }
}
</style>
</head>
<body>
<div class="container">
<header id="main-header">
<h1>🎮 解压乐园</h1>
<p class="subtitle">选择一款游戏,释放你的压力</p>
</header>
<div class="menu-grid" id="menu">
<div class="game-card" onclick="showGame('bubble')">
<div class="game-icon">🫧</div>
<div class="game-title">泡泡爆破</div>
<div class="game-desc">点击彩色泡泡,享受爆破的快感</div>
</div>
<div class="game-card" onclick="showGame('fruit')">
<div class="game-icon">🍉</div>
<div class="game-title">水果忍者</div>
<div class="game-desc">滑动切开飞来的水果,畅快淋漓</div>
</div>
<div class="game-card" onclick="showGame('popit')">
<div class="game-icon">🔘</div>
<div class="game-title">无限泡泡纸</div>
<div class="game-desc">经典解压神器,捏爆每一个泡泡</div>
</div>
<div class="game-card" onclick="showGame('sand')">
<div class="game-icon">🏖️</div>
<div class="game-title">沙画艺术</div>
<div class="game-desc">用流沙创作美丽的画作</div>
</div>
<div class="game-card" onclick="showGame('zen')">
<div class="game-icon">🎋</div>
<div class="game-title">禅意花园</div>
<div class="game-desc">耙沙、摆石,寻找内心的平静</div>
</div>
<div class="game-card" onclick="showGame('fluid')">
<div class="game-icon">💧</div>
<div class="game-title">流体模拟</div>
<div class="game-desc">触摸屏幕,观赏美丽的流体效果</div>
</div>
<div class="game-card" onclick="showGame('drum')">
<div class="game-icon">🥁</div>
<div class="game-title">节奏打击垫</div>
<div class="game-desc">敲击节奏,释放内心的节拍</div>
</div>
<div class="game-card" onclick="showGame('breathe')">
<div class="game-icon">🧘</div>
<div class="game-title">呼吸练习</div>
<div class="game-desc">跟随节奏深呼吸,放松身心</div>
</div>
<div class="game-card" onclick="showGame('smash')">
<div class="game-icon">🔨</div>
<div class="game-title">破坏球</div>
<div class="game-desc">砸碎一切,尽情发泄压力</div>
</div>
<div class="game-card" onclick="showGame('draw')">
<div class="game-icon">🎨</div>
<div class="game-title">自由涂鸦</div>
<div class="game-desc">随心所欲地绘画,表达自我</div>
</div>
</div>
<!-- 游戏区域 -->
<div id="game-container" style="display: none;">
<!-- 泡泡游戏 -->
<div class="game-area" id="bubble-area">
<button class="back-btn" onclick="backToMenu()">← 返回菜单</button>
<div class="score-board">得分: <span id="bubble-score">0</span></div>
<h2 style="text-align: center; margin-bottom: 20px; color: #333;">🫧 泡泡爆破</h2>
<div id="bubble-game"></div>
</div>
<!-- 水果游戏 -->
<div class="game-area" id="fruit-area">
<button class="back-btn" onclick="backToMenu()">← 返回菜单</button>
<div class="score-board">得分: <span id="fruit-score">0</span></div>
<h2 style="text-align: center; margin-bottom: 20px; color: #333;">🍉 水果忍者</h2>
<div id="fruit-game"></div>
</div>
<!-- 泡泡纸游戏 -->
<div class="game-area" id="popit-area">
<button class="back-btn" onclick="backToMenu()">← 返回菜单</button>
<h2 style="text-align: center; margin-bottom: 20px; color: #333;">🔘 无限泡泡纸</h2>
<div style="text-align: center; margin-bottom: 15px; color: #666;">点击泡泡来捏爆它们!</div>
<div id="popit-game"></div>
</div>
<!-- 沙画游戏 -->
<div class="game-area" id="sand-area">
<button class="back-btn" onclick="backToMenu()">← 返回菜单</button>
<h2 style="text-align: center; margin-bottom: 20px; color: #333;">🏖️ 沙画艺术</h2>
<canvas id="sand-canvas" width="800" height="400"></canvas>
<div class="color-palette">
<div class="color-btn active" style="background: #FFD700" onclick="setSandColor('#FFD700')"></div>
<div class="color-btn" style="background: #FF6B6B" onclick="setSandColor('#FF6B6B')"></div>
<div class="color-btn" style="background: #4ECDC4" onclick="setSandColor('#4ECDC4')"></div>
<div class="color-btn" style="background: #95E1D3" onclick="setSandColor('#95E1D3')"></div>
<div class="color-btn" style="background: #F38181" onclick="setSandColor('#F38181')"></div>
<div class="color-btn" style="background: #AA96DA" onclick="setSandColor('#AA96DA')"></div>
<div class="color-btn" style="background: #FCBAD3" onclick="setSandColor('#FCBAD3')"></div>
<div class="color-btn" style="background: #FFFFD2" onclick="setSandColor('#FFFFD2')"></div>
</div>
<div style="text-align: center; margin-top: 10px;">
<button class="tool-btn" onclick="clearSand()">清空画布</button>
</div>
</div>
<!-- 禅意花园 -->
<div class="game-area" id="zen-area">
<button class="back-btn" onclick="backToMenu()">← 返回菜单</button>
<h2 style="text-align: center; margin-bottom: 20px; color: #333;">🎋 禅意花园</h2>
<div style="text-align: center; margin-bottom: 10px; color: #666;">拖动鼠标耙沙,点击放置石头</div>
<div id="zen-garden"></div>
</div>
<!-- 流体游戏 -->
<div class="game-area" id="fluid-area">
<button class="back-btn" onclick="backToMenu()">← 返回菜单</button>
<h2 style="text-align: center; margin-bottom: 20px; color: white;">💧 流体模拟</h2>
<canvas id="fluid-canvas" width="800" height="400"></canvas>
<div class="fluid-controls">
<button class="fluid-btn" onclick="changeFluidColor()">切换颜色</button>
<button class="fluid-btn" onclick="clearFluid()">清空</button>
<button class="fluid-btn" onclick="toggleFluidRain()">自动雨滴: 关</button>
</div>
</div>
<!-- 打击垫 -->
<div class="game-area" id="drum-area">
<button class="back-btn" onclick="backToMenu()">← 返回菜单</button>
<h2 style="text-align: center; margin-bottom: 20px; color: white;">🥁 节奏打击垫</h2>
<div style="text-align: center; color: rgba(255,255,255,0.8); margin-bottom: 20px;">点击或按键盘 A-Z 演奏</div>
<div id="drum-game">
<div class="drum-pad" data-sound="kick" data-key="q"><span>🥁</span></div>
<div class="drum-pad" data-sound="snare" data-key="w"><span>🎵</span></div>
<div class="drum-pad" data-sound="hihat" data-key="e"><span>🎶</span></div>
<div class="drum-pad" data-sound="tom" data-key="a"><span>🎼</span></div>
<div class="drum-pad" data-sound="clap" data-key="s"><span>👏</span></div>
<div class="drum-pad" data-sound="crash" data-key="d"><span>💥</span></div>
<div class="drum-pad" data-sound="bass" data-key="z"><span>🎸</span></div>
<div class="drum-pad" data-sound="bell" data-key="x"><span>🔔</span></div>
<div class="drum-pad" data-sound="shake" data-key="c"><span>🌟</span></div>
</div>
</div>
<!-- 呼吸练习 -->
<div class="game-area" id="breathe-area">
<button class="back-btn" onclick="backToMenu()">← 返回菜单</button>
<h2 style="text-align: center; margin-bottom: 20px; color: #333;">🧘 呼吸练习</h2>
<div id="breathe-game">
<div class="breath-circle" onclick="toggleBreath()">
<span id="breath-text">吸气</span>
</div>
<div class="breath-text" id="breath-instruction">跟随圆圈呼吸,点击暂停/继续</div>
</div>
</div>
<!-- 破坏球 -->
<div class="game-area" id="smash-area">
<button class="back-btn" onclick="backToMenu()">← 返回菜单</button>
<div class="score-board">破坏数: <span id="smash-score">0</span></div>
<h2 style="text-align: center; margin-bottom: 20px; color: white;">🔨 破坏球</h2>
<div id="smash-game"></div>
</div>
<!-- 涂鸦板 -->
<div class="game-area" id="draw-area">
<button class="back-btn" onclick="backToMenu()">← 返回菜单</button>
<h2 style="text-align: center; margin-bottom: 20px; color: #333;">🎨 自由涂鸦</h2>
<canvas id="draw-canvas" width="800" height="400"></canvas>
<div class="draw-tools">
<input type="color" id="draw-color" value="#333333" style="width: 50px; height: 40px; border: none; border-radius: 10px; cursor: pointer;">
<input type="range" class="size-slider" id="draw-size" min="1" max="50" value="5">
<button class="tool-btn" onclick="setDrawTool('pen')">✏️ 画笔</button>
<button class="tool-btn" onclick="setDrawTool('eraser')">🧹 橡皮</button>
<button class="tool-btn" onclick="clearDraw()">🗑️ 清空</button>
<button class="tool-btn" onclick="saveDraw()">💾 保存</button>
</div>
</div>
</div>
</div>
<script>
// 音频上下文
const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioCtx = new AudioContext();
// 播放音效
function playSound(type) {
const oscillator = audioCtx.createOscillator();
const gainNode = audioCtx.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);
switch(type) {
case 'pop':
oscillator.frequency.setValueAtTime(800, audioCtx.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(100, audioCtx.currentTime + 0.1);
gainNode.gain.setValueAtTime(0.3, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.1);
oscillator.start(audioCtx.currentTime);
oscillator.stop(audioCtx.currentTime + 0.1);
break;
case 'slice':
oscillator.type = 'sawtooth';
oscillator.frequency.setValueAtTime(600, audioCtx.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(1200, audioCtx.currentTime + 0.1);
gainNode.gain.setValueAtTime(0.2, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.15);
oscillator.start(audioCtx.currentTime);
oscillator.stop(audioCtx.currentTime + 0.15);
break;
case 'drum':
oscillator.frequency.setValueAtTime(150, audioCtx.currentTime);
gainNode.gain.setValueAtTime(0.5, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.2);
oscillator.start(audioCtx.currentTime);
oscillator.stop(audioCtx.currentTime + 0.2);
break;
case 'bell':
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(800, audioCtx.currentTime);
gainNode.gain.setValueAtTime(0.3, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.5);
oscillator.start(audioCtx.currentTime);
oscillator.stop(audioCtx.currentTime + 0.5);
break;
}
}
// 导航功能
function showGame(game) {
document.getElementById('main-header').style.display = 'none';
document.getElementById('menu').style.display = 'none';
document.getElementById('game-container').style.display = 'block';
// 隐藏所有游戏区域
document.querySelectorAll('.game-area').forEach(area => {
area.classList.remove('active');
});
// 显示选中的游戏
document.getElementById(game + '-area').classList.add('active');
// 初始化对应游戏
switch(game) {
case 'bubble': initBubbleGame(); break;
case 'fruit': initFruitGame(); break;
case 'popit': initPopItGame(); break;
case 'sand': initSandGame(); break;
case 'zen': initZenGarden(); break;
case 'fluid': initFluidGame(); break;
case 'drum': initDrumGame(); break;
case 'breathe': initBreatheGame(); break;
case 'smash': initSmashGame(); break;
case 'draw': initDrawGame(); break;
}
}
function backToMenu() {
// 清理游戏循环
if (window.gameLoop) {
cancelAnimationFrame(window.gameLoop);
window.gameLoop = null;
}
if (window.fruitInterval) {
clearInterval(window.fruitInterval);
window.fruitInterval = null;
}
if (window.smashInterval) {
clearInterval(window.smashInterval);
window.smashInterval = null;
}
document.getElementById('main-header').style.display = 'block';
document.getElementById('menu').style.display = 'grid';
document.getElementById('game-container').style.display = 'none';
document.querySelectorAll('.game-area').forEach(area => {
area.classList.remove('active');
});
}
// 游戏1: 泡泡爆破
let bubbleScore = 0;
function initBubbleGame() {
const container = document.getElementById('bubble-game');
container.innerHTML = '';
bubbleScore = 0;
document.getElementById('bubble-score').textContent = '0';
function createBubble() {
const bubble = document.createElement('div');
bubble.className = 'bubble';
const size = Math.random() * 60 + 40;
bubble.style.width = size + 'px';
bubble.style.height = size + 'px';
bubble.style.left = Math.random() * (container.offsetWidth - size) + 'px';
bubble.style.top = Math.random() * (container.offsetHeight - size) + 'px';
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8', '#F7DC6F'];
bubble.style.background = `radial-gradient(circle at 30% 30%, ${colors[Math.floor(Math.random() * colors.length)]}, rgba(255,255,255,0.3))`;
bubble.addEventListener('click', function(e) {
e.stopPropagation();
playSound('pop');
bubbleScore += 10;
document.getElementById('bubble-score').textContent = bubbleScore;
// 爆破效果
const pop = document.createElement('div');
pop.className = 'pop-effect';
pop.style.left = e.pageX - container.offsetLeft + 'px';
pop.style.top = e.pageY - container.offsetTop + 'px';
pop.innerHTML = '💥';
pop.style.fontSize = '2em';
container.appendChild(pop);
setTimeout(() => pop.remove(), 300);
bubble.remove();
createBubble();
});
container.appendChild(bubble);
}
// 创建初始泡泡
for (let i = 0; i < 8; i++) {
setTimeout(() => createBubble(), i * 200);
}
}
// 游戏2: 水果忍者
let fruitScore = 0;
function initFruitGame() {
const container = document.getElementById('fruit-game');
container.innerHTML = '';
fruitScore = 0;
document.getElementById('fruit-score').textContent = '0';
const fruits = ['🍎', '🍊', '🍋', '🍉', '🍇', '🍓', '🍑', '🍒', '🥝', '🥥'];
const blade = document.createElement('div');
blade.className = 'blade';
container.appendChild(blade);
let isMouseDown = false;
let lastX = 0, lastY = 0;
container.addEventListener('mousemove', (e) => {
const rect = container.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
blade.style.left = (x - 30) + 'px';
blade.style.top = (y - 30) + 'px';
if (isMouseDown && lastX !== 0) {
// 创建刀光轨迹
const trail = document.createElement('div');
trail.className = 'slash-trail';
const angle = Math.atan2(y - lastY, x - lastX);
const length = Math.sqrt(Math.pow(x - lastX, 2) + Math.pow(y - lastY, 2));
trail.style.width = length + 'px';
trail.style.left = lastX + 'px';
trail.style.top = lastY + 'px';
trail.style.transform = `rotate(${angle}rad)`;
trail.style.transformOrigin = '0 50%';
container.appendChild(trail);
setTimeout(() => trail.remove(), 100);
// 检测切割
document.querySelectorAll('.fruit').forEach(fruit => {
const fruitRect = fruit.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
const fx = fruitRect.left - containerRect.left + fruitRect.width/2;
const fy = fruitRect.top - containerRect.top + fruitRect.height/2;
const dist = Math.sqrt(Math.pow(x - fx, 2) + Math.pow(y - fy, 2));
if (dist < 40 && !fruit.classList.contains('sliced')) {
fruit.classList.add('sliced');
playSound('slice');
fruitScore += 5;
document.getElementById('fruit-score').textContent = fruitScore;
setTimeout(() => fruit.remove(), 300);
}
});
}
lastX = x;
lastY = y;
});
container.addEventListener('mousedown', () => {
isMouseDown = true;
blade.style.transform = 'scale(1.2)';
});
container.addEventListener('mouseup', () => {
isMouseDown = false;
blade.style.transform = 'scale(1)';
lastX = 0;
lastY = 0;
});
// 生成水果
window.fruitInterval = setInterval(() => {
if (document.querySelectorAll('.fruit').length < 10) {
const fruit = document.createElement('div');
fruit.className = 'fruit';
fruit.textContent = fruits[Math.floor(Math.random() * fruits.length)];
fruit.style.left = Math.random() * (container.offsetWidth - 50) + 'px';
fruit.style.top = Math.random() * (container.offsetHeight - 50) + 'px';
// 随机移动
let dx = (Math.random() - 0.5) * 4;
let dy = (Math.random() - 0.5) * 4;
function move() {
if (!fruit.parentElement || fruit.classList.contains('sliced')) return;
let x = parseFloat(fruit.style.left);
let y = parseFloat(fruit.style.top);
x += dx;
y += dy;
if (x <= 0 || x >= container.offsetWidth - 50) dx = -dx;
if (y <= 0 || y >= container.offsetHeight - 50) dy = -dy;
fruit.style.left = x + 'px';
fruit.style.top = y + 'px';
requestAnimationFrame(move);
}
move();
container.appendChild(fruit);
}
}, 1000);
}
// 游戏3: 捏泡泡纸
function initPopItGame() {
const container = document.getElementById('popit-game');
container.innerHTML = '';
for (let i = 0; i < 24; i++) {
const bubble = document.createElement('div');
bubble.className = 'pop-bubble';
bubble.innerHTML = '○';
bubble.addEventListener('click', function() {
if (!this.classList.contains('popped')) {
this.classList.add('popped');
this.innerHTML = '●';
playSound('pop');
setTimeout(() => {
this.classList.remove('popped');
this.innerHTML = '○';
}, 2000);
}
});
container.appendChild(bubble);
}
}
// 游戏4: 沙画
let sandColor = '#FFD700';
function initSandGame() {
const canvas = document.getElementById('sand-canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#1a1a2e';
ctx.fillRect(0, 0, canvas.width, canvas.height);
let isDrawing = false;
let particles = [];
function addSand(x, y) {
for (let i = 0; i < 5; i++) {
const px = x + (Math.random() - 0.5) * 20;
const py = y + (Math.random() - 0.5) * 20;
particles.push({x: px, y: py, vy: 0, color: sandColor});
}
}
function update() {
ctx.fillStyle = '#1a1a2e';
ctx.fillRect(0, 0, canvas.width, canvas.height);
particles = particles.filter(p => {
p.vy += 0.5; // 重力
p.y += p.vy;
// 碰撞检测
const imageData = ctx.getImageData(Math.floor(p.x), Math.floor(p.y) + 2, 1, 1);
const below = imageData.data[3] > 0;
if (p.y >= canvas.height - 2 || below) {
p.y -= p.vy;
p.vy = 0;
ctx.fillStyle = p.color;
ctx.fillRect(p.x, p.y, 2, 2);
return false; // 停止粒子,绘制为静态
}
ctx.fillStyle = p.color;
ctx.fillRect(p.x, p.y, 2, 2);
return true;
});
requestAnimationFrame(update);
}
update();
canvas.addEventListener('mousedown', (e) => {
isDrawing = true;
const rect = canvas.getBoundingClientRect();
addSand(e.clientX - rect.left, e.clientY - rect.top);
});
canvas.addEventListener('mousemove', (e) => {
if (isDrawing) {
const rect = canvas.getBoundingClientRect();
addSand(e.clientX - rect.left, e.clientY - rect.top);
}
});
canvas.addEventListener('mouseup', () => isDrawing = false);
canvas.addEventListener('mouseleave', () => isDrawing = false);
}
function setSandColor(color) {
sandColor = color;
document.querySelectorAll('.color-btn').forEach(btn => btn.classList.remove('active'));
event.target.classList.add('active');
}
function clearSand() {
const canvas = document.getElementById('sand-canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#1a1a2e';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
// 游戏5: 禅意花园
function initZenGarden() {
const container = document.getElementById('zen-garden');
container.innerHTML = '';
// 添加沙子纹理
for (let i = 0; i < 100; i++) {
const sand = document.createElement('div');
sand.className = 'sand-particle';
sand.style.left = Math.random() * 100 + '%';
sand.style.top = Math.random() * 100 + '%';
sand.style.opacity = Math.random() * 0.5 + 0.2;
container.appendChild(sand);
}
// 添加可拖动的石头
const rocks = ['🪨', '🗿', '🌑', '🏔️'];
for (let i = 0; i < 5; i++) {
const rock = document.createElement('div');
rock.className = 'rock';
rock.textContent = rocks[Math.floor(Math.random() * rocks.length)];
rock.style.left = Math.random() * 80 + 10 + '%';
rock.style.top = Math.random() * 80 + 10 + '%';
let isDragging = false;
let startX, startY, initialX, initialY;
rock.addEventListener('mousedown', (e) => {
isDragging = true;
startX = e.clientX;
startY = e.clientY;
initialX = rock.offsetLeft;
initialY = rock.offsetTop;
rock.style.zIndex = 1000;
});
document.addEventListener('mousemove', (e) => {
if (isDragging) {
const dx = e.clientX - startX;
const dy = e.clientY - startY;
rock.style.left = (initialX + dx) + 'px';
rock.style.top = (initialY + dy) + 'px';
}
});
document.addEventListener('mouseup', () => {
isDragging = false;
rock.style.zIndex = '';
});
container.appendChild(rock);
}
// 耙沙效果
let isRaking = false;
let lastX = 0, lastY = 0;
container.addEventListener('mousedown', (e) => {
if (e.target.classList.contains('rock')) return;
isRaking = true;
const rect = container.getBoundingClientRect();
lastX = e.clientX - rect.left;
lastY = e.clientY - rect.top;
});
container.addEventListener('mousemove', (e) => {
if (!isRaking) return;
const rect = container.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const trail = document.createElement('div');
trail.className = 'rake-trail';
const angle = Math.atan2(y - lastY, x - lastX);
const length = Math.sqrt(Math.pow(x - lastX, 2) + Math.pow(y - lastY, 2));
trail.style.width = length + 'px';
trail.style.left = lastX + 'px';
trail.style.top = lastY + 'px';
trail.style.transform = `rotate(${angle}rad)`;
container.appendChild(trail);
// 限制轨迹数量
const trails = container.querySelectorAll('.rake-trail');
if (trails.length > 50) {
trails[0].remove();
}
lastX = x;
lastY = y;
});
container.addEventListener('mouseup', () => isRaking = false);
container.addEventListener('mouseleave', () => isRaking = false);
}
// 游戏6: 流体模拟
let fluidColor = [100, 200, 255];
let fluidRain = false;
function initFluidGame() {
const canvas = document.getElementById('fluid-canvas');
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
let fluid = [];
for (let i = 0; i < width; i++) {
fluid[i] = [];
for (let j = 0; j < height; j++) {
fluid[i][j] = {x: 0, y: 0};
}
}
let damping = 0.99;
function updateFluid() {
// 传播
for (let i = 1; i < width - 1; i++) {
for (let j = 1; j < height - 1; j++) {
fluid[i][j].x = (
fluid[i-1][j].x + fluid[i+1][j].x +
fluid[i][j-1].x + fluid[i][j+1].x
) / 2 - fluid[i][j].x;
fluid[i][j].x *= damping;
}
}
// 渲染
const imageData = ctx.createImageData(width, height);
for (let i = 0; i < width; i++) {
for (let j = 0; j < height; j++) {
const idx = (j * width + i) * 4;
const val = Math.abs(fluid[i][j].x) * 255;
imageData.data[idx] = fluidColor[0] * val / 255;
imageData.data[idx + 1] = fluidColor[1] * val / 255;
imageData.data[idx + 2] = fluidColor[2] * val / 255;
imageData.data[idx + 3] = 255;
}
}
ctx.putImageData(imageData, 0, 0);
// 自动雨滴
if (fluidRain && Math.random() < 0.1) {
const x = Math.floor(Math.random() * (width - 20)) + 10;
const y = Math.floor(Math.random() * (height - 20)) + 10;
fluid[x][y].x = 500;
}
window.gameLoop = requestAnimationFrame(updateFluid);
}
updateFluid();
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
const x = Math.floor(e.clientX - rect.left);
const y = Math.floor(e.clientY - rect.top);
if (x > 0 && x < width - 1 && y > 0 && y < height - 1) {
fluid[x][y].x = 1000;
}
});
}
function changeFluidColor() {
fluidColor = [
Math.floor(Math.random() * 255),
Math.floor(Math.random() * 255),
Math.floor(Math.random() * 255)
];
}
function clearFluid() {
const canvas = document.getElementById('fluid-canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
function toggleFluidRain() {
fluidRain = !fluidRain;
event.target.textContent = `自动雨滴: ${fluidRain ? '开' : '关'}`;
}
// 游戏7: 打击垫
function initDrumGame() {
const pads = document.querySelectorAll('.drum-pad');
pads.forEach(pad => {
pad.addEventListener('click', () => {
playDrum(pad.dataset.sound);
pad.classList.add('active');
setTimeout(() => pad.classList.remove('active'), 100);
});
});
document.addEventListener('keydown', (e) => {
const pad = document.querySelector(`.drum-pad[data-key="${e.key.toLowerCase()}"]`);
if (pad) {
playDrum(pad.dataset.sound);
pad.classList.add('active');
setTimeout(() => pad.classList.remove('active'), 100);
}
});
}
function playDrum(type) {
const oscillator = audioCtx.createOscillator();
const gainNode = audioCtx.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);
switch(type) {
case 'kick':
oscillator.frequency.setValueAtTime(150, audioCtx.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.5);
gainNode.gain.setValueAtTime(0.8, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.5);
break;
case 'snare':
oscillator.type = 'triangle';
oscillator.frequency.setValueAtTime(250, audioCtx.currentTime);
gainNode.gain.setValueAtTime(0.5, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.2);
break;
case 'hihat':
oscillator.type = 'square';
oscillator.frequency.setValueAtTime(800, audioCtx.currentTime);
gainNode.gain.setValueAtTime(0.2, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.05);
break;
case 'tom':
oscillator.frequency.setValueAtTime(200, audioCtx.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(100, audioCtx.currentTime + 0.3);
gainNode.gain.setValueAtTime(0.5, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.3);
break;
case 'clap':
oscillator.type = 'sawtooth';
oscillator.frequency.setValueAtTime(400, audioCtx.currentTime);
gainNode.gain.setValueAtTime(0.3, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.1);
break;
case 'crash':
oscillator.type = 'sawtooth';
oscillator.frequency.setValueAtTime(600, audioCtx.currentTime);
gainNode.gain.setValueAtTime(0.4, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 1);
break;
case 'bass':
oscillator.type = 'square';
oscillator.frequency.setValueAtTime(100, audioCtx.currentTime);
gainNode.gain.setValueAtTime(0.4, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.4);
break;
case 'bell':
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(800, audioCtx.currentTime);
gainNode.gain.setValueAtTime(0.3, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.6);
break;
case 'shake':
oscillator.type = 'triangle';
oscillator.frequency.setValueAtTime(1200, audioCtx.currentTime);
gainNode.gain.setValueAtTime(0.2, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.1);
break;
}
oscillator.start(audioCtx.currentTime);
oscillator.stop(audioCtx.currentTime + 1);
}
// 游戏8: 呼吸练习
let breathRunning = true;
function initBreatheGame() {
const circle = document.querySelector('.breath-circle');
const text = document.getElementById('breath-text');
const instruction = document.getElementById('breath-instruction');
let phase = 0; // 0: 吸气, 1: 屏息, 2: 呼气
function breathe() {
if (!breathRunning) return;
if (phase === 0) {
text.textContent = '吸气';
instruction.textContent = '慢慢吸气...';
circle.style.animation = 'breathe 4s ease-in-out forwards';
setTimeout(() => {
phase = 1;
breathe();
}, 4000);
} else if (phase === 1) {
text.textContent = '屏息';
instruction.textContent = '保持住...';
setTimeout(() => {
phase = 2;
breathe();
}, 2000);
} else {
text.textContent = '呼气';
instruction.textContent = '慢慢呼气...';
circle.style.animation = 'none';
circle.offsetHeight; // 触发重绘
circle.style.transform = 'scale(1)';
setTimeout(() => {
phase = 0;
breathe();
}, 4000);
}
}
breathe();
}
function toggleBreath() {
breathRunning = !breathRunning;
if (breathRunning) {
initBreatheGame();
}
}
// 游戏9: 破坏球
let smashScore = 0;
function initSmashGame() {
const container = document.getElementById('smash-game');
container.innerHTML = '';
smashScore = 0;
document.getElementById('smash-score').textContent = '0';
const items = ['📺', '📱', '💻', '🖥️', '📷', '⏰', '🍽️', '🍷', '🏺', '🪞', '🪟', '🚪', '💾', '📀', '🎮', '📦'];
const hammer = document.createElement('div');
hammer.className = 'hammer';
hammer.textContent = '🔨';
container.appendChild(hammer);
container.addEventListener('mousemove', (e) => {
const rect = container.getBoundingClientRect();
hammer.style.left = (e.clientX - rect.left - 25) + 'px';
hammer.style.top = (e.clientY - rect.top - 25) + 'px';
});
container.addEventListener('mousedown', () => {
hammer.classList.add('smashing');
playSound('drum');
// 检测碰撞
const hammerRect = hammer.getBoundingClientRect();
document.querySelectorAll('.breakable').forEach(item => {
const itemRect = item.getBoundingClientRect();
if (hammerRect.left < itemRect.right &&
hammerRect.right > itemRect.left &&
hammerRect.top < itemRect.bottom &&
hammerRect.bottom > itemRect.top) {
if (!item.classList.contains('broken')) {
item.classList.add('broken');
playSound('crash');
smashScore++;
document.getElementById('smash-score').textContent = smashScore;
// 碎片效果
for (let i = 0; i < 5; i++) {
const particle = document.createElement('div');
particle.className = 'particle';
particle.textContent = '✨';
particle.style.left = itemRect.left - container.getBoundingClientRect().left + Math.random() * 50 + 'px';
particle.style.top = itemRect.top - container.getBoundingClientRect().top + 'px';
container.appendChild(particle);
setTimeout(() => particle.remove(), 1000);
}
setTimeout(() => item.remove(), 500);
}
}
});
});
container.addEventListener('mouseup', () => {
hammer.classList.remove('smashing');
});
// 生成物品
window.smashInterval = setInterval(() => {
if (document.querySelectorAll('.breakable').length < 8) {
const item = document.createElement('div');
item.className = 'breakable';
item.textContent = items[Math.floor(Math.random() * items.length)];
item.style.left = Math.random() * (container.offsetWidth - 50) + 'px';
item.style.top = Math.random() * (container.offsetHeight - 50) + 'px';
container.appendChild(item);
}
}, 1500);
}
// 游戏10: 涂鸦板
let drawTool = 'pen';
function initDrawGame() {
const canvas = document.getElementById('draw-canvas');
const ctx = canvas.getContext('2d');
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
let isDrawing = false;
let lastX = 0;
let lastY = 0;
canvas.addEventListener('mousedown', (e) => {
isDrawing = true;
const rect = canvas.getBoundingClientRect();
lastX = e.clientX - rect.left;
lastY = e.clientY - rect.top;
});
canvas.addEventListener('mousemove', (e) => {
if (!isDrawing) return;
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
if (drawTool === 'pen') {
ctx.globalCompositeOperation = 'source-over';
ctx.strokeStyle = document.getElementById('draw-color').value;
ctx.lineWidth = document.getElementById('draw-size').value;
} else {
ctx.globalCompositeOperation = 'destination-out';
ctx.lineWidth = 20;
}
ctx.stroke();
lastX = x;
lastY = y;
});
canvas.addEventListener('mouseup', () => isDrawing = false);
canvas.addEventListener('mouseleave', () => isDrawing = false);
}
function setDrawTool(tool) {
drawTool = tool;
}
function clearDraw() {
const canvas = document.getElementById('draw-canvas');
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function saveDraw() {
const canvas = document.getElementById('draw-canvas');
const link = document.createElement('a');
link.download = '我的涂鸦.png';
link.href = canvas.toDataURL();
link.click();
}
</script>
</body>
</html>Game Source: 解压乐园 - 放松小游戏合集
Creator: StormViper16
Libraries: none
Complexity: complex (1620 lines, 63.3 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: game-stormviper16-ms4o6ohr" to link back to the original. Then publish at arcadelab.ai/publish.