跳过

AI开发贪吃蛇

发布时间: at 15:52
本文收录在以下合集中:

本文为AI开发实例,所有代码均为AI生成,红色字体为本人开发中思考过程,仅供参考。 使用工具:智谱清言 项目:贪吃蛇游戏开发 时间:2024年11月10日15:52:08 用户:祎果 AI:ChatGLM

开门见山提问开始

用户_祎果

使用H5和js写一个贪吃蛇小游戏


ChatGLM

当然可以。以下是一个简单的贪吃蛇小游戏的基本代码,使用HTML5和JavaScript实现。这个例子中,我们将创建一个基本的游戏界面,控制蛇的移动,以及食物的随机生成和蛇的增长逻辑。 HTML部分(index.html):

<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>贪吃蛇小游戏</title>
    <style>
      #gameCanvas {
        border: 1px solid black;
        background-color: #ddd;
      }
    </style>
  </head>
  <body>
    <canvas id="gameCanvas" width="400" height="400"></canvas>
    <script src="game.js"></script>
  </body>
</html>

JavaScript部分(game.js):

const canvas = document.getElementById('gameCanvas')
const ctx = canvas.getContext('2d')
const scale = 20
const rows = canvas.height / scale
const columns = canvas.width / scale
let snake
;(function setup() {
  snake = new Snake()
  fruit = new Fruit()
  fruit.pickLocation()
  window.setInterval(() => {
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    fruit.draw()
    snake.update()
    snake.draw()
    if (snake.eat(fruit)) {
      fruit.pickLocation()
    }
    snake.checkCollision()
    document.querySelector('#score').innerText = snake.total
  }, 250)
})()
window.addEventListener('keydown', evt => {
  const direction = evt.key.replace('Arrow', '')
  snake.changeDirection(direction)
})
function Snake() {
  this.x = 0
  this.y = 0
  this.xSpeed = scale * 1
  this.ySpeed = 0
  this.total = 0
  this.tail = []
  this.draw = function () {
    ctx.fillStyle = '#FFFFFF'
    for (let i = 0; i < this.tail.length; i++) {
      ctx.fillRect(this.tail[i].x, this.tail[i].y, scale, scale)
    }
    ctx.fillRect(this.x, this.y, scale, scale)
  }
  this.update = function () {
    for (let i = 0; i < this.tail.length - 1; i++) {
      this.tail[i] = this.tail[i + 1]
    }
    this.tail[this.total - 1] = {x: this.x, y: this.y}
    this.x += this.xSpeed
    this.y += this.ySpeed
    if (this.x > canvas.width) {
      this.x = 0
    }
    if (this.y > canvas.height) {
      this.y = 0
    }
    if (this.x < 0) {
      this.x = canvas.width
    }
    if (this.y < 0) {
      this.y = canvas.height
    }
  }
  this.changeDirection = function (direction) {
    switch (direction) {
      case 'Up':
        this.xSpeed = 0
        this.ySpeed = -scale * 1
        break
      case 'Down':
        this.xSpeed = 0
        this.ySpeed = scale * 1
        break
      case 'Left':
        this.xSpeed = -scale * 1
        this.ySpeed = 0
        break
      case 'Right':
        this.xSpeed = scale * 1
        this.ySpeed = 0
        break
    }
  }
  this.eat = function (fruit) {
    if (this.x === fruit.x && this.y === fruit.y) {
      this.total++
      return true
    }
    return false
  }
  this.checkCollision = function () {
    for (let i = 0; i < this.tail.length; i++) {
      if (this.x === this.tail[i].x && this.y === this.tail[i].y) {
        this.total = 0
        this.tail = []
      }
    }
  }
}
function Fruit() {
  this.x
  this.y
  this.pickLocation = function () {
    this.x = (Math.floor(Math.random() * rows - 1) + 1) * scale
    this.y = (Math.floor(Math.random() * columns - 1) + 1) * scale
  }
  this.draw = function () {
    ctx.fillStyle = '#FF0000'
    ctx.fillRect(this.x, this.y, scale, scale)
  }
}

