Бархӯрдҳо
Бе бархӯрд бозӣ нест
Тир ба душман расид, қаҳрамон ба платформа истод, тӯб аз ракетка баргашт, мор себро хӯрд — ҳамаи ин санҷиши бархӯрдҳо аст: оё ду шакл ҳозир якдигарро мебуранд. Ҳолст инро намедонад (дар он танҳо пикселҳо ҳастанд), бинобар ин бархӯрдҳоро аз рӯи ададҳои ҳолати бозӣ ҳисоб мекунанд.
Дар аксари бозиҳои 2D объектҳоро барои бархӯрд то ду шакл сода мекунанд: росткунҷа ва доира. Ҳатто агар дар экран персонажи мураккаб кашида шуда бошад, «хитбокс»-и он — росткунҷаи оддӣ аст.
Росткунҷа бо росткунҷа (AABB)
Росткунҷаҳоеро, ки тарафҳояшон ба канорҳои экран параллеланд, AABB (axis-aligned bounding box) меноманд. Санҷиш — аз баръакс: росткунҷаҳо намебуранд, агар яке пурра аз дигаре чаптар, ростар, болотар ё поёнтар бошад. Дар ҳамаи ҳолатҳои дигар — мебуранд.
function rectsOverlap(a, b) {
return (
a.x < b.x + b.w && // канори чапи a аз канори рости b чаптар
a.x + a.w > b.x && // канори рости a аз канори чапи b ростар
a.y < b.y + b.h && // болои a аз поёни b болотар
a.y + a.h > b.y // поёни a аз болои b поёнтар
);
}
< ва >-и қатъӣ маънои онро доранд, ки ламс бо канорҳо ҳанӯз бархӯрд нест. Агар дар бозӣ дигар хел лозим бошад,
ба <= ва >= иваз мекунанд.
Доира бо доира
Доираҳо вақте мебуранд, ки масофаи байни марказҳо аз суммаи радиусҳо хурд бошад:
function circlesOverlap(a, b) {
const dist = Math.hypot(a.x - b.x, a.y - b.y); // √(dx² + dy²)
return dist < a.r + b.r;
}
Math.hypot(dx, dy) — дарозии гипотенуза, яъне масофа аз рӯи теоремаи Пифагор. Вақте ки объектҳо
хеле зиёданд, решаро ҳисоб намекунанд ва квадратҳоро муқоиса мекунанд: dx * dx + dy * dy < (a.r + b.r) ** 2.
Доира бо росткунҷа
Тӯб ва хишт, танга ва платформа. Усули дақиқ — ёфтани нуқтаи росткунҷа, ки ба маркази доира наздиктарин аст, ва санҷиши масофа то он:
function circleRect(c, r) {
const nearX = Math.max(r.x, Math.min(c.x, r.x + r.w));
const nearY = Math.max(r.y, Math.min(c.y, r.y + r.h));
return Math.hypot(c.x - nearX, c.y - nearY) < c.r;
}
Дар аркадаҳои оддӣ аксар вақт боз ҳам соддатар мекунанд: доираро квадрат бо тарафи 2r ҳисоб мекунанд ва
rectsOverlap-ро истифода мебаранд. Хато танҳо дар кунҷҳо намоён аст.
Бозгашт аз деворҳо
Тӯб набояд аз майдон берун парад. Ҳар деворро месанҷем: агар тӯб ба он даромада бошад — онро ба ҳудуд бармегардонем ва суръатро тағйири самт медиҳем:
if (ball.x - ball.r < 0) { // девори чап
ball.x = ball.r;
ball.vx = Math.abs(ball.vx); // акнун бешубҳа ба рост парвоз мекунад
}
if (ball.x + ball.r > canvas.width) { // девори рост
ball.x = canvas.width - ball.r;
ball.vx = -Math.abs(ball.vx); // акнун бешубҳа ба чап парвоз мекунад
}
Чаро на ball.vx = -ball.vx? Дар як кадр тӯб метавонад ба девор чуқур дарояд. Агар танҳо
суръатро баръакс кунем, дар кадри оянда вай метавонад ҳанӯз набарояд — ва суръат боз баръакс мешавад, тӯб
«мечаспад» ва меларзад. Баргардондан ба ҳудуд ва Math.abs бозгаштро боэътимод мекунанд.
Пас аз бархӯрд чӣ кор кардан
Бархӯрд — танҳо «ҳа / не» аст. Минбаъд бозӣ ҳал мекунад:
for (const enemy of enemies) {
if (rectsOverlap(bullet, enemy)) {
enemy.alive = false;
bullet.alive = false;
score += 10;
}
}
enemies = enemies.filter((e) => e.alive);
Ҳангоми гузаштан аз массив бевосита хориҷ кардан хатарнок аст (индексҳо ҷой иваз мекунанд), бинобар ин аввал
alive = false қайд мекунанд, баъд тавассути filter хориҷ мекунанд.
Объектҳои аз ҳад тез
Агар тир дар як кадр 50 пиксел парвоз кунад, девор бошад 10 ғафсӣ дошта бошад, дар як кадр тир ҳанӯз пеши девор аст, дар кадри оянда — аллакай пушти он, ва буриш рух намедиҳад. Инро «туннелшавӣ» меноманд. Воситаҳои оддӣ: суръатро маҳдуд кардан, объектҳоро ғафстар кардан ё объектҳои тезро дар як кадр бо якчанд қадами хурд ҳаракат додан.
Хулоса
- Хитбоксҳо — росткунҷаҳо ва доираҳо, ададҳои ҳолатро месанҷем, на пикселҳоро.
- AABB: чор муқоисаи канорҳо; доираҳо:
Math.hypot(dx, dy) < r1 + r2. - Бозгашт: ба ҳудуд баргардондан ва самтро тавассути
Math.absдодан. - Пас аз бархӯрд объектҳоро қайд мекунем ва бо
filterхориҷ мекунем.