43 lines
1.9 KiB
C
43 lines
1.9 KiB
C
|
|
#pragma once
|
|||
|
|
// -----------------------------------------------------------------------------
|
|||
|
|
// Карта тайлов: EMPTY / WALL. Декартов мир, тайл = 1.0 юнита.
|
|||
|
|
// Здесь же DDA-рейкаст (Amanatides & Woo) и circle-vs-AABB разрешение коллизий.
|
|||
|
|
// Об изометрии этот модуль не знает.
|
|||
|
|
// -----------------------------------------------------------------------------
|
|||
|
|
#include <cstdint>
|
|||
|
|
|
|||
|
|
#include "core/math.h"
|
|||
|
|
#include "tuning.h"
|
|||
|
|
|
|||
|
|
enum class Tile : uint8_t
|
|||
|
|
{
|
|||
|
|
EMPTY = 0,
|
|||
|
|
WALL = 1,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
struct Tilemap
|
|||
|
|
{
|
|||
|
|
Tile tiles[MAP_W * MAP_H] = {};
|
|||
|
|
|
|||
|
|
void Generate(); // единственный захардкоженный уровень
|
|||
|
|
|
|||
|
|
static bool InBounds(int x, int y) { return unsigned(x) < unsigned(MAP_W) && unsigned(y) < unsigned(MAP_H); }
|
|||
|
|
|
|||
|
|
Tile At(int x, int y) const { return InBounds(x, y) ? tiles[y * MAP_W + x] : Tile::WALL; }
|
|||
|
|
void Set(int x, int y, Tile t) { if (InBounds(x, y)) tiles[y * MAP_W + x] = t; }
|
|||
|
|
|
|||
|
|
// Вне карты считаем стеной — так рейкасты и коллизии не убегают наружу.
|
|||
|
|
bool IsWall(int x, int y) const { return At(x, y) == Tile::WALL; }
|
|||
|
|
bool IsWallAt(Vec2 p) const { return IsWall(int(std::floor(p.x)), int(std::floor(p.y))); }
|
|||
|
|
|
|||
|
|
// Amanatides & Woo. true, если отрезок a->b пересекает стену. Без аллокаций.
|
|||
|
|
// tHit (если нужен) — параметр входа в стену вдоль отрезка, [0..1].
|
|||
|
|
bool RaycastBlocked(Vec2 a, Vec2 b, float* tHit = nullptr) const;
|
|||
|
|
|
|||
|
|
// Выталкивание круга из стен (несколько итераций — из-за углов).
|
|||
|
|
void ResolveCircle(Vec2& p, float r) const;
|
|||
|
|
|
|||
|
|
// Есть ли стена в круге радиуса r вокруг p (для отбраковки кандидатов).
|
|||
|
|
bool CircleHitsWall(Vec2 p, float r) const;
|
|||
|
|
};
|