这个代码实现了一个基本的贪吃蛇游戏,包括蛇的移动、食物的随机生成以及蛇吃到食物后的增长。你可以在此基础上添加更多的功能,比如分数显示、游戏结束逻辑等。


用户_祎果

有一个bug,如果我按下前进方向的反方向(例如朝右走的时候按下左)蛇的长度会缩短直到变成1,解决一下这个bug


ChatGLM

确实,按照当前的代码,如果蛇朝一个方向移动,然后立即按下相反的方向,蛇会吃掉自己的尾巴,导致长度缩短。为了修复这个bug,我们需要在改变方向时添加一个检查,确保新的方向不是当前移动方向的反方向。 以下是修复后的changeDirection方法:

this.changeDirection = function (direction) {
  const oppositeDirections = {
    Up: 'Down',
    Down: 'Up',
    Left: 'Right',
    Right: 'Left',
  }
  // 防止蛇掉头
  if (oppositeDirections[direction] !== this.currentDirection) {
    switch (direction) {
      case 'Up':
        this.xSpeed = 0
        this.ySpeed = -scale * 1
        break
      case 'Down':
        this.xSpeed = 0
        this.ySpeed = scale * 1
        break
      case 'Left':
        this.xSpeed = -scale * 1
        this.ySpeed = 0
        break
      case 'Right':
        this.xSpeed = scale * 1
        this.ySpeed = 0
        break
    }
    this.currentDirection = direction // 更新当前方向
  }
}

Snake构造函数中,我们需要添加一个currentDirection属性来跟踪蛇当前的移动方向:

function Snake() {
  this.currentDirection = 'Right' // 初始化当前方向
  this.x = 0
  this.y = 0
  this.xSpeed = scale * 1
  this.ySpeed = 0
  this.total = 0
  this.tail = []
  // ... 其他代码保持不变
}

这样,changeDirection方法现在会检查蛇是否尝试向相反方向移动,并且在这种情况下不会改变方向。这样就可以防止蛇吃掉自己的尾巴了。


用户_祎果

能加个暂停功能吗?


ChatGLM

当然可以。为了添加暂停功能,我们可以在JavaScript中添加一个变量来跟踪游戏是否暂停,并提供一个方法来切换暂停状态。同时,我们还需要修改游戏循环,使其在游戏暂停时不更新游戏状态。 以下是添加暂停功能的步骤:

  1. Snake构造函数中添加一个paused属性。
  2. 添加一个togglePause方法来切换暂停状态。
  3. 修改gameLoop函数,使其在游戏暂停时不执行更新。 以下是完整的代码示例,包括了暂停功能:
<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>贪吃蛇小游戏</title>
    <style>
      #gameCanvas {
        border: 1px solid black;
        background-color: #ddd;
      }
    </style>
  </head>
  <body>
    <canvas id="gameCanvas" width="400" height="400"></canvas>
    <script>
      var canvas = document.getElementById('gameCanvas')
      var ctx = canvas.getContext('2d')
      var scale = 20
      var rows = canvas.height / scale
      var columns = canvas.width / scale
      function Snake() {
        this.x = 0
        this.y = 0
        this.xSpeed = scale * 1
        this.ySpeed = 0
        this.total = 0
        this.tail = []
        this.currentDirection = 'Right'
        this.paused = false // 添加暂停状态
      }
      Snake.prototype.draw = function () {
        ctx.fillStyle = '#000000'
        for (var i = 0; i < this.tail.length; i++) {
          ctx.fillRect(this.tail[i].x, this.tail[i].y, scale, scale)
        }
        ctx.fillRect(this.x, this.y, scale, scale)
      }
      Snake.prototype.update = function () {
        if (!this.paused) {
          // 检查是否暂停
          for (var i = 0; i < this.tail.length - 1; i++) {
            this.tail[i] = this.tail[i + 1]
          }
          if (this.total >= 1) {
            this.tail[this.total - 1] = {x: this.x, y: this.y}
          }
          this.x += this.xSpeed
          this.y += this.ySpeed
        }
      }
      Snake.prototype.changeDirection = function (direction) {
        // ...(之前的代码保持不变)
      }
      Snake.prototype.togglePause = function () {
        this.paused = !this.paused // 切换暂停状态
      }
      var snake = new Snake()
      var food = {
        x: (Math.floor(Math.random() * rows - 1) + 1) * scale,
        y: (Math.floor(Math.random() * columns - 1) + 1) * scale,
      }
      function gameLoop() {
        ctx.clearRect(0, 0, canvas.width, canvas.height)
        snake.update()
        snake.draw()
        food.draw()
        // ...(其他游戏逻辑保持不变)
        setTimeout(gameLoop, 1000 / 10) // 10 updates per second
      }
      gameLoop()
      // 添加键盘事件监听器
      window.addEventListener('keydown', function (e) {
        var direction = ''
        switch (e.keyCode) {
          case 37:
            direction = 'Left'
            break
          case 38:
            direction = 'Up'
            break
          case 39:
            direction = 'Right'
            break
          case 40:
            direction = 'Down'
            break
          case 32: // 按空格键暂停/继续游戏
            snake.togglePause()
            return // 不需要改变方向
        }
        snake.changeDirection(direction)
      })
    </script>
  </body>
