-
Nikitos создал
Закрываю §1.3 в части, которая достижима: события контакта говорят, что СТОЛКНУЛОСЬ, но импульса в них НЕТ — солвер считает его после события. Поэтому «сила удара» (по ней считают урон) была недостижима, как и вопрос «касаются ли эти двое прямо сейчас». ЧТО СДЕЛАНО (через b2Body_GetContactData — манифолд с импульсом предыдущего шага): * C: r2d_physics_contact_between (импульс, число точек, нормаль) и r2d_physics_contacts_of (с кем и с каким импульсом); * engine.touching(a, b) → bool, engine.contactBetween(a, b) → {impulse, points, nx, ny} | null, engine.contactsOf(id, cap) → [{other, impulse, points}]; * $.world.touching / contactBetween / contactImpulse / contactsOf. Импульс берём НАИБОЛЬШИЙ по точкам манифолда: «сила удара» — это удар, а не сумма касаний. ПРОВЕРКА (tests/agent/highlevel_contact_test.py, 16 проверок): в полёте контакта нет; на полу touching true, импульс 0.1222 при 2 точках контакта и вертикальной нормали; далёкий узел не касается; contactsOf перечисляет тело с импульсом; и главное — ПИК УДАРА 0.2249 против покоя 0.1222, то есть по импульсу можно отличить удар от лежания. ТОНКОСТЬ, которую стоит помнить: импульс удара виден на кадре СТОЛКНОВЕНИЯ, а touching в этот момент ещё false — манифолд появляется на следующем шаге. Поэтому пик ищется чтением импульса КАЖДЫЙ кадр, а не только когда касание уже есть. Я на этом обжёгся в тесте и записал в доки. ЧЕСТНО ПРО НЕДОСТАЮЩЕЕ: нескольких ФОРМ на тело нет — у тела движка одна форма, поэтому «попал в голову, а не в ногу» пока недостижимо: нужны несколько форм на тело, и это отдельная работа. Форма не различается и в событиях контакта. Записано в API.md и world.md, чтобы не искали field, которого нет. ДОКИ: world.md §2.2 (таблица полей, момент чтения), API.md (три функции), TASKS §1.3 переписан. Полный qjs, агентские тесты, doc_coverage, doc_claims, duplicate_keys, быстрый набор — зелёные.06543427