Catatan: Semua yang berikut mengasumsikan permukaan bola tidak gesekan (sehingga tidak akan mulai berputar atau melambung karena berbeda).
Pada saat tabrakan, bola akan menyentuh sudut. Ketika benda padat bertabrakan, suatu gaya akan bertindak di sepanjang permukaan yang disebut normal, yaitu tegak lurus terhadap permukaan pada titik tumbukan.
Karena itu bola, tegak lurus ke permukaan mengarah ke pusat bola. Ok, jadi kita tahu arah gaya, bagaimana dengan besarnya? Dengan asumsi tabrakan elastis (dan bahwa persegi panjang tidak bisa bergerak), bola harus melambung pada kecepatan yang sama dengan yang ditimbulkannya.
Biarkan (nDx, nDy) menjadi kecepatan setelah tumbukan, (oDx, oDy) kecepatan sebelum tumbukan, dan (x, y) posisi bola pada titik tumbukan. Lebih jauh kita asumsikan sudut bola bertabrakan adalah pada (0,0).
Mengekspresikan wawasan kami sebagai formula, kami memiliki:
(nDx, nDy) = (oDx, oDy) + c * (x, y)
length (nDx, nDy) = length (oDx, oDy)
Yang setara dengan:
nDx = oDx + c * x
nDy = oDy + c * y
nDx^2 + nDy^2 = oDx^2 + oDy^2
Mengganti dua persamaan pertama dalam yang terakhir, kita dapatkan:
(oDx + c * x)^2 + (oDy + c * y)^2 = oDx^2 + oDy^2
Memperluas menggunakan thorem binomial
(a+b)^2 = a^2 + 2ab + b^2
hasil:
oDx^2 + 2 * oDx * c * x + (c * x) ^ 2 + oDy^2 + 2 * oDy * c * y + (c * y) ^ 2 = oDx^2 + oDy^2
2 * oDx * c * x + 2 * oDy * c * y + (c * x) ^ 2 + (c * y) ^ 2 = 0
(2 * oDx * x + 2 * oDy * y) * c + (x^2 + y^2) * c^2 = 0
Persamaan kuadrat ini untuk c
memiliki dua solusi, salah satunya adalah 0. Jelas, itu bukan solusi yang kami minati, karena umumnya arah bola akan berubah sebagai hasil dari tabrakan. Untuk mendapatkan solusi lain, kami membagi kedua sisi dengan c dan mendapatkan:
(2 * oDx * x + 2 * oDy * y) + (x^2 + y^2) * c = 0
Itu adalah:
c = -(2 * oDx * x + 2 * oDy * y) / (x^2 + y^2)
Untuk meringkas, kami memiliki:
c = -(2 * oDx * x + 2 * oDy * y) / (x^2 + y^2)
nDx = oDx + c * x
nDy = oDy + c * y
Edit : Dalam kode:
if (collision) {
float x = ballX - cornerX;
float y = ballY - cornerY;
float c = -2 * (ballDx * x + ballDy * y) / (x * x + y * y);
ballDx = ballDx + c * x;
ballDy = ballDy + c * y;
}
Beberapa pertimbangan implementasi: Meskipun Anda dapat memperkirakan (x, y) dengan posisi bola setelah langkah simulasi, perkiraan ini akan mengubah sudut defleksi dan karenanya sangat terlihat, sehingga langkah simulasi Anda harus sangat halus (mungkin seperti itu sehingga bola tidak bergerak lebih dari 1/20 diamaternya per langkah). Untuk solusi yang lebih akurat, Anda dapat menghitung waktu tabrakan terjadi, dan membagi langkah simulasi pada waktu itu, yaitu melakukan langkah parsial hingga titik tabrakan, dan langkah parsial lain untuk sisa langkah.
Sunting 2: Menghitung titik dampak
Misalkan r adalah jari-jari, (x0, y0) posisi dan (dx, dy) kecepatan bola pada awal langkah simulasi. Untuk kesederhanaan, mari kita asumsikan bahwa sudut yang dimaksud terletak pada (0,0).
Kita tahu:
(x,y) = (x0, y0) + (dx, dy) * t
Kami ingin
length(x,y) = r
Itu adalah
(x0 + dx * t) ^ 2 + (y0 + dy * t) ^ 2 = r^2
x0^2 + 2 * x0 * dx * t + dx^2 * t^2 + y0^2 + 2 * y0 * dy * t + dy^2 * t^2 = r ^ 2
(dx^2 + dy^2) * t^2 + (2 * x0 * dx + 2 * y0 * dy) * t + (x0^2 + y0^2 - r^2) = 0
\____ _____/ \____________ ___________/ \_______ ________/
\/ \/ \/
a b c
Itu adalah persamaan kuadrat dalam t. Jika diskriminatif
D = b^2 - 4 * a * c
negatif, tidak memiliki solusi, yaitu bola tidak akan pernah menyentuh sudut pada jalannya yang sekarang. Jika tidak, dua solusi diberikan oleh
t1 = (-b - sqrt(D)) / (2 * a)
t2 = (-b + sqrt(D)) / (2 * a)
Kami tertarik pada saat tabrakan dimulai, yang merupakan waktu sebelumnya t1
.
Metode Anda akan menjadi:
// compute a,b,c and D as given above
if (D >= 0) {
t = (-b - sqrt(D)) / (2 * a);
if (0 < t && t <= ts) {
// collision during this timestep!
x = x + t * dx;
y = y + t * dy;
ts = ts - t;
// change dx and dy using the deflection formula
}
}
x = x + ts * dx;
y = y + ts * dy;