squad-proto/src/sim/target.h

53 lines
2.5 KiB
C
Raw Normal View History

Прототип боевого ядра: отряд, хоррор-слой, ближний бой Тактический отряд с автоматическим огнём в изометрии, собственный софтверный растеризатор (raylib только окно, ввод и финальный блит). Ядро (спек, раздел 6): - LaneClear: проверка линии огня по своим, стенам и дальности; - решатель огневых позиций с гистерезисом и коммитом; - резервирование линий огня и расступание из чужих секторов; - пули-снаряды, дружественный урон физически возможен. Хоррор-слой (render-only): свет и туман войны с памятью карты, светящиеся трассеры, кровь, виньетка, зерно, напряжение. Ближний бой: сектор удара, три фазы, связка из трёх ударов, своя дисциплина «не бить сквозь своего». Проверка: squad_proto.exe --accept прогоняет критерии приёмки раздела 11 плюс блок M7 по ближнему бою — все PASS, FRIENDLY_HITS = 0 за 3 минуты боя. Сборка: cmake -S . -B build && cmake --build build --config Release raylib 6.0 подтягивается через FetchContent. Документация — CLAUDE.md как оглавление, содержание в docs/. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
#pragma once
// -----------------------------------------------------------------------------
// Мишени: статичные, не атакуют, респавнятся на том же месте.
// 12 штук кучками (5 / 3 / 3 / 1) — расстановка захардкожена.
//
// Target — компонент ECS: сущности мишеней создаются в SpawnTargets, а вектор,
// по которому ходят правила, — это плотный массив пула (см. ecs/ecs.h).
// -----------------------------------------------------------------------------
#include <vector>
#include "core/math.h"
#include "ecs/ecs.h"
#include "tuning.h"
struct Target
{
ecs::Entity self = ecs::NO_ENTITY;
Vec2 pos{};
// Своё место. Удар отбрасывает мишень, после чего она возвращается сюда:
// без отдачи попадание в упор ничем не отличается от промаха.
Vec2 home{};
Vec2 vel{};
float hp = 0.0f;
float maxHp = 0.0f;
float respawnTimer = 0.0f;
float radius = 0.34f;
bool alive = true;
// Сопротивление отбросу, 0..1. 0 — мишень летит от удара как есть,
// 1 — не сдвигается вообще. Тяжёлая цель гасит импульс клинка, и это
// единственное, чем она отличается от лёгкой при равном HP.
float knockResist = 0.0f;
// Во сколько раз ослабляется импульс с учётом общего множителя из tuning.
float KnockScale() const
{
const float r = Clampf(knockResist * g_tune.knockResistScale, 0.0f, 0.98f);
return 1.0f - r;
}
};
// Импульс от удара (dir нормализован вызывающим). speed — импульс ДО того,
// как мишень ему сопротивляется: сопротивление применяется здесь, в одном месте,
// иначе половина источников урона про него забудет.
void KnockTarget(Target& t, Vec2 dir, float speed);
void SpawnTargets(ecs::World& world);
void UpdateTargets(std::vector<Target>& targets, float dt);
// Число живых мишеней (знаменатель в оценке покрытия, спек 6.5).
int CountAliveTargets(const std::vector<Target>& targets);