</html>

在这个代码中,我们添加了一个togglePause方法来切换paused属性,并且在update方法中检查paused属性,以确定是否应该更新蛇的位置。我们还添加了一个键盘事件监听器来监听空格键(键码为32),当按下空格键时,调用togglePause方法来暂停或继续游戏。


用户_祎果

还是按照之前分开game.js和index.html的方式写吧

这里是因为写的过程中格式变了,出于保持格式一致和考虑单文件太长AI容易出bug两个原因,我让AI修改了格式


ChatGLM

当然可以。下面是按照您的要求,将游戏逻辑分离到game.js文件中的代码。 首先是index.html文件:

<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>贪吃蛇小游戏</title>
    <style>
      #gameCanvas {
        border: 1px solid black;
        background-color: #ddd;
      }
    </style>
  </head>
  <body>
    <canvas id="gameCanvas" width="400" height="400"></canvas>
    <script src="game.js"></script>
  </body>
</html>

接下来是game.js文件的内容:

var canvas = document.getElementById('gameCanvas')
var ctx = canvas.getContext('2d')
var scale = 20
var rows = canvas.height / scale
var columns = canvas.width / scale
function Snake() {
  this.x = 0
  this.y = 0
  this.xSpeed = scale * 1
  this.ySpeed = 0
  this.total = 0
  this.tail = []
  this.paused = false // 添加暂停状态
}
Snake.prototype.draw = function () {
  ctx.fillStyle = '#000000'
  for (var i = 0; i < this.tail.length; i++) {
    ctx.fillRect(this.tail[i].x, this.tail[i].y, scale, scale)
  }
  ctx.fillRect(this.x, this.y, scale, scale)
}
Snake.prototype.update = function () {
  if (!this.paused) {
    // 检查是否暂停
    for (var i = 0; i < this.tail.length - 1; i++) {
      this.tail[i] = this.tail[i + 1]
    }
    if (this.total >= 1) {
      this.tail[this.total - 1] = {x: this.x, y: this.y}
    }
    this.x += this.xSpeed
    this.y += this.ySpeed
  }
}
Snake.prototype.changeDirection = function (direction) {
  switch (direction) {
    case 'Left':
      if (this.currentDirection !== 'Right') {
        this.xSpeed = -scale
        this.ySpeed = 0
        this.currentDirection = direction
      }
      break
    case 'Up':
      if (this.currentDirection !== 'Down') {
        this.xSpeed = 0
        this.ySpeed = -scale
        this.currentDirection = direction
      }
      break
    case 'Right':
      if (this.currentDirection !== 'Left') {
        this.xSpeed = scale
        this.ySpeed = 0
        this.currentDirection = direction
      }
      break
    case 'Down':
      if (this.currentDirection !== 'Up') {
        this.xSpeed = 0
        this.ySpeed = scale
        this.currentDirection = direction
      }
      break
  }
}
Snake.prototype.togglePause = function () {
  this.paused = !this.paused // 切换暂停状态
}
function Food() {
  this.x = (Math.floor(Math.random() * rows - 1) + 1) * scale
  this.y = (Math.floor(Math.random() * columns - 1) + 1) * scale
  this.draw = function () {
    ctx.fillStyle = '#FF0000'
    ctx.fillRect(this.x, this.y, scale, scale)
  }
}
var snake = new Snake()
var food = new Food()
function gameLoop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  snake.update()
  snake.draw()
  food.draw()
  // Check for collision with food
  if (snake.x === food.x && snake.y === food.y) {
    snake.total++
    food = new Food()
  }
  // Check for collision with self
  for (var i = 0; i < snake.tail.length; i++) {
    if (snake.x === snake.tail[i].x && snake.y === snake.tail[i].y) {
      snake.total = 0
      snake.tail = []
    }
  }
  setTimeout(gameLoop, 1000 / 10) // 10 updates per second
}
gameLoop()
// Add keyboard event listener
window.addEventListener('keydown', function (e) {
  var direction = ''
  switch (e.keyCode) {
    case 37:
      direction = 'Left'
      break
    case 38:
      direction = 'Up'
      break
    case 39:
      direction = 'Right'
      break
    case 40:
      direction = 'Down'
      break
    case 32: // Space key to pause/resume the game
      snake.togglePause()
      return // No need to change direction
  }
  snake.changeDirection(direction)
})

