1.简介
最近需要开发一个网页应用,想到了使用ChatGpt生成Html页面,生成的效果非常好,说几句话就可以实现复杂的功能。不过需要一步步耐心的引导。然后我就想到可以用ChatGpt生成一个网页游戏。这个游戏包含了人物移动、跳跃、射击、生命值,敌人的生成、移动。还有金币掉落、商店功能。如下图所示:
2.环境介绍
- ChatGpt:现在已经开放注册,不需要手机号了。如果由于网络环境访问不了,则可以用国内的大模型(比如Kimi、讯飞星火))代替,效果我没有测试,感兴趣的可以自己尝试一下。
- VS Code:强大的文本编辑器,适合用来做网页开发。不过本项目其实不需要写代码,只要复制ChatGpt生成的代码保存就可以,所以使用记事本也满足需求了。
- Edge浏览器:用来调试我们生成的游戏,有开发人员工具,很方便实用。
3.实现过程
刚开始是想实现一个简单的平台跳跃游戏,主角躲避敌人,营救公主获得胜利。后来我又加入了射击游戏的元素,可以击杀敌人。最后我增加了经济系统,可以获取和花费金币。
4.提示过程
以下是我引导ChatGpt的记录
- 视频:
- **
---------------------文字记录:---------------------
You:
- 使用html+js实现一个用WASD或者方向键控制人物在画面中移动
ChatGPT:
- 好的,我来为你提供一个简单的示例,使用HTML和JavaScript来实现通过WASD键或方向键来控制一个人物在画面中移动。我们将使用HTML来创建一个画布,然后在JavaScript中编写代码来控制人物的移动。
首先,让我们创建一个HTML文件,命名为index.html
,在其中添加以下内容:
[代码省略]
接下来,我们创建JavaScript文件,命名为game.js
,在其中添加以下内容:
[代码省略]
这段代码创建了一个简单的画布和一个蓝色的人物,然后监听键盘事件来控制人物的移动。按下W、A、S、D键或方向键即可控制人物上、下、左、右移动。
你可以将这两段代码保存到同一目录下,并在浏览器中打开index.html
文件,即可看到效果。
3.5
You:
- 在人物运动到边缘时,阻止其继续移动
ChatGPT:
- 好的,我们可以对人物的移动进行边界检测,当人物触碰到画布的边缘时,阻止其继续移动。我来修改一下JavaScript代码:
[代码省略]
在代码中,我们在每次移动之前都检查了人物的位置,如果人物即将移动到画布的边缘,我们就阻止其继续移动。这样就可以确保人物不会超出画布边界。保存并运行这段代码,你将看到人物移动时会自动停止在画布边缘。
3.5
You:
- 增加一个移动速度参数,用来控制人物的移动速度。取消按住按键到连续移动的延迟
ChatGPT:
- 好的,我会添加一个移动速度参数,并取消按住按键时出现的连续移动延迟。我们可以通过使用
setInterval
函数来实现按住按键后的连续移动效果。下面是修改后的代码:
[代码省略]
在这个修改后的代码中,我们创建了一个keys
对象来记录按键的状态,按键按下时设置为true
,松开时设置为false
。然后,我们在每帧中检查按键的状态,并根据按键状态来更新人物的位置。同时,我们使用setInterval
函数来控制游戏循环,取消了按住按键时的连续移动延迟。
3.5
You:
- 将游戏画布扩展,填充屏幕宽度,画布长宽比为16:9
ChatGPT:
- 好的,让我们来调整画布的尺寸,使其填充整个屏幕,并保持16:9的长宽比。我会修改HTML和JavaScript代码来实现这一点。
首先,我们需要修改HTML文件index.html
中的画布元素:
[代码省略]
接下来,我们修改JavaScript文件game.js
中的相关代码,以确保画布具有16:9的长宽比,并填充整个屏幕:
[代码省略]
这样,我们的画布将会以16:9的长宽比填充整个屏幕,并且人物移动的控制功能将保持不变。
3.5
You:
- 添加实时响应屏幕尺寸,改变画布的尺寸功能
ChatGPT:
- 好的,让我们添加实时响应屏幕尺寸变化的功能,并在屏幕尺寸变化时改变画布的尺寸。这样可以确保画布始终填充整个屏幕,并且在窗口大小改变时保持比例。
我们需要在game.js
文件中添加监听窗口大小变化的事件,并在事件触发时更新画布尺寸。下面是修改后的代码:
[代码省略]
现在,当窗口大小变化时,画布尺寸会自动调整以保持16:9的长宽比,并且人物的移动控制功能也会继续工作。
3.5
You:
- 给人物添加持续的重力,按下上键或W键时,给人物施加一个向上的力
ChatGPT:
- 好的,我们可以为人物添加一个重力效果,并在按下上键或W键时给人物施加一个向上的力。这样就可以模拟人物在空中跳跃的效果。
我们需要为人物添加一个垂直速度属性,以及一个表示重力的加速度属性。在每一帧更新人物的位置时,根据重力和施加的力来更新人物的垂直速度和位置。
下面是修改后的JavaScript代码:
[代码省略]
现在,当按下上键或W键时,人物会施加一个向上的力,并在空中跳跃,同时受到重力的作用。
3.5
You:
- 请把左右移动的逻辑保留。添加一个红色方块代表敌人,玩家方块碰到敌人方块就会失败。游戏失败时显示一个重新开始的界面,该界面包括失败文字和重新开始按钮,点击重新开始则重置到初始状态
ChatGPT:
- 好的,我们来添加一个敌人方块,当玩家方块碰到敌人方块时显示一个重新开始的界面。我们还会保留左右移动的逻辑,并且在玩家失败时提供一个重新开始按钮。
首先,我们需要在HTML文件index.html
中添加一个隐藏的重新开始界面:
[代码省略]
接下来,我们修改JavaScript文件game.js
,添加敌人方块和重新开始逻辑:
[代码省略]
这样,当玩家方块碰到敌人方块时,会显示一个重新开始的界面。点击重新开始按钮后,游戏将重置到初始状态。
4o
You:
- 画布中间添加一段阶梯,玩家可以跳上阶梯,到达画布中心的位置。右下角放置一个绿色方块,触碰到绿色方块后,游戏胜利。游戏胜利后显示一个胜利界面,包含游戏胜利的文字,和重新开始的按钮
ChatGPT:
- 好的,让我们在游戏中添加一个阶梯,放置一个绿色的胜利方块,并在玩家触碰到绿色方块后显示一个胜利界面。我们需要在HTML文件中添加一个新的胜利界面,同时修改JavaScript文件以实现这些功能。
首先,修改HTML文件index.html
,添加一个新的胜利界面:
[代码省略]
接下来,修改JavaScript文件game.js
,添加阶梯、胜利方块和胜利逻辑:
[代码省略]
现在,当玩家方块碰到敌人方块时,会显示一个重新开始的界面,当玩家触碰到绿色方块时,会显示一个胜利界面。点击重新开始按钮后,游戏将重置到初始状态。
4o
You:
- 红色方块替换成骷髅的emoji,在游戏开始后,会追赶玩家。玩家增加生命值属性,初始有三点生命值,每次碰到骷髅emoji就会损失一点生命值。玩家的生命值使用红色爱心emoji,显示在屏幕的左上方
ChatGPT:
- 好的,我们可以添加生命值系统,并用红色爱心Emoji显示在屏幕的左上方。骷髅Emoji会追赶玩家,每次碰到玩家会减少玩家的生命值,生命值为0时显示失败界面。
首先,我们需要确保在HTML文件中设置了字体以支持Emoji。然后,我们在JavaScript文件中实现这些功能。
修改后的HTML文件index.html
如下:
[代码省略]
修改后的JavaScript文件game.js
如下:
[代码省略]
现在,当玩家碰到骷髅Emoji时,生命值减少并显示在左上角。如果生命值降至0,显示失败界面。触碰绿色方块后显示胜利界面,并提供重新开始的选项。
4o
You:
- 将玩家方块替换成🥷,绿色方块替换为👸,删除中间的阶梯。保留之前按键功能,新增按下J键或者Z键时,从玩家方块位置向鼠标所在位置发射一个匕首emoji,匕首emoji触碰到画布边缘会消失,触碰到敌人则将敌人消灭。每过3秒就生成一个新的敌人追赶玩家
ChatGPT:
- 好的,我们可以将玩家和目标方块替换成Emoji,同时添加发射匕首的功能,以及每过3秒生成一个新的敌人追赶玩家。我们会删除中间的阶梯,保持之前的按键功能,并且处理发射匕首的逻辑。
下面是修改后的HTML文件index.html
:
[代码省略]
修改后的JavaScript文件game.js
如下:
[代码省略]
在这个版本中,我们实现了以下功能:
- 使用🥷作为玩家方块,使用👸作为目标方块。
- 添加了发射匕首的功能,按下J键或者Z键时,从玩家位置向鼠标位置发射匕首Emoji🗡️。
- 每3秒生成一个新的敌人追赶玩家。
- 玩家碰到敌人会减少生命值,生命值为0时显示失败界面。
- 玩家触碰目标方块时显示胜利界面。
4o
You:
- 敌人生成位置应该至少距离玩家5个身位。每过10秒钟,敌人的生命值就会增加1。增加一个积分参数,记录玩家击杀的敌人数量。敌人被消灭后有20%概率会生成一个有钱袋emoji,钱袋拥有重力。当玩家接近钱袋1个身位时,钱袋会飞向玩家。钱袋触碰到玩家时,增加玩家的金币,金币数量最少为1个,并会随着游戏时长线性增长。增加一个积分UI和金币数量UI。点击金币数量UI时,打开一个商店面板。商店面板有标题、关闭按钮和一个升级物品列表。玩家花费金币可以在商店中购买生命值升级、移动速度升级、匕首伤害升级、敌人减速升级、金币数量升级
ChatGPT:
- 添加这些新功能需要多方面的修改,包括敌人生成、敌人属性、积分和金币系统,以及UI界面和商店功能的实现。下面是详细的实现步骤:
修改HTML文件
增加一个商店面板和UI显示部分:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>人物移动控制</title>
<style>body, html {margin: 0;padding: 0;overflow: hidden;display: flex;justify-content: center;align-items: center;height: 100%;background-color: #f0f0f0;}canvas {display: block;margin: 0 auto;background-color: #ffffff;}#gameOver, #gameWin, #shopPanel {display: none;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);text-align: center;}#gameOver button, #gameWin button, #shopPanel button {margin-top: 20px;padding: 10px 20px;font-size: 16px;}#life, #score, #gold {position: absolute;top: 10px;font-size: 24px;}#life { left: 10px; }#score { left: 120px; }#gold { left: 230px; cursor: pointer; }#shopPanel {background-color: white;padding: 20px;border: 2px solid black;}#shopPanel h1 { margin: 0; }#shopPanel ul { list-style: none; padding: 0; }#shopPanel li { margin: 10px 0; }
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="gameOver"><h1>游戏失败</h1><button onclick="restartGame()">重新开始</button>
</div>
<div id="gameWin"><h1>游戏胜利</h1><button onclick="restartGame()">重新开始</button>
</div>
<div id="shopPanel"><h1>商店</h1><button onclick="closeShop()">关闭</button><ul id="shopItems"><!-- 升级物品列表 --></ul>
</div>
<div id="life"></div>
<div id="score"></div>
<div id="gold" onclick="openShop()"></div>
<script src="game.js"></script>
</body>
</html>
修改JavaScript文件
添加和修改必要的功能实现。
// 获取画布和上下文
var canvas = document.getElementById("gameCanvas");
var ctx = canvas.getContext("2d");// 获取UI元素
var gameOverScreen = document.getElementById("gameOver");
var gameWinScreen = document.getElementById("gameWin");
var lifeDisplay = document.getElementById("life");
var scoreDisplay = document.getElementById("score");
var goldDisplay = document.getElementById("gold");
var shopPanel = document.getElementById("shopPanel");
var shopItems = document.getElementById("shopItems");// 设置画布尺寸
var aspectRatio = 16 / 9; // 16:9的长宽比function resizeCanvas() {var screenWidth = window.innerWidth;var screenHeight = window.innerHeight;// 根据长宽比调整画布尺寸if (screenWidth / screenHeight > aspectRatio) {canvas.width = screenHeight * aspectRatio;canvas.height = screenHeight;} else {canvas.width = screenWidth;canvas.height = screenWidth / aspectRatio;}// 居中画布canvas.style.marginTop = (screenHeight - canvas.height) / 2 + "px";canvas.style.marginLeft = (screenWidth - canvas.width) / 2 + "px";
}// 初始化画布尺寸
resizeCanvas();// 监听窗口大小变化事件
window.addEventListener("resize", function() {resizeCanvas();
});// 定义玩家对象
var player = {x: canvas.width / 2,y: canvas.height - 50, // 开始时放在地面width: 50,height: 50,speed: 5,gravity: 0.2, // 重力加速度velocityY: 0, // 垂直速度life: 3, // 生命值gold: 0 // 金币数量
};// 定义敌人对象列表
var enemies = [];// 定义匕首对象列表
var daggers = [];// 定义钱袋对象列表
var bags = [];// 定义胜利对象
var goal = {x: canvas.width - 70,y: canvas.height - 70,width: 50,height: 50
};// 定义键盘状态对象,用于记录按键状态
var keys = {};// 游戏状态
var gameOver = false;
var gameWin = false;// 积分
var score = 0;// 监听键盘按下和松开事件
document.addEventListener("keydown", function(event) {keys[event.key] = true;// 监听J键或者Z键发射匕首if (event.key === "j" || event.key === "z") {shootDagger(event);}
});document.addEventListener("keyup", function(event) {keys[event.key] = false;
});// 监听鼠标点击事件,获取鼠标位置
canvas.addEventListener("click", shootDagger);// 更新生命值显示
function updateLifeDisplay() {var lifeText = "";for (var i = 0; i < player.life; i++) {lifeText += "❤️";}lifeDisplay.innerHTML = lifeText;
}// 更新积分显示
function updateScoreDisplay() {scoreDisplay.innerHTML = `积分: ${score}`;
}// 更新金币显示
function updateGoldDisplay() {goldDisplay.innerHTML = `金币: ${player.gold}`;
}// 检查碰撞函数
function checkCollision(rect1, rect2) {return (rect1.x < rect2.x + rect2.width &&rect1.x + rect1.width > rect2.x &&rect1.y < rect2.y + rect2.height &&rect1.y + rect1.height > rect2.y);
}// 更新人物位置函数
function update() {if (gameOver || gameWin) return;// 应用重力player.velocityY += player.gravity;// 根据按键调整人物位置if ((keys["ArrowUp"] || keys["w"]) && player.y >= canvas.height - player.height) {// 当按下上键或W键且人物在地面上时,施加向上的力player.velocityY = -8; // 设置一个较大的向上速度,模拟跳跃效果}if (keys["ArrowLeft"] || keys["a"]) {if (player.x > 0) {player.x -= player.speed;}}if (keys["ArrowRight"] || keys["d"]) {if (player.x + player.width < canvas.width) {player.x += player.speed;}}// 更新人物的垂直位置player.y += player.velocityY;// 确保人物在画布内部if (player.y > canvas.height - player.height) {player.y = canvas.height - player.height;player.velocityY = 0;}// 更新敌人位置和生命值enemies.forEach(enemy => {if (enemy.x < player.x) {enemy.x += enemy.speed;} else {enemy.x -= enemy.speed;}if (enemy.y < player.y) {enemy.y += enemy.speed;} else {enemy.y -= enemy.speed;}// 检查与敌人的碰撞if (checkCollision(player, enemy)) {player.life -= 1;updateLifeDisplay();if (player.life <= 0) {gameOver = true;gameOverScreen.style.display = "block";} else {// 重置玩家位置player.x = canvas.width / 2;player.y = canvas.height - 50;player.velocityY = 0;}}});// 更新匕首位置daggers.forEach((dagger, index) => {dagger.x += dagger.vx;dagger.y += dagger.vy;// 移除超过边界的匕首if (dagger.x < 0 || dagger.x > canvas.width || dagger.y < 0 || dagger.y > canvas.height) {daggers.splice(index, 1);}// 检查匕首与敌人的碰撞enemies.forEach((enemy, enemyIndex) => {if (checkCollision(dagger, enemy)) {// 减少敌人生命值enemy.life -= dagger.damage;if (enemy.life <= 0) {enemies.splice(enemyIndex, 1);score += 1;updateScoreDisplay();// 20%概率生成钱袋if (Math.random() < 0.2) {spawnBag(enemy.x, enemy.y);}}daggers.splice(index, 1);}});});// 更新钱袋位置bags.forEach((bag, index) => {bag.y += bag.gravity;// 检查钱袋与玩家的距离var dx = bag.x - player.x;var dy = bag.y - player.y;var distance = Math.sqrt(dx * dx + dy * dy);if (distance < player.width) {bag.vx = (player.x - bag.x) / distance * 5;bag.vy = (player.y - bag.y) / distance * 5;bag.x += bag.vx;bag.y += bag.vy;}// 检查钱袋与玩家的碰撞if (checkCollision(player, bag)) {player.gold += bag.value;updateGoldDisplay();bags.splice(index, 1);}});// 检查与胜利方块的碰撞if (checkCollision(player, goal)) {gameWin = true;gameWinScreen.style.display = "block";}
}// 发射匕首函数
function shootDagger(event) {if (gameOver || gameWin) return;var rect = canvas.getBoundingClientRect();var mouseX = event.clientX - rect.left;var mouseY = event.clientY - rect.top;var angle = Math.atan2(mouseY - player.y, mouseX - player.x);var dagger = {x: player.x,y: player.y,width: 20,height: 20,vx: Math.cos(angle) * 10,vy: Math.sin(angle) * 10,damage: 1 // 匕首初始伤害};daggers.push(dagger);
}// 渲染函数,用于绘制人物、敌人、匕首、钱袋和胜利方块
function draw() {if (gameOver || gameWin) return;// 清除画布ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制人物ctx.font = "50px Arial";ctx.fillText("🥷", player.x, player.y + player.height);// 绘制敌人(骷髅emoji)enemies.forEach(enemy => {ctx.fillText("💀", enemy.x, enemy.y + enemy.height);});// 绘制胜利方块(👸)ctx.fillText("👸", goal.x, goal.y + goal.height);// 绘制匕首daggers.forEach(dagger => {ctx.fillText("🗡️", dagger.x, dagger.y + dagger.height);});// 绘制钱袋bags.forEach(bag => {ctx.fillText("💰", bag.x, bag.y + bag.height);});
}// 生成新敌人
function spawnEnemy() {if (gameOver || gameWin) return;// 确保敌人生成位置距离玩家至少5个身位var newEnemy;do {newEnemy = {x: Math.random() * (canvas.width - 50),y: Math.random() * (canvas.height - 50),width: 50,height: 50,speed: 2, // 敌人速度life: 1 // 敌人初始生命值};} while (Math.abs(newEnemy.x - player.x) < player.width * 5 && Math.abs(newEnemy.y - player.y) < player.height * 5);enemies.push(newEnemy);
}// 生成钱袋
function spawnBag(x, y) {var newBag = {x: x,y: y,width: 30,height: 30,gravity: 0.1,value: Math.floor(Math.random() * (player.gold + 1) + 1), // 金币数量随着游戏时长线性增长vx: 0,vy: 0};bags.push(newBag);
}// 每10秒增加敌人的生命值
function increaseEnemyLife() {enemies.forEach(enemy => {enemy.life += 1;});
}// 主循环
function gameLoop() {// 更新人物位置update();// 渲染画面draw();
}// 启动游戏循环,取消按住按键的连续移动延迟
setInterval(gameLoop, 1000 / 60);// 每3秒生成一个新的敌人
setInterval(spawnEnemy, 3000);// 每10秒增加敌人的生命值
setInterval(increaseEnemyLife, 10000);// 重新开始游戏函数
function restartGame() {player.x = canvas.width / 2;player.y = canvas.height - 50;player.velocityY = 0;player.life = 3;player.gold = 0;score = 0;updateLifeDisplay();updateScoreDisplay();updateGoldDisplay();enemies = [];daggers = [];bags = [];spawnEnemy(); // 立即生成一个敌人gameOver = false;gameWin = false;gameOverScreen.style.display = "none";gameWinScreen.style.display = "none";
}// 打开商店面板
function openShop() {shopPanel.style.display = "block";
}// 关闭商店面板
function closeShop() {shopPanel.style.display = "none";
}// 购买升级物品函数
function buyUpgrade(type) {switch(type) {case 'life':if (player.gold >= 10) {player.gold -= 10;player.life += 1;updateLifeDisplay();updateGoldDisplay();}break;case 'speed':if (player.gold >= 10) {player.gold -= 10;player.speed += 1;updateGoldDisplay();}break;case 'dagger':if (player.gold >= 10) {player.gold -= 10;daggers.forEach(dagger => dagger.damage += 1);updateGoldDisplay();}break;case 'enemySlow':if (player.gold >= 10) {player.gold -= 10;enemies.forEach(enemy => enemy.speed -= 0.5);updateGoldDisplay();}break;case 'gold':if (player.gold >= 10) {player.gold -= 10;player.gold += Math.floor(Math.random() * 10 + 1);updateGoldDisplay();}break;}
}// 初始化商店物品列表
function initShopItems() {shopItems.innerHTML = `<li><button οnclick="buyUpgrade('life')">生命值升级 (10金币)</button></li><li><button οnclick="buyUpgrade('speed')">移动速度升级 (10金币)</button></li><li><button οnclick="buyUpgrade('dagger')">匕首伤害升级 (10金币)</button></li><li><button οnclick="buyUpgrade('enemySlow')">敌人减速升级 (10金币)</button></li><li><button οnclick="buyUpgrade('gold')">金币数量升级 (10金币)</button></li>`;
}// 初始化游戏
function initGame() {resizeCanvas();updateLifeDisplay();updateScoreDisplay();updateGoldDisplay();initShopItems();spawnEnemy();
}// 启动游戏
initGame();
解释
- UI显示与交互 :增加了生命值、积分和金币的UI显示,以及商店面板和相关交互逻辑。
- 敌人生成 :每3秒生成一个新敌人,确保生成位置距离玩家至少5个身位。每10秒增加所有敌人的生命值。
- 钱袋逻辑 :匕首消灭敌人后有20%的概率生成钱袋,钱袋受重力影响,并会向靠近的玩家飞去。玩家碰到钱袋后增加金币。
- 商店系统 :点击金币UI可以打开商店面板,玩家可以花费金币购买各种升级。
- 其他改动 :保留了之前的键盘控制和匕首发射逻辑,并在玩家碰到胜利目标或生命值为0时显示相应界面。
5.总结
最后实现的游戏虽然比较简陋,但是已经可以看出ChatGpt的无限潜力,相信在不不久的将来,可以不用写代码也能生成出有趣而又复杂的游戏出来。