iT邦幫忙

2021 iThome 鐵人賽

DAY 1
0
Modern Web

Vite 出小蜜蜂~和卡比一起玩網頁遊戲開發!系列 第 11

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

  • 分享至 

  • xImage
  •  

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 },
    },
  };
}

關於兔兔們:


上一篇
[Day9] Vite 出小蜜蜂~撞擊行為 Collision Behavior!
下一篇
[Day11] Vite 出小蜜蜂~ Enemy!
系列文
Vite 出小蜜蜂~和卡比一起玩網頁遊戲開發!19
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言