这样,游戏的逻辑就被封装在了game.js文件中,而index.html


用户_祎果

能加个得分显示吗?


ChatGLM

当然可以。我们可以在HTML中添加一个元素来显示得分,并在JavaScript中更新这个得分。以下是添加得分显示的完整代码。 首先是更新后的index.html文件:

<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>贪吃蛇小游戏</title>
    <style>
      #gameCanvas {
        border: 1px solid black;
        background-color: #ddd;
      }
      #score {
        font-family: Arial, sans-serif;
        font-size: 24px;
        margin-top: 10px;
      }
    </style>
  </head>
  <body>
    <canvas id="gameCanvas" width="400" height="400"></canvas>
    <div id="score">得分: 0</div>
    <script src="game.js"></script>
  </body>
</html>

接下来是game.js文件的更新:

var canvas = document.getElementById('gameCanvas')
var ctx = canvas.getContext('2d')
var scoreElement = document.getElementById('score') // 获取得分元素
var scale = 20
var rows = canvas.height / scale
var columns = canvas.width / scale
var score = 0 // 初始化得分
function Snake() {
  // ... Snake的其余代码保持不变
}
// ... Snake的方法保持不变
function Food() {
  // ... Food的其余代码保持不变
}
var snake = new Snake()
var food = new Food()
function gameLoop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  snake.update()
  snake.draw()
  food.draw()
  // Check for collision with food
  if (snake.x === food.x && snake.y === food.y) {
    snake.total++
    score += 10 // 每次吃到食物得分增加10
    updateScore() // 更新得分显示
    food = new Food()
  }
  // Check for collision with self
  for (var i = 0; i < snake.tail.length; i++) {
    if (snake.x === snake.tail[i].x && snake.y === snake.tail[i].y) {
      snake.total = 0
      score = 0 // 重置得分
      updateScore() // 更新得分显示
      snake.tail = []
    }
  }
  setTimeout(gameLoop, 1000 / 10) // 10 updates per second
}
gameLoop()
// Update the score display
function updateScore() {
  scoreElement.textContent = '得分: ' + score
}
// Add keyboard event listener
window.addEventListener('keydown', function (e) {
  // ... 键盘事件监听器的其余代码保持不变
})

现在,当蛇吃到食物时,得分会增加,并且在页面上显示当前的得分。如果蛇撞到自己,得分会重置为0。通过updateScore函数,我们可以确保得分始终在页面上正确显示。


用户_祎果

记录回到我让你添加暂停功能的位置

