我们如何构建面向开发者的益智游戏 Purrfect Code

八月 01, 2024

Link to Youtube Video (visible only when JS is disabled)

Purrfect Code”是一款全新的推箱子编程益智游戏,由 Flutter、Dart 和 Flame 游戏引擎提供支持,旨在挑战开发者通过编写代码来破解谜题。


游戏概览

在“Purrfect Code”中,玩家的任务是对 Google 新的空间站总部的门卫机器人重新编程,因为空间站总部收到了一批被误运的猫。游戏的目标是帮助机器人安全地收集装有猫的箱子,并将箱子推到传送板上,以便将这些猫送回家。玩家需要编写 JavaScript 代码来控制机器人的移动,同时尝试发现有效的解决方案,以破解基于网格的谜题。

游戏是探索编码的有趣方式,需要您运用智慧和发挥创造力。游戏总共有五个关卡,每个关卡都侧重于编程概念,并且难度逐步增加。

游戏循环如下:

  1. 玩家编写 JavaScript 代码来移动机器人(向上、向下、向左或向右)

2. 然后,玩家运行代码并观察机器人是否能通过关卡

3. 如果所有装有猫的箱子被推到传送板上,即表示通关

4. 系统根据玩家的解决方案效率打分,包括机器人移动次数以及代码的简洁性

使用 Flutter、Dart 和 Flame 构建游戏

我们之所以选择使用 Flutter 和 Dart 来开发“Purrfect Code”,是因为这两者拥有强大而灵活的框架,适用于创建多平台应用和游戏。Flutter 的微件系统和响应式编程模型让我们能够在浏览器中为各种屏幕尺寸创建响应式界面。Dart 的强类型和面向对象的编程功能让我们能够轻松设计代码并保持代码库整洁。Flame 游戏引擎建立在 Flutter 之上,为游戏开发所需的基本功能提供了良好的基础,让我们能够专注于游戏的逻辑和独特方面。从本质上来讲,Purrfect Code 是游戏/应用的独特混合,既有 IDE 风格的界面,也有包含动画精灵和声音的游戏视图。显然,Flutter 和 Flame 是这个项目的不二之选。


Chrome 和 JavaScript:利用内置浏览器支持

游戏的编程概念一旦确定,我们就需要选择玩家将使用的编程语言。我们想要使用开发者熟悉且常用的编程语言。最初,我们考虑使用 Python 作为游戏中的编程语言。但是,经过一番考虑,我们决定使用 JavaScript,以利用 Chrome 提供的内置 JavaScript 支持。通过使用 JavaScript,我们可以利用浏览器的原生功能,而无需加载其他语言解释器。这一决定不仅简化了我们的开发过程,而且还确保了顺畅的玩家体验,因为所需的依赖项极少,所以游戏可以快速加载。

今年在 Google I/O 大会上发布的 Flutter 3.22 版本引入了对 WebAssembly (WASM) 的支持,让我们能够优化对游戏性能至关重要的部分。通过将某些游戏逻辑编译为 WASM,我们确保“Purrfect Code”可以在浏览器中高效运行,同时在不影响性能的情况下提供流畅且响应迅速的游戏体验。

var dir = [moveEast,moveNorth,moveWest,moveSouth];
for(i=0;i<4;i++){
    for(j=0;j<5;j++)dir[i]();
}

Flame 游戏引擎:模块化和高效的游戏开发

为了将“Purrfect Code”变为现实,我们使用了 Flame 游戏引擎,这是一款基于 Flutter 构建而来的开源模块化游戏引擎,可为游戏开发提供许多常用的功能。Flame 不仅可以利用 Flutter 强大的基础设施,同时还能简化构建项目所需的代码。它提供了一个简单而有效的游戏循环实现和广泛的基本功能,如音频播放、精灵管理、动画功能、碰撞和 Flame 组件系统 (FCS)。该引擎基于组件的架构、精灵渲染和动画支持让我们能够创建具有视觉吸引力的图形、流畅的动画和交互式游戏元素,而无需白费力气做重复工作。利用 Flame,开发流程更加高效,基本功能现已准备就绪。正因如此,我们才能专注于为玩家打造有吸引力的游戏体验。


利用 Flame 实现游戏功能

Flame 提供简单而有效的游戏循环实现和广泛的基本功能,如音频播放、精灵管理、动画功能、碰撞和 Flame 组件系统 (FCS)。

Flame 的精灵渲染和动画系统让我们能够将游戏的角色和环境变为现实,而无需编写图形代码。我们可以创建精灵表,定义动画序列,并流畅地为角色的动作制作动画和特效。我们使用 Flame 的优先级系统为我们的“自上而下”游戏视角编写了一个可视化分类系统。我们的美术师利用许多重叠功能设计关卡,以增强精灵的深度感,并使游戏视图较少呈现“网格状”外观。我们需要确保机器人在网格后面移动时,网格会被正确地遮挡。Flame 的优先级系统让我们能够为不同的视觉元素分配优先级,确保这些元素按正确的顺序绘制并正确重叠。这个系统足够灵活,我们因而可以纳入一个阴影系统,其中单个组件的动画阴影可以反映物体的动作,并赋予艺术深度,使场景更真实,更容易直观地理解。

