Dette er et eksempel på, hvordan man kan benytte p5.Vector klassen til at simulere kollision mellem 2 cirkler.
Den resulterende hastighedsvektor efter kollisionen beregnes ved at benytte reflektion om normalvektoren til de sammenstødende cirkelperiferier.
Reflektionen kan beregnes ved hjælp af formlen
$$\vec r = \vec d - 2 (\vec d \cdot \vec n) \vec n$$
hvor \( \vec d \) er den indkommende vektor, \( \vec n = \frac{\vec n}{|\vec n|}\) er en normaliseret normal-vektor til cirkelperiferien, og \( \vec r \) er reflektionen af \( \vec d \) omkring \( \vec n \).
Se også implementationen af reflect().
\(\vec n\) er en normal vektor til overfladen, og denne er normaliseret dvs. $$\vec n = \frac{\vec n}{|\vec n|}$$
Projektionen \(\vec p\) af \(\vec d\) på overfladens normalvektor \(\vec n\) findes ved hjælp af skalar produktet $$\vec p = (\vec d \cdot \vec n)\vec n$$
Vektoren \(\vec e\) bruges som hjælp i beregningen
$$\vec e = \vec d - \vec p$$
Da indfaldsvinkel og udfaldsvinkel er ens, og desuden er størrelsen af den indgående vektor og reflektionen ens \(|\vec d| = |\vec r|\) fås
$$\vec r = -\vec d + 2\vec e$$
Derefter kan formlerne kombineres
$$ \begin{aligned} \vec r &= -\vec d + 2(\vec d - \vec p) \\ &= -\vec d + 2(\vec d - (\vec d \cdot \vec n)\vec n) \\ &= -\vec d + 2\vec d - 2(\vec d \cdot \vec n)\vec n \\ &= \vec d - 2(\vec d \cdot \vec n)\vec n \end{aligned} $$
Eksemplet består er opdelt i 3 filer, som er inkluderet i html filen således:
<script src="ball.js"></script>
<script src="bat.js"></script>
<script src="sketch.js"></script>
Det overordnede programflow styres i sketch.js
.
let ball;
let bat;
function setup() {
createCanvas(windowWidth, windowHeight);
ball = new Ball(width / 2, height / 2)
bat = new Bat(0,0)
}
function draw() {
background(220);
ball.render();
ball.update();
bat.render();
bat.update();
bat.collision(ball)
}
Filen ball.js
indeholder en klassen Ball.
class Ball {
constructor(x, y) {
this.pos = createVector(x, y)
this.vel = createVector(12, 3)
this.r = 40
this.isColliding = false
this.collisionHandled = false
}
update() {
this.pos.add(this.vel);
this.edges();
}
edges() {
const x = this.pos.x;
if (x - this.r < 0 || x + this.r >= width) {
this.vel.x = -this.vel.x
}
const y = this.pos.y;
if (y - this.r < 0 || y + this.r >= height) {
this.vel.y = -this.vel.y
}
}
render() {
push();
if (this.isColliding) {
strokeWeight(5)
}
if (this.collisionHandled) {
fill('green')
}
circle(this.pos.x, this.pos.y, this.r * 2);
pop();
}
}
Filen bat.js
indeholder en klassen Bat.
class Bat {
constructor(x, y) {
this.pos = createVector(x, y)
this.r = 60
}
update() {
this.pos = createVector(mouseX, mouseY)
}
render() {
push();
fill('red')
circle(this.pos.x, this.pos.y, this.r * 2);
pop();
}
collision(other) {
const distance = this.pos.dist(other.pos);
other.isColliding = distance < this.r + other.r
if (other.isColliding) {
if (!other.collisionHandled) {
this._resolveCollision(other);
other.collisionHandled = true;
}
} else {
other.collisionHandled = false;
}
}
_resolveCollision(other) {
const surfaceNormal = p5.Vector.sub(this.pos, other.pos);
other.vel.reflect(surfaceNormal);
}
}
Bemærk hvordan reflect() benyttes til beregning af hastigheden efter kollisionen.
Prøv det kørende eksempel