[Day16] Vite 出小蜜蜂~ Text 文字!

Day16

接下来,卡比想要先去做 介面 (HUD)
方便我们进入到计分系统的时候,可以顺便验证分数。

首先,我们让画面能够渲染 文字

Text

首先我们要增加新的 Renderer
透过不同的 type 区分我们要渲染的画面物件。

-- src/types.ts

interface GraphicsRenderer {
  renderer: {
    type: "graphics";
    src: number[][];
  };
}

interface TextRenderer {
  renderer: {
    type: "text";
    src: string;
  };
}

export type Renderer = GraphicsRenderer | TextRenderer;

Font

接下来我们要去找接近 70s 8bit 的字体。

-- src/style.css

@import url("https://fonts.googleapis.com/css2?family=VT323&display=swap");

Render Text

render 这边,
我们要新增一个函式,专门负责产生 PIXI.Text 物件到画面上。

-- src/systems/render.ts

function Text(instance: Renderer) {
  if (instance.renderer.type !== "text") return;

  const src = instance.renderer.src;

  return new _Text(src, {
    fontFamily: "VT323",
    fontSize: 12,
    fill: 0xffffff,
  });
}

稍微调整一下 render 函式。

export function render(stage: Container, instance: GameObject & Renderer) {
  let child: DisplayObject | undefined;

  if (instance.renderer.type === "graphics" && canTransform(instance)) {
    child = Graphics(graphics, instance);
  }

  if (instance.renderer.type === "text") {
    child = Text(instance);
  }

  child && stage.addChild(child);
}
function Graphics(
  graphics: _Graphics,
  { renderer, position }: Renderer & Transform
) {
  const src = renderer.src;

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

      graphics.beginFill(0xffffff);

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

      graphics.endFill();
    }
  }

+ return graphics;
}

Mount

接着我们新增一个新的资料夹, src/HUD 并建立 Game.ts
专门存放游戏画面的介面。

先测试一下文字的渲染是否正常运行。

export default function GameHUD(): GameObject & Renderer {
  return {
    renderer: {
      type: "text",
      src: "SCORE",
    },
  };
}

安置到场景上即可。

-- src/scenes/Game.ts

export default function Game(screen: Rectangle): Scene<Container> {
  let instances: GameObject[] = [
    LaserCannon(screen),
    ...spawn(Enemy, points),
+   GameHUD(),
  ];

  const update = ap(
    SequentialMovement({
      counts: instances.filter(isEnemy).length,
      step: 2,
    }),
    RandomlyShoot({
      row: ROW_WIDTH,
      rate: 1000,
    })
  );

  return {
    update(delta) {
      collisionDetect(instances.filter(canCollision).filter(canTransform));

      update(delta, instances);

      instances.forEach((instance) => {
        if (canControl(instance)) {
          instance.handleInput(getKeyPressed());
        }

        if (canShoot(instance) && instance.canShoot) {
          requestAnimationFrame(() => {
            instances = [...instances, instance.shoot()];
          });

          instance.canShoot = false;
        }

        if (instance.destroy) {
          requestAnimationFrame(() => {
            instances = instances.filter((_instance) => _instance !== instance);
          });

          return;
        }

        instance.update?.(delta);
      });
    },

    render(stage) {
      clear();

      instances
        .filter(canRender)
        .forEach((instance) => render(stage, instance));
    },
  };
}

关於兔兔们:


<<:  第7章:管理本地端主机之使用者与群组(一)

>>:  [Day 12] 第一主餐 pt.5-MySQL Django一起串联,就是这麽简单

Day 11 漏洞分析 - Vulnerability Analysis (nikto)

经过连续十天的收集情报,体验了各式工具,可以发现前面介绍的大部分工具都是单纯的收集情报,少部分则可以...

现实生活中的无耳猫

. . . (未完待续) 现实生活中的无耳猫 ...

[D09] still placeholder

写在前面 still placeholder still placeholder still pla...

Day16 NiFi - 与 MongoDB 对接设定

今天要介绍如何用 NiFi 来对 MongoDB 的资料做操作。MongoDB 是我们最熟悉的 Do...

Day 20 - 规划各功能模组的介面

紧接着今天我们要来规划各个功能模组的介面了! 首先是登入後的首页,会陈列使用者上传记帐资讯,包含图片...