粒子碰撞模拟器

你需要实现 EventScheduler 类,这是粒子碰撞模拟器的核心算法模块,负责管理和调度所有碰撞事件。

算法原理:事件驱动模拟

传统的物理模拟使用固定时间步长(如每秒60帧),但这会导致碰撞检测不精确。事件驱动模拟采用完全不同的思路:

  1. 预测所有可能的碰撞事件及其发生时间
  2. 将事件放入优先级队列(按时间排序)
  3. 跳转到下一个事件的时间点,精确处理碰撞
  4. 碰撞后重新预测受影响粒子的未来碰撞

这种方法能够精确模拟物理过程,无论粒子速度多快都不会"穿透"。

EventScheduler 接口

class EventScheduler {
  constructor()  // 初始化事件调度器,创建优先级队列
  
  clear(): void  // 清空事件队列
  
  peekNextValidEvent(particles: Particle[]): CollisionEvent | null
  // 获取下一个有效事件(不移除),需过滤过时事件
  
  processNextValidEvent(particles: Particle[]): CollisionEvent | null
  // 处理并移除下一个有效事件
  
  predictCollisionsForParticle(particle, allParticles, container, currentTime): void
  // 为单个粒子预测所有碰撞事件并加入队列
  
  predictAllCollisions(particles, container, currentTime): void
  // 预测所有粒子的碰撞事件
}

可用的工具类

PriorityQueue - 优先级队列

new PriorityQueue((a, b) => a.time - b.time)
queue.push(event)  // 插入
queue.peek()       // 查看顶部
queue.pop()        // 移除顶部
queue.isEmpty()    // 是否为空

PhysicsCalculator - 物理计算工具

// 计算两个粒子的碰撞时间
PhysicsCalculator.calculateParticleCollisionTime(p1, p2)

// 计算粒子与墙壁的碰撞时间
PhysicsCalculator.calculateWallCollisionTime(particle, container)
// 返回: { time: number, wall?: 'top'|'bottom'|'left'|'right' }

数据类型

interface Particle {
  id: number;
  x: number, y: number;        // 位置
  vx: number, vy: number;      // 速度
  radius: number, mass: number;
  collisionCount: number;      // 碰撞计数
}

interface CollisionEvent {
  time: number;                // 碰撞时间
  type: 'particle' | 'wall';
  particleA: number;           // 粒子A的ID
  particleB?: number;          // 粒子B的ID
  wall?: 'top'|'bottom'|'left'|'right';
  countA: number;              // 粒子A的碰撞计数
  countB?: number;             // 粒子B的碰撞计数
}

提交代码后,点击"生成粒子"和"开始模拟"按钮测试你的实现。