在 ChatGPT 成功帮助解决 Excel 操作之后,继续探索边界,请它出手写一个小游戏。常见的益智小游戏,无非以下几种:
- 贪食蛇
- 扫雷
- 俄罗斯方块
- 汉诺塔
考验一下 ChatGPT 的极限。
首先我在网页版 ChatGPT 上,请它写一个贪食蛇的游戏。
问:
请用 JavaScript 写一款简单的贪食蛇游戏。
第一次,ChatGPT 试图将所有代码写进单一 HTML 文件,很快就超时了。
问:
超时了,请分模块编写,先写 HTML 及 CSS 结构,从外部引用 JavaScript,JavaScript 命名为 main.js。
答:
好的,以下是分模块编写的贪食蛇游戏的 HTML 和 CSS 结构,以及外部引用的 main.js 文件。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>贪食蛇游戏</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id="canvas"></canvas>
<script src="main.js"></script>
</body>
</html>
style.css
canvas {
border: 1px solid #ccc;
}
接下来写 main.js,编写至 gameOver
方法,再次超时。
答:
// 获取canvas元素和绘图上下文
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// 定义常量和变量
var GRID_SIZE = 10;
var WIDTH = canvas.width / GRID_SIZE;
var HEIGHT = canvas.height / GRID_SIZE;
var snake = {
body: [{x: 3, y: 1}, {x: 2, y: 1}, {x: 1, y: 1}],
direction: 'right'
};
var food = {x: 10, y: 10};
var score = 0;
// 绘制网格
function drawGrid() {
ctx.beginPath();
ctx.strokeStyle = '#ddd';
for (var x = 0; x <= canvas.width; x += GRID_SIZE) {
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
}
for (var y = 0; y <= canvas.height; y += GRID_SIZE) {
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
}
ctx.stroke();
}
// 绘制蛇
function drawSnake() {
ctx.fillStyle = 'green';
for (var i = 0; i < snake.body.length; i++) {
var cell = snake.body[i];
ctx.fillRect(cell.x * GRID_SIZE, cell.y * GRID_SIZE, GRID_SIZE, GRID_SIZE);
}
}
// 绘制食物
function drawFood() {
ctx.fillStyle = 'red';
ctx.fillRect(food.x * GRID_SIZE, food.y * GRID_SIZE, GRID_SIZE, GRID_SIZE);
}
// 更新蛇的位置
function updateSnake() {
var head = {x: snake.body[0].x, y: snake.body[0].y};
switch (snake.direction) {
case 'up': head.y--; break;
case 'down': head.y++; break;
case 'left': head.x--; break;
case 'right': head.x++; break;
}
snake.body.unshift(head);
if (head.x === food.x && head.y === food.y) {
food.x = Math.floor(Math.random() * WIDTH);
food.y = Math.floor(Math.random() * HEIGHT);
score++;
} else {
snake.body.pop();
}
}
// 检查游戏是否结束
function checkGameOver() {
var head = snake.body[0];
if (head.x < 0 || head.x >= WIDTH || head.y < 0 || head.y >= HEIGHT) {
gameOver();
}
for (var i = 1; i < snake.body.length; i++) {
if (head.x === snake.body[i].x && head.y === snake.body[i].y) {
gameOver();
}
}
}
// 游戏结束
function gameOver() {
alert('游戏结束
问:
还是超时,写继续写 游戏结束
的代码。
答:
抱歉,我不小心把代码截断了。以下是游戏结束部分的代码:
// 游戏结束
function gameOver() {
alert('游戏结束,得分:' + score);
clearInterval(intervalId);
}
// 处理按键事件
function handleKeydown(event) {
switch (event.keyCode) {
case 37: // 左箭头
if (snake.direction !== 'right') {
snake.direction = 'left';
}
break;
case 38: // 上箭头
if (snake.direction !== 'down') {
snake.direction = 'up';
}
break;
case 39: // 右箭头
if (snake.direction !== 'left') {
snake.direction = 'right';
}
break;
case 40: // 下箭头
if (snake.direction !== 'up') {
snake.direction = 'down';
}
break;
}
}
// 主循环
var intervalId = setInterval(function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawGrid();
updateSnake();
drawSnake();
drawFood();
checkGameOver();
}, 100);
// 处理按键事件
document.addEventListener('keydown', handleKeydown);
很了不起,以上代码组装起来,可以正常运行:
https://chenzixin.com/ivy/bit/snake/
但有以下缺陷:
- 页面加载即开始运行,没有
startGame
方法; - 游戏结束,用
alert
弹出得分,不够友好;
第一个问题,我现在还没有能力改进,第二问题简单:
模拟一个控制台:
<textarea id="console"></textarea> <br>
<input type="button" id="retry" value="Retry">
重写 gameOver 方法:
function gameOver() {
document.querySelector("#console").innerHTML = 'Game over, the Score: ' + score;
clearInterval(intervalId);
}
刷新页面,重启游戏:
function restart(){
location.reload();
}
document.querySelector("#retry").addEventListener('click', restart);
很好了,看看你能得多少分?我玩了几局,得分都在 10 以下,手和脑的速度,都退化了。
能看画面调大吗?看了下代码,并没有显式定义 canvas 的宽和高,我想到去 CSS 中修改:
canvas {
width: 600px;
height: 300px;
border: 1px solid #ccc;
}
但发现格子变大,画面变形,查了下资料才知道,canvas 的默认宽高,就是 300*150,修改 CSS,只是改变了画布的大小,画纸还是默认值,引擎会放大画纸以适应画布。因此,只能通过 JavaScript 修改:
canvas.width = 600; // default: 300
canvas.height = 300; // default: 150
知识又增加了。