erdes commited on
Commit
4642ac1
·
verified ·
1 Parent(s): 3e26f53

写一个贪吃蛇游戏,有丰富的自定义设置 - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +891 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Snake
3
- emoji: 🏆
4
- colorFrom: red
5
- colorTo: red
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: snake
3
+ emoji: 🐳
4
+ colorFrom: green
5
+ colorTo: pink
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,891 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>贪吃蛇游戏 - Snake Customizer</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
11
+
12
+ :root {
13
+ --grid-size: 20px;
14
+ --grid-color: #374151;
15
+ --snake-color: #10B981;
16
+ --food-color: #EF4444;
17
+ --obstacle-color: #6B7280;
18
+ --bg-color: #111827;
19
+ --speed: 150;
20
+ }
21
+
22
+ .game-container {
23
+ position: relative;
24
+ background-color: var(--bg-color);
25
+ background-image:
26
+ linear-gradient(var(--grid-color) 1px, transparent 1px),
27
+ linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
28
+ background-size: var(--grid-size) var(--grid-size);
29
+ }
30
+
31
+ .snake-head {
32
+ background-color: var(--snake-color);
33
+ border-radius: 4px;
34
+ box-shadow: 0 0 5px rgba(16, 185, 129, 0.7);
35
+ }
36
+
37
+ .snake-body {
38
+ background-color: var(--snake-color);
39
+ border-radius: 2px;
40
+ }
41
+
42
+ .food {
43
+ background-color: var(--food-color);
44
+ border-radius: 50%;
45
+ box-shadow: 0 0 8px rgba(239, 68, 68, 0.8);
46
+ animation: pulse 1.5s infinite;
47
+ }
48
+
49
+ .obstacle {
50
+ background-color: var(--obstacle-color);
51
+ border-radius: 3px;
52
+ }
53
+
54
+ .retro-font {
55
+ font-family: 'Press Start 2P', cursive;
56
+ }
57
+
58
+ .custom-slider::-webkit-slider-thumb {
59
+ -webkit-appearance: none;
60
+ appearance: none;
61
+ width: 20px;
62
+ height: 20px;
63
+ border-radius: 50%;
64
+ background: #10B981;
65
+ cursor: pointer;
66
+ }
67
+
68
+ .custom-slider::-moz-range-thumb {
69
+ width: 20px;
70
+ height: 20px;
71
+ border-radius: 50%;
72
+ background: #10B981;
73
+ cursor: pointer;
74
+ }
75
+
76
+ .color-preview {
77
+ width: 30px;
78
+ height: 30px;
79
+ border-radius: 4px;
80
+ cursor: pointer;
81
+ }
82
+
83
+ .settings-panel {
84
+ transition: transform 0.3s ease-in-out;
85
+ }
86
+
87
+ .settings-panel.hidden {
88
+ transform: translateX(100%);
89
+ }
90
+
91
+ .game-over {
92
+ background: rgba(0, 0, 0, 0.8);
93
+ backdrop-filter: blur(4px);
94
+ }
95
+
96
+ @keyframes pulse {
97
+ 0% { transform: scale(1); }
98
+ 50% { transform: scale(1.1); }
99
+ 100% { transform: scale(1); }
100
+ }
101
+
102
+ @keyframes snakeMove {
103
+ 0% { transform: scale(0.9); }
104
+ 50% { transform: scale(1); }
105
+ 100% { transform: scale(0.9); }
106
+ }
107
+ </style>
108
+ </head>
109
+ <body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
110
+ <!-- 标题区域 -->
111
+ <header class="py-4 px-6 bg-gray-800 border-b border-green-500">
112
+ <div class="container mx-auto flex justify-between items-center">
113
+ <h1 class="text-2xl md:text-3xl font-bold text-green-400 retro-font flex items-center">
114
+ <i class="fas fa-snake mr-3"></i>贪吃蛇游戏 - Snake Customizer
115
+ </h1>
116
+ <div class="flex items-center">
117
+ <span id="score-display" class="bg-gray-700 px-4 py-2 rounded-lg text-green-300 retro-font">分数: 0</span>
118
+ <button id="settings-toggle" class="ml-4 bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg transition">
119
+ <i class="fas fa-cog"></i> 设置
120
+ </button>
121
+ </div>
122
+ </div>
123
+ </header>
124
+
125
+ <!-- 主内容区 -->
126
+ <main class="flex-grow flex flex-col md:flex-row container mx-auto px-4 py-6 gap-6">
127
+ <!-- 游戏区域 -->
128
+ <div class="flex-grow flex flex-col items-center">
129
+ <div class="game-container w-full max-w-2xl h-96 md:h-[500px] rounded-xl overflow-hidden border-2 border-green-500 relative" id="game-canvas">
130
+ <!-- 游戏结束提示 -->
131
+ <div id="game-over" class="game-over absolute inset-0 flex flex-col items-center justify-center hidden">
132
+ <h2 class="text-3xl font-bold text-red-500 mb-4 retro-font">游戏结束!</h2>
133
+ <p class="text-xl text-green-300 mb-6 retro-font">最终分数: <span id="final-score">0</span></p>
134
+ <button id="restart-btn" class="bg-green-600 hover:bg-green-700 text-white px-6 py-3 rounded-lg text-xl transition">
135
+ <i class="fas fa-redo mr-2"></i>重新开始
136
+ </button>
137
+ </div>
138
+ </div>
139
+
140
+ <!-- 控制按钮 -->
141
+ <div class="mt-6 flex flex-wrap justify-center gap-4">
142
+ <button id="start-btn" class="bg-green-600 hover:bg-green-700 text-white px-6 py-3 rounded-lg text-lg transition">
143
+ <i class="fas fa-play mr-2"></i>开始游戏
144
+ </button>
145
+ <button id="pause-btn" class="bg-yellow-600 hover:bg-yellow-700 text-white px-6 py-3 rounded-lg text-lg transition">
146
+ <i class="fas fa-pause mr-2"></i>暂停
147
+ </button>
148
+ <button id="reset-btn" class="bg-red-600 hover:bg-red-700 text-white px-6 py-3 rounded-lg text-lg transition">
149
+ <i class="fas fa-sync mr-2"></i>重置
150
+ </button>
151
+ </div>
152
+
153
+ <!-- 移动设备控制 -->
154
+ <div class="mt-6 grid grid-cols-3 gap-2 w-64">
155
+ <div></div>
156
+ <button id="up-btn" class="bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg text-center">
157
+ <i class="fas fa-arrow-up"></i>
158
+ </button>
159
+ <div></div>
160
+ <button id="left-btn" class="bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg text-center">
161
+ <i class="fas fa-arrow-left"></i>
162
+ </button>
163
+ <div></div>
164
+ <button id="right-btn" class="bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg text-center">
165
+ <i class="fas fa-arrow-right"></i>
166
+ </button>
167
+ <div></div>
168
+ <button id="down-btn" class="bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg text-center">
169
+ <i class="fas fa-arrow-down"></i>
170
+ </div>
171
+ </div>
172
+ </div>
173
+
174
+ <!-- 设置面板 -->
175
+ <div id="settings-panel" class="settings-panel w-full md:w-80 bg-gray-800 rounded-xl p-6 border border-green-500 h-fit">
176
+ <div class="flex justify-between items-center mb-6">
177
+ <h2 class="text-xl font-bold text-green-400"><i class="fas fa-sliders-h mr-2"></i>游戏设置</h2>
178
+ <button id="close-settings" class="text-gray-400 hover:text-white">
179
+ <i class="fas fa-times"></i>
180
+ </button>
181
+ </div>
182
+
183
+ <div class="space-y-6">
184
+ <!-- 难度设置 -->
185
+ <div>
186
+ <h3 class="text-lg font-semibold mb-2 text-gray-300"><i class="fas fa-tachometer-alt mr-2"></i>难度设置</h3>
187
+ <div class="space-y-4">
188
+ <div>
189
+ <label class="block mb-1 text-gray-400">游戏速度</label>
190
+ <div class="flex items-center">
191
+ <span class="mr-2 text-sm">慢</span>
192
+ <input type="range" min="50" max="300" value="150" class="custom-slider w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer" id="speed-slider">
193
+ <span class="ml-2 text-sm">快</span>
194
+ </div>
195
+ <div class="text-right text-sm text-green-400" id="speed-value">中等</div>
196
+ </div>
197
+
198
+ <div>
199
+ <label class="block mb-1 text-gray-400">网格大小</label>
200
+ <div class="flex gap-2">
201
+ <button data-size="15" class="grid-size-btn flex-1 bg-gray-700 hover:bg-gray-600 py-2 rounded">小</button>
202
+ <button data-size="20" class="grid-size-btn flex-1 bg-green-600 py-2 rounded">中</button>
203
+ <button data-size="25" class="grid-size-btn flex-1 bg-gray-700 hover:bg-gray-600 py-2 rounded">大</button>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ </div>
208
+
209
+ <!-- 游戏模式 -->
210
+ <div>
211
+ <h3 class="text-lg font-semibold mb-2 text-gray-300"><i class="fas fa-gamepad mr-2"></i>游戏模式</h3>
212
+ <div class="space-y-2">
213
+ <label class="flex items-center cursor-pointer">
214
+ <input type="checkbox" id="wall-collision" class="form-checkbox h-5 w-5 text-green-500" checked>
215
+ <span class="ml-2 text-gray-300">墙壁碰撞</span>
216
+ </label>
217
+
218
+ <label class="flex items-center cursor-pointer">
219
+ <input type="checkbox" id="obstacles" class="form-checkbox h-5 w-5 text-green-500">
220
+ <span class="ml-2 text-gray-300">添加障碍物</span>
221
+ </label>
222
+
223
+ <label class="flex items-center cursor-pointer">
224
+ <input type="checkbox" id="grow-mode" class="form-checkbox h-5 w-5 text-green-500">
225
+ <span class="ml-2 text-gray-300">成长模式</span>
226
+ </label>
227
+ </div>
228
+ </div>
229
+
230
+ <!-- 外观设置 -->
231
+ <div>
232
+ <h3 class="text-lg font-semibold mb-2 text-gray-300"><i class="fas fa-palette mr-2"></i>外观设置</h3>
233
+ <div class="grid grid-cols-2 gap-4">
234
+ <div>
235
+ <label class="block mb-1 text-gray-400">蛇的颜色</label>
236
+ <div class="flex gap-2">
237
+ <div class="color-preview bg-green-500" data-color="#10B981" title="绿色"></div>
238
+ <div class="color-preview bg-blue-500" data-color="#3B82F6" title="蓝色"></div>
239
+ <div class="color-preview bg-purple-500" data-color="#8B5CF6" title="紫色"></div>
240
+ </div>
241
+ </div>
242
+
243
+ <div>
244
+ <label class="block mb-1 text-gray-400">食物颜色</label>
245
+ <div class="flex gap-2">
246
+ <div class="color-preview bg-red-500" data-color="#EF4444" title="红色"></div>
247
+ <div class="color-preview bg-yellow-500" data-color="#F59E0B" title="黄色"></div>
248
+ <div class="color-preview bg-pink-500" data-color="#EC4899" title="粉色"></div>
249
+ </div>
250
+ </div>
251
+
252
+ <div>
253
+ <label class="block mb-1 text-gray-400">网格颜色</label>
254
+ <div class="flex gap-2">
255
+ <div class="color-preview bg-gray-500" data-color="#6B7280" title="灰色"></div>
256
+ <div class="color-preview bg-blue-400" data-color="#60A5FA" title="浅蓝"></div>
257
+ <div class="color-preview bg-green-400" data-color="#34D399" title="浅绿"></div>
258
+ </div>
259
+ </div>
260
+
261
+ <div>
262
+ <label class="block mb-1 text-gray-400">背景颜色</label>
263
+ <div class="flex gap-2">
264
+ <div class="color-preview bg-gray-900" data-color="#111827" title="深灰"></div>
265
+ <div class="color-preview bg-gray-800" data-color="#1F2937" title="中灰"></div>
266
+ <div class="color-preview bg-gray-700" data-color="#374151" title="浅灰"></div>
267
+ </div>
268
+ </div>
269
+ </div>
270
+ </div>
271
+
272
+ <!-- 高级设置 -->
273
+ <div>
274
+ <h3 class="text-lg font-semibold mb-2 text-gray-300"><i class="fas fa-cogs mr-2"></i>高级设置</h3>
275
+ <div class="space-y-2">
276
+ <div>
277
+ <label class="block mb-1 text-gray-400">初始长度</label>
278
+ <input type="range" min="3" max="10" value="4" class="custom-slider w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer" id="initial-length">
279
+ <div class="text-right text-sm text-green-400" id="length-value">4</div>
280
+ </div>
281
+
282
+ <div>
283
+ <label class="block mb-1 text-gray-400">食物数量</label>
284
+ <input type="range" min="1" max="5" value="1" class="custom-slider w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer" id="food-count">
285
+ <div class="text-right text-sm text-green-400" id="food-count-value">1</div>
286
+ </div>
287
+ </div>
288
+ </div>
289
+ </div>
290
+
291
+ <button id="apply-settings" class="mt-8 w-full bg-green-600 hover:bg-green-700 text-white py-3 rounded-lg text-lg transition">
292
+ <i class="fas fa-check-circle mr-2"></i>应用设���
293
+ </button>
294
+ </div>
295
+ </main>
296
+
297
+ <!-- 游戏说明 -->
298
+ <footer class="bg-gray-800 border-t border-green-500 py-6 px-4">
299
+ <div class="container mx-auto">
300
+ <h2 class="text-xl font-bold text-green-400 mb-4"><i class="fas fa-info-circle mr-2"></i>游戏说明</h2>
301
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4 text-gray-300">
302
+ <div class="bg-gray-700 p-4 rounded-lg">
303
+ <h3 class="font-semibold text-green-300 mb-2"><i class="fas fa-keyboard mr-2"></i>控制方式</h3>
304
+ <p>键盘方向键或WASD控制蛇的移动方向</p>
305
+ <p>移动设备可使用屏幕上的方向按钮</p>
306
+ </div>
307
+ <div class="bg-gray-700 p-4 rounded-lg">
308
+ <h3 class="font-semibold text-green-300 mb-2"><i class="fas fa-star mr-2"></i>游戏目标</h3>
309
+ <p>控制蛇吃到食物(红色圆点)</p>
310
+ <p>每吃到一个食物,蛇身长度增加,分数增加</p>
311
+ </div>
312
+ <div class="bg-gray-700 p-4 rounded-lg">
313
+ <h3 class="font-semibold text-green-300 mb-2"><i class="fas fa-skull mr-2"></i>游戏结束</h3>
314
+ <p>蛇撞到墙壁(如果开启墙壁碰撞)</p>
315
+ <p>蛇撞到自己的身体</p>
316
+ <p>蛇撞到障碍物(如果开启障碍物)</p>
317
+ </div>
318
+ </div>
319
+ </div>
320
+ </footer>
321
+
322
+ <script>
323
+ // 游戏状态变量
324
+ let game = {
325
+ canvas: null,
326
+ ctx: null,
327
+ gridSize: 20,
328
+ width: 0,
329
+ height: 0,
330
+ snake: [],
331
+ direction: 'right',
332
+ nextDirection: 'right',
333
+ food: [],
334
+ obstacles: [],
335
+ score: 0,
336
+ isRunning: false,
337
+ isPaused: false,
338
+ gameLoop: null,
339
+ speed: 150,
340
+ wallCollision: true,
341
+ obstaclesEnabled: false,
342
+ growMode: false,
343
+ initialLength: 4,
344
+ foodCount: 1
345
+ };
346
+
347
+ // 颜色设置
348
+ const colors = {
349
+ snake: '#10B981',
350
+ food: '#EF4444',
351
+ grid: '#374151',
352
+ bg: '#111827',
353
+ obstacle: '#6B7280'
354
+ };
355
+
356
+ // DOM 元素
357
+ const elements = {
358
+ gameContainer: document.getElementById('game-canvas'),
359
+ scoreDisplay: document.getElementById('score-display'),
360
+ gameOver: document.getElementById('game-over'),
361
+ finalScore: document.getElementById('final-score'),
362
+ restartBtn: document.getElementById('restart-btn'),
363
+ startBtn: document.getElementById('start-btn'),
364
+ pauseBtn: document.getElementById('pause-btn'),
365
+ resetBtn: document.getElementById('reset-btn'),
366
+ settingsPanel: document.getElementById('settings-panel'),
367
+ settingsToggle: document.getElementById('settings-toggle'),
368
+ closeSettings: document.getElementById('close-settings'),
369
+ applySettings: document.getElementById('apply-settings'),
370
+ speedSlider: document.getElementById('speed-slider'),
371
+ speedValue: document.getElementById('speed-value'),
372
+ wallCollision: document.getElementById('wall-collision'),
373
+ obstacles: document.getElementById('obstacles'),
374
+ growMode: document.getElementById('grow-mode'),
375
+ initialLength: document.getElementById('initial-length'),
376
+ lengthValue: document.getElementById('length-value'),
377
+ foodCount: document.getElementById('food-count'),
378
+ foodCountValue: document.getElementById('food-count-value'),
379
+ gridSizeBtns: document.querySelectorAll('.grid-size-btn'),
380
+ colorPreviews: document.querySelectorAll('.color-preview'),
381
+ upBtn: document.getElementById('up-btn'),
382
+ downBtn: document.getElementById('down-btn'),
383
+ leftBtn: document.getElementById('left-btn'),
384
+ rightBtn: document.getElementById('right-btn')
385
+ };
386
+
387
+ // 初始化游戏
388
+ function initGame() {
389
+ // 获取游戏区域尺寸
390
+ const rect = elements.gameContainer.getBoundingClientRect();
391
+ game.width = Math.floor(rect.width / game.gridSize) * game.gridSize;
392
+ game.height = Math.floor(rect.height / game.gridSize) * game.gridSize;
393
+
394
+ // 创建画布
395
+ game.canvas = document.createElement('canvas');
396
+ game.canvas.width = game.width;
397
+ game.canvas.height = game.height;
398
+ game.canvas.classList.add('absolute');
399
+ elements.gameContainer.innerHTML = '';
400
+ elements.gameContainer.appendChild(game.canvas);
401
+ game.ctx = game.canvas.getContext('2d');
402
+
403
+ // 重置游戏状态
404
+ resetGame();
405
+
406
+ // 更新CSS变量
407
+ updateCSSVariables();
408
+ }
409
+
410
+ // 重置游戏
411
+ function resetGame() {
412
+ game.snake = [];
413
+ game.food = [];
414
+ game.obstacles = [];
415
+ game.direction = 'right';
416
+ game.nextDirection = 'right';
417
+ game.score = 0;
418
+ game.isRunning = false;
419
+ game.isPaused = false;
420
+
421
+ // 隐藏游戏结束画面
422
+ elements.gameOver.classList.add('hidden');
423
+
424
+ // 更新分数显示
425
+ updateScore();
426
+
427
+ // 创建初始蛇
428
+ createSnake();
429
+
430
+ // 创建食物
431
+ createFood();
432
+
433
+ // 创建障碍物(如果启用)
434
+ if (game.obstaclesEnabled) {
435
+ createObstacles();
436
+ }
437
+
438
+ // 绘制游戏
439
+ drawGame();
440
+ }
441
+
442
+ // 创建蛇
443
+ function createSnake() {
444
+ game.snake = [];
445
+ const startX = Math.floor(game.width / game.gridSize / 4) * game.gridSize;
446
+ const startY = Math.floor(game.height / game.gridSize / 2) * game.gridSize;
447
+
448
+ for (let i = 0; i < game.initialLength; i++) {
449
+ game.snake.push({
450
+ x: startX - i * game.gridSize,
451
+ y: startY
452
+ });
453
+ }
454
+ }
455
+
456
+ // 创建食物
457
+ function createFood() {
458
+ for (let i = 0; i < game.foodCount; i++) {
459
+ let newFood;
460
+ let overlapping;
461
+
462
+ do {
463
+ overlapping = false;
464
+ newFood = {
465
+ x: Math.floor(Math.random() * (game.width / game.gridSize)) * game.gridSize,
466
+ y: Math.floor(Math.random() * (game.height / game.gridSize)) * game.gridSize
467
+ };
468
+
469
+ // 检查是否与蛇重叠
470
+ for (const segment of game.snake) {
471
+ if (segment.x === newFood.x && segment.y === newFood.y) {
472
+ overlapping = true;
473
+ break;
474
+ }
475
+ }
476
+
477
+ // 检查是否与现有食物重叠
478
+ for (const food of game.food) {
479
+ if (food.x === newFood.x && food.y === newFood.y) {
480
+ overlapping = true;
481
+ break;
482
+ }
483
+ }
484
+
485
+ // 检查是否与障碍物重叠
486
+ for (const obstacle of game.obstacles) {
487
+ if (obstacle.x === newFood.x && obstacle.y === newFood.y) {
488
+ overlapping = true;
489
+ break;
490
+ }
491
+ }
492
+ } while (overlapping);
493
+
494
+ game.food.push(newFood);
495
+ }
496
+ }
497
+
498
+ // 创建障碍物
499
+ function createObstacles() {
500
+ const obstacleCount = Math.floor((game.width / game.gridSize) * (game.height / game.gridSize) * 0.05);
501
+
502
+ for (let i = 0; i < obstacleCount; i++) {
503
+ let newObstacle;
504
+ let overlapping;
505
+
506
+ do {
507
+ overlapping = false;
508
+ newObstacle = {
509
+ x: Math.floor(Math.random() * (game.width / game.gridSize)) * game.gridSize,
510
+ y: Math.floor(Math.random() * (game.height / game.gridSize)) * game.gridSize
511
+ };
512
+
513
+ // 检查是否与蛇重叠
514
+ for (const segment of game.snake) {
515
+ if (segment.x === newObstacle.x && segment.y === newObstacle.y) {
516
+ overlapping = true;
517
+ break;
518
+ }
519
+ }
520
+
521
+ // 检查是否与食物重叠
522
+ for (const food of game.food) {
523
+ if (food.x === newObstacle.x && food.y === newObstacle.y) {
524
+ overlapping = true;
525
+ break;
526
+ }
527
+ }
528
+
529
+ // 检查是否与其他障碍物重叠
530
+ for (const obstacle of game.obstacles) {
531
+ if (obstacle.x === newObstacle.x && obstacle.y === newObstacle.y) {
532
+ overlapping = true;
533
+ break;
534
+ }
535
+ }
536
+ } while (overlapping);
537
+
538
+ game.obstacles.push(newObstacle);
539
+ }
540
+ }
541
+
542
+ // 移动蛇
543
+ function moveSnake() {
544
+ if (!game.isRunning || game.isPaused) return;
545
+
546
+ // 更新方向
547
+ game.direction = game.nextDirection;
548
+
549
+ // 计算新头部位置
550
+ const head = {...game.snake[0]};
551
+
552
+ switch (game.direction) {
553
+ case 'up':
554
+ head.y -= game.gridSize;
555
+ break;
556
+ case 'down':
557
+ head.y += game.gridSize;
558
+ break;
559
+ case 'left':
560
+ head.x -= game.gridSize;
561
+ break;
562
+ case 'right':
563
+ head.x += game.gridSize;
564
+ break;
565
+ }
566
+
567
+ // 检查墙壁碰撞
568
+ if (game.wallCollision) {
569
+ if (head.x < 0 || head.x >= game.width || head.y < 0 || head.y >= game.height) {
570
+ gameOver();
571
+ return;
572
+ }
573
+ } else {
574
+ // 穿墙处理
575
+ if (head.x < 0) head.x = game.width - game.gridSize;
576
+ if (head.x >= game.width) head.x = 0;
577
+ if (head.y < 0) head.y = game.height - game.gridSize;
578
+ if (head.y >= game.height) head.y = 0;
579
+ }
580
+
581
+ // 检查自身碰撞
582
+ for (let i = 0; i < game.snake.length; i++) {
583
+ if (head.x === game.snake[i].x && head.y === game.snake[i].y) {
584
+ gameOver();
585
+ return;
586
+ }
587
+ }
588
+
589
+ // 检查障碍物碰撞
590
+ if (game.obstaclesEnabled) {
591
+ for (const obstacle of game.obstacles) {
592
+ if (head.x === obstacle.x && head.y === obstacle.y) {
593
+ gameOver();
594
+ return;
595
+ }
596
+ }
597
+ }
598
+
599
+ // 添加新头部
600
+ game.snake.unshift(head);
601
+
602
+ // 检查食物碰撞
603
+ let ateFood = false;
604
+ for (let i = 0; i < game.food.length; i++) {
605
+ if (head.x === game.food[i].x && head.y === game.food[i].y) {
606
+ // 移除被吃的食物
607
+ game.food.splice(i, 1);
608
+
609
+ // 增加分数
610
+ game.score += 10;
611
+ updateScore();
612
+
613
+ // 创建新食物
614
+ createFood();
615
+
616
+ ateFood = true;
617
+ break;
618
+ }
619
+ }
620
+
621
+ // 如果没有吃到食物,移除尾部
622
+ if (!ateFood && !game.growMode) {
623
+ game.snake.pop();
624
+ }
625
+
626
+ // 绘制游戏
627
+ drawGame();
628
+ }
629
+
630
+ // 绘制游戏
631
+ function drawGame() {
632
+ // 清除画布
633
+ game.ctx.clearRect(0, 0, game.width, game.height);
634
+
635
+ // 绘制蛇
636
+ for (let i = 0; i < game.snake.length; i++) {
637
+ const segment = game.snake[i];
638
+ game.ctx.fillStyle = i === 0 ? colors.snake : colors.snake;
639
+ game.ctx.fillRect(segment.x, segment.y, game.gridSize, game.gridSize);
640
+
641
+ // 添加特殊样式
642
+ if (i === 0) {
643
+ game.ctx.fillStyle = '#047857';
644
+ game.ctx.fillRect(segment.x + 2, segment.y + 2, game.gridSize - 4, game.gridSize - 4);
645
+ } else {
646
+ game.ctx.fillStyle = '#065F46';
647
+ game.ctx.fillRect(segment.x + 1, segment.y + 1, game.gridSize - 2, game.gridSize - 2);
648
+ }
649
+ }
650
+
651
+ // 绘制食物
652
+ for (const food of game.food) {
653
+ game.ctx.fillStyle = colors.food;
654
+ game.ctx.beginPath();
655
+ game.ctx.arc(food.x + game.gridSize/2, food.y + game.gridSize/2, game.gridSize/2 - 1, 0, Math.PI * 2);
656
+ game.ctx.fill();
657
+
658
+ // 添加高光
659
+ game.ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
660
+ game.ctx.beginPath();
661
+ game.ctx.arc(food.x + game.gridSize/3, food.y + game.gridSize/3, game.gridSize/6, 0, Math.PI * 2);
662
+ game.ctx.fill();
663
+ }
664
+
665
+ // 绘制障碍物
666
+ for (const obstacle of game.obstacles) {
667
+ game.ctx.fillStyle = colors.obstacle;
668
+ game.ctx.fillRect(obstacle.x, obstacle.y, game.gridSize, game.gridSize);
669
+
670
+ // 添加纹理
671
+ game.ctx.fillStyle = '#4B5563';
672
+ game.ctx.fillRect(obstacle.x + 2, obstacle.y + 2, game.gridSize - 4, game.gridSize - 4);
673
+ }
674
+ }
675
+
676
+ // 游戏结束
677
+ function gameOver() {
678
+ game.isRunning = false;
679
+ clearInterval(game.gameLoop);
680
+
681
+ // 显示游戏结束画面
682
+ elements.finalScore.textContent = game.score;
683
+ elements.gameOver.classList.remove('hidden');
684
+ }
685
+
686
+ // 开始游戏
687
+ function startGame() {
688
+ if (game.isRunning) return;
689
+
690
+ game.isRunning = true;
691
+ game.isPaused = false;
692
+
693
+ // 开始游戏循环
694
+ game.gameLoop = setInterval(moveSnake, 300 - game.speed);
695
+ }
696
+
697
+ // 暂停游戏
698
+ function pauseGame() {
699
+ if (!game.isRunning) return;
700
+
701
+ game.isPaused = !game.isPaused;
702
+
703
+ if (game.isPaused) {
704
+ clearInterval(game.gameLoop);
705
+ elements.pauseBtn.innerHTML = '<i class="fas fa-play mr-2"></i>继续';
706
+ } else {
707
+ game.gameLoop = setInterval(moveSnake, 300 - game.speed);
708
+ elements.pauseBtn.innerHTML = '<i class="fas fa-pause mr-2"></i>暂停';
709
+ }
710
+ }
711
+
712
+ // 更新分数显示
713
+ function updateScore() {
714
+ elements.scoreDisplay.textContent = `分数: ${game.score}`;
715
+ }
716
+
717
+ // 更新CSS变量
718
+ function updateCSSVariables() {
719
+ document.documentElement.style.setProperty('--grid-size', `${game.gridSize}px`);
720
+ document.documentElement.style.setProperty('--grid-color', colors.grid);
721
+ document.documentElement.style.setProperty('--snake-color', colors.snake);
722
+ document.documentElement.style.setProperty('--food-color', colors.food);
723
+ document.documentElement.style.setProperty('--obstacle-color', colors.obstacle);
724
+ document.documentElement.style.setProperty('--bg-color', colors.bg);
725
+ document.documentElement.style.setProperty('--speed', game.speed);
726
+ }
727
+
728
+ // 应用设置
729
+ function applySettings() {
730
+ // 更新游戏设置
731
+ game.speed = parseInt(elements.speedSlider.value);
732
+ game.wallCollision = elements.wallCollision.checked;
733
+ game.obstaclesEnabled = elements.obstacles.checked;
734
+ game.growMode = elements.growMode.checked;
735
+ game.initialLength = parseInt(elements.initialLength.value);
736
+ game.foodCount = parseInt(elements.foodCount.value);
737
+
738
+ // 更新速度显示
739
+ if (game.speed < 100) {
740
+ elements.speedValue.textContent = '慢';
741
+ } else if (game.speed < 200) {
742
+ elements.speedValue.textContent = '中等';
743
+ } else {
744
+ elements.speedValue.textContent = '快';
745
+ }
746
+
747
+ // 更新长度显示
748
+ elements.lengthValue.textContent = game.initialLength;
749
+
750
+ // 更新食物数量显示
751
+ elements.foodCountValue.textContent = game.foodCount;
752
+
753
+ // 重新初始化游戏
754
+ initGame();
755
+
756
+ // 关闭设置面板
757
+ elements.settingsPanel.classList.add('hidden');
758
+ }
759
+
760
+ // 事件监听器
761
+ function setupEventListeners() {
762
+ // 键盘控制
763
+ document.addEventListener('keydown', (e) => {
764
+ if (!game.isRunning) return;
765
+
766
+ switch (e.key) {
767
+ case 'ArrowUp':
768
+ case 'w':
769
+ case 'W':
770
+ if (game.direction !== 'down') game.nextDirection = 'up';
771
+ break;
772
+ case 'ArrowDown':
773
+ case 's':
774
+ case 'S':
775
+ if (game.direction !== 'up') game.nextDirection = 'down';
776
+ break;
777
+ case 'ArrowLeft':
778
+ case 'a':
779
+ case 'A':
780
+ if (game.direction !== 'right') game.nextDirection = 'left';
781
+ break;
782
+ case 'ArrowRight':
783
+ case 'd':
784
+ case 'D':
785
+ if (game.direction !== 'left') game.nextDirection = 'right';
786
+ break;
787
+ }
788
+ });
789
+
790
+ // 按钮事件
791
+ elements.startBtn.addEventListener('click', startGame);
792
+ elements.pauseBtn.addEventListener('click', pauseGame);
793
+ elements.resetBtn.addEventListener('click', resetGame);
794
+ elements.restartBtn.addEventListener('click', resetGame);
795
+
796
+ // 设置面板事件
797
+ elements.settingsToggle.addEventListener('click', () => {
798
+ elements.settingsPanel.classList.remove('hidden');
799
+ });
800
+
801
+ elements.closeSettings.addEventListener('click', () => {
802
+ elements.settingsPanel.classList.add('hidden');
803
+ });
804
+
805
+ elements.applySettings.addEventListener('click', applySettings);
806
+
807
+ // 网格大小按钮
808
+ elements.gridSizeBtns.forEach(btn => {
809
+ btn.addEventListener('click', () => {
810
+ elements.gridSizeBtns.forEach(b => b.classList.remove('bg-green-600'));
811
+ btn.classList.add('bg-green-600');
812
+ game.gridSize = parseInt(btn.dataset.size);
813
+ initGame();
814
+ });
815
+ });
816
+
817
+ // 颜色选择
818
+ elements.colorPreviews.forEach(preview => {
819
+ preview.addEventListener('click', () => {
820
+ const color = preview.dataset.color;
821
+ const role = preview.parentElement.querySelector('label').textContent;
822
+
823
+ switch (role) {
824
+ case '蛇的颜色':
825
+ colors.snake = color;
826
+ break;
827
+ case '食物颜色':
828
+ colors.food = color;
829
+ break;
830
+ case '网格颜色':
831
+ colors.grid = color;
832
+ break;
833
+ case '背景颜色':
834
+ colors.bg = color;
835
+ break;
836
+ }
837
+
838
+ updateCSSVariables();
839
+ drawGame();
840
+ });
841
+ });
842
+
843
+ // 滑块事件
844
+ elements.speedSlider.addEventListener('input', () => {
845
+ const speed = parseInt(elements.speedSlider.value);
846
+ if (speed < 100) {
847
+ elements.speedValue.textContent = '慢';
848
+ } else if (speed < 200) {
849
+ elements.speedValue.textContent = '中等';
850
+ } else {
851
+ elements.speedValue.textContent = '快';
852
+ }
853
+ });
854
+
855
+ elements.initialLength.addEventListener('input', () => {
856
+ elements.lengthValue.textContent = elements.initialLength.value;
857
+ });
858
+
859
+ elements.foodCount.addEventListener('input', () => {
860
+ elements.foodCountValue.textContent = elements.foodCount.value;
861
+ });
862
+
863
+ // 移动设备控制按钮
864
+ elements.upBtn.addEventListener('click', () => {
865
+ if (game.direction !== 'down') game.nextDirection = 'up';
866
+ });
867
+
868
+ elements.downBtn.addEventListener('click', () => {
869
+ if (game.direction !== 'up') game.nextDirection = 'down';
870
+ });
871
+
872
+ elements.leftBtn.addEventListener('click', () => {
873
+ if (game.direction !== 'right') game.nextDirection = 'left';
874
+ });
875
+
876
+ elements.rightBtn.addEventListener('click', () => {
877
+ if (game.direction !== 'left') game.nextDirection = 'right';
878
+ });
879
+ }
880
+
881
+ // 页面加载完成后初始化
882
+ window.addEventListener('load', () => {
883
+ initGame();
884
+ setupEventListeners();
885
+ });
886
+
887
+ // 响应窗口大小变化
888
+ window.addEventListener('resize', initGame);
889
+ </script>
890
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=erdes/snake" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
891
+ </html>