[Day10] Vite 出小蜜蜂~Function Composition!

Day10

接下来,要帮 Squid 也装上 Laser
敌人的 Laser 跟我们的外观是不一样的,
但是卡比希望可以利用原本已经写好的 Laser 函式,
减少重复的程序码。

Function Composition

首先,新建一个资料夹 src/army 并建立 src/army/index.ts
Laser 搬到 src/army/index.ts
并将其重构成 Base,用来当我们的基础。

type Army = GameObject & Transform & Renderer & Collision;
type BaseProps = {
  src: number[][];
  position: Vector;
  update: (army: Army) => void;
};
function Base({ src, position, update }: BaseProps): Army {
  return {
    renderer: {
      type: "graphics",
      src,
    },

    position,
    update() {
      update(this);
    },

    collider: {
      size: { x: src[0].length, y: src.length },
    },

    collision: {
      start(other) {
        other.destroy = true;
        this.destroy = true;
      },
    },
  };
}

接着,建立 Laser

type LaserProps = Omit<BaseProps, "src">;
export function Laser({ position, update }: LaserProps) {
  return Base({ src: [[1], [1], [1], [1]], position, update });
}

并透过 LaserCannon 来提供我们 positionupdate

export default function LaserCannon(screen: {
  width: number;
  height: number;
}): TLaserCannon {
  let timePass = 0;

  return {
    renderer: {
      type: "graphics",
      src: [
        [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0],
        [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0],
        [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
      ],
    },

    position: { x: 10, y: screen.height - 20 },

    canShoot: false,
    shoot() {
      const { x, y } = this.position;

+     return Laser({
+       position: { x: x + 5, y: y - 4 },
+       update(it) {
+         it.position.y -= 1;
+       },
+     });
    },

    handleInput(this: TLaserCannon, pressed) {
      if (pressed.includes(Key.Space) && timePass > 500) {
        this.canShoot = true;
        timePass = 0;
      }

      const width = screen.width - this.renderer.src[0].length;

      if (pressed.includes(Key.Left)) {
        this.position.x = clamp(0, width, this.position.x - 1);
        return;
      }

      if (pressed.includes(Key.Right)) {
        this.position.x = clamp(0, width, this.position.x + 1);
        return;
      }
    },

    update(delta) {
      timePass += delta;
    },
  };
}

Enemy Laser

接着来建立 EnemyLaser
因为我们将一些逻辑共用了,所以很快就可以做出来。

export function EnemyLaser({ position, update }: LaserProps) {
  return Base({
    src: [
      [0, 1, 0],
      [1, 0, 0],
      [0, 1, 0],
      [0, 0, 1],
      [0, 1, 0],
      [1, 0, 0],
      [0, 1, 0],
    ],
    position,
    update,
  });
}

调整一下 Squid,使其每一秒射击一次,便大功告成了。

type Enemy = GameObject & Transform & Renderer & Collision & Shooter;
export default function Squid(): Enemy {
  const images = [image1, image2];

  let current = 0;
  let timePass = 0;

  return {
    position: { x: 0, y: 0 },

    update(delta) {
      timePass += delta;

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

        this.renderer.src = images[current % images.length];
        this.canShoot = true;
      }
    },

    canShoot: false,
    shoot() {
      const { x, y } = this.position;
      const [w, h] = [image1[0].length, image1.length];

      return EnemyLaser({
        position: { x: x + w / 2, y: y + h + 1 },
        update(it) {
          it.position.y += 1;
        },
      });
    },

    renderer: {
      type: "graphics",
      src: images[current % images.length],
    },

    collider: {
      size: { x: image1[0].length, y: image1.length },
    },
  };
}

关於兔兔们:


<<:  Day12 - 敏捷式接案实践( 四 ) - 收入管理

>>:  [Day11]PHP函数01

学习日记-1

最近几天在网站上看了有管git的资料, 发现了 "连猴子都能懂的Git指南" 就...

Day11 - 在 Next.js 中使用 CSR - feat. useSWR

为什麽我们需要 SWR ? 先前我们已经了解了 CSR、SSR 与 SSG 的优劣,SSR 与 SS...

铁人赛 Day15 -- RWD响应式网页 -- 用手机、电脑、平板的拢来啦

什麽是RWD? 响应式网页设计(Responsive Web Design),可以让不同的设备都可以...

Day01:碎碎念

前言 大家好,我是 Enola~ 正在坎坷自学 iOS 开发中, 参加这次 30 天的铁人赛是为了记...

卡夫卡的藏书阁【Book2】- 学习资源介绍和Kafka架构微介绍

居高临下远眺百塔之城布拉格的高堡区,卡夫卡的衣冠冢就藏身其中 就让每天一点的卡夫卡陪伴我们熬过这3...