前端用js实现【星露谷物语】钓鱼小游戏
2024-11-03 08:48 阅读(217)

前言

本人是一个完全没写过游戏的前端,最近心血来潮,打算用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