-
Nikitos создал
Последний хвост §1.3: у тела движка была ОДНА форма, поэтому «попал в голову, а не в ногу» было недостижимо. Теперь у тела до 8 форм-зон, каждая со смещением от центра, а в контакте видно, КАКАЯ форма столкнулась. ЧТО СДЕЛАНО: * C: r2d_physics_add_shape(p, id, desc, dx, dy) и r2d_physics_shape_count; user data формы теперь кодирует И тело, И номер формы: (id+1) << 8 | index. Появился r2d__shape_index_of_shape; contact_between/contacts_of отдают индексы форм (shapeA/shapeB, shape/shapeOther); * engine.addShape(body, desc), engine.shapeCount(body); * $.world.zone(node, {type, w, h, x, y, tag, sensor, ...}), zoneTag, zoneCount, zonesTouching; метод узла .zone({...}). Имя метода — `zone`, а НЕ `shape`: `.shape()` уже занято формой хитбокса, и мой первый вариант молча перезаписался вторым def (это и обнаружилось тем, что `.shape({...})` возвращал обёртку, а формы не добавлялись). СМЕЩЕНИЕ ЗОНЫ — ОТДЕЛЬНЫЕ ПАРАМЕТРЫ dx/dy, а не поля описания тела. Сначала я положил смещение в R2DBodyDesc (shape_dx/shape_dy), и это тихо сломало ВСЕ коллизии: тела стали пролетать сквозь стены. Внешне всё выглядело здоровым — тела создавались, массы были правильные (смещение не меняет площадь), луч видел стены. Диагноз дал только контрольный опыт: с инлайн-созданием формы коллизии возвращались, а через helper — нет. ТРИ ГРАБЛИ, на которые я наступил, и что их ловит: 1. `&sd` вместо `sd` в helper — движок падал с SIGTRAP на старте. Компилятор предупреждал, а я warnings не смотрел; теперь смотрю. 2. Смещение в описании тела — сломало коллизии (см. выше). 3. Имя `.shape()` занято — переименовал в `.zone()`. ПРОВЕРКА (tests/agent/highlevel_zones_test.py, 16 проверок): зоны получают индексы 1 и 2 (0 — основная форма), теги читаются; и главное — ФИЗИКА: пол касается формы 2 → тега `legs`, а НЕ головы; на втором теле стена касается зоны `foot`, а не основной формы. То есть зоны действительно разнесены в пространстве, а не «настройка сохранилась». ЧЕСТНО ПРО ГРАБЛИ В ТЕСТЕ: проверка «шип падает сверху в голову» оказалась хрупкой — шип у меня проскакивал мимо, а зоны часто перекрываются, и тогда пара касается нескольких форм сразу. Поэтому проверяю через `contactsOf` (какая форма лежит на полу) и добавил `zonesTouching` — он отдаёт ВСЕ задетые зоны, а не первую. Это записано в world.md §2.3. ДОКИ: world.md §2.3 (поля зоны, перекрытие, предел 8 форм), API.md (engine.addShape с прямым предупреждением, что x/y — смещение, а не позиция), TASKS §1.3 и §12.6. Полный qjs, агентские тесты (включая contact и tug, которые эту регрессию и поймали), doc_coverage, doc_claims, duplicate_keys, быстрый набор — зелёные.53fc4716