我们代码库中的 BoxShadow 类就是一个很好的例子,它展示了我们如何为游戏中移动箱子的对象创建动态和交互式阴影。通过扩展 SpriteAnimationComponent 并实现 GridElement 与 HasVisibility 的混合,我们能够为箱子阴影和传送箱子的动画加载精灵表,为打开、关闭、空闲和传送状态定义多个动画,并将它们集成到基于网格的布局中。onLoad 方法用于加载动画并根据组件的网格位置设置组件的初始位置和优先级,而 update 方法用于确保如果箱子在遮挡对象的前面或后面移动,则组件的优先级会动态更新。通过使用 Flame 的优先级和动画系统,我们能够创建阴影效果,始终帮助用户在视觉上理解虚拟空间,并使其更具可信度,从而呈现更完整的视觉效果。

节选自 box_shadow.dart。在 GitHub 上查看完整类,以了解详情。

@override
  Future<void> onLoad() async {
    await _loadAnimations().then((_) => {animation = _boxClosed});
 
 
    position.add(Vector2(
        ((gridPosition.x * gridPixelDimensions.x) + gridPixelOffset.x),
        ((gridPosition.y * gridPixelDimensions.y) + gridPixelOffset.y)));
    priority = getLayeredGridValue();
  }
  @override
  void update(double dt) async {
    super.update(dt);
 
 
    if (getLayeredGridValue() != priority) {
      priority = getLayeredGridValue();
    }
  }

Google 开发者计划和徽章

我们希望游戏的安装包不大,希望将其部署为一个简单的网页版游戏,并希望避免为游戏设置后端。但我们确实希望以某种方式奖励开发者取得的进步,类似于热门游戏平台中的成就系统。我们没有构建单独的后端系统来跟踪玩家的进度和成就,而是与 Google 开发者计划集成,允许玩家点击链接并在完成关卡后收集会在其个人资料中显示的徽章,让开发者社区中的开发者获得成就感和认可感。

Purrfect Code Google Developer Program profile badges

Project IDX:简化的开发环境

在“Purrfect Code”的开发过程中,我们利用了 Google 的 Project IDX,这是一个人工智能辅助工作区,用于在云中进行全栈、多平台应用程序开发。由于我们已经习惯在 VS Code 中工作,Project IDX 为我们的游戏编码、调试和测试提供了一个熟悉的环境,使我们能够快速启动和运行。 Flutter 和 Dart 已经在浏览器中设置完毕并准备就绪,我们可以直接进行开发,而无需进行本地环境配置的麻烦。 Project IDX 提供的智能代码完成、实时错误检查和集成调试工具帮助我们保持高生产力。如果您好奇,Project IDX 是快速尝试 Purrfect Code 并直接从浏览器探索其代码的好方法。 单击此链接可直接在 IDX 中打开项目并自行运行该项目。请务必选中询问这是否是 Flutter 应用程序的复选框。


快速、安全的 Firebase Hosting

我们选择了 Firebase Hosting,以确保在全球范围内安全高效地交付 Purrfect Code。该平台的零配置 SSL 可保证内容通过 HTTPS 提供,以提高安全性。此外,它支持使用 GitHub 代码库中的现代 Web 框架和自动化构建功能,从而实现更新的快速部署。Firebase CLI、本地模拟和预览 URL 简化了我们的测试和协作流程。这些功能,再加上未来通过利用 Gemini 示例模板进行 AI 集成来发展游戏的潜力,使 Firebase Hosting 成为我们发布游戏的理想选择。


使用 WASM 配置 Firebase

Purrfect Code 使用的是 Web Assembly,需要在部署期间执行额外步骤。在我们的 firebase.json 配置中,为了能够使用 WASM 构建网页版本,我们添加了一个预部署命令。“--no-strip-wasm”参数会阻止代码运行最后一个最小化步骤,这导致更难以读取错误和进行调试。WASM 还要求针对多线程和内存共享使用跨源打开程序策略和跨源嵌入程序策略。

"hosting": {
      "predeploy": "flutter build web --wasm",
      "public": "build/web",
      "ignore": [
        "firebase.json",
        "**/.*"
      ],
      "headers": [
        {
          "source": "**/*",
          "headers": [
            {
              "key": "cross-origin-opener-policy",
              "value": "same-origin"
            },
            {
              "key": "cross-origin-embedder-policy",
              "value": "require-corp"
            }
          ]
        }
      ]
    }

学习和资源

在“Purrfect Code”的整个开发过程中,我们依靠各种资源,并从现有项目中汲取灵感,我们希望这个项目能为相关工作提供参考价值。以下是我们认为有价值的一些重要学习资源和参考资料:


参考项目

我们使用 Super DashI/O Flip 这两款游戏作为最佳实践和实施想法的参考。两个项目都为构建 Flutter 游戏、处理游戏状态和实施游戏机制提供了宝贵的见解。Super Dash 与我们的游戏直接相关,因为它很简单,不需要后端服务,就像我们的游戏一样。I/O Flip 更大,并且确实需要后端以及生成式 AI 功能支持,因此开发者可能会对需要这些功能的游戏感兴趣。如果您对利用 Flutter 制作游戏感兴趣,这两款游戏都是宝贵的资源。


总结

我们希望“Purrfect Code”不仅能提供愉快的游戏体验,还能为有兴趣使用 Flutter 和 Flame 进行游戏开发的开发者提供学习资源。事实证明,FlutterFlameChrome 的组合非常合适为我们的游戏/应用程序混合体提供了 UI 开发、图形渲染、声音管理等方面的坚实基础。我们鼓励您探索游戏的源代码并尝试进一步扩展它。添加新功能、关卡和游戏机制的可能性有很多。跳转到 Project IDX 中的代码库,选中询问这是否是 Flutter 应用程序的框,然后尽情发挥您的创造力!