HTML5 Canvas · Oyun mantığı ve çarpışma
Daire çarpışması: yuvarlak vuruş ve mesafe sınaması
Daire (
disk ), merkez (x, y) ve yarıçap r ile tanımlanır; çarpışma testi
düzlemde mesafeye indirgenir. Canvas 2D prototiplerde top, mermi, tekerlek silueti ve dönen
sprite için yuvarlak primer çarpışma modeli sık seçilir — dikdörtgen kutu ile
köşe artefaktları istemiyorsanız daire, görsel ile mantıksal sınırın hizalanmasını
kolaylaştırır.
Aynı düzlemde eksen hizalı kutular
AABB çarpışması sayfasında; bu sayfa
daire–daire ve daire–kutu köprüsünü sabitler.
Hareket entegrasyonu ve sürtünme Hız ve hareket ile; zaman adımı Delta time ile birlikte düşünülmelidir — çarpışma geometrisini çözdükten sonra hız güncellemesi ayrı katmandır — Temel fizik ve Oyun durumu mantığı komşu başlıklardadır.
Özet: daire temsili
| Alan | Anlam | Canvas notu |
|---|---|---|
x, y |
Merkez ( dünya veya ekran öncesi uzay) | Çizimde arc merkezi ile aynı olmalıdır |
r |
Yarıçap ( bitmap / dünya birimi) | lineWidth yarı genişliği dışarı taşmaz; kontur gereksinimi ayrı hesap
|
r² |
Kare mesafe karşılaştırması | Math.sqrt maliyetini sınamada sıkça kaçının |
Temsil: merkez, yarıçap ve tuval birimi
Üretimde küçük bir nesne { x, y, r } sözleşmesi tutun; yarıçap ile çapı (
2r ) karıştırmak çok yaygın bir hatadır. Sprite çizimi merkezde değil köşede
başlıyorsa, sanat kökenli offset’i tek import fonksiyonunda merkeze taşıyın —
AABB · kutu
temsilindeki
çıpa uyarısı burada da geçerlidir.
Yuvarlak «görsel» keskin piksel hatlı olabilir; çarpışma dairesi ile görünen piksel sınırı birebir olmak zorunda değildir — oyun tasarımı gevşek veya sıkı vuruş alanı seçer. Debug için yarı saydam halka çizmek AABB’deki gibi değerlidir.
ctx.arc(x, y, r, …) ile doldurma, merkez ve yarıçapı doğrudan kullanır; ince
kontur çiziyorsanız yarıçapın yarısı kadar dışarı taşan hattı çarpışmaya dahil etmek
isteyip istemediğinize karar verin — çoğu oyunda çarpışma yine merkez /
r üzerinden kalır, kontur salt görseldir.
Daire–daire: kare mesafe ve örtüşme
İki dairenin merkezleri dx, dy ile ayrılmış olsun;
örtüşme için
dx² + dy² ≤ (r₁ + r₂)² yeterlidir. Karşılaştırmadan önce kare kök almıyorsanız
hem dal sayısı hem de sayısal profil iyileşir — yön vektörü gerektiğinde tek sefer
Math.hypot(dx, dy) veya Math.sqrt çağrısı yapılır.
Kenar teması (
tam değme ) için < veya ≤ seçimi AABB sayfasındaki gibi takım
kararıdır. Yumuşak çarpışma (
soft contact ) eklemek için eşiği küçük bir epsilon ile genişletmek
titremeyi azaltabilir; epsilon politikasını tek yerde toplayın.
Bir daire diğerinin tamamını kapsıyorsa yine aynı eşitsizlik geçerlidir; ekstra «içerde mi»
dalı gerekmez — gövde büyüklüğü farklı olduğunda tam içerme için ayrıca
d + rküçük ≤ rbüyük (
merkez mesafesi + küçük yarıçap ) gibi kural tabanlı testler yazılabilir.
/** { x, y, r } daireleri. Örtüşme yoksa mesafe karesi hesaplanmaz (isteğe bağlı erken çıkış). */
function overlapsCircles(a, b) {
const dx = b.x - a.x;
const dy = b.y - a.y;
const pr = a.r + b.r;
return dx * dx + dy * dy <= pr * pr;
}
Ayırma: normal, merkez çakışması ve gömülülük
Örtüşme derinliği yaklaşık olarak pen = r₁ + r₂ - d (
d merkez mesafesidir ). Birim normal, merkezlerden biri diğerine doğru:
nx = dx / d, ny = dy / d. Eşit kütlede her daireyi yarı
gömülülük kadar itmek simetrik çözümdür; bir gövde kinematikse tüm itme diğerine gider.
Kütle oranı biliniyorsa itişleri ters kütleyle orantılı paylaştırmak (
inverse mass ağırlığı ) daha tutarlıdır — örnek kod (
circle-separate-equal.js ) basit
eşitlik varsayar; üretimde oranı parametre yapın.
Konum düzeltmesi ile hız düzeltmesini karıştırmayın: önce gömülülüğü kapatın, sonra normal yönde hız bileşenini güncelleyin — aynı karede ikisini birbirine bağlı çözmek titreşim üretir.
d === 0 veya çok küçük olduğunda yön belirsizdir — rastgele eksen veya son kare
hız vektörü ile kırılma kullanın; aksi halde NaN yayılır. Bu özel durum üretimde sık
görülür (
üst üste spawn, snap ). Örnekteki sabit eksen (
(1, 0) ) deterministik ve ucuzdur; deterministik olmayan oyunlarda spawn
sırasını kaydırmak bazen daha doğal çözüm olur.
/**
* Eşit kütle: örtüşmeyi iki yarıya böler. Örtüşme yoksa aynı nesneleri döner.
*/
function separateCirclesEqualMass(a, b) {
const dx = b.x - a.x;
const dy = b.y - a.y;
const minD = a.r + b.r;
const d2 = dx * dx + dy * dy;
if (d2 >= minD * minD) return { a, b };
let d = Math.sqrt(d2);
let nx = dx;
let ny = dy;
if (d < 1e-8) {
nx = 1;
ny = 0;
d = 1;
} else {
nx /= d;
ny /= d;
}
const pen = minD - d;
const half = pen * 0.5;
return {
a: { ...a, x: a.x - nx * half, y: a.y - ny * half },
b: { ...b, x: b.x + nx * half, y: b.y + ny * half },
};
}
Daire–AABB: kutuya en yakın nokta
Eksen hizalı kutunun içinde veya kenarında, daire merkezine en yakın nokta
clamp ile bulunur; merkez bu noktaya olan vektörün uzunluğu
r’den küçük veya eşitse çakışma vardır. Bu, daire–dikdörtgen testinin standart
«ucuz» yoludur; köşede doğru çalışır. Merkez kutunun içindeyse en yakın nokta merkezin
kendisidir; sınamada mesafe sıfırdır ve çarpışma örtüşme yarıçapıyla belirlenir — «içte
takılı kaldım» durumu başka bir şeydir (
genelde ayırma eksikliği ).
Kutu temsilini AABB · çakışma sınaması ile aynı min/max sözleşmesinde tutun. Sıfır kalınlıkta çizgi duvarlar için kutu yüksekliği / genişliği sıfıra düşerse test bozulur; çarpışma hacmini en az birkaç dünya birimi kalınlıkta tutmak pratikte daha dayanıklıdır.
Oyuncu daire, dünya karo kutularıyla etkileşiyorsa önce karo uzayından AABB üretin, sonra bu testi uygulayın — geometri katmanı tek kalır. Yalnız örtüşme yeterliyse aşağıdaki fonksiyon kafi; kutudan «iterek çıkarma» istiyorsanız en yakın yüzey normallerine göre daireyi dışarı kaydıran küçük bir adım ( AABB çözünürlük düşüncesinin dairesel karşılığı ) ek katmandır.
function clamp(v, lo, hi) {
return Math.max(lo, Math.min(hi, v));
}
/** box: { minX, minY, maxX, maxY }. c: { x, y, r } */
function overlapsCircleAABB(c, box) {
const qx = clamp(c.x, box.minX, box.maxX);
const qy = clamp(c.y, box.minY, box.maxY);
const dx = c.x - qx;
const dy = c.y - qy;
return dx * dx + dy * dy <= c.r * c.r;
}
Hız, teğet ve sürtünme: geometri sonrası
Çarpışma düzleminde normal n bilindiğinde, hızın normal bileşeni yansıtma veya
sünekliğe (
restitution ) tabidir; teğet bileşen sürtünme ile süzülür. Bu sayfa
skaler çarpışma ve konum düzeltmesine odaklanır; vektör cebiri detayı
Temel fizik ve entegrasyon
Hız ve hareket ile
birleştirilir — önce iç içe geçmeyi çözün, sonra hızı güncelleyin. Çok düşük göreli hızda
sürtünme tam kaydırmayı durdurabilir; istifleme (
stacking ) sorunları çoğu zaman çözüm sırası ve epsilon ile
ilgilidir,
saf geometri ile çözülmez.
Çoklu çarpışmada daireler zincir oluşturduğunda tek geçişlik ayırma yeterli olmayabilir; AABB · çözünürlük bölümündeki iterasyon ve sıra uyarısı burada da geçerlidir. Oyuncu–top–duvar üçgeninde önce duvarı çözüp sonra top–oyuncu sırası vermek, beklenmedik sıçramayı azaltır — tamamen tasarım kararı.
Ölçek, tünel ve geniş faz
Hızlı mermi ince duvarı tek karede atlayabilir; daire testi örnekleme anlarında yapılıyorsa tünel riski AABB ile aynı sınıftadır — Delta time küçültme, alt adım veya süpürme ürün kararıdır — AABB · tünel ile hizalı düşünün. Bazı projelerde yalnız kritik gövdeler ( oyuncu ) için sabit alt adım, mermiler için süpürme / genişleştirilmiş hit kullanılır — karma strateji kabul edilebilir.
Çok daire için ikili döngü O(n²)’dir; karo ızgarası veya uzamsal hash ile adayları düşürün — politika AABB · geniş faz bölümündeki gibi seçilir. Daire–daire çiftleri için geniş faz yine aynı hücre listelerinden beslenebilir; kutu ve daireyi aynı dünya hücre anahtarına düşürmek boru hattını sade tutar.
Anti-kalıplar: çap ve kök maliyeti
Çap / yarıçap karışıklığı: İki katı mesafe ile kıyaslama yapmak sürekli
yanlış pozitif / negatif üretir. Çözüm: tek modülde r tanımı ve testlerde hep
r₁ + r₂.
Her çiftte sqrt: Önce kare mesafe ile eleme; yön için tek kök. Örtüşme yoksa kök çağırmayın — özellikle geniş fazdan sonra dar liste için fark edilir.
d ≈ 0 yok saymak: Üst üste spawn’da normal üretilemez; korumalı eksen seçin veya spawn noktasını birbirinden uzaklaştırın.
Merkez hizasız sprite: Çizimle çarpışma farklı çıpa kullanıyor; tek import’ta merkeze taşıyın ( Temsil ).
Önce hız, sonra konum: Gövde hâlâ iç içeyken impuls uygulamak enerji biriktirir; sırayı tersine çevirin ( Geometri sonrası ).
Bu sayfanın sınırı
Elips, sürekli çarpışma tespiti ( GJK ) veya fizik motoru entegrasyonu burada işlenmez. Amaç: Canvas 2D’de daire ve basit kutu etkileşimini doğru kurmaktır.
{ x, y, r }sözleşmesi tüm modüllerde aynı mı?- Kare mesafe önce, kök sonra politika uygulanıyor mu?
- Merkez çakışması için korumalı normal var mı?
- Hız güncellemesi ayırma sonrası mı geliyor?
- n² çift listesi büyüdü mü; geniş faz planlandı mı?
- Daire–kutu için sıfır kalınlık «çizgi duvar» kutusu üretilmedi mi?