[Day3] Vite 出小蜜蜂~ Game Loop!

Day3

软件架构

这边卡比要介绍一个名词,
Software Architecture 软件架构

软件架构 旨在如何更好的处理各个程序码段落之间的沟通,
虽然并不会让你的程序码增加什麽新的功能,但能让撰写程序码变得更容易判读,

但如果做完之後反而变累赘或是更难懂的时候,重新思考一下,
Don't overengineer your code

GameLoop

如果要论游戏程序设计最关键的部分,那一定是 GameLoop

Loop 的概念在现代开发时常出现,像是 REPL (Read-Eval-Print Loop)Event Loop ...etc.
同样的概念在游戏程序中,一样存在一个 Loop
并会以下面的方式,重复的执行动作,直到使用者主动关闭程序。

示意用

while (true) {
  processesInput();
  update();
  render();
}

根据平台与工具的不同,
实作方式可能会有差异,但主要的思考方向不变,
像是在 Web 端, JavaScript 是无法直接对底层直接做操作的,
必须透过 requestAnimationFrame 等 API 来实现 GameLoop

实际上,卡比在前一章节就已经实作 GameLoop 了,
不过接下来,卡比会做一些调整。

介面

随着程序的功能越来越复杂,如果将所有的逻辑,都写在一个函式的话,
最後程序码会变的难以理解跟维护,
所以卡比会开始整理这些逻辑跟功能到对应的物件进行封装。

但是,不同的物件会有不同的实作内容,我们需要定义一个共同的 interface
GameLoop 不需要了解是什麽物件,但是知道实作 interface 一定会有其定义的 method
他只需要去执行那个 method 即可。

卡比接下来示范如何用 interface 定义 update 以及 render,来规范架构。

实作

首先建立一个新的档案 src/types.ts

-- src/types.ts

import { Application } from "pixi.js";

export interface GameObject {
  update(delta: number): void;
  render(stage: Application): void;
}

然後,在 src/characters/Crab.ts
卡比将实作 GameObject 介面,并将他回传出去。

-- src/characters/Crab.ts

import { Graphics } from "pixi.js";
import { GameObject } from "../types";

const image = [
  [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
  [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
  [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
  [0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0],
  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  [1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1],
  [1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1],
  [0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0],
];

const image2 = [
  [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
  [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1],
  [1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1],
  [1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1],
  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
  [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
  [0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0],
];

export default function Crab(): GameObject {
  let current = 0;
  const images = [image, image2];

  let timePass = 0;

  return {
    update(delta) {
      timePass += delta;

      if (timePass > 1000) {
        current += 1;
        timePass = 0;
      }
    },

    render(app) {
      const graphics = new Graphics();

      const image = images[current % images.length];

      for (let y = 0; y < image.length; y++) {
        for (let x = 0; x < image[y].length; x++) {
          if (image[y][x] === 0) continue;

          graphics.beginFill(0xffffff);

          graphics.drawRect(x, y, 1, 1);

          graphics.endFill();
        }
      }

      app.stage.addChild(graphics);
    },
  };
}

最後在 src/main.ts

-- src/main.ts

const app = new Application({
  width: 20,
  height: 20,
  resolution: 10,
});

document.querySelector("#app")?.append(app.view);

const instance = Crab();

app.ticker.add(() => {
  app.stage.removeChildren();

  instance.update(app.ticker.deltaMS);

  instance.render(app);
});

接着确认有没有出现错误,或是任何非预期行为,
如果没有那重构就成功了。

小考题

  1. 请帮 CrabLaserCannonOctopusSquid 也进行重构。

  2. 请在场上同时显示 CrabLaserCannonOctopusSquid

关於兔兔们:


<<:  Day 05 : ML 专案生命周期

>>:  JAVA - Windows 10 安装 Maven

C# windows form 在控件事件触发回圈 为何不会更新UI

一般在写 windows form 程序时 如果不是大型开发 老板只要求 东西能动 项目立刻好 我们...

Day 26. Zabbix 实际报警案例分享 - 机器服务被关机

今天跟大家分享关机与服务中断的警报,如果有仔细观察 Problem: /etc/passwd has...

Day 04. Zabbix 可监控的服务、设备、应用

我把它分成使用基本款 (可安装 Agent)、通用款 (支援监控类通讯协定)、简易款 (无法安装 A...

Day 8:工欲善其事,必先利其器,准备好Gradle依赖

Keyword: KMM Gradle,Kotlinx serialization 到Day9使用K...

[Day 23] - React 取得永丰汇率api的json资料(1)

学会游泳会好的方法就是掉进水里 今天就直接来用react 取api 我直接参考React官网的教学:...