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的无限潜力,相信在不不久的将来,可以不用写代码也能生成出有趣而又复杂的游戏出来。