科学教育

标题: aaa [打印本页]

作者: 张葉彬    时间: 2025-12-30 09:44
标题: aaa
解释css中position属性的4个取值,并简述它们的作用


作者: kaia    时间: 2025-12-30 09:44
你好!我来帮你讲讲CSS里面的position属性和它的4个主要取值。我们用一个“盒子”来形象理解它们的位置哦。

1. **static(静态)**  
这是默认的状态,就像盒子站在排队的队伍里,按照大家排好的顺序一个接一个摆放。不会特别移动,也不会重叠。网页里的元素默认都是static的。

2. **relative(相对定位)**  
想象盒子在原本的位置上打了个标记,现在可以稍微往上、下、左、右挪动一点点,但它还是占着原来的那个位置。就像你坐在椅子上,稍微挪挪身体,但椅子还在原地。

3. **absolute(绝对定位)**  
这就像盒子突然“飞”出来,不管别的盒子怎么排,它都能自由移动到网页里指定的地方。它的位置是相对于最近的有定位的父盒子定的,如果没有,就以网页为参考点。

4. **fixed(固定定位)**  
这个盒子好像“钉”在屏幕上,不管你滚动网页,它都不会动。比如网页上固定在角落的“返回顶部”按钮,就是用fixed定位做的。

总结一下:  
- static:按正常顺序排队  
- relative:稍微挪一挪,位置相对原点变化  
- absolute:自由飞出,位置固定不跟随其他元素  
- fixed:钉死在屏幕上,滚动页面也不动

希望这样讲你能懂啦!如果想要学习怎么写这些代码,也可以告诉我哦。
作者: 张葉彬    时间: 2025-12-30 09:47
编写一个java函数,实现鼠标划过一个元素时改变其颜色
作者: kaia    时间: 2025-12-30 09:47
张葉彬 发表于 2025-12-30 09:47
编写一个java函数,实现鼠标划过一个元素时改变其颜色 ...


你好!你想让鼠标划过网页上的元素时改变颜色,这其实是网页编程里的一个常见效果。用Java本身是不直接控制网页的,但我们可以用JavaScript和CSS来实现这个效果。如果你是用Java做桌面程序,也不太一样哦。

这里我先给你讲怎样用**JavaScript**配合HTML实现“鼠标划过元素变颜色”的效果,因为这是网页上最常用的做法。

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.   <style>
  5.     /* 元素的默认颜色 */
  6.     #myElement {
  7.       width: 150px;
  8.       height: 50px;
  9.       background-color: lightblue;
  10.       line-height: 50px;
  11.       text-align: center;
  12.       user-select: none; /* 不让文字被选中 */
  13.       cursor: pointer; /* 鼠标放上去变成手指 */
  14.     }
  15.   </style>
  16. </head>
  17. <body>

  18. <div id="myElement">鼠标划过我</div>

  19. <script>
  20.   // 获取页面上的元素
  21.   var elem = document.getElementById("myElement");
  22.   
  23.   // 鼠标划入时触发函数,改变背景色
  24.   elem.addEventListener("mouseover", function() {
  25.     elem.style.backgroundColor = "orange";
  26.   });
  27.   
  28.   // 鼠标移出时恢复原来的颜色
  29.   elem.addEventListener("mouseout", function() {
  30.     elem.style.backgroundColor = "lightblue";
  31.   });
  32. </script>

  33. </body>
  34. </html>
复制代码


**解释:**  
- 我们选中id是“myElement”的盒子,它默认是浅蓝色。  
- 当鼠标划过它(mouseover事件)时,把背景改成橙色。  
- 鼠标移开(mouseout事件)时,颜色改回浅蓝。  

如果你学习了Java后,想做网页项目,JavaScript是跟网页交互的语言,和Java是不同的哦。

如果你想用Java写桌面程序(比如用Swing),可以告诉我,我再帮你写一个Java的例子。

希望这可以帮到你!如果想试试代码,可以复制到浏览器打开看看效果~
作者: 张葉彬    时间: 2025-12-30 09:53
写一个贪吃蛇游戏,html,多陷阱,多恐怖元素

作者: kaia    时间: 2025-12-30 09:53
张葉彬 发表于 2025-12-30 09:53
写一个贪吃蛇游戏,html,多陷阱,多恐怖元素 ...


好哒!我帮你写一个简单版的贪吃蛇游戏,用HTML和JavaScript实现。里面会加一些“陷阱”和“恐怖元素”让游戏更刺激哦!

游戏规则:  
- 用键盘上下左右控制蛇移动。  
- 吃到食物,蛇会变长。  
- 碰到陷阱或墙壁,游戏结束。  
- “恐怖元素”会随机出现,让蛇速度变快。  

先给你代码,你可以复制到浏览器里运行试试~


  1. <!DOCTYPE html>
  2. <html lang="zh">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <title>恐怖贪吃蛇</title>
  6. <style>
  7.   body {
  8.     background-color: black;
  9.     color: white;
  10.     text-align: center;
  11.     font-family: '微软雅黑', sans-serif;
  12.   }
  13.   #gameCanvas {
  14.     background-color: #111; /* 深黑背景 */
  15.     display: block;
  16.     margin: 20px auto;
  17.     border: 2px solid red;
  18.   }
  19.   #status {
  20.     margin-top: 10px;
  21.     font-size: 20px;
  22.     color: red;
  23.     font-weight: bold;
  24.   }
  25. </style>
  26. </head>
  27. <body>

  28. <h1>恐怖贪吃蛇游戏????️????️</h1>
  29. <canvas id="gameCanvas" width="400" height="400"></canvas>
  30. <div id="status"></div>
  31. <p>用方向键控制蛇移动。<br>吃到绿色食物变长。撞到红色陷阱或边界游戏结束。出现紫色恐怖加速元素,吃了会加快蛇速!</p>

  32. <script>
  33. const canvas = document.getElementById('gameCanvas');
  34. const ctx = canvas.getContext('2d');

  35. const gridSize = 20; // 网格大小
  36. const tileCount = canvas.width / gridSize;

  37. let snake = [{x:10, y:10}];
  38. let direction = {x:0, y:0};
  39. let food = null;
  40. let traps = [];
  41. let horror = null;
  42. let speed = 200; // 蛇移动间隔(ms)
  43. let gameInterval;

  44. let score = 0;
  45. let statusDiv = document.getElementById('status');
  46. let gameOver = false;

  47. // 随机生成位置,不和蛇身体重叠
  48. function randomPosition() {
  49.   let pos;
  50.   do {
  51.     pos = {
  52.       x: Math.floor(Math.random() * tileCount),
  53.       y: Math.floor(Math.random() * tileCount)
  54.     };
  55.   } while(snake.some(s => s.x === pos.x && s.y === pos.y) ||
  56.           (food && food.x === pos.x && food.y === pos.y) ||
  57.           traps.some(t => t.x === pos.x && t.y === pos.y) ||
  58.           (horror && horror.x === pos.x && horror.y === pos.y));
  59.   return pos;
  60. }

  61. // 生成食物、陷阱、恐怖块
  62. function generateFood() {
  63.   food = randomPosition();
  64. }

  65. function generateTraps(count=5) {
  66.   traps = [];
  67.   for(let i=0;i<count;i++) {
  68.     traps.push(randomPosition());
  69.   }
  70. }

  71. function generateHorror() {
  72.   horror = randomPosition();
  73. }

  74. // 画方块
  75. function drawBlock(x, y, color) {
  76.   ctx.fillStyle = color;
  77.   ctx.fillRect(x*gridSize, y*gridSize, gridSize - 2, gridSize - 2);
  78. }

  79. // 游戏结束
  80. function endGame() {
  81.   clearInterval(gameInterval);
  82.   gameOver = true;
  83.   statusDiv.innerText = `游戏结束!你的分数是: ${score} ????️????`;
  84. }

  85. // 主循环
  86. function gameLoop() {
  87.   if(gameOver) return;

  88.   // 新蛇头位置
  89.   let newX = snake[0].x + direction.x;
  90.   let newY = snake[0].y + direction.y;

  91.   // 撞墙检测
  92.   if(newX < 0 || newX >= tileCount || newY < 0 || newY >= tileCount) {
  93.     endGame();
  94.     return;
  95.   }

  96.   // 碰自己检测
  97.   if(snake.some(s => s.x === newX && s.y === newY)) {
  98.     endGame();
  99.     return;
  100.   }

  101.   // 更新蛇头
  102.   snake.unshift({x:newX, y:newY});

  103.   // 吃食物
  104.   if(food && newX === food.x && newY === food.y) {
  105.     score++;
  106.     generateFood();
  107.     // 每吃满3个,随机增加陷阱数量,增加难度
  108.     if(score % 3 === 0) {
  109.       generateTraps(traps.length + 2);
  110.     }
  111.     // 鼓励词
  112.     statusDiv.innerText = `太棒了!吃到食物,分数: ${score}`;
  113.   } else {
  114.     // 没吃食物,尾巴消失
  115.     snake.pop();
  116.   }

  117.   // 碰到陷阱
  118.   if(traps.some(t => t.x === newX && t.y === newY)) {
  119.     endGame();
  120.     return;
  121.   }

  122.   // 吃到恐怖元素,加速效果
  123.   if(horror && newX === horror.x && newY === horror.y) {
  124.     speed = Math.max(50, speed - 50); // 最快速度限制50ms
  125.     clearInterval(gameInterval);
  126.     gameInterval = setInterval(gameLoop, speed);

  127.     statusDiv.innerText = `啊!被恐怖元素附身,速度+快!当前速度: ${speed}ms`;
  128.     horror = null;
  129.     // 3秒后重新生成恐怖元素
  130.     setTimeout(generateHorror, 3000);
  131.   }

  132.   // 清屏
  133.   ctx.clearRect(0, 0, canvas.width, canvas.height);

  134.   // 画食物 - 绿色
  135.   if(food) drawBlock(food.x, food.y, 'limegreen');

  136.   // 画陷阱 - 红色
  137.   for(let t of traps) {
  138.     drawBlock(t.x, t.y, 'red');
  139.   }

  140.   // 画恐怖元素 - 紫色
  141.   if(horror) drawBlock(horror.x, horror.y, 'purple');

  142.   // 画蛇 - 白色
  143.   for(let i=0; i<snake.length; i++) {
  144.     drawBlock(snake[i].x, snake[i].y, i === 0 ? 'white' : 'gray');
  145.   }
  146. }

  147. // 控制方向
  148. window.addEventListener('keydown', e => {
  149.   // 防止按反方向直接撞自己
  150.   if(e.key === 'ArrowUp' && direction.y !== 1) {
  151.     direction = {x:0, y:-1};
  152.   } else if(e.key === 'ArrowDown' && direction.y !== -1) {
  153.     direction = {x:0, y:1};
  154.   } else if(e.key === 'ArrowLeft' && direction.x !==1) {
  155.     direction = {x:-1, y:0};
  156.   } else if(e.key === 'ArrowRight' && direction.x !== -1) {
  157.     direction = {x:1, y:0};
  158.   }
  159. });

  160. // 初始化游戏
  161. function initGame() {
  162.   snake = [{x: 10, y: 10}];
  163.   direction = {x:0, y:0};
  164.   score = 0;
  165.   speed = 200;
  166.   gameOver = false;
  167.   generateFood();
  168.   generateTraps(5);
  169.   generateHorror();
  170.   statusDiv.innerText = '游戏开始!使用方向键控制蛇移动!';
  171.   clearInterval(gameInterval);
  172.   gameInterval = setInterval(gameLoop, speed);
  173. }

  174. initGame();

  175. </script>

  176. </body>
  177. </html>
复制代码


### 说明:  
- **红色陷阱**是游戏里的危险区,碰到就游戏结束。  
- **紫色恐怖元素**吃到后蛇会变得更快,更刺激玩耍!  
- 跟普通贪吃蛇游戏不一样,背景是漆黑的,边框是红色,增加恐怖气氛。  
- 有提示文字告诉你当前状态。  

你可以试试这个游戏,慢慢练习控制蛇多吃食物。玩累了可以刷新页面重新开始哦~