这一步是因为前面格式变了,然后出现了bug,无法正常运行了,所以这里让AI把思维回退一下到稳定的位置重来。这里重来也是考虑到这是一个完整的实例,多覆盖一些情况,正常开发遇到这种情况可以复制代码新建对话。


ChatGLM

当然,让我们回到添加暂停功能的位置,并在此基础上添加得分显示。以下是更新后的代码,包括暂停功能和得分显示。 首先是index.html文件:

<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>贪吃蛇小游戏</title>
    <style>
      #gameCanvas {
        border: 1px solid black;
        background-color: #ddd;
      }
      #score {
        font-family: Arial, sans-serif;
        font-size: 24px;
        margin-top: 10px;
      }
    </style>
  </head>
  <body>
    <canvas id="gameCanvas" width="400" height="400"></canvas>
    <div id="score">得分: 0</div>
    <script src="game.js"></script>
  </body>
</html>

接下来是game.js文件,包括暂停功能和得分显示:

var canvas = document.getElementById('gameCanvas')
var ctx = canvas.getContext('2d')
var scoreElement = document.getElementById('score') // 获取得分元素
var scale = 20
var rows = canvas.height / scale
var columns = canvas.width / scale
var score = 0 // 初始化得分
var paused = false // 初始化暂停状态
function Snake() {
  // ... Snake的其余代码保持不变
}
// ... Snake的方法保持不变
function Food() {
  // ... Food的其余代码保持不变
}
var snake = new Snake()
var food = new Food()
function gameLoop() {
  if (!paused) {
    // 如果游戏没有暂停,则更新游戏
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    snake.update()
    snake.draw()
    food.draw()
    // Check for collision with food
    if (snake.x === food.x && snake.y === food.y) {
      snake.total++
      score += 10 // 每次吃到食物得分增加10
      updateScore() // 更新得分显示
      food = new Food()
    }
    // Check for collision with self
    for (var i = 0; i < snake.tail.length; i++) {
      if (snake.x === snake.tail[i].x && snake.y === snake.tail[i].y) {
        snake.total = 0
        score = 0 // 重置得分
        updateScore() // 更新得分显示
        snake.tail = []
      }
    }
  }
  setTimeout(gameLoop, 1000 / 10) // 10 updates per second
}
gameLoop()
// Update the score display
function updateScore() {
  scoreElement.textContent = '得分: ' + score
}
// Toggle pause state
function togglePause() {
  paused = !paused
}
// Add keyboard event listener
window.addEventListener('keydown', function (e) {
  var direction = ''
  switch (e.keyCode) {
    case 37:
      direction = 'Left'
      break
    case 38:
      direction = 'Up'
      break
    case 39:
      direction = 'Right'
      break
    case 40:
      direction = 'Down'
      break
    case 32: // Space key to pause/resume the game
      togglePause()
      return // No need to change direction
  }
  if (direction && snake.direction !== direction && snake.direction !== oppositeDirection(direction)) {
    snake.changeDirection(direction)
  }
})
// Helper function to get the opposite direction
function oppositeDirection(direction) {
  switch (direction) {
    case 'Up':
      return 'Down'
    case 'Down':
      return 'Up'
    case 'Left':
      return 'Right'
    case 'Right':
      return 'Left'
  }
}

在这个版本的game.js中,我们添加了一个paused变量来跟踪游戏是否暂停,并定义了一个togglePause函数来切换暂停状态。在gameLoop函数中,我们检查paused变量,如果游戏没有暂停,则继续更新游戏状态。此外,我们还添加了一个得分显示,并在蛇吃到食物时更新得分。


用户_祎果

请把你刚刚的回答,var的使用换成const和let

这里是写完代码后我观察发现关键字换了,出于规范让他修改了一下,不自己修改是为了保持AI的思维连贯性,否则就要复制代码刷新AI的思路了。


ChatGLM

当然,以下是使用constlet替换var的代码: 首先是index.html文件,它保持不变:

