<script setup lang="ts">
import P5 from 'p5';

definePage({
  meta: {
    title: 'p5.js 粒子效果演示',
  },
});

// 用于挂载 p5 canvas 的 DOM 元素的引用
const sketchContainer = ref<HTMLElement | null>(null);
// p5 实例
let instance: null | P5 = null;

// 定义粒子类
class Particle {
  x: number;
  y: number;
  vx: number;
  vy: number;
  alpha: number;
  lifespan: number;
  p: P5; // p5 实例引用

  constructor(p: P5, x: number, y: number) {
    this.p = p;
    this.x = x;
    this.y = y;
    // 随机速度
    this.vx = p.random(-1, 1);
    this.vy = p.random(-2, 0); // 倾向于向上移动
    this.alpha = 255; // 初始透明度
    this.lifespan = 255; // 生命周期，与透明度关联
  }

  // 更新粒子状态
  update() {
    this.x += this.vx;
    this.y += this.vy;
    this.lifespan -= 5; // 逐渐消失
    this.alpha = this.lifespan;
  }

  // 绘制粒子
  display() {
    this.p.noStroke();
    // 可以根据速度或生命周期改变颜色
    this.p.fill(255, this.alpha); // 白色，逐渐透明
    this.p.ellipse(this.x, this.y, 8, 8); // 绘制小圆点
  }

  // 检查粒子是否存活
  isDead() {
    return this.lifespan < 0;
  }
}

// 粒子数组
const particles: Particle[] = [];

// p5 sketch 定义
const sketch = (p: P5) => {
  // setup 函数只运行一次
  p.setup = () => {
    // 创建一个 600x400 像素的画布
    p.createCanvas(600, 400);
    p.background(51); // 设置深灰色背景
  };

  // draw 函数会持续循环执行
  p.draw = () => {
    p.background(51); // 每帧都重绘背景，以实现动画效果

    // 在鼠标位置创建新粒子 (每帧创建 2 个)
    for (let i = 0; i < 2; i++) {
      particles.push(new Particle(p, p.mouseX, p.mouseY));
    }

    // 更新和显示所有粒子
    // 从后向前遍历数组，这样可以在遍历过程中安全地删除元素
    for (let i = particles.length - 1; i >= 0; i--) {
      particles[i].update();
      particles[i].display();
      // 如果粒子生命周期结束，则从数组中移除
      if (particles[i].isDead()) {
        particles.splice(i, 1);
      }
    }
  };
};

// 组件挂载后初始化 p5 实例
onMounted(() => {
  if (sketchContainer.value) {
    instance = new P5(sketch, sketchContainer.value);
  }
});

// 组件卸载前移除 p5 实例，释放资源
onUnmounted(() => {
  instance?.remove();
});
</script>

<template>
  <div class="p-4">
    <h1 class="text-2xl font-bold mb-4">p5.js 粒子效果演示</h1>

    <div class="mb-4">
      <h2 class="text-xl font-semibold mb-2">粒子系统</h2>
      <p>
        这是一个使用 p5.js 创建的简单粒子系统演示。粒子会从鼠标指针的位置生成，并向上漂浮然后逐渐消失。 p5.js
        使得创建这类动态和交互式的视觉效果变得相对容易。
      </p>
    </div>

    <h2 class="text-xl font-semibold mb-2">演示区域</h2>
    <p class="mb-2">在下面的深灰色区域移动鼠标，观察粒子效果：</p>
    <!-- p5 canvas 将会挂载到这个 div -->
    <div ref="sketchContainer" class="border border-gray-400 inline-block"></div>
  </div>
</template>