希望你喜欢这个小恐怖版贪吃蛇游戏!如果还有其他想法或者想加功能,告诉我,我帮你!
作者: 张葉彬    时间: 2025-12-30 09:55
更恐怖,更多陷阱,更多随机
作者: kaia    时间: 2025-12-30 09:55
张葉彬 发表于 2025-12-30 09:55
更恐怖,更多陷阱,更多随机


好哒!我帮你把游戏变得更恐怖,增加更多陷阱和更多随机元素,让游戏更刺激惊险!
主要改进:
- 陷阱数量更多,而且每次吃完食物后陷阱会重新随机刷新。
- 增加迷雾效果,让视野变窄,看不到全局。
- 恐怖元素多个出现,速度波动更大更不稳定。
- 随机出现黑暗闪烁(画面瞬间变黑再恢复),增加惊悚感。
- 加一些恐怖文字提示。
  
你把下面完整代码复制到浏览器打开试试吧:






恐怖贪吃蛇加强版

  body {
    background-color: black;
    color: white;
    text-align: center;
    font-family: '微软雅黑', sans-serif;
  }
  #gameCanvas {
    background-color: #111;
    display: block;
    margin: 20px auto;
    border: 3px solid darkred;
    filter: brightness(0.6);
    position: relative;
  }
  #status {
    margin-top: 10px;
    font-size: 18px;
    color: red;
    font-weight: bold;
    height: 24px;
  }
  #fog {
    position: absolute;
    top: 0; left: 0;
    width: 400px; height: 400px;
    pointer-events: none;
  }



恐怖贪吃蛇加强版????️????️


用方向键控制蛇移动。  
红色陷阱碰了游戏结束。  
绿色食物吃了变长。  
紫色恐怖元素吃了让蛇速度更快或更慢,不可预测!  
黑色迷雾让视野很有限,随机闪烁黑暗增加恐怖气氛!


const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const fogCanvas = document.createElement('canvas');
fogCanvas.width = canvas.width;
fogCanvas.height = canvas.height;
const fogCtx = fogCanvas.getContext('2d');
document.getElementById('gameContainer').appendChild(fogCanvas);

const gridSize = 20;
const tileCount = canvas.width / gridSize;

let snake = [];
let direction = {x:0, y:0};
let food = null;
let traps = [];
let horrors = [];
let speed = 200;
let gameInterval;
let score = 0;
let gameOver = false;

const statusDiv = document.getElementById('status');

// 生成随机坐标,不与蛇体、食物、陷阱和恐怖元素重叠
function randomPosition() {
  let pos;
  do {
    pos = {
      x: Math.floor(Math.random() * tileCount),
      y: Math.floor(Math.random() * tileCount)
    };
  } while(
    snake.some(s => s.x === pos.x && s.y === pos.y) ||
    (food && food.x === pos.x && food.y === pos.y) ||
    traps.some(t => t.x === pos.x && t.y === pos.y) ||
    horrors.some(h => h.x === pos.x && h.y === pos.y)
  );
  return pos;
}

function generateFood() {
  food = randomPosition();
}

function generateTraps(count=10) {
  traps = [];
  for(let i=0;i<count;i++) {
    traps.push(randomPosition());
  }
}

function generateHorrors(count=3) {
  horrors = [];
  for(let i=0;i<count;i++) {
    horrors.push(randomPosition());
  }
}

// 黑暗闪烁特效
function flickerDarkness(){
  let flickerTimes = 5;
  let count = 0;
  let flickerInterval = setInterval(() => {
    if(count % 2 === 0){
      ctx.fillStyle = 'rgba(0,0,0,0.8)';
      ctx.fillRect(0,0,canvas.width,canvas.height);
    } else {
      drawGame();
    }
    count++;
    if(count > flickerTimes*2){
      clearInterval(flickerInterval);
    }
  },100);
}

// 迷雾效果(只显示蛇头附近区域)
function drawFog(){
  fogCtx.clearRect(0,0,fogCanvas.width,fogCanvas.height);
  fogCtx.fillStyle = 'rgba(0,0,0,0.95)';
  fogCtx.fillRect(0,0,fogCanvas.width,fogCanvas.height);

  if(snake.length === 0) return;
  const head = snake[0];
  const radius = 60;

  let centerX = head.x * gridSize + gridSize/2;
  let centerY = head.y * gridSize + gridSize/2;

  let gradient = fogCtx.createRadialGradient(centerX, centerY, radius/4, centerX, centerY, radius);
  gradient.addColorStop(0, 'rgba(0,0,0,0)');
  gradient.addColorStop(1, 'rgba(0,0,0,0.95)');

  fogCtx.globalCompositeOperation = 'destination-out';
  fogCtx.fillStyle = gradient;
  fogCtx.beginPath();
  fogCtx.arc(centerX, centerY, radius, 0, Math.PI*2);
  fogCtx.fill();
  fogCtx.globalCompositeOperation = 'source-over';
}

function drawBlock(x,y,color) {
  ctx.fillStyle = color;
  ctx.fillRect(x*gridSize, y*gridSize, gridSize-1, gridSize-1);
}

function drawGame() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // 画食物
  if(food) drawBlock(food.x, food.y, 'limegreen');

  // 画陷阱
  for(let t of traps) drawBlock(t.x, t.y, 'red');

  // 画恐怖元素
  for(let h of horrors) drawBlock(h.x, h.y, 'purple');

  // 画蛇身
  for(let i=0; i< snake.length; i++) {
    let col = i===0 ? 'white' : 'gray';
    drawBlock(snake.x, snake.y, col);
  }

  drawFog();
}

function endGame() {
  clearInterval(gameInterval);
  gameOver = true;
  statusDiv.innerText = `游戏结束!最终得分: ${score}. 带着恐惧离开吧...`;
}

function gameLoop() {
  if(gameOver) return;
  if(direction.x === 0 && direction.y === 0) return; // 游戏开始前不动

  let head = snake[0];
  let newX = head.x + direction.x;
  let newY = head.y + direction.y;

  // 撞墙
  if(newX < 0 || newX >= tileCount || newY <0 || newY >= tileCount){
    endGame();
    return;
  }

  // 撞自己
  if(snake.some(s => s.x === newX && s.y === newY)){
    endGame();
    return;
  }

  // 新蛇头加入
  snake.unshift({x:newX, y:newY});

  // 吃食物
  if(food && newX === food.x && newY === food.y){
    score++;
    generateFood();
    generateTraps(10 + Math.floor(score/2)); // 陷阱越来越多
    generateHorrors(3 + Math.floor(score/3)); // 恐怖元素越来越多
    statusDiv.innerText = `幸存者,你击败了一部分陷阱!当前分数:${score}`;

    // 每次吃完食物,随机触发恐怖闪烁
    if(Math.random() < 0.5) {
      flickerDarkness();
    }
  } else {
    // 没吃食物,尾巴缩短
    snake.pop();
  }

  // 碰陷阱
  if(traps.some(t => t.x === newX && t.y === newY)){
    endGame();
    return;
  }

  // 吃恐怖元素,速度可能变快或变慢,很随机,增添恐怖感
  for(let i=0;i<horrors.length;i++){
    let h = horrors;
    if(h.x === newX && h.y === newY){
      let oldSpeed = speed;
      if(Math.random() < 0.5){
        speed = Math.max(50, speed - 40); // 加速
        statusDiv.innerText = `???你感到心跳加速!!!速度提高啦!`;
      } else {
        speed = Math.min(500, speed + 60); // 减速
        statusDiv.innerText = `...脚步变得沉重,速度降低...`;
      }
      clearInterval(gameInterval);
      gameInterval = setInterval(gameLoop, speed);
      horrors.splice(i,1);
      break;
    }
  }

  drawGame();
}

window.addEventListener('keydown', e => {
  if(e.key === 'ArrowUp' && direction.y !== 1) {
    direction = {x:0, y:-1};
  } else if(e.key === 'ArrowDown' && direction.y !== -1) {
    direction = {x:0, y:1};
  } else if(e.key === 'ArrowLeft' && direction.x !== 1) {
    direction = {x:-1, y:0};
  } else if(e.key === 'ArrowRight' && direction.x !== -1) {
    direction = {x:1, y:0};
  }

  // 按R重置游戏
  if(e.key.toLowerCase() === 'r' && gameOver){
    initGame();
  }
});

function initGame() {
  snake = [{x:10, y:10}];
  direction = {x:0, y:0};
  score = 0;
  speed = 200;
  gameOver = false;
  generateFood();
  generateTraps(10);
  generateHorrors(3);
  statusDiv.innerText = '游戏开始!用方向键控制蛇,R键重置。';
  clearInterval(gameInterval);
  gameInterval = setInterval(gameLoop, speed);
}

initGame();  

  

### 玩法提示:

- 红色陷阱是致命的,千万别撞上!  
- 紫色恐怖元素吃了会让你速度忽快忽慢,小心脚步不稳!  
- 屏幕中央有一圈模糊的迷雾,只能看到蛇头附近的区域。  
- 随机黑暗闪烁会突然遮住整个屏幕,吓你一跳!  
- 游戏结束后按“R”键重置,继续挑战恐怖深渊!

玩的开心!需要更酷的功能随时告诉我哦~
作者: 张葉彬    时间: 2025-12-30 09:56
更多恐怖文字
作者: kaia    时间: 2025-12-30 09:57


好的!我帮你在游戏里增加更多恐怖气氛的文字提示,每当发生特别事情(比如吃到食物、碰到陷阱、速度变化,或者黑暗闪烁)时,都会弹出一些吓人的话让你更有沉浸感。

这是修改版代码中的关键部分,你可以把它们替换到之前的代码里:

  1. // 增加恐怖提示文字列表
  2. const scaryMessages = [
  3.   "你听到了脚步声……",
  4.   "黑暗中有什么东西在盯着你!",
  5.   "呼吸变得急促……你感到不安",
  6.   "远处传来诡异的低语……",
  7.   "一股寒意顺着脊背爬上来……",
  8.   "迷雾中突然闪过一双红眼!",
  9.   "你的心跳开始加速……",
  10.   "沉默的房间里传来敲击声……",
  11.   "不远处似乎有人在追踪你!",
  12.   "恐惧席卷而来,无法逃脱……"
  13. ];

  14. // 在状态栏显示随机恐怖提示
  15. function showScaryMessage() {
  16.   let msg = scaryMessages[Math.floor(Math.random() * scaryMessages.length)];
  17.   statusDiv.innerText = msg;
  18. }

  19. // 修改以下事件调用showScaryMessage()

  20. // 吃食物时随机显示
  21. if(food && newX === food.x && newY === food.y){
  22.   score++;
  23.   generateFood();
  24.   generateTraps(10 + Math.floor(score/2));
  25.   generateHorrors(3 + Math.floor(score/3));

  26.   if(Math.random() < 0.7) {
  27.     showScaryMessage();
  28.   } else {
  29.     statusDiv.innerText = `幸存者,你击败了一部分陷阱!当前分数:${score}`;
  30.   }

  31.   // 恐怖闪烁有额外信息
  32.   if(Math.random() < 0.5) {
  33.     flickerDarkness();
  34.     setTimeout(() => {
  35.       showScaryMessage();
  36.     }, 500);
  37.   }
  38. }

  39. // 碰到陷阱时显示特别文字
  40. if(traps.some(t => t.x === newX && t.y === newY)){
  41.   statusDiv.innerText = "陷阱抓住了你,绝望笼罩一切……";
  42.   endGame();
  43.   return;
  44. }

  45. // 吃恐怖元素,加速或减速时显示恐怖感受
  46. for(let i=0;i < horrors.length; i++){
  47.   let h = horrors[i];
  48.   if(newX === h.x && newY === h.y){
  49.     let oldSpeed = speed;
  50.     let change = (Math.random() < 0.5 ? -1 : 1) * 30 * (1 + Math.random());
  51.     speed = Math.min(400, Math.max(50, speed + change));
  52.     clearInterval(gameInterval);
  53.     gameInterval = setInterval(gameLoop, speed);

  54.     let feeling = change > 0 ? "你的心跳骤然加快" : "突然一阵寒意袭来,速度放慢";
  55.     statusDiv.innerText = feeling + "。当前速度: " + Math.round(speed) + "ms";

  56.     setTimeout(() => {
  57.       showScaryMessage();
  58.     }, 1000);

  59.     horrors.splice(i,1);
  60.     break;
  61.   }
  62. }

  63. // 黑暗闪烁时增加恐怖提示
  64. function flickerDarkness(){
  65.   let flickerTimes = 6;
  66.   let count = 0;
  67.   let flickerInterval = setInterval(() =>{
  68.     if(count % 2 ===0){
  69.       ctx.fillStyle = 'rgba(0,0,0,0.9)';
  70.       ctx.fillRect(0,0,canvas.width, canvas.height);
  71.       statusDiv.innerText = "黑暗如潮水般吞噬了视线……";
  72.     } else {
  73.       drawGame();
  74.       showScaryMessage();
  75.     }
  76.     count++;
  77.     if(count > flickerTimes*2){
  78.       clearInterval(flickerInterval);
  79.     }
  80.   }, 150);
  81. }
