前言
本人是一个完全没写过游戏的前端,最近心血来潮,打算用javascript实现【星露谷物语】中钓鱼小游戏,如有不妥之处,还望不吝赐教。
钓鱼界面
这是游戏中的
这是我要实现的
游戏逻辑
橘黄色的是水域边框,蓝色是水域,水域中的绿色是钓竿,右侧是进度条。鼠标左键可以控制钓竿在水域范围内上下移动,鱼可以在水域内上下运动。保持鱼在钓鱼杆范围内则进度条会上升,反之会下降,钓竿碰到顶部或底部会反弹。随机更新鱼的移动方向,每秒随机改变一次方向。进度条达到100%或者0%,游戏结束。
代码实现
核心物品有3个:钓竿、鱼、进度条。
游戏状态管理
负责更新钓竿、鱼、进度条的状态,检查游戏是否结束,获取游戏结果
/**
* 游戏状态管理
* 负责管理和更新游戏中的各个组件状态
*/
class GameState {
/**
* 初始化游戏中的三个主要组件:钓鱼杆、鱼和进度条
*/
constructor() {
this.fishingbar = new FishingBar(); // 创建钓鱼杆实例
this.fish = new Fish(); // 创建鱼实例
this.progressbar = new ProgressBar(); // 创建进度条实例
}
/**
* 更新游戏状态
* 依次更新钓鱼杆、鱼和进度条的状态
*/
update() {
this.fishingbar.update(); // 更新钓鱼杆状态
this.fish.update(); // 更新鱼的状态
this.progressbar.update(this.fishingbar, this.fish); // 根据钓鱼杆和鱼的状态更新进度条
}
/**
* 检查游戏是否结束
* @returns {boolean} 当进度条达到最低或最高点时返回true
*/
isGameOver() {
return this.progressbar.height <= 0 || this.progressbar.height >= 960;
}
/**
* 获取游戏结果
* @returns {string} 根据进度条高度返回胜利或失败信息
*/
getResult() {
return this.progressbar.height > 480
? "恭喜获胜!"
: "失败了,再接再厉!";
}
}
游戏渲染器
负责游戏画面的渲染:游戏画布、绘制游戏背景(包括左侧黄色区域、中间蓝色水域和右侧棕色进度条区域)、渲染游戏画面(背景、钓鱼杆、鱼、进度条)。
/**
* 游戏渲染器
* 负责游戏画面的渲染
*/
class GameRenderer {
/**
* @param {HTMLCanvasElement} canvas - 游戏画布元素
*/
constructor(canvas) {
this.canvas = canvas; // 保存画布引用
this.ctx = canvas.getContext("2d"); // 获取2D渲染上下文
this.fishImage = new Image(); // 创建鱼的图片对象
this.fishImage.src = "fish.jpeg"; // 设置鱼图片的源
}
/**
* 绘制游戏背景
* 包括左侧黄色区域、中间蓝色水域和右侧棕色进度条区域
*/
drawBackground() {
this.ctx.fillStyle = "rgb(238, 173, 79)"; // 设置左侧区域颜色
this.ctx.fillRect(0, 0, 96, 960); // 绘制左侧区域
this.ctx.fillStyle = "rgb(99, 142, 234)"; // 设置中间水域颜色
this.ctx.fillRect(24, 24, 48, 960 - 48); // 绘制水域
this.ctx.fillStyle = "rgb(136, 89, 57)"; // 设置右侧进度条区域颜色
this.ctx.fillRect(96, 0, 24, 960); // 绘制进度条区域
}
/**
* 渲染游戏画面
* @param {GameState} gameState - 当前游戏状态
*/
render(gameState) {
this.drawBackground(); // 绘制背景
gameState.fishingbar.draw(this.ctx); // 绘制钓鱼杆
gameState.fish.draw(this.ctx, this.fishImage); // 绘制鱼
gameState.progressbar.draw(this.ctx); // 绘制进度条
}
}
游戏控制器
负责处理游戏逻辑和鼠标点击事件,这是游戏的核心逻辑区域。等待鱼图片加载完成后启动游戏循环(gameLoop函数),gameLoop函数用来处理游戏状态更新和画面渲染(如果检查游戏是否结束并显示显示游戏结果,否则更新游戏状态并渲染游戏画面,利用浏览器提供的requestAnimationFrame动画帧api请求下一帧动画。
/**
* 游戏控制器
* 负责处理游戏逻辑和用户输入
*/
class GameController {
/**
* 构造函数
* @param {HTMLCanvasElement} canvas - 游戏画布元素
*/
constructor(canvas) {
this.gameState = new GameState(); // 创建游戏状态实例
this.renderer = new GameRenderer(canvas); // 创建渲染器实例
this.addEventListeners(canvas);
}
addEventListeners(canvas) {
canvas.addEventListener("mousedown", () =>
this.gameState.fishingbar.up(true)
);
canvas.addEventListener("mouseup", () =>
this.gameState.fishingbar.up(false)
);
}
/**
* 游戏主循环
* 处理游戏状态更新和画面渲染
*/
gameLoop = () => {
if (this.gameState.isGameOver()) {
// 检查游戏是否结束
alert(this.gameState.getResult()); // 显示游戏结果
return;
}
this.gameState.update(); // 更新游戏状态
this.renderer.render(this.gameState); // 渲染游戏画面
requestAnimationFrame(this.gameLoop); // 请求下一帧动画
};
/**
* 开始游戏
* 等待鱼图片加载完成后启动游戏循环
*/
start() {
this.renderer.fishImage.onload = () => {
this.gameLoop(); // 图片加载完成后开始游戏循环
};
}
}
全部代码: https://code.juejin.cn/pen/7432596515073622070