<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>贪吃蛇小游戏</title>
    <style>
      #gameCanvas {
        border: 1px solid black;
        background-color: #ddd;
      }
      #score {
        font-family: Arial, sans-serif;
        font-size: 24px;
        margin-top: 10px;
      }
    </style>
  </head>
  <body>
    <canvas id="gameCanvas" width="400" height="400"></canvas>
    <div id="score">得分: 0</div>
    <script src="game.js"></script>
  </body>
</html>

接下来是更新后的game.js文件:

const canvas = document.getElementById('gameCanvas')
const ctx = canvas.getContext('d')
const scoreElement = document.getElementById('score') // 获取得分元素
const scale = 20
const rows = canvas.height / scale
const columns = canvas.width / scale
let score = 0 // 初始化得分
let paused = false // 初始化暂停状态
function Snake() {
  // ... Snake的其余代码保持不变
}
// ... Snake的方法保持不变
function Food() {
  // ... Food的其余代码保持不变
}
const snake = new Snake()
const food = new Food()
function gameLoop() {
  if (!paused) {
    // 如果游戏没有暂停,则更新游戏
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    snake.update()
    snake.draw()
    food.draw()
    // Check for collision with food
    if (snake.x === food.x && snake.y === food.y) {
      snake.total++
      score += 10 // 每次吃到食物得分增加10
      updateScore() // 更新得分显示
      food = new Food()
    }
    // Check for collision with self
    for (let i = 0; i < snake.tail.length; i++) {
      if (snake.x === snake.tail[i].x && snake.y === snake.tail[i].y) {
        snake.total = 0
        score = 0 // 重置得分
        updateScore() // 更新得分显示
        snake.tail = []
      }
    }
  }
  setTimeout(gameLoop, 1000 / 10) // 10 updates per second
}
gameLoop()
// Update the score display
function updateScore() {
  scoreElement.textContent = '得分: ' + score
}
// Toggle pause state
function togglePause() {
  paused = !paused
}
// Add keyboard event listener
window.addEventListener('keydown', function (e) {
  let direction = ''
  switch (e.keyCode) {
    case 37:
      direction = 'Left'
      break
    case 38:
      direction = 'Up'
      break
    case 39:
      direction = 'Right'
      break
    case 40:
      direction = 'Down'
      break
    case 32: // Space key to pause/resume the game
      togglePause()
      return // No need to change direction
  }
  if (direction && snake.direction !== direction && snake.direction !== oppositeDirection(direction)) {
    snake.changeDirection(direction)
  }
})
// Helper function to get the opposite direction
function oppositeDirection(direction) {
  switch (direction) {
    case 'Up':
      return 'Down'
    case 'Down':
      return 'Up'
    case 'Left':
      return 'Right'
    case 'Right':
      return 'Left'
  }
}

在这个版本的代码中,我使用了const来声明那些不会改变的变量,如canvasctxscoreElementscalerowscolumnssnakefood。而let用于声明那些在代码执行过程中可能会改变的变量,如scorepaused和循环中的i。使用constlet可以提高代码的可读性和可维护性,并且letconst有块级作用域,而var是函数作用域。


用户_祎果

这是现在的代码,运行发现不生成食物,检查并修改:

《此处省略代码……》

这一步是用AI给的最新代码无法运行,所以我把代码复制过来让他检查了,正常开发的话可以看到控制台有报错,解决也不难,但是我做这个实例是演示AI功能,所以假设用户完全不懂不修改任何代码。


ChatGLM

在提供的代码中,Food类的pickLocation方法没有被调用,这就是为什么食物没有被生成的原因。我们需要在创建新的食物实例时调用pickLocation方法来为食物设置一个随机的位置。以下是修正后的代码段: 在gameLoop函数中,当蛇吃到食物后,应该调用food.pickLocation()来为新生成的食物设置位置:

function gameLoop() {
  if (!paused) {
    // 如果游戏没有暂停,则更新游戏
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    snake.update()
    snake.draw()
    food.draw()
    // Check for collision with food
    if (snake.x === food.x && snake.y === food.y) {
      snake.total++
      score += 10 // 每次吃到食物得分增加10
      updateScore() // 更新得分显示
      food = new Food() // 创建新的食物实例
      food.pickLocation() // 为新食物设置位置
    }
    // Check for collision with self
    for (let i = 0; i < snake.tail.length; i++) {
      if (snake.x === snake.tail[i].x && snake.y === snake.tail[i].y) {
        snake.total = 0
        score = 0 // 重置得分
        updateScore() // 更新得分显示
        snake.tail = []
      }
    }
  }
  setTimeout(gameLoop, 1000 / 10) // 10 updates per second
}