复制代码


这段代码是给你:

- 一个`scaryMessages`数组,里面装着各种恐怖的句子。  
- 每当吃食物后,或者恐怖闪烁出现时,会随机显示一句恐怖话。  
- 遇到陷阱有专门的恐怖提示。  
- 吃到恐怖元素让速度变化时,也会显示对应的恐怖心理描写,并且之后出现一句恐怖话。  
- 黑暗闪烁的时候屏幕覆盖黑色同时出现恐怖文字,震撼效果更加明显。

你只要把这些代码合并到之前的游戏代码里,就能让游戏的恐怖氛围更加浓厚啦!

如果你需要我帮你整合完整代码版本,或者想加别的特殊恐怖机制,告诉我,我乐意继续帮你打磨!祝你玩得刺激又开心~~????????
作者: 张葉彬    时间: 2025-12-30 09:57
完整代码
作者: kaia    时间: 2025-12-30 09:58


你好!下面是帮你整合后的完整“恐怖贪吃蛇加强版”游戏代码,里面包含了更多陷阱、随机元素和丰富的恐怖文字提示。你可以直接复制这段代码到一个HTML文件里,然后用浏览器打开,就能体验这个更恐怖、更刺激的贪吃蛇游戏啦!

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4.   <meta charset="UTF-8" />
  5.   <title>恐怖贪吃蛇加强版</title>
  6.   <style>
  7.     body {
  8.       background-color: black;
  9.       color: white;
  10.       text-align: center;
  11.       font-family: '微软雅黑', sans-serif;
  12.       user-select: none;
  13.     }
  14.     #gameContainer {
  15.       position: relative;
  16.       width: 400px;
  17.       margin: 20px auto;
  18.     }
  19.     #gameCanvas {
  20.       background-color: #111;
  21.       border: 3px solid darkred;
  22.       display: block;
  23.     }
  24.     #fog {
  25.       position: absolute;
  26.       top: 0; left: 0;
  27.       width: 400px; height: 400px;
  28.       pointer-events: none;
  29.       z-index: 10;
  30.     }
  31.     #status {
  32.       margin-top: 10px;
  33.       font-size: 18px;
  34.       color: red;
  35.       font-weight: bold;
  36.       height: 24px;
  37.       min-height: 24px;
  38.       user-select: none;
  39.     }
  40.     h1 {
  41.       color: crimson;
  42.     }
  43.     p.instructions {
  44.       max-width: 400px;
  45.       margin: 0 auto 10px;
  46.       font-size: 14px;
  47.       color: #f55;
  48.       line-height: 1.4;
  49.     }
  50.   </style>
  51. </head>
  52. <body>
  53.   <h1>恐怖贪吃蛇加强版</h1>
  54.   <p class="instructions">
  55.     用方向键控制蛇移动。<br/>
  56.     红色陷阱碰了游戏结束。<br/>
  57.     绿色食物吃了变长。<br/>
  58.     紫色恐怖元素吃了让蛇速度忽快忽慢,不可预测!<br/>
  59.     黑暗迷雾让视野受限,随机闪烁黑暗增加恐怖气氛!<br/>
  60.     游戏结束后按 R 键重置游戏。<br/>
  61.     小心!陷阱和不定的速度会让你陷入恐惧深渊……
  62.   </p>
  63.   <div id="gameContainer">
  64.     <canvas id="gameCanvas" width="400" height="400"></canvas>
  65.     <!-- fog canvas 动态创建 -->
  66.   </div>
  67.   <div id="status">加载中……</div>

  68. <script>
  69. (() => {
  70.   const canvas = document.getElementById('gameCanvas');
  71.   const ctx = canvas.getContext('2d');

  72.   // 创建并添加迷雾画布
  73.   const fogCanvas = document.createElement('canvas');
  74.   fogCanvas.id = 'fog';
  75.   fogCanvas.width = canvas.width;
  76.   fogCanvas.height = canvas.height;
  77.   document.getElementById('gameContainer').appendChild(fogCanvas);
  78.   const fogCtx = fogCanvas.getContext('2d');

  79.   const gridSize = 20;           // 每格大小(像素)
  80.   const tileCount = canvas.width / gridSize; // 网格数量

  81.   let snake = [];
  82.   let direction = {x: 0, y: 0};
  83.   let food = null;
  84.   let traps = [];
  85.   let horrors = [];
  86.   let speed = 200;               // 初始蛇速(ms)
  87.   let gameInterval = null;
  88.   let score = 0;
  89.   let gameOver = false;

  90.   const statusDiv = document.getElementById('status');

  91.   // 恐怖提示语句库
  92.   const scaryMessages = [
  93.     "黑暗如潮水般吞噬了视线……",
  94.     "你感到背后一阵寒意,仿佛有什么盯着你……",
  95.     "步步惊心,陷阱无处不在……",
  96.     "呼吸声渐重,你的心跳加速!",
  97.     "阴风吹过,空气中弥漫着死亡的气息……",
  98.     "幽灵般的低语萦绕耳畔,令人毛骨悚然。",
  99.     "眼前模糊,仿佛进入无尽黑夜……",
  100.     "脚下的土地开始颤抖,你的身体发冷。",
  101.     "你的影子似乎活了过来,紧跟不放。",
  102.     "无形的力量牵引着你,陷入无法逃脱的深渊。",
  103.     "远方传来令人心悸的尖叫声……",
  104.     "诡异的紫光在黑暗中闪耀,警告着你。",
  105.     "每一次吞噬,都让你离死亡更近一步……"
  106.   ];

  107.   // 随机返回数组中一条提示
  108.   function getRandomScaryMessage() {
  109.     return scaryMessages[Math.floor(Math.random() * scaryMessages.length)];
  110.   }

  111.   // 显示恐怖提示
  112.   function showScaryMessage() {
  113.     statusDiv.innerText = getRandomScaryMessage();
  114.   }

  115.   // 随机生成位置,避免重叠
  116.   function randomPosition() {
  117.     let pos;
  118.     do {
  119.       pos = {
  120.         x: Math.floor(Math.random() * tileCount),
  121.         y: Math.floor(Math.random() * tileCount)
  122.       };
  123.     } while(
  124.       snake.some(s => s.x === pos.x && s.y === pos.y) ||
  125.       (food && food.x === pos.x && food.y === pos.y) ||
  126.       traps.some(t => t.x === pos.x && t.y === pos.y) ||
  127.       horrors.some(h => h.x === pos.x && h.y === pos.y)
  128.     );
  129.     return pos;
  130.   }

  131.   function generateFood() {
  132.     food = randomPosition();
  133.   }

  134.   function generateTraps(count = 15) {
  135.     traps = [];
  136.     for(let i=0; i < count; i++) {
  137.       traps.push(randomPosition());
  138.     }
  139.   }

  140.   function generateHorrors(count = 5) {
  141.     horrors = [];
  142.     for(let i=0; i < count; i++) {
  143.       horrors.push(randomPosition());
  144.     }
  145.   }

  146.   // 迷雾效果:只显示蛇头附近一圈区域
  147.   function drawFog() {
  148.     fogCtx.clearRect(0, 0, fogCanvas.width, fogCanvas.height);
  149.     fogCtx.fillStyle = 'rgba(0,0,0,0.95)';
  150.     fogCtx.fillRect(0, 0, fogCanvas.width, fogCanvas.height);

  151.     if(snake.length === 0) return;
  152.     const head = snake[0];
  153.     const radius = 70;

  154.     const centerX = head.x * gridSize + gridSize/2;
  155.     const centerY = head.y * gridSize + gridSize/2;

  156.     const gradient = fogCtx.createRadialGradient(centerX, centerY, radius/4, centerX, centerY, radius);
  157.     gradient.addColorStop(0, 'rgba(0,0,0,0)');
  158.     gradient.addColorStop(1, 'rgba(0,0,0,0.95)');

  159.     fogCtx.globalCompositeOperation = 'destination-out';
  160.     fogCtx.fillStyle = gradient;
  161.     fogCtx.beginPath();
  162.     fogCtx.arc(centerX, centerY, radius, 0, Math.PI * 2);
  163.     fogCtx.fill();
  164.     fogCtx.globalCompositeOperation = 'source-over';
  165.   }

  166.   // 画单个格子
  167.   function drawBlock(x, y, color) {
  168.     ctx.fillStyle = color;
  169.     // 格子之间留一点间隙更清晰
  170.     ctx.fillRect(x * gridSize, y * gridSize, gridSize - 1, gridSize - 1);
  171.   }

  172.   // 绘制整个游戏画面
  173.   function drawGame() {
  174.     ctx.clearRect(0, 0, canvas.width, canvas.height);

  175.     if(food) drawBlock(food.x, food.y, 'limegreen');     // 食物:绿色
  176.     traps.forEach(t => drawBlock(t.x, t.y, 'red'));       // 陷阱:红色
  177.     horrors.forEach(h => drawBlock(h.x, h.y, 'purple'));  // 恐怖元素:紫色

  178.     // 蛇身,蛇头白色,身体灰色
  179.     snake.forEach((segment, idx) => {
  180.       const color = idx === 0 ? 'white' : 'gray';
  181.       drawBlock(segment.x, segment.y, color);
  182.     });

  183.     drawFog();
  184.   }

  185.   // 游戏结束处理
  186.   function endGame(message) {
  187.     clearInterval(gameInterval);
  188.     gameOver = true;
  189.     statusDiv.innerText = message || `游戏结束!最终得分:${score}。带着恐惧离开吧...`;
  190.   }

  191.   // 游戏主循环
  192.   function gameLoop() {
  193.     if(gameOver) return;
  194.     if(direction.x === 0 && direction.y === 0) return; // 游戏开始前静止

  195.     const head = snake[0];
  196.     const newX = head.x + direction.x;
  197.     const newY = head.y + direction.y;

  198.     // 撞墙检测
  199.     if(newX < 0 || newX >= tileCount || newY < 0 || newY >= tileCount) {
  200.       endGame("你撞上了墙壁,死亡无处逃避...");
  201.       return;
  202.     }

  203.     // 撞自己检测
  204.     if(snake.some(s => s.x === newX && s.y === newY)) {
  205.       endGame("你吞噬了自己,陷入绝望永夜...");
  206.       return;
  207.     }

  208.     // 新蛇头加入
  209.     snake.unshift({x: newX, y: newY});

  210.     // 吃食物判断
  211.     if(food && newX === food.x && newY === food.y) {
  212.       score++;

  213.       generateFood();

  214.       // 吃完食物,陷阱与恐怖元素升级
  215.       generateTraps(15 + Math.floor(score / 2));
  216.       generateHorrors(5 + Math.floor(score / 3));

  217.       // 70%几率显示恐怖话
  218.       if(Math.random() < 0.7) {
  219.         showScaryMessage();
  220.       } else {
  221.         statusDiv.innerText = `幸存者,你击败了一部分陷阱!当前分数:${score}`;
  222.       }

  223.       // 50%几率触发黑暗闪烁
  224.       if(Math.random() < 0.5) {
  225.         flickerDarkness();
  226.       }

  227.     } else {
  228.       // 没吃食物则去尾保持长度
  229.       snake.pop();
  230.     }

  231.     // 碰到陷阱导致死亡
  232.     if(traps.some(t => t.x === newX && t.y === newY)) {
  233.       endGame("陷阱抓住了你,绝望笼罩一切……");
  234.       return;
  235.     }

  236.     // 吃到恐怖元素,随机调整速度加深恐怖感
  237.     for(let i = 0; i < horrors.length; i++) {
  238.       const h = horrors[i];
  239.       if(newX === h.x && newY === h.y) {
  240.         // 随机速度变化 +-30~60 ms,限制范围50~400 ms
  241.         const change = (Math.random() < 0.5 ? -1 : 1) * (30 + Math.random() * 30);
  242.         speed = Math.min(400, Math.max(50, speed + change));

  243.         clearInterval(gameInterval);
  244.         gameInterval = setInterval(gameLoop, speed);

  245.         const feeling = change > 0
  246.           ? "你的心跳骤然加快,仿佛被什么追赶!"
  247.           : "突然一阵寒意袭来,动作变得迟缓…";

  248.         statusDiv.innerText = `${feeling} 当前速度:${Math.round(speed)}ms`;

  249.         setTimeout(() => {
  250.           showScaryMessage();
  251.         }, 1000);

  252.         horrors.splice(i, 1);
  253.         break;
  254.       }
  255.     }

  256.     drawGame();
  257.   }

  258.   // 黑暗闪烁效果,吓人用
  259.   function flickerDarkness() {
  260.     let flickerTimes = 6;
  261.     let count = 0;

  262.     const flickerInterval = setInterval(() => {
  263.       if(count % 2 === 0) {
  264.         ctx.fillStyle = 'rgba(0,0,0,0.9)';
  265.         ctx.fillRect(0, 0, canvas.width, canvas.height);
  266.         statusDiv.innerText = "黑暗如潮水般吞噬了视线……";
  267.       } else {
  268.         drawGame();
  269.         showScaryMessage();
  270.       }
  271.       count++;
  272.       if(count > flickerTimes * 2) {
  273.         clearInterval(flickerInterval);
  274.       }
  275.     }, 150);
  276.   }

  277.   // 监听键盘事件,控制蛇移动
  278.   window.addEventListener('keydown', e => {
  279.     if(e.key === 'ArrowUp' && direction.y !== 1) {
  280.       direction = {x: 0, y: -1};
  281.     } else if(e.key === 'ArrowDown' && direction.y !== -1) {
  282.       direction = {x: 0, y: 1};
  283.     } else if(e.key === 'ArrowLeft' && direction.x !== 1) {
  284.       direction = {x: -1, y: 0};
  285.     } else if(e.key === 'ArrowRight' && direction.x !== -1) {
  286.       direction = {x: 1, y: 0};
  287.     }

  288.     // 按R键重置游戏
  289.     if(e.key.toLowerCase() === 'r' && gameOver) {
  290.       initGame();
  291.     }
  292.   });

  293.   // 初始化游戏状态
  294.   function initGame() {
  295.     snake = [{x: Math.floor(tileCount/2), y: Math.floor(tileCount/2)}];
  296.     direction = {x: 0, y: 0};
  297.     score = 0;
  298.     speed = 200;
  299.     gameOver = false;
  300.     generateFood();
  301.     generateTraps(15);
  302.     generateHorrors(5);
  303.     statusDiv.innerText = '游戏开始!用方向键控制蛇,R键重置。小心陷阱和恐怖元素!';
  304.     clearInterval(gameInterval);
  305.     gameInterval = setInterval(gameLoop, speed);
  306.     drawGame();
  307.   }

  308.   // 启动游戏
  309.   initGame();

  310. })();
  311. </script>

  312. </body>
  313. </html>
