iT邦幫忙

2024 iThome 鐵人賽

DAY 21
0

提供更多範例,讓使用者了解此元件用法吧。( •̀ ω •́ )✧

物體性質

調整物體性質,產生更多樣的交互作用。

src\components\wrapper-physics\examples\body-property.vue

<template>
  <div class="flex flex-col gap-4 w-full border border-gray-300 p-6">
    <div class="flex gap-2">
      <div
        class="p-2 px-4 border rounded cursor-pointer select-none"
        @click="wrapperRef?.start()"
      >
        開始
      </div>
      <div
        class="p-2 px-4 border rounded cursor-pointer select-none"
        @click="wrapperRef?.reset()"
      >
        重置
      </div>
    </div>

    <wrapper-physics
      ref="wrapperRef"
      class="flex flex-col items-center justify-center border h-[30rem]"
    >
      <div class="flex">
        <wrapper-physics-body
          v-for="item, i in list"
          :key="i"
          v-bind="item"
        >
          {{ item.text }}
        </wrapper-physics-body>
      </div>

      <wrapper-physics-body>
        🐟
      </wrapper-physics-body>
    </wrapper-physics>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

import WrapperPhysics from '../wrapper-physics.vue';
import WrapperPhysicsBody from '../wrapper-physics-body.vue';

type BodyProp = InstanceType<typeof WrapperPhysicsBody>['$props'];

interface Item extends BodyProp {
  text: string;
}

const wrapperRef = ref<InstanceType<typeof WrapperPhysics>>();

/** 回彈力設為 1.5,表示回彈速度會是進入速度的 1.5 倍
 * 
 * 畫面會超嗨喔!ᕕ( ゚ ∀。)ᕗ 
 */
const restitution = 1.5;

const list: Item[] = [
  { text: '靜', isStatic: true },
  { text: '追', restitution },
  { text: '趕', restitution },
  { text: '慢', frictionAir: 1 },
  { text: '跑', restitution },
  { text: '跳', restitution },
  { text: '止', isStatic: true },
  { text: '碰', restitution },
  { text: '🐟', restitution },
]
</script>

在文件中引入範例。

docs\components\wrapper-physics\index.md

...

<script setup>
...
import BodyProperty from '../../../src/components/wrapper-physics/examples/body-property.vue'
</script>

...

### 物體性質

調整物體性質,產生更多樣的交互作用

<body-property/>

::: details 查看範例原始碼
<<< ../../../src/components/wrapper-physics/examples/body-property.vue
:::

...

一起嗨起來。◝( •ω• )◟

動畫.gif

重力方向

調整重力方向,讓元素飄起來!(ノ>ω<)ノ

src\components\wrapper-physics\examples\adjust-gravity.vue

<template>
  <div class="flex flex-col w-full border border-gray-300">
    <wrapper-physics
      v-bind="env"
      immediate
      class="flex flex-col items-center justify-center border-b h-[30rem]"
    >
      <div class="flex">
        <wrapper-physics-body
          v-for="item in list"
          :key="item"
          class=" select-none"
          :class="item"
        >
          🐟
        </wrapper-physics-body>
      </div>
    </wrapper-physics>

    <div class=" flex flex-col p-4 ">
      <div class="flex gap-6">
        <label>
          重力 x 分量
        </label>

        <input
          v-model.number="env.gravity.x"
          type="range"
          min="-2"
          max="2"
          step="0.1"
          class="flex-1"
        >

        <div class="w-6 text-right">
          {{ env.gravity.x }}
        </div>
      </div>

      <div class="flex gap-6">
        <label>
          重力 y 分量
        </label>

        <input
          v-model.number="env.gravity.y"
          type="range"
          min="-2"
          max="2"
          step="0.1"
          class="flex-1"
        >

        <div class="w-6 text-right">
          {{ env.gravity.y }}
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, } from 'vue';

import WrapperPhysics from '../wrapper-physics.vue';
import WrapperPhysicsBody from '../wrapper-physics-body.vue';

type BodyProp = InstanceType<typeof WrapperPhysicsBody>['$props'];

const env = ref({
  gravity: {
    scale: 0.001,
    x: 0,
    y: 1,
  },
});

const list = [
  'text-base', 'text-lgF', 'text-xl',
  'text-2xl', 'text-3xl', 'text-4xl',
  'text-5xl', 'text-6xl', 'text-7xl',
];
</script>

在文件中引入範例。

docs\components\wrapper-physics\index.md

...

<script setup>
...
import AdjustGravity from '../../../src/components/wrapper-physics/examples/adjust-gravity.vue'
</script>

...

### 調整重力

調整重力方向,讓元素飄起來!(ノ>ω<)ノ

<adjust-gravity/>

::: details 查看範例原始碼
<<< ../../../src/components/wrapper-physics/examples/adjust-gravity.vue
:::

...

重力異想世界!ᕕ( ゚ ∀。)ᕗ

動畫.gif

最後讓我們補充一下原理簡介。

docs\components\wrapper-physics\index.md

...

## 原理

概念為利用 Matter.js 模擬物理效果,並將對應元素之狀態同步至 DOM 元素上。

::: tip 甚麼是 Matter.js
Matter.js 是一個很成熟的 JavaScript 2D 物理引擎套件,官網上有很多有趣的範例

📚 [Matter.js](https://brm.io/matter-js/)
:::

具體流程如下:

1. wrapper-physics 收集內部註冊的 wrapper-physics-body。
1. 根據 body 的位置、尺寸與 prop,建立對應的 Matter.js 物體。
1. 透過 Matter.js 模擬物理效果並將物理效果儲存。
1. body 取得儲存的物理效果,並同步至 DOM 元素上。

如此這般,我們成功實現物理效果模擬了!就像是替身一樣!(ノ>ω<)ノ

## API

### Props

<<< ../../../src/components/wrapper-physics/wrapper-physics.vue/#Props

### Methods

<<< ../../../src/components/wrapper-physics/wrapper-physics.vue/#Methods

### Slots

<<< ../../../src/components/wrapper-physics/wrapper-physics.vue/#Slots

總結

  • 新增「物體性質」範例,展示更豐富的物體交互作用
  • 新增「重力方向」範例,展示重力設定效果

以上程式碼已同步至 GitLab,大家可以前往下載:

GitLab - D21


上一篇
D20 - 物理包裝器:單元測試
下一篇
D22 - 物理包裝器:e2e 測試
系列文
要不要 Vue 點酷酷的元件?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言