iT邦幫忙

2021 iThome 鐵人賽

DAY 1
0
Modern Web

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

[Day9] Vite 出小蜜蜂~撞擊行為 Collision Behavior!

  • 分享至 

  • xImage
  •  

Day9

Collision Behavior

LaserSquid 相互撞擊時,
我們想要將 Squid 從場上移除。
我們需要一個 event 讓我們得知發生撞擊,並且需要做什麼事情。

新增一個 collision 參數,
當開始發生撞擊時, start 函式會被調用,並傳入當前撞擊的物件。

export interface Collision {
  collider: {
    size: Vector;
  };

  collision?: {
    start?<T extends GameObject & Collision>(this: T, collider: T): void;
  };
}

當撞擊發生時執行 start 函式,

note
我們希望 start 函式的 this 指向 GameObject 本身而非元件,
故使用 call 並傳入物件作為 this

export function collisionDetect(instances: (Collision & Transform)[]) {
  for (let i = 0; i < instances.length; i++) {
    for (let j = i + 1; j < instances.length; j++) {
      const A = instances[i];
      const B = instances[j];

      const o1 = {
        x: A.position.x,
        y: A.position.y,
        w: A.collider.size.x,
        h: A.collider.size.y,
      };
      const o2 = {
        x: B.position.x,
        y: B.position.y,
        w: B.collider.size.x,
        h: B.collider.size.y,
      };

      if (hitTest(o1, o2)) {
+       A.collision?.start?.call(A, B);
+       B.collision?.start?.call(B, A);
      }
    }
  }
}

我們需要實作一個機制,讓系統知道我們要銷毀某個物件。
destroy 被設置成 true 時,
我們就要將該物件移除。

export interface GameObject {
  destroy?: boolean;
  update?(delta: number): void;
}
export default function Game(screen: Rectangle): Scene<Container> {
  let instances: GameObject[] = [LaserCannon(screen), Squid()];

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

      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) {
      instances
        .filter(canRender)
        .forEach((instance) => render(stage, instance));
    },
  };
}

Laser 撞到其他物件時,就將 Laser 自己跟撞擊到的物件移除。

function Laser({
  x,
  y,
}: Vector): GameObject & Transform & Renderer & Collision {
  return {
    renderer: {
      type: "graphics",
      src: [[1], [1], [1], [1]],
    },

    position: { x, y },

    update() {
      this.position.y -= 1;
    },

    collider: {
      size: { x: 1, y: 4 },
    },

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

關於兔兔們:


上一篇
[Day8] Vite 出小蜜蜂~撞擊檢測 Collision Detection!
下一篇
[Day10] Vite 出小蜜蜂~Function Composition!
系列文
Vite 出小蜜蜂~和卡比一起玩網頁遊戲開發!19
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言