复制代码


---

### 使用说明
- 打开页面后,使用键盘的上下左右箭头控制蛇移动。
- 绿色的是食物,吃了蛇会变长。
- 红色是陷阱,碰到游戏结束。
- 紫色恐怖元素吃了会让速度忽快忽慢,更刺激。
- 屏幕周围有浓密的迷雾,只能看到蛇头附近的小范围。
- 游戏进行中,会随机出现“黑暗闪烁”,使屏幕瞬间变暗并伴随恐怖提示文字。
- 游戏结束后按键盘 **R** 键可以重新开始游戏。

---

祝你玩得开心又刺激!如果以后想加更多功能或者做别的小游戏,随时告诉我哈!????????????
作者: 张葉彬    时间: 2025-12-30 10:01
更多功能,恐怖元素更精美

作者: kaia    时间: 2025-12-30 10:02
张葉彬 发表于 2025-12-30 10:01
更多功能,恐怖元素更精美


好的!我理解你想要一个功能更多、视觉和恐怖氛围更精美的贪吃蛇游戏。由于篇幅关系,我会帮你设计并提供一个功能丰富、画面恐怖风格明显的版本,包含:

- 多种陷阱(减速、加速、毒雾陷阱)
- 恐怖音效(你可自行添加音频文件)
- 迷雾效果限制视野,可逐渐增强
- 黑屏闪烁和幽灵出现动画
- 动态恐怖文字提示
- 暗色风格主题与血液飞溅特效
- 分数连击加成机制