此外,为了确保食物不会生成在蛇的身体上,我们可以在Food类的pickLocation方法中添加一个检查,确保生成的食物位置不在蛇的身体上:

function Food() {
  this.pickLocation = function () {
    let locationFound = false
    while (!locationFound) {
      this.x = (Math.floor(Math.random() * rows - 1) + 1) * scale
      this.y = (Math.floor(Math.random() * columns - 1) + 1) * scale
      locationFound = true // 假设位置是好的,除非下面的循环证明不是
      // 检查食物是否生成在蛇的身体上
      for (let i = 0; i < snake.tail.length; i++) {
        if (this.x === snake.tail[i].x && this.y === snake.tail[i].y) {
          locationFound = false // 如果食物在蛇的身体上,重新寻找位置
          break
        }
      }
    }
  }
  // ...其余Food类的代码保持不变
}

这样,每次生成新的食物时,都会确保它不会出现在蛇的身体上。

这里AI不仅找到了问题,还顺手优化了之前未发现的bug,好评。


用户_祎果

以下是修改后的Food和gameloop,还是没有生成食物:

《此处省略代码……》

这里是还有问题,因为咱不懂代码,所以让AI来解决。


ChatGLM

代码看起来是正确的,但是食物没有被生成的原因可能是因为rowscolumns的计算方式不正确。在初始化变量时,rowscolumns应该是基于scale来计算的,确保食物生成在网格内。让我们来检查并修正这部分代码。 首先,确保rowscolumns的计算是正确的:

const rows = Math.floor(canvas.height / scale)
const columns = Math.floor(canvas.width / scale)

然后,在Food类的pickLocation方法中,确保食物的坐标是在网格内:

this.pickLocation = function () {
  let locationFound = false
  while (!locationFound) {
    this.x = (Math.floor(Math.random() * (columns - 1)) + 1) * scale
    this.y = (Math.floor(Math.random() * (rows - 1)) + 1) * scale
    locationFound = true
    for (let i = 0; i < snake.tail.length; i++) {
      if (this.x === snake.tail[i].x && this.y === snake.tail[i].y) {
        locationFound = false
        break
      }
    }
  }
}

注意,在计算this.xthis.y时,我们使用了(columns - 1)(rows - 1)来确保食物不会生成在边界之外。 最后,确保在游戏开始时,食物的位置被初始化:

let food = new Food()
food.pickLocation() // 初始化食物位置

现在,让我们将这些修改整合到一起,并确保gameLoop函数在页面加载时被调用:

// ... 其他代码保持不变
// 初始化食物位置
let food = new Food()
food.pickLocation()
// 开始游戏循环
gameLoop()

确保你的HTML元素<canvas>具有正确的宽度和高度,这样rowscolumns的计算才会正确。例如:

<canvas id="gameCanvas" width="400" height="400"></canvas>

如果上述修改后食物仍然没有被生成,请检查控制台是否有错误,并确保scalecanvas.widthcanvas.height的值是正确的。如果控制台没有错误,食物应该会在游戏开始时被生成,并且在蛇吃到食物后重新生成。

这里AI发现了问题,然后我观察AI的回答发现是没有初始化食物位置,于是采纳了初始化食物位置这一行代码。


用户_祎果

加上初始化初始化食物位置后成功了

这里是完成了,出于礼貌回复了一下。


ChatGLM

太好了,我很高兴听到这个问题已经被解决了!如果你在开发过程中遇到任何其他问题,或者想要添加更多功能到你的贪吃蛇游戏中,比如增加难度级别、改进用户界面、添加音效等,随时欢迎你提问。祝你在编程和游戏开发中取得更多的进步!

AI情绪价值拉满。