每條游來游去的小魚,都是正在瀏覽這一頁的訪客,有一條是你自己 ( ´ ▽ ` )ノ 覺得干擾閱讀的話,可以把小魚關掉。
群
bg一群小魚游啊游 ◝( •ω• )◟
這個元件的靈感來自沖繩美麗海水族館 ヾ(◍'౪`◍)ノ゙
前陣子到沖繩美麗海水族館看大鯨鯊,偏偏撞上暑假,
人潮比水缸裡的魚還多。
動線擠得像打結的漁網,
我像隻被困的小魚,只能無助地扭動,慢慢向前。
頂著嘈雜與體溫交織的悶熱,
穿過人群,終於抵達心裡惦念的那一隅。
還沒回過神,溫柔的蔚藍已輕撫我的臉龐。
頭頂是被水光切割成無數碎片的天幕,群魚在光裡閃爍。
時間被浪花輕輕托起,
午後在海色中悄悄沉沒。
上下的界線消失,萬物無語,
只剩悸動的心跳與悠游的魚群。
然而終究無法久留,
只能在漸暗的光裡回身,
像一尾不得不離開洄游的小魚。
緩緩退向出口,
任嘈雜與擁擠重新聚攏。
| 名稱 | 描述 |
|---|---|
| JS 動畫 | 基於 JavaScript 實現的動畫,達成更複雜、精準的動畫控制,常見套件有 GSAP、anime.js 等 |
| 物理模擬 | 模擬真實世界物理現象,如重力、碰撞、速度等物理效果 |
| 向量計算 | 處理方向、加速度、速度等等數學運算 |
| Boids | 模擬鳥群、魚群等群體行為的演算法,常用於動畫和遊戲 AI |
| Spatial Hash Grid | 空間雜湊網格,將空間劃分為格子快速查詢鄰近物件,常用於碰撞偵測與群體模擬 |
| Quaternion | 四元數,用於表示和計算三維空間中的旋轉,避免萬向節鎖(Gimbal lock)問題,常用於 3D 引擎 |
| Euler Angle | 歐拉角,用於表示三維空間中的旋轉(如 yaw, pitch, roll),容易理解但可能產生萬向節鎖(Gimbal lock)問題 |
| Zdog | 輕量級偽 3D 引擎,用圓潤的幾何圖形繪製可愛的等角透視插圖 |
小魚會朝著滑鼠所在位置游動
<template> <div class="w-full flex flex-col gap-4 example-wrap"> <bg-flock /> </div></template>
<script setup lang="ts">import BgFlock from '../bg-flock.vue'</script>自定義 boid
Section titled “自定義 boid”討厭魚?組一個自己喜歡的生物吧 (・∀・)9
群
<template> <div class="w-full flex flex-col gap-4 example-wrap"> <bg-flock ref="bgRef" :count="50" :target-shell="{ radius: 150, band: 20, swirlSpeed: -0.5, }" > <div class="scene h-full w-full"> <div class="camera"> <div v-for="(boid, i) in viewBoids" :key="i" class="boid flex preserve-3d" :style="boid.style" > <div class="body flex-center text-[8px] text-white"> {{ i }} </div> </div>
<div class="label font-liu-jian-mao-cao z-0 flex-center"> {{ t('flock') }} </div> </div> </div> </bg-flock> </div></template>
<script setup lang="ts">import type { CSSProperties } from 'vue'import { computed, useTemplateRef } from 'vue'import { useI18n } from 'vue-i18n'import { useFontLoader } from '../../../composables/use-font-loader'import BgFlock from '../bg-flock.vue'
useFontLoader([{ family: 'Liu Jian Mao Cao', source: '/fonts/Liu_Jian_Mao_Cao/LiuJianMaoCao-Regular.woff2', descriptors: { weight: '400' },}])
const { t } = useI18n()
const bgRef = useTemplateRef('bgRef')
const viewBoids = computed<Array<{ style: CSSProperties }>>(() => { const result: Array<{ style: CSSProperties }> = []
const boidList = bgRef.value?.boidList ?? [] for (const boid of boidList) { const { yaw, pitch, position } = boid
const { x, y, z } = position
const transform = `translate3d(${x}px, ${y}px, ${z}px)` + ` rotateY(${yaw}rad)` + ` rotateZ(${pitch}rad)`
result.push({ style: { transform, zIndex: `${Math.round(z)}`, }, }) } return result})</script>
<style scoped lang="sass">.scene position: relative overflow: hidden /* 透視感 */ perspective: 700px isolation: isolate
.camera position: absolute inset: 0 transform-style: preserve-3d /* 可調整角度,可以製造俯視、仰視等等視角 */ // transform: rotateX(30deg)
.boid position: absolute left: 0 top: 0 pointer-events: none will-change: transform transform-origin: 0 50% 0
/* 基本箭頭(朝 +X 方向),用 clip-path 畫圖形 */.body width: 30px height: 20px background: linear-gradient(90deg, light-dark(#2ecc71, #3e5c47), light-dark(#a6f7c5, #b6e3c5)) clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 25% 50%, 0% 0%)
.label width: 100% height: 100% font-size: 20vh color: light-dark(#333, #DDD)</style>讓整個網頁變成大海吧!ヾ(◍'౪`◍)ノ゙
<template> <div class="w-full"> <base-checkbox v-model="enable" :label="t('enable')" class="example-ctrl" />
<bg-flock v-if="enable" class="pointer-events-none left-0 top-0 z-50 h-full w-full !fixed" :count="300" :size="10" :target-shell="{ radius: 150, band: 50, swirlSpeed: 0.5, }" /> </div></template>
<script setup lang="ts">import { ref } from 'vue'import { useI18n } from 'vue-i18n'import BaseCheckbox from '../../base-checkbox.vue'import BgFlock from '../bg-flock.vue'
const { t } = useI18n()
const enable = ref(false)</script>基於 Boids 演算法,預設的魚使用 zdog 繪製。
這個影片介紹得很好,也很推薦大家看看 The Nature of Code,這本書算是我的啟蒙讀物。(*´∀`)~♥
interface Props { /** 初始 boid 數量 */ count?: number; /** 小魚尺寸 */ size?: number; /** 速度倍率 */ playbackRate?: number;
boidOptions?: Partial<Pick< BoidOptions, 'maxForce' | 'maxSpeed' | 'angSmooth' >>; /** 行為權重 */ behaviorWeights?: BehaviorWeights; /** 行為半徑,決定特定行為的考量範圍 */ behaviorRadii?: BehaviorRadii; /** Shell 模式,用於模擬魚環繞特定目標成球的樣子 * * 無則維持原本單點 target 的行為 */ targetShell?: { radius: number; band: number; swirlSpeed: number; };}Methods
Section titled “Methods”interface Expose { boidList: ShallowRef<Boid[]>;}