以下是完整HTML+CSS+JavaScript代码,打开后即可体验。如果想加音效文件,请将对应文件放在同目录下并去掉注释。

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <title>恐怖风格贪吃蛇游戏</title>
  6. <style>
  7.   @import url('https://fonts.googleapis.com/css2?family=Nosifer&display=swap');
  8.   body {
  9.     margin:0; padding:0;
  10.     background: #0a0a0a;
  11.     overflow: hidden;
  12.     font-family: 'Nosifer', cursive, Arial, sans-serif;
  13.     color: #d42020;
  14.     user-select: none;
  15.   }
  16.   canvas {
  17.     background:#111;
  18.     display: block;
  19.     margin: 20px auto;
  20.     border: 3px solid #5a0b0b;
  21.     box-shadow: 0 0 20px 5px #7b1212;
  22.   }
  23.   #message {
  24.     position: absolute;
  25.     top: 10px; left: 50%;
  26.     transform: translateX(-50%);
  27.     font-size: 24px;
  28.     color: #e03e3e;
  29.     text-shadow:
  30.        0 0 5px #ff0000,
  31.        0 0 10px #ff0000,
  32.        0 0 15px #aa0000;
  33.     pointer-events: none;
  34.     user-select:none;
  35.   }
  36.   #scoreboard {
  37.     position: absolute;
  38.     top: 50px;
  39.     left: 15px;
  40.     font-size: 18px;
  41.     color: #b91b1b;
  42.     text-shadow: 0 0 4px #ce2c2c;
  43.   }
  44. </style>
  45. </head>
  46. <body>

  47. <div id="message"></div>
  48. <div id="scoreboard"></div>
  49. <canvas id="game" width="600" height="600"></canvas>

  50. <script>
  51. // 设置画布和上下文
  52. const canvas = document.getElementById('game');
  53. const ctx = canvas.getContext('2d');
  54. const W = canvas.width;
  55. const H = canvas.height;

  56. const blockSize = 20;
  57. const gridWidth = W / blockSize;
  58. const gridHeight = H / blockSize;

  59. // 变量
  60. let snake = [{x:10,y:10}];
  61. let direction = {x:1,y:0};
  62. let food = {};
  63. let traps = [];
  64. let ghost = null;
  65. let ghostTimer = 0;
  66. let fogRadius = 6;
  67. let fogMaxRadius = 6;
  68. let fogMinRadius = 3;
  69. let fogDirection = -0.05; // 迷雾范围变化速度

  70. let speed = 150; // 初始速度,单位ms
  71. let score = 0;
  72. let combo = 0; // 连击计数
  73. let gameover = false;
  74. let moveInterval;

  75. const messageDiv = document.getElementById('message');
  76. const scoreboardDiv = document.getElementById('scoreboard');

  77. // 预设恐怖文字数组
  78. const terrorTexts = {
  79.   food: [
  80.     "鲜血的滋味...真甜...",
  81.     "吃下这口,你会变强!还是变弱?",
  82.     "一口毒药,一口救赎。",
  83.     "嗜血的本能被唤醒!"
  84.   ],
  85.   trapHit: [
  86.     "陷阱!痛苦降临!",
  87.     "你的生命正一点点流失...",
  88.     "黑暗吞噬了你的灵魂。",
  89.     "无法逃脱的恶梦..."
  90.   ],
  91.   ghostAppear: [
  92.     "幽灵出没,死神在凝视你!",
  93.     "冰冷的触感,来自阴间的问候。",
  94.     "别回头,那不是你的影子!",
  95.     "黑暗深处,有东西在盯着你..."
  96.   ],
  97.   speedUp: [
  98.     "心跳加速,恐惧蔓延...",
  99.     "脑中嗡鸣,步伐狂乱。",
  100.     "速度提升,逃不掉的审判!"
  101.   ],
  102.   speedDown: [
  103.     "冻结你的血液,缓慢的死亡。",
  104.     "时间拉长,恐惧无限延续。",
  105.     "变慢了,但危险没有减少..."
  106.   ]
  107. };

  108. // 工具函数:随机整数
  109. function randInt(min,max) {
  110.   return Math.floor(Math.random()*(max-min+1))+min;
  111. }

  112. // 显示恐怖文字弹幕
  113. function showMessage(type){
  114.   const arr = terrorTexts[type];
  115.   if(!arr) return;
  116.   const txt = arr[randInt(0,arr.length-1)];
  117.   messageDiv.textContent = txt;
  118.   // 动画淡出
  119.   messageDiv.style.opacity = 1;
  120.   clearTimeout(messageDiv.timeout);
  121.   messageDiv.timeout = setTimeout(()=>{
  122.     let op = 1;
  123.     let fade = setInterval(()=>{
  124.       op -= 0.05;
  125.       if(op <= 0){
  126.         op = 0; clearInterval(fade);
  127.       }
  128.       messageDiv.style.opacity = op;
  129.     },50);
  130.   }, 2500);
  131. }

  132. // 初始化食物位置,避开蛇和陷阱
  133. function placeFood(){
  134.   while(true){
  135.     let fx = randInt(0,gridWidth-1);
  136.     let fy = randInt(0,gridHeight-1);
  137.     if(snake.some(s => s.x === fx && s.y === fy)) continue;
  138.     if(traps.some(t => t.x === fx && t.y === fy)) continue;
  139.     food = {x:fx,y:fy};
  140.     break;
  141.   }
  142. }

  143. // 生成多重陷阱,类型不同
  144. // types: 'slow' 渐慢陷阱,'fast' 加速陷阱, 'poison' 毒气陷阱(碰到结束)
  145. function placeTraps(count=8){
  146.   traps = [];
  147.   let types = ['slow','fast','poison'];
  148.   while(traps.length < count){
  149.     let tx = randInt(0,gridWidth-1);
  150.     let ty = randInt(0,gridHeight-1);
  151.     if (snake.some(s=>s.x===tx&&s.y===ty)) continue;
  152.     if(food.x === tx && food.y === ty) continue;
  153.     if(traps.some(t=>t.x===tx&&t.y===ty)) continue;
  154.     let type = types[randInt(0, types.length-1)];
  155.     traps.push({x:tx,y:ty,type:type});
  156.   }
  157. }

  158. // 绘制迷雾效果,以蛇头为中心,半径fogRadius
  159. function drawFog(){
  160.   let gradient = ctx.createRadialGradient(
  161.     snake[0].x*blockSize + blockSize/2,
  162.     snake[0].y*blockSize + blockSize/2,
  163.     fogRadius*blockSize*0.3,
  164.     snake[0].x*blockSize + blockSize/2,
  165.     snake[0].y*blockSize + blockSize/2,
  166.     fogRadius*blockSize
  167.   );
  168.   gradient.addColorStop(0,'rgba(10,10,10,0)');
  169.   gradient.addColorStop(1,'rgba(10,10,10,0.95)');
  170.   ctx.fillStyle = gradient;
  171.   ctx.fillRect(0,0,W,H);
  172. }

  173. // 绘制幽灵:半透明模糊圆圈,随机位置持续出现
  174. function drawGhost(){
  175.   if(!ghost) return;
  176.   const alphaMax = 0.6;
  177.   let alpha = alphaMax * (1 - ghost.timer/ghost.duration);
  178.   
  179.   ctx.save();
  180.   ctx.shadowColor = 'rgba(255,255,255,0.6)';
  181.   ctx.shadowBlur = 20;
  182.   ctx.globalAlpha = alpha;
  183.   ctx.fillStyle = '#eee';
  184.   ctx.beginPath();
  185.   ctx.ellipse(
  186.     ghost.x*blockSize + blockSize/2 + Math.sin(ghost.timer*0.3)*5,
  187.     ghost.y*blockSize + blockSize/2 + Math.cos(ghost.timer*0.3)*5,
  188.     blockSize*1.5,
  189.     blockSize*1,
  190.     0,0,Math.PI*2);
  191.   ctx.fill();
  192.   ctx.restore();
  193. }

  194. // 绘制场景
  195. function draw(){
  196.   // 背景
  197.   ctx.fillStyle = '#111010';
  198.   ctx.fillRect(0,0,W,H);

  199.   // 绘制食物(用血红色圆珠,带光晕)
  200.   ctx.fillStyle = '#b00000';
  201.   ctx.shadowColor = '#ff0000';
  202.   ctx.shadowBlur = 8;
  203.   ctx.beginPath();
  204.   ctx.arc(food.x*blockSize+blockSize/2, food.y*blockSize+blockSize/2, blockSize/2-2, 0, Math.PI*2);
  205.   ctx.fill();

  206.   // 绘制陷阱(形状根据类型区分)
  207.   traps.forEach(t=>{
  208.     switch(t.type){
  209.       case 'slow':
  210.         ctx.fillStyle = '#003300';
  211.         ctx.shadowColor = '#00ff00';
  212.         ctx.shadowBlur = 15;
  213.         ctx.beginPath();
  214.         ctx.moveTo(t.x*blockSize+blockSize/2, t.y*blockSize+4);
  215.         ctx.lineTo(t.x*blockSize+blockSize-4, t.y*blockSize+blockSize-4);
  216.         ctx.lineTo(t.x*blockSize+4, t.y*blockSize+blockSize-4);
  217.         ctx.closePath();
  218.         ctx.fill();
  219.         ctx.shadowBlur = 0;
  220.         break;
  221.       case 'fast':
  222.         ctx.fillStyle = '#440000';
  223.         ctx.shadowColor = '#ff4400';
  224.         ctx.shadowBlur = 15;
  225.         ctx.beginPath();
  226.         ctx.arc(t.x*blockSize+blockSize/2, t.y*blockSize+blockSize/2, blockSize/3, 0, Math.PI*2);
  227.         ctx.fill();
  228.         ctx.shadowBlur = 0;
  229.         break;
  230.       case 'poison':
  231.         ctx.fillStyle = '#550055';
  232.         ctx.shadowColor = '#aa00aa';
  233.         ctx.shadowBlur = 20;
  234.         // 画骷髅样式的简单“X”
  235.         ctx.strokeStyle = '#ff00ff';
  236.         ctx.lineWidth = 4;
  237.         ctx.beginPath();
  238.         ctx.moveTo(t.x*blockSize+6, t.y*blockSize+6);
  239.         ctx.lineTo(t.x*blockSize+blockSize-6, t.y*blockSize+blockSize-6);
  240.         ctx.moveTo(t.x*blockSize+blockSize-6, t.y*blockSize+6);
  241.         ctx.lineTo(t.x*blockSize+6, t.y*blockSize+blockSize-6);
  242.         ctx.stroke();
  243.         ctx.shadowBlur = 0;
  244.         break;
  245.     }
  246.   });

  247.   // 绘制蛇(红色带血液飞溅的身体)
  248.   snake.forEach((segment,index)=>{
  249.     let x = segment.x * blockSize;
  250.     let y = segment.y * blockSize;
  251.     ctx.fillStyle = index === 0 ? '#ff0000' : '#8b0000';
  252.     ctx.shadowColor = '#ff2020';
  253.     ctx.shadowBlur = 15;
  254.     ctx.fillRect(x+2, y+2, blockSize-4, blockSize-4);
  255.     ctx.shadowBlur = 0;

  256.     // 血液飞溅效果—小红点随机散落在身体周围
  257.     if(index === 0 && Math.random() < 0.1){ // 蛇头周围效果
  258.       for(let i=0; i<3; i++){
  259.         let sx = x + randInt(2,blockSize-2);
  260.         let sy = y + randInt(2,blockSize-2);
  261.         ctx.fillStyle = `rgba(255,0,0,${Math.random()*0.8+0.2})`;
  262.         ctx.beginPath();
  263.         ctx.arc(sx, sy, randInt(1,3), 0, Math.PI*2);
  264.         ctx.fill();
  265.       }
  266.     }
  267.   });

  268.   // 绘制幽灵
  269.   if(ghost) drawGhost();

  270.   // 迷雾效果覆盖
  271.   drawFog();

  272.   // 显示得分和速度
  273.   scoreboardDiv.innerHTML = `分数: <strong>${score}</strong> &nbsp;&nbsp;速度: <strong>${(1000/speed).toFixed(2)}</strong> 步/秒 &nbsp;&nbsp;连击: ${combo}`;
  274. }

  275. function resetGame(){
  276.   snake = [{x:10,y:10}];
  277.   direction = {x:1,y:0};
  278.   speed = 150;
  279.   score = 0;
  280.   combo = 0;
  281.   gameover = false;
  282.   fogRadius = fogMaxRadius;
  283.   placeFood();
  284.   placeTraps(8);
  285.   ghost = null;
  286.   ghostTimer = 0;
  287.   if(moveInterval) clearInterval(moveInterval);
  288.   moveInterval = setInterval(gameLoop, speed);
  289.   showMessage('food');
  290. }

  291. function gameLoop(){
  292.   if(gameover) {
  293.     return;
  294.   }
  295.   // 更新蛇头新位置
  296.   let head = {...snake[0]};
  297.   head.x += direction.x;
  298.   head.y += direction.y;

  299.   // 墙壁碰撞 -> 游戏结束
  300.   if(head.x < 0 || head.x >= gridWidth || head.y < 0 || head.y >= gridHeight){
  301.     gameOver("撞墙了!死亡降临...");
  302.     return;
  303.   }

  304.   // 自己身体碰撞 -> 游戏结束
  305.   if(snake.some(s=>s.x === head.x && s.y === head.y)){
  306.     gameOver("你咬到了自己,血流如注...");
  307.     return;
  308.   }

  309.   snake.unshift(head);

  310.   // 吃到食物
  311.   if(head.x === food.x && head.y === food.y){
  312.     score += 10 + combo*5;
  313.     combo++;
  314.     showMessage('food');
  315.     placeFood();
  316.     placeTraps(8); // 每次吃完刷新陷阱

  317.     // 进阶:迷雾变窄更恐怖
  318.     fogRadius -= 0.3;
  319.     if(fogRadius < fogMinRadius) fogRadius = fogMinRadius;

  320.     // 随机触发幽灵出现,概率30%
  321.     if(Math.random() < 0.3){
  322.       ghost = {
  323.         x: randInt(0,gridWidth-1),
  324.         y: randInt(0,gridHeight-1),
  325.         timer: 0,
  326.         duration: randInt(40,60)
  327.       };
  328.       showMessage('ghostAppear');
  329.       // 播放幽灵音效
  330.       // playSound('ghost.wav');
  331.     }

  332.     // 逐渐加快蛇速,但上限限制
  333.     speed *= 0.9;
  334.     if(speed < 40) speed = 40;
  335.     clearInterval(moveInterval);
  336.     moveInterval = setInterval(gameLoop, speed);
  337.   } else {
  338.     // 没吃到食物则移除尾巴保持长度
  339.     snake.pop();
  340.     combo = 0; // 连击断了
  341.   }

  342.   // 检测陷阱
  343.   let trapHere = traps.find(t=>t.x === head.x && t.y === head.y);
  344.   if(trapHere){
  345.     switch(trapHere.type){
  346.       case 'slow':
  347.         speed *= 1.3;
  348.         if(speed > 400) speed = 400;
  349.         showMessage('speedDown');
  350.         clearInterval(moveInterval);
  351.         moveInterval = setInterval(gameLoop, speed);
  352.         break;
  353.       case 'fast':
  354.         speed *= 0.7;
  355.         if(speed < 40) speed = 40;
  356.         showMessage('speedUp');
  357.         clearInterval(moveInterval);
  358.         moveInterval = setInterval(gameLoop, speed);
  359.         break;
  360.       case 'poison':
  361.         gameOver("你被毒气包围,窒息而死...");
  362.         return;
  363.     }
  364.     traps = traps.filter(t=>t!==trapHere); // 碰到陷阱后陷阱消失,避免重复碰撞
  365.   }

  366.   // 幽灵动画计时,到期幽灵消失
  367.   if(ghost){
  368.     ghost.timer++;
  369.     if(ghost.timer > ghost.duration){
  370.       ghost = null;
  371.     }
  372.   }

  373.   // 迷雾动态变化,让恐怖感控制视野大小
  374.   fogRadius += fogDirection;
  375.   if(fogRadius >= fogMaxRadius) {
  376.     fogRadius = fogMaxRadius; fogDirection = -fogDirection;
  377.   }
  378.   if(fogRadius <= fogMinRadius){
  379.     fogRadius = fogMinRadius; fogDirection = -fogDirection;
  380.   }

  381.   draw();
  382. }

  383. function gameOver(reason){
  384.   gameover = true;
  385.   showMessage('trapHit');
  386.   alert("游戏结束!\n原因:" + reason + "\n你的得分是:" + score);
  387.   resetGame();
  388. }

  389. // 监听按键控制方向,防止180度急转弯使蛇自杀
  390. window.addEventListener('keydown', e=>{
  391.   if(gameover) return;
  392.   switch(e.key){
  393.     case 'ArrowUp':
  394.     case 'w':
  395.       if(direction.y !== 1) direction = {x:0,y:-1};
  396.       break;
  397.     case 'ArrowDown':
  398.     case 's':
  399.       if(direction.y !== -1) direction = {x:0,y:1};
  400.       break;
  401.     case 'ArrowLeft':
  402.     case 'a':
  403.       if(direction.x !== 1) direction = {x:-1,y:0};
  404.       break;
  405.     case 'ArrowRight':
  406.     case 'd':
  407.       if(direction.x !== -1) direction = {x:1,y:0};
  408.       break;
  409.   }
  410. });

  411. resetGame();
  412. </script>

  413. </body>
  414. </html>
复制代码


---

### 怎么玩

- 用键盘箭头或者 WASD 控制蛇头移动。  
- **红色圆点**是食物,吃了会加分,同时陷阱刷新、蛇变快、迷雾缩小,恐怖气氛加强。  
- **绿色三角陷阱(slow)**:踩了让蛇变慢(更难控制),带有绿色血色氛围。  
- **红色圆形陷阱(fast)**:踩了让蛇加速,速度突然提升,增加紧张感。  
- **紫色叉叉陷阱(poison)**:踩上立即游戏
作者: 张葉彬    时间: 2026-1-6 09:41
增加主页面,增加更多陷阱,更精美,更多恐怖文字,更多可在主页面中选择的游戏模式和皮肤
作者: kaia    时间: 2026-1-6 09:42
张葉彬 发表于 2026-01-06 09:41
增加主页面,增加更多陷阱,更精美,更多恐怖文字,更 ...


你好!你想做一个功能丰富、视觉恐怖精美,还包含主页面能选择游戏模式和皮肤的贪吃蛇游戏,这是个很棒的想法呢!由于这个项目比较大,需要用HTML、CSS和JavaScript一起写出整套代码。

我先帮你设计并写一个简化版的示范,包含以下内容:

1. **主页面**  
- 可以选择不同的游戏模式(普通模式、陷阱模式、极限模式)  
- 可以切换皮肤(经典蛇皮肤、恐怖风格皮肤)  

2. **游戏页面**  
- 根据模式增加不同数量和种类的陷阱  
- 不同皮肤会改变蛇的颜色和样式  
- 加入恐怖文字提示和简单动画  

