碰撞检测
采用事件驱动模型来模拟小球的运动及碰撞,首先预测所有的碰撞事件,按碰撞时间存入优先队列,
碰撞发生时重新计算发生碰撞的小球的速度,方向,重新预测该小球可能发生的的碰撞事件存入优先队列
同时定义一个重复的事件存入优先队列,用来模拟时钟及重绘每个小球的位置。
遍历优先队列模型小球的运动和碰撞,示意图如下:
public class CollisionSystem {
private static final double HZ = 0.5; // number of redraw events per clock tick
private MinPQ<Event> pq; // the priority queue
private double t = 0.0; // simulation clock time
private Particle[] particles; // the array of particles
/**
* Initializes a system with the specified collection of particles.
* The individual particles will be mutated during the simulation.
*
* @param particles the array of particles
*/
public CollisionSystem(Particle[] particles) {
this.particles = particles.clone(); // defensive copy
}
// updates priority queue with all new events for particle a
//预测可能与小球a发生的所有碰撞事件存入优先队列
private void predict(Particle a, double limit) {
if (a == null) return;
// particle-particle collisions
for (int i = 0; i < particles.length; i++) {
//预测小球a与小球particles[i]发生碰撞的时间,如果时间有效存入优先队列
double dt = a.timeToHit(particles[i]);
if (t + dt <= limit)
pq.insert(new Event(t + dt, a, particles[i]));
}
// particle-wall collisions
//预测小球与墙发生碰撞的时间,如果时间有效存入优先队列
double dtX = a.timeToHitVerticalWall();
double dtY = a.timeToHitHorizontalWall();
if (t + dtX <= limit) pq.insert(new Event(t + dtX, a, null));
if (t + dtY <= limit) pq.insert(new Event(t + dtY, null, a));
}
// redraw all particles
private void redraw(double limit) {
StdDraw.clear();
for (int i = 0; i < particles.length; i++) {
particles[i].draw();
}
StdDraw.show();
StdDraw.pause(20);
if (t < limit) {
pq.insert(new Event(t + 1.0 / HZ, null, null));
}
}
/**
* Simulates the system of particles for the specified amount of time.
*
* @param limit the amount of time
*/
public void simulate(double limit) {
// initialize PQ with collision events and redraw event
pq = new MinPQ<Event>();
//预测每个小球可能的碰撞事件
for (int i = 0; i < particles.length; i++) {
predict(particles[i], limit);
}
//模拟时钟,重绘小球位置
pq.insert(new Event(0, null, null)); // redraw event
// the main event-driven simulation loop
while (!pq.isEmpty()) {
// get impending event, discard if invalidated
Event e = pq.delMin();
if (!e.isValid()) continue;
Particle a = e.a;
Particle b = e.b;
// physical collision, so update positions, and then simulation clock
for (int i = 0; i < particles.length; i++)
particles[i].move(e.time - t); //移动小球的位置
t = e.time;
// process event
if (a != null &