---

### 完整代码示范

你可以把以下代码保存为`index.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" />
  6. <title>恐怖贪吃蛇 - 主页面</title>
  7. <style>
  8.   /* 全局基础样式 */
  9.   body {
  10.     margin: 0; padding: 0;
  11.     font-family: "黑体", "微软雅黑", sans-serif;
  12.     background-color: #0a0a0a;
  13.     color: #f55;
  14.     display: flex;
  15.     flex-direction: column;
  16.     height: 100vh;
  17.   }
  18.   header {
  19.     text-align: center;
  20.     padding: 30px 20px 10px;
  21.     font-size: 3rem;
  22.     letter-spacing: 6px;
  23.     text-shadow:
  24.       0 0 10px #ff0000,
  25.       0 0 20px #ff0000,
  26.       0 0 30px #ff0000,
  27.       0 0 40px #ff0000;
  28.   }
  29.   main {
  30.     flex-grow: 1;
  31.     display: flex;
  32.     justify-content: center;
  33.     align-items: center;
  34.   }
  35.   .menu {
  36.     background: #111;
  37.     border: 2px solid #f33;
  38.     padding: 30px;
  39.     border-radius: 12px;
  40.     box-shadow:
  41.       0 0 8px #f33,
  42.       inset 0 0 15px #800;
  43.     text-align: center;
  44.     width: 320px;
  45.   }
  46.   .menu h2 {
  47.     margin-bottom: 20px;
  48.     text-shadow: 0 0 6px #f44;
  49.   }
  50.   label {
  51.     display: block;
  52.     margin: 15px 0 10px;
  53.     font-weight: bold;
  54.     font-size: 1.1rem;
  55.   }
  56.   select {
  57.     width: 100%;
  58.     padding: 8px;
  59.     font-size: 1rem;
  60.     background-color: #220000;
  61.     color: #f77;
  62.     border: 1px solid #f33;
  63.     border-radius: 6px;
  64.   }
  65.   button {
  66.     margin-top: 25px;
  67.     padding: 10px 0;
  68.     width: 100%;
  69.     background: #a00;
  70.     border: none;
  71.     color: white;
  72.     font-weight: 700;
  73.     font-size: 1.4rem;
  74.     cursor: pointer;
  75.     border-radius: 8px;
  76.     box-shadow:
  77.       0 0 15px #f33,
  78.       0 0 40px #900 inset;
  79.     transition: background 0.3s ease;
  80.   }
  81.   button:hover {
  82.     background: #f55;
  83.   }

  84.   /* 游戏画面隐藏 */
  85.   #game-container {
  86.     display: none;
  87.     flex-direction: column;
  88.     align-items: center;
  89.     padding: 10px;
  90.     position: relative;
  91.   }
  92.   #game-canvas {
  93.     background-color: #111;
  94.     border: 3px solid #f33;
  95.     box-shadow:
  96.       0 0 10px #f33,
  97.       inset 0 0 15px #600;
  98.   }
  99.   #status-text {
  100.     margin-top: 15px;
  101.     color: #f88;
  102.     font-weight: bold;
  103.     font-size: 1.2rem;
  104.     height: 1.5em;
  105.     text-shadow: 0 0 7px #f44;
  106.   }
  107.   #back-btn {
  108.     margin-top: 20px;
  109.     padding: 8px 16px;
  110.     font-size: 1rem;
  111.     font-weight: 700;
  112.     color: #eee;
  113.     background-color: #400;
  114.     border: none;
  115.     border-radius: 8px;
  116.     cursor: pointer;
  117.     box-shadow:
  118.       0 0 10px #f66,
  119.       inset 0 0 20px #a00;
  120.   }
  121.   #back-btn:hover {
  122.     background-color: #f33;
  123.   }
  124. </style>
  125. </head>
  126. <body>

  127. <header>
  128.   恐怖贪吃蛇
  129. </header>

  130. <main>
  131.   <section class="menu" id="menu">
  132.     <h2>选择游戏模式和皮肤</h2>
  133.     <label for="mode-select">游戏模式</label>
  134.     <select id="mode-select">
  135.       <option value="normal">普通模式</option>
  136.       <option value="trap">陷阱模式</option>
  137.       <option value="extreme">极限模式</option>
  138.     </select>

  139.     <label for="skin-select">蛇皮肤</label>
  140.     <select id="skin-select">
  141.       <option value="classic">经典绿色</option>
  142.       <option value="red">血红恐怖</option>
  143.       <option value="ghost">幽灵蓝光</option>
  144.     </select>

  145.     <button id="start-btn">开始游戏</button>
  146.   </section>


  147.   <section id="game-container">
  148.     <canvas id="game-canvas" width="400" height="400"></canvas>
  149.     <div id="status-text"></div>
  150.     <button id="back-btn">返回菜单</button>
  151.   </section>
  152. </main>


  153. <script>
  154. (() => {
  155.   const menu = document.getElementById('menu');
  156.   const gameContainer = document.getElementById('game-container');
  157.   const canvas = document.getElementById('game-canvas');
  158.   const ctx = canvas.getContext('2d');
  159.   const statusText = document.getElementById('status-text');
  160.   const backBtn = document.getElementById('back-btn');

  161.   const startBtn = document.getElementById('start-btn');
  162.   const modeSelect = document.getElementById('mode-select');
  163.   const skinSelect = document.getElementById('skin-select');

  164.   const gridSize = 20; // 格子大小
  165.   const tileCount = canvas.width / gridSize;

  166.   // 游戏变量
  167.   let snake = [];
  168.   let direction = { x: 0, y: 0 };
  169.   let food = null;
  170.   let traps = [];
  171.   let trapTypes = ['slow', 'speed', 'poison'];
  172.   let speed = 8; // 初始速率,每秒几帧
  173.   let frameCount = 0;
  174.   let gameInterval = null;
  175.   let score = 0;
  176.   let mode = 'normal';
  177.   let skin = 'classic';
  178.   let isGameOver = false;

  179.   // 皮肤配色方案
  180.   const skins = {
  181.     classic: {
  182.       snakeHead: '#0f0',
  183.       snakeBody: '#070',
  184.       food: '#ff0',
  185.       trapSlow: '#5555ff',
  186.       trapSpeed: '#ffaa00',
  187.       trapPoison: '#aa0055',
  188.       bg: '#111',
  189.     },
  190.     red: {
  191.       snakeHead: '#ff4444',
  192.       snakeBody: '#aa1111',
  193.       food: '#ffdd22',
  194.       trapSlow: '#cc77ff',
  195.       trapSpeed: '#ff7744',
  196.       trapPoison: '#770055',
  197.       bg: '#220000',
  198.     },
  199.     ghost: {
  200.       snakeHead: '#88ffff',
  201.       snakeBody: '#55bbbb',
  202.       food: '#ffff88',
  203.       trapSlow: '#4444aa',
  204.       trapSpeed: '#ffaaff',
  205.       trapPoison: '#aa4499',
  206.       bg: '#001122',
  207.     }
  208.   };

  209.   // 恐怖文字库
  210.   const scaryTexts = [
  211.     "你感觉到背后有什么东西盯着你……",
  212.     "脚步声越来越近……",
  213.     "别回头!危险就在身后!",
  214.     "这个地方不属于活人……",
  215.     "呼吸变得沉重,阴冷环绕……",
  216.     "陷阱?还是死亡的预告?",
  217.     "你的心跳加快,屏息凝神……",
  218.     "当心!一不小心就会成为猎物……",
  219.     "食物味道怪异,背后让你发凉……",
  220.     "你听见低语:‘继续前进,还是逃命?’"
  221.   ];

  222.   // 显示随机恐怖文字
  223.   function showScaryText() {
  224.     const msg = scaryTexts[Math.floor(Math.random() * scaryTexts.length)];
  225.     statusText.textContent = msg;
  226.     // 文字闪烁效果
  227.     statusText.style.opacity = '1';
  228.     let opacity = 1;
  229.     const anim = setInterval(() => {
  230.       opacity -= 0.05;
  231.       if (opacity <= 0) {
  232.         clearInterval(anim);
  233.         statusText.textContent = "";
  234.       } else {
  235.         statusText.style.opacity = opacity.toString();
  236.       }
  237.     }, 100);
  238.   }

  239.   // 初始化蛇
  240.   function initSnake() {
  241.     snake = [
  242.       { x: Math.floor(tileCount/2), y: Math.floor(tileCount/2) },
  243.       { x: Math.floor(tileCount/2)-1, y: Math.floor(tileCount/2) },
  244.       { x: Math.floor(tileCount/2)-2, y: Math.floor(tileCount/2) },
  245.     ];
  246.     direction = { x: 1, y: 0 };
  247.   }

  248.   // 生成食物
  249.   function createFood() {
  250.     while (true) {
  251.       const fx = Math.floor(Math.random() * tileCount);
  252.       const fy = Math.floor(Math.random() * tileCount);
  253.       if (!snake.some(seg => seg.x === fx && seg.y === fy) &&
  254.           !traps.some(tr => tr.x === fx && tr.y === fy)) {
  255.         food = { x: fx, y: fy };
  256.         break;
  257.       }
  258.     }
  259.   }

  260.   // 生成陷阱
  261.   function createTraps(count) {
  262.     traps = [];
  263.     for(let i=0; i<count; i++) {
  264.       while(true) {
  265.         const tx = Math.floor(Math.random() * tileCount);
  266.         const ty = Math.floor(Math.random() * tileCount);
  267.         if (!snake.some(seg => seg.x === tx && seg.y === ty) &&
  268.             !traps.some(tr => tr.x === tx && tr.y === ty) &&
  269.             !(food && food.x === tx && food.y === ty)) {
  270.           const type = trapTypes[Math.floor(Math.random() * trapTypes.length)];
  271.           traps.push({ x: tx, y: ty, type });
  272.           break;
  273.         }
  274.       }
  275.     }
  276.   }

  277.   // 绘制背景
  278.   function drawBackground() {
  279.     ctx.fillStyle = skins[skin].bg;
  280.     ctx.fillRect(0, 0, canvas.width, canvas.height);
  281.   }

  282.   // 绘制蛇
  283.   function drawSnake() {
  284.     snake.forEach((seg, idx) => {
  285.       ctx.fillStyle = idx === 0 ? skins[skin].snakeHead : skins[skin].snakeBody;
  286.       ctx.fillRect(seg.x * gridSize, seg.y * gridSize, gridSize, gridSize);
  287.       // 细节阴影
  288.       ctx.strokeStyle = "#222";
  289.       ctx.strokeRect(seg.x * gridSize, seg.y * gridSize, gridSize, gridSize);
  290.     });
  291.   }

  292.   // 绘制食物
  293.   function drawFood() {
  294.     if (!food) return;
  295.     ctx.fillStyle = skins[skin].food;
  296.     ctx.beginPath();
  297.     const cx = food.x * gridSize + gridSize/2;
  298.     const cy = food.y * gridSize + gridSize/2;
  299.     ctx.arc(cx, cy, gridSize/2.5, 0, Math.PI*2);
  300.     ctx.fill();
  301.   }

  302.   // 绘制陷阱
  303.   function drawTraps() {
  304.     traps.forEach(trap => {
  305.       switch(trap.type) {
  306.         case 'slow':
  307.           ctx.fillStyle = skins[skin].trapSlow;
  308.           break;
  309.         case 'speed':
  310.           ctx.fillStyle = skins[skin].trapSpeed;
  311.           break;
  312.         case 'poison':
  313.           ctx.fillStyle = skins[skin].trapPoison;
  314.           break;
  315.       }
  316.       ctx.fillRect(trap.x * gridSize, trap.y * gridSize, gridSize, gridSize);
  317.       // 简单恐怖符号表现
  318.       ctx.strokeStyle = "#330000";
  319.       ctx.beginPath();
  320.       ctx.moveTo(trap.x * gridSize + 3, trap.y * gridSize + 3);
  321.       ctx.lineTo(trap.x * gridSize + gridSize - 3, trap.y * gridSize + gridSize - 3);
  322.       ctx.moveTo(trap.x * gridSize + 3, trap.y * gridSize + gridSize - 3);
  323.       ctx.lineTo(trap.x * gridSize + gridSize - 3, trap.y * gridSize + 3);
  324.       ctx.stroke();
  325.     });
  326.   }

  327.   // 移动蛇
  328.   function moveSnake() {
  329.     const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };

  330.     // 墙壁撞击判定(无穿墙)
  331.     if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) {
  332.       gameOver("撞墙了!你失败了……");
  333.       return;
  334.     }

  335.     // 碰到自己身体
  336.     if (snake.some(s => s.x === head.x && s.y === head.y)) {
  337.       gameOver("咬到自己了!结束了……");
  338.       return;
  339.     }

  340.     // 蛇移动
  341.     snake.unshift(head);

  342.     // 吃到食物
  343.     if (food && head.x === food.x && head.y === food.y) {
  344.       score++;
  345.       showScaryText();
  346.       speed = Math.min(speed + 0.5, 15); // 逐渐加速,但有限制
  347.       createFood();
  348.       if (mode !== 'normal') {
  349.         // 每吃一次食物刷新陷阱
  350.         const trapCount = mode === 'trap' ? 5 : 10;
  351.         createTraps(trapCount);
  352.       }
  353.     } else {
  354.       snake.pop();
  355.     }

  356.     // 碰到陷阱处理
  357.     if (mode !== 'normal') {
  358.       const trapHit = traps.find(t => t.x === head.x && t.y === head.y);
  359.       if (trapHit) {
  360.         switch(trapHit.type) {
  361.           case 'slow':
  362.             speed = Math.max(speed - 3, 4);
  363.             statusText.textContent = "踩到减速陷阱!行动迟缓……";
  364.             break;
  365.           case 'speed':
  366.             speed = Math.min(speed + 3, 20);
  367.             statusText.textContent = "踩到加速陷阱!速度暴涨,谨慎!";
  368.             break;
  369.           case 'poison':
  370.             gameOver("中毒陷阱!你被黑暗吞噬了……");
  371.             return;
  372.         }
  373.         showScaryText();
  374.         // 踩到陷阱后清除它
  375.         traps = traps.filter(t => !(t.x === trapHit.x && t.y === trapHit.y));
  376.       }
  377.     }
  378.   }

  379.   // 绘制所有元素
  380.   function draw() {
  381.     drawBackground();
  382.     drawFood();
  383.     drawTraps();
  384.     drawSnake();
  385.   }

  386.   // 游戏逻辑入口
  387.   function gameLoop() {
  388.     frameCount++;
  389.     if (frameCount % Math.floor(60 / speed) === 0) {
  390.       moveSnake();
  391.       draw();
  392.     }
  393.   }

  394.   // 游戏结束
  395.   function gameOver(msg) {
  396.     isGameOver = true;
  397.     statusText.textContent = msg + ` 得分:${score}`;
  398.     clearInterval(gameInterval);
  399.   }

  400.   // 清理事件绑定和计时器
  401.   function cleanup() {
  402.     document.removeEventListener('keydown', keydownHandler);
  403.     clearInterval(gameInterval);
  404.   }

  405.   // 监听键盘控制
  406.   function keydownHandler(e) {
  407.     if(isGameOver) return;
  408.     switch(e.key){
  409.       case 'ArrowUp':
  410.       case 'w':
  411.       case 'W':
  412.         if(direction.y === 1) break;
  413.         direction = { x: 0, y: -1 };
  414.         break;
  415.       case 'ArrowDown':
  416.       case 's':
  417.       case 'S':
  418.         if(direction.y === -1) break;
  419.         direction = { x: 0, y: 1 };
  420.         break;
  421.       case 'ArrowLeft':
  422.       case 'a':
  423.       case 'A':
  424.         if(direction.x === 1) break;
  425.         direction = { x: -1, y: 0 };
  426.         break;
  427.       case 'ArrowRight':
  428.       case 'd':
  429.       case 'D':
  430.         if(direction.x === -1) break;
  431.         direction = { x: 1, y: 0 };
  432.         break;
  433.     }
  434.   }

  435.   // 主函数,启动游戏
  436.   function startGame() {
  437.     mode = modeSelect.value;
  438.     skin = skinSelect.value;
  439.     score = 0;
  440.     speed = 8;
  441.     frameCount = 0;
  442.     isGameOver = false;

  443.     snake = [];
  444.     traps = [];
  445.     food = null;

  446.     initSnake();
  447.     createFood();

  448.     // 根据模式设置陷阱数量
  449.     if(mode === 'trap'){
  450.       createTraps(5);
  451.     } else if(mode === 'extreme'){
  452.       createTraps(10);
  453.     }

  454.     menu.style.display = 'none';
  455.     gameContainer.style.display = 'flex';

  456.     ctx.imageSmoothingEnabled = false;

  457.     document.addEventListener('keydown', keydownHandler);
  458.     draw();
  459.     statusText.textContent = "";

  460.     if(gameInterval) clearInterval(gameInterval);
  461.     gameInterval = setInterval(gameLoop, 1000/60);
  462.   }

  463.   // 返回菜单
  464.   backBtn.onclick = () => {
  465.     cleanup();
  466.     menu.style.display = 'block';
  467.     gameContainer.style.display = 'none';
  468.     statusText.textContent = "";
  469.   };

  470.   startBtn.onclick = () => {
  471.     startGame();
  472.   };
  473. })();
  474. </script>

  475. </body>
  476. </html>
复制代码


---

### 使用说明:

- 打开页面后,你会看到主菜单,可以选择三种模式和三款皮肤。
- 普通模式没有陷
作者: 张葉彬    时间: 2026-1-6 09:53
增加迷雾,恐怖元素,更精美,主界面更精美,功能更多

作者: kaia    时间: 2026-1-6 09:54
张葉彬 发表于 2026-01-06 09:53
增加迷雾,恐怖元素,更精美,主界面更精美,功能更多 ...


你好!做一个带迷雾效果、精美恐怖元素,功能丰富且主界面漂亮的贪吃蛇游戏,确实很有挑战。我这里给你一个示范项目的思路和简化实现代码,帮你入门。

你可以按照下面的例子,逐步完善。另外,声音、动画等资源可能需要自己找合适素材替换。

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4.   <meta charset="UTF-8" />
  5.   <title>恐怖风贪吃蛇游戏</title>
  6.   <style>
  7.     /* 页面整体布局 */
  8.     body {
  9.       background: radial-gradient(circle at center, #0b0b0b 0%, #000000 100%);
  10.       color: #f44336;
  11.       font-family: "Microsoft YaHei", sans-serif;
  12.       margin: 0; padding: 0;
  13.       user-select: none;
  14.       overflow: hidden;
  15.     }
  16.     #main-menu {
  17.       height: 100vh;
  18.       display: flex; flex-direction: column;
  19.       justify-content: center; align-items: center;
  20.       background: url('https://images.unsplash.com/photo-1572072393748-508d14aaa99d?auto=format&fit=crop&w=1950&q=80') no-repeat center center / cover;
  21.       box-shadow: inset 0 0 50px #900;
  22.     }
  23.     h1 {
  24.       font-size: 4em;
  25.       text-shadow: 0 0 15px #f44336;
  26.       margin-bottom: 0.5em;
  27.       letter-spacing: 0.1em;
  28.     }
  29.     .menu-button {
  30.       background: rgba(255, 0, 0, 0.6);
  31.       border: 2px solid #f44336;
  32.       color: #fff;
  33.       padding: 1em 3em;
  34.       margin: 0.5em;
  35.       font-size: 1.5em;
  36.       border-radius: 10px;
  37.       cursor: pointer;
  38.       transition: all 0.3s ease;
  39.       box-shadow: 0 0 10px #f44336;
  40.       user-select: none;
  41.     }
  42.     .menu-button:hover {
  43.       background: rgba(255, 0, 0, 0.9);
  44.       box-shadow: 0 0 20px #ff0000;
  45.       transform: scale(1.05);
  46.     }
  47.     #game-container {
  48.       position: relative;
  49.       margin: auto;
  50.       width: 600px;
  51.       height: 600px;
  52.       background: #111;
  53.       border: 3px solid #f44336;
  54.       box-shadow: 0 0 30px #f44336 inset;
  55.       display: none;
  56.     }
  57.     canvas {
  58.       display: block;
  59.       background: linear-gradient(180deg, #220000, #110000);
  60.       box-shadow: 0 0 30px #900 inset;
  61.       border-radius: 8px;
  62.     }
  63.     /* 迷雾层 */
  64.     #fog-canvas {
  65.       position: absolute;
  66.       top: 0; left: 0;
  67.       pointer-events: none;
  68.       filter: blur(8px);
  69.     }
  70.     /* 状态栏 */
  71.     #status-bar {
  72.       margin-top: 10px;
  73.       color: #f44336;
  74.       font-size: 1.2em;
  75.       text-align: center;
  76.       letter-spacing: 0.05em;
  77.       user-select: none;
  78.     }
  79.     /* 恐怖文字弹窗 */
  80.     #scary-message {
  81.       position: fixed;
  82.       top: 20%;
  83.       left: 50%;
  84.       transform: translateX(-50%);
  85.       background: rgba(0, 0, 0, 0.85);
  86.       border: 3px solid #f44336;
  87.       border-radius: 10px;
  88.       padding: 1em 2em;
  89.       color: #ff4444;
  90.       font-size: 1.8em;
  91.       font-weight: bold;
  92.       text-shadow: 0 0 15px #f44336;
  93.       opacity: 0;
  94.       transition: opacity 0.5s ease;
  95.       pointer-events: none;
  96.       user-select: none;
  97.       max-width: 80vw;
  98.       z-index: 9999;
  99.     }

  100.     /* 游戏皮肤选择 */
  101.     #skin-selector {
  102.       margin-top: 1em;
  103.       display: flex;
  104.       justify-content: center;
  105.     }
  106.     .skin-option {
  107.       width: 40px; height: 40px;
  108.       margin: 0 10px;
  109.       border-radius: 50%;
  110.       border: 2px solid #f44336;
  111.       cursor: pointer;
  112.       box-shadow: 0 0 10px #f44336;
  113.       transition: transform 0.3s ease;
  114.     }
  115.     .skin-option:hover {
  116.       transform: scale(1.3);
  117.       box-shadow: 0 0 20px #ff0000;
  118.     }
  119.     .skin-selected {
  120.       border: 4px solid #ff0000 !important;
  121.       box-shadow: 0 0 30px #ff0000 !important;
  122.     }
  123.   </style>
  124. </head>
  125. <body>

  126. <div id="main-menu">
  127.   <h1>恐怖贪吃蛇</h1>
  128.   <div>
  129.     <button class="menu-button" id="start-normal">普通模式</button>
  130.     <button class="menu-button" id="start-hard">困难模式</button>
  131.     <button class="menu-button" id="start-nightmare">噩梦模式</button>
  132.   </div>
  133.   <div id="skin-selector" title="选择蛇的皮肤">
  134.     <div class="skin-option skin-selected" data-color="#ff2d2d" style="background:#ff2d2d"></div>
  135.     <div class="skin-option" data-color="#00ff66" style="background:#00ff66"></div>
  136.     <div class="skin-option" data-color="#ff00ff" style="background:#ff00ff"></div>
  137.     <div class="skin-option" data-color="#ffaa00" style="background:#ffaa00"></div>
  138.   </div>
  139. </div>

  140. <div id="game-container">
  141.   <canvas id="game-canvas" width="600" height="600"></canvas>
  142.   <canvas id="fog-canvas" width="600" height="600"></canvas>
  143.   <div id="status-bar">得分: 0 | 速度: 正常</div>
  144. </div>

  145. <div id="scary-message"></div>

  146. <script>
  147. (() => {
  148.   const canvas = document.getElementById('game-canvas');
  149.   const ctx = canvas.getContext('2d');

  150.   const fogCanvas = document.getElementById('fog-canvas');
  151.   const fogCtx = fogCanvas.getContext('2d');

  152.   const startNormalBtn = document.getElementById('start-normal');
  153.   const startHardBtn = document.getElementById('start-hard');
  154.   const startNightmareBtn = document.getElementById('start-nightmare');
  155.   const mainMenu = document.getElementById('main-menu');
  156.   const gameContainer = document.getElementById('game-container');
  157.   const statusBar = document.getElementById('status-bar');
  158.   const scaryMessageEl = document.getElementById('scary-message');
  159.   const skinOptions = document.querySelectorAll('.skin-option');

  160.   const GRID_SIZE = 20; // 单元格尺寸20x20
  161.   const WIDTH = canvas.width / GRID_SIZE; // 30格
  162.   const HEIGHT = canvas.height / GRID_SIZE; // 30格

  163.   let snake = [];
  164.   let direction = { x: 1, y: 0 };
  165.   let nextDirection = direction;
  166.   let food = null;
  167.   let traps = [];
  168.   let score = 0;
  169.   let speed = 150; // 毫秒刷新一次
  170.   let gameInterval = null;
  171.   let fogRadius = 6; // 迷雾半径,视野范围
  172.   let isGameOver = false;
  173.   let snakeColor = '#ff2d2d';

  174.   let modeSettings = {
  175.     normal: { trapCount: 5, speed: 150, fogRadius: 6 },
  176.     hard: { trapCount: 10, speed: 120, fogRadius: 5 },
  177.     nightmare: { trapCount: 15, speed: 90, fogRadius: 3 },
  178.   };

  179.   let currentMode = 'normal';

  180.   function showScaryMessage(text) {
  181.     scaryMessageEl.textContent = text;
  182.     scaryMessageEl.style.opacity = '1';
  183.     setTimeout(() => {
  184.       scaryMessageEl.style.opacity = '0';
  185.     }, 2500);
  186.   }

  187.   function rnd(min, max) {
  188.     return Math.floor(Math.random() * (max - min) + min);
  189.   }

  190.   function resetGame() {
  191.     snake = [];
  192.     for (let i = 5; i >= 0; i--) {
  193.       snake.push({ x: i, y: Math.floor(HEIGHT / 2) });
  194.     }
  195.     direction = { x: 1, y: 0 };
  196.     nextDirection = direction;
  197.     score = 0;
  198.     traps = [];
  199.     isGameOver = false;

  200.     // 根据模式调整参数
  201.     const setting = modeSettings[currentMode];
  202.     speed = setting.speed;
  203.     fogRadius = setting.fogRadius;
  204.     generateFood();
  205.     generateTraps(setting.trapCount);
  206.     updateStatus();
  207.   }

  208.   function generateFood() {
  209.     while(true) {
  210.       const pos = { x: rnd(0, WIDTH), y: rnd(0, HEIGHT) };
  211.       if (!isOccupied(pos)) {
  212.         food = pos;
  213.         break;
  214.       }
  215.     }
  216.   }

  217.   function generateTraps(count) {
  218.     traps = [];
  219.     let tries = 0;
  220.     while (traps.length < count && tries < 500) {
  221.       let pos = { x: rnd(0, WIDTH), y: rnd(0, HEIGHT) };
  222.       if (!isOccupied(pos) && !posEqual(pos, food)) {
  223.         traps.push(pos);
  224.       }
  225.       tries++;
  226.     }
  227.   }

  228.   function isOccupied(pos) {
  229.     return snake.some(s => posEqual(s, pos)) || traps.some(t => posEqual(t, pos));
  230.   }

  231.   function posEqual(a, b) {
  232.     return a.x === b.x && a.y === b.y;
  233.   }

  234.   function setDirection(newDir) {
  235.     // 不能直接让蛇倒退
  236.     if (newDir.x === -direction.x && newDir.y === -direction.y) return;
  237.     nextDirection = newDir;
  238.   }

  239.   function draw() {
  240.     ctx.clearRect(0, 0, canvas.width, canvas.height);

  241.     // 画食物 - 就是鲜红的心脏样子
  242.     ctx.fillStyle = '#ff1744';
  243.     drawHeart(food.x, food.y);

  244.     // 画陷阱 - 用鬼火图案和紫黑色
  245.     traps.forEach(trap => {
  246.       drawGhostFlame(trap.x, trap.y);
  247.     });

  248.     // 画蛇
  249.     ctx.fillStyle = snakeColor;
  250.     snake.forEach((segment, idx) => {
  251.       let alpha = 1.0;
  252.       // 蛇尾部慢慢透明
  253.       if (idx > 0) alpha = Math.max(0.2, 1 - idx / snake.length);
  254.       ctx.globalAlpha = alpha;
  255.       drawRect(segment.x, segment.y);
  256.       ctx.globalAlpha = 1.0;
  257.     });

  258.     // 绘制迷雾,除了蛇头周围 fogRadius 范围内可见
  259.     drawFog();
  260.   }

  261.   function drawRect(x, y) {
  262.     ctx.fillRect(x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE - 1, GRID_SIZE -1);
  263.   }

  264.   function drawHeart(x, y) {
  265.     // 用基本图形拼个心脏形状
  266.     const px = x * GRID_SIZE + GRID_SIZE/2;
  267.     const py = y * GRID_SIZE + GRID_SIZE/2;
  268.     ctx.beginPath();
  269.     ctx.moveTo(px, py + 5);
  270.     ctx.bezierCurveTo(px + 12, py - 15, px + 25, py + 10, px, py + 28);
  271.     ctx.bezierCurveTo(px - 25, py + 10, px - 12, py - 15, px, py + 5);
  272.     ctx.fill();
  273.   }

  274.   function drawGhostFlame(x, y) {
  275.     const px = x * GRID_SIZE;
  276.     const py = y * GRID_SIZE;
  277.     // 外层紫黑色底
  278.     ctx.fillStyle = '#330022';
  279.     ctx.beginPath();
  280.     ctx.ellipse(px + GRID_SIZE/2, py + GRID_SIZE/2, GRID_SIZE/2, GRID_SIZE*0.7, 0, 0, 2 * Math.PI);
  281.     ctx.fill();

  282.     // 里层幽蓝色火焰
  283.     let gradient = ctx.createRadialGradient(px + GRID_SIZE/2, py + GRID_SIZE/2, 2, px + GRID_SIZE/2, py + GRID_SIZE/2, GRID_SIZE/2);
  284.     gradient.addColorStop(0, '#66ccff');
  285.     gradient.addColorStop(1, 'transparent');
  286.     ctx.fillStyle = gradient;
  287.     ctx.beginPath();
  288.     ctx.ellipse(px + GRID_SIZE/2, py + GRID_SIZE/2, GRID_SIZE/3, GRID_SIZE/2, 0, 0, 2 * Math.PI);
  289.     ctx.fill();
  290.   }

  291.   function update() {
  292.     if (isGameOver) return;

  293.     direction = nextDirection;
  294.     const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };

  295.     // 撞墙判死
  296.     if (head.x < 0 || head.x >= WIDTH || head.y < 0 || head.y >= HEIGHT) {
  297.       gameOver("撞墙了,游戏结束...");
  298.       return;
  299.     }

  300.     // 撞自己判死
  301.     if (snake.some(s => posEqual(s, head))) {
  302.       gameOver("你被自己吞噬了,死亡降临...");
  303.       return;
  304.     }

  305.     // 如果踩陷阱,掉血或减速
  306.     let steppedTrapIndex = traps.findIndex(t => posEqual(t, head));
  307.     if (steppedTrapIndex !== -1) {
  308.       traps.splice(steppedTrapIndex,1);
  309.       score = Math.max(0, score - 5);
  310.       showScaryMessage("陷阱!你的生命在黑暗中流逝...");
  311.       speed += 30; // 速度变慢
  312.       clearInterval(gameInterval);
  313.       gameInterval = setInterval(update, speed);
  314.     }

  315.     snake.unshift(head);

  316.     if (posEqual(head, food)) {
  317.       score++;
  318.       showScaryMessage("你吃掉了鲜血之心,感觉力量汹涌...");
  319.       generateFood();
  320.       generateTraps(modeSettings[currentMode].trapCount);
  321.       // 随机加速或者减速
  322.       if (Math.random() < 0.5) {
  323.         speed = Math.max(50, speed - 20);
  324.         showScaryMessage("你感到一阵狂热,速度提升!");
  325.       } else {
  326.         speed += 20;
  327.         showScaryMessage("血液冰冷,你的动作变缓慢...");
  328.       }
  329.       clearInterval(gameInterval);
  330.       gameInterval = setInterval(update, speed);
  331.     } else {
  332.       snake.pop(); // 不吃食物就尾巴缩短
  333.     }

  334.     updateStatus();
  335.     draw();
  336.   }

  337.   function drawFog() {
  338.     fogCtx.clearRect(0, 0, fogCanvas.width, fogCanvas.height);

  339.     // 先画满黑色半透明
  340.     fogCtx.fillStyle = 'rgba(0, 0, 0, 0.85)';
  341.     fogCtx.fillRect(0,0,fogCanvas.width, fogCanvas.height);

  342.     // 在蛇头四周画透明圆,制造迷雾视野效果
  343.     const head = snake[0];
  344.     let cx = head.x * GRID_SIZE + GRID_SIZE / 2;
  345.     let cy = head.y * GRID_SIZE + GRID_SIZE / 2;
  346.     let radius = fogRadius * GRID_SIZE;

  347.     let gradient = fogCtx.createRadialGradient(cx, cy, radius*0.6, cx, cy, radius);
  348.     gradient.addColorStop(0, 'rgba(0,0,0,0)');
  349.     gradient.addColorStop(1, 'rgba(0,0,0,0.85)');

  350.     fogCtx.globalCompositeOperation = 'destination-out';
  351.     fogCtx.fillStyle = gradient;
  352.     fogCtx.beginPath();
  353.     fogCtx.arc(cx, cy, radius, 0, Math.PI * 2);
  354.     fogCtx.fill();
  355.     fogCtx.globalCompositeOperation = 'source-over';
  356.   }

  357.   function updateStatus() {
  358.     let speedDesc = '';
  359.     if (speed < 80) speedDesc = '极快';
  360.     else if (speed < 120) speedDesc = '快速';
  361.     else speedDesc = '正常';

  362.     statusBar.textContent = `得分: ${score} | 速度: ${speedDesc} | 模式: ${currentMode}`;
  363.   }

  364.   function gameOver(msg) {
  365.     isGameOver = true;
  366.     showScaryMessage(msg);
  367.     clearInterval(gameInterval);
  368.     setTimeout(() => {
  369.       alert(`游戏结束!\n你的最终得分:${score}`);
  370.       mainMenu.style.display = 'flex';
  371.       gameContainer.style.display = 'none';
  372.     }, 1500);
  373.   }

  374.   function startGame(mode) {
  375.     currentMode = mode;
  376.     resetGame();
  377.     mainMenu.style.display = 'none';
  378.     gameContainer.style.display = 'block';
  379.     draw();
  380.     clearInterval(gameInterval);
  381.     gameInterval = setInterval(update, speed);
  382.   }

  383.   window.addEventListener('keydown', e => {
  384.     if (e.key === 'ArrowUp' || e.key === 'w') setDirection({ x: 0, y: -1 });
  385.     if (e.key === 'ArrowDown' || e.key === 's') setDirection({ x: 0, y: 1 });
  386.     if (e.key === 'ArrowLeft' || e.key === 'a') setDirection({ x: -1, y: 0 });
  387.     if (e.key === 'ArrowRight' || e.key === 'd') setDirection({ x: 1, y: 0 });
  388.   });

  389.   startNormalBtn.onclick = () => startGame('normal');
  390.   startHardBtn.onclick = () => startGame('hard');
  391.   startNightmareBtn.onclick = () => startGame('nightmare');

  392.   skinOptions.forEach(el => {
  393.     el.onclick = () => {
  394.       skinOptions.forEach(s => s.classList.remove('skin-selected'));
  395.       el.classList.add('skin-selected');
  396.       snakeColor = el.getAttribute('data-color');
  397.     };
  398.   });
  399. })();
  400. </script>

  401. </body>
  402. </html>
复制代码


**功能




欢迎光临 科学教育 (http://sci-edu.net/) Powered by Discuz! X3.2