Refactor WorldPos, WindowsPos done
This commit is contained in:
parent
47977d9979
commit
8a49c12909
@ -5,7 +5,6 @@
|
||||
#include "log.hpp"
|
||||
#include "math.hpp"
|
||||
#include "sprite.hpp"
|
||||
#include "coorginates.hpp"
|
||||
|
||||
Entity::Entity(WorldPos position) : m_Position(position) {
|
||||
LOG_DEBUG("spawning entity at position ", position);
|
||||
|
@ -26,10 +26,15 @@ void GameLoop::Run() {
|
||||
const auto &tiles = map.GetMapTiles();
|
||||
for (size_t row = 0; row < tiles.size(); row++) {
|
||||
for (size_t col = 0; col < tiles[row].size(); col++) {
|
||||
const auto& camera = m_Game->GetCamera();
|
||||
// LOG_DEBUG("Drawing rect (", row, ", ", col, ")");
|
||||
m_Window->DrawRect(
|
||||
map.TileEdgeToWorld(TilePos{row, col}),
|
||||
map.GetTileSize(), tiles[row][col]->R, tiles[row][col]->G,
|
||||
camera.WorldToWindow(
|
||||
map.TileEdgeToWorld(
|
||||
TilePos{static_cast<int32_t>(row), static_cast<int32_t>(col)}
|
||||
)
|
||||
),
|
||||
camera.WorldToWindow(map.GetTileSize()), tiles[row][col]->R, tiles[row][col]->G,
|
||||
tiles[row][col]->B, tiles[row][col]->A);
|
||||
}
|
||||
}
|
||||
@ -37,13 +42,15 @@ void GameLoop::Run() {
|
||||
// draw the path, if it exists
|
||||
WorldPos start_pos = m_Game->GetPlayer()->GetPosition();
|
||||
for (const auto& next_pos: m_Game->GetPath()) {
|
||||
m_Window->DrawLine(start_pos, next_pos);
|
||||
const auto& camera = m_Game->GetCamera();
|
||||
m_Window->DrawLine(camera.WorldToWindow(start_pos), camera.WorldToWindow(next_pos));
|
||||
start_pos = next_pos;
|
||||
}
|
||||
|
||||
// draw all the entities (player etc)
|
||||
for (auto &entity : m_Game->GetEntities()) {
|
||||
m_Window->DrawSprite(entity->GetPosition(), entity->GetSprite());
|
||||
const auto& camera = m_Game->GetCamera();
|
||||
m_Window->DrawSprite(camera.WorldToWindow(entity->GetPosition()), entity->GetSprite());
|
||||
}
|
||||
|
||||
m_Window->Flush();
|
||||
|
@ -17,23 +17,24 @@ Map::Map(int rows, int cols) : m_Cols(cols), m_Rows(rows) {
|
||||
}
|
||||
|
||||
WorldPos Map::TileToWorld(TilePos p) const {
|
||||
return WorldPos{(p.x + 0.5) * TILE_SIZE, (p.y + 0.5) * TILE_SIZE};
|
||||
return WorldPos{(p.x() + 0.5f) * TILE_SIZE, (p.y() + 0.5f) * TILE_SIZE};
|
||||
}
|
||||
|
||||
WorldPos Map::TileEdgeToWorld(TilePos p) const {
|
||||
return WorldPos{p.x * TILE_SIZE, p.y * TILE_SIZE};
|
||||
return WorldPos{p.x() * TILE_SIZE, p.y() * TILE_SIZE};
|
||||
}
|
||||
|
||||
TilePos Map::WorldToTile(WorldPos p) const {
|
||||
return TilePos{p.x / TILE_SIZE, p.y / TILE_SIZE};
|
||||
return TilePos{static_cast<int32_t>(p.x() / TILE_SIZE), static_cast<int32_t>(p.y() / TILE_SIZE)};
|
||||
}
|
||||
|
||||
// TODO this should probably use something like WorldSize or WorldVec to make the distinction clear
|
||||
WorldPos Map::GetTileSize() const { return WorldPos{TILE_SIZE, TILE_SIZE}; }
|
||||
|
||||
const Tile *Map::GetTileAt(TilePos p) const {
|
||||
assert(IsTilePosValid(p));
|
||||
size_t row = p.x;
|
||||
size_t col = p.y;
|
||||
size_t row = p.x();
|
||||
size_t col = p.y();
|
||||
|
||||
return m_Tiles[row][col];
|
||||
}
|
||||
@ -43,10 +44,10 @@ const Tile *Map::GetTileAt(WorldPos p) const {
|
||||
}
|
||||
|
||||
bool Map::IsTilePosValid(TilePos p) const {
|
||||
if (p.x < 0 || p.y < 0)
|
||||
if (p.x() < 0 || p.y() < 0)
|
||||
return false;
|
||||
size_t row = static_cast<size_t>(p.x);
|
||||
size_t col = static_cast<size_t>(p.y);
|
||||
size_t row = static_cast<size_t>(p.x());
|
||||
size_t col = static_cast<size_t>(p.y());
|
||||
|
||||
return row < m_Tiles.size() && col < m_Tiles[0].size();
|
||||
}
|
||||
@ -75,14 +76,14 @@ std::vector<TilePos> Map::GetNeighbors(TilePos center) const
|
||||
void Map::PaintCircle(TilePos center, unsigned radius, TileType tile_type)
|
||||
{
|
||||
// get rectangle that wraps the circle
|
||||
TilePos corner1 = TilePos{center.x - radius, center.y - radius};
|
||||
TilePos corner2 = TilePos{center.x + radius, center.y + radius};
|
||||
TilePos corner1 = TilePos{center.x() - static_cast<int32_t>(radius), center.y() - static_cast<int32_t>(radius)};
|
||||
TilePos corner2 = TilePos{center.x() + static_cast<int32_t>(radius), center.y() + static_cast<int32_t>(radius)};
|
||||
// iterate through all valid points, setting the type
|
||||
const unsigned radius_squared = radius * radius;
|
||||
for (int x = corner1.x; x < corner2.x; x++) {
|
||||
for (int y = corner1.y; y < corner2.y; y++) {
|
||||
for (int x = corner1.x(); x < corner2.x(); x++) {
|
||||
for (int y = corner1.y(); y < corner2.y(); y++) {
|
||||
TilePos current_tile = {x, y};
|
||||
unsigned distance_squared = center.distance_squared(current_tile);
|
||||
unsigned distance_squared = static_cast<unsigned>(center.DistanceTo(current_tile) * center.DistanceTo(current_tile));
|
||||
if (IsTilePosValid(current_tile) && distance_squared < radius_squared)
|
||||
{
|
||||
// y is row, x is col
|
||||
@ -94,19 +95,20 @@ void Map::PaintCircle(TilePos center, unsigned radius, TileType tile_type)
|
||||
|
||||
void Map::PaintLine(TilePos start_tile, TilePos stop_tile, double width, TileType tile_type)
|
||||
{
|
||||
const Vec2D<double> start(start_tile);
|
||||
const Vec2D<double> stop(stop_tile);
|
||||
const double line_length = start.distance(stop);
|
||||
const Vec2D<double> step((stop-start)/line_length);
|
||||
const Vec2D<double> ortho = step.orthogonal();
|
||||
const vec<double, 2> start{static_cast<double>(start_tile.x()), static_cast<double>(start_tile.y())};
|
||||
const vec<double, 2> stop{static_cast<double>(stop_tile.x()), static_cast<double>(stop_tile.y())};
|
||||
const double line_length = start.DistanceTo(stop);
|
||||
const vec<double, 2> step = (stop - start) / line_length;
|
||||
const vec<double, 2> ortho = step.GetOrthogonal();
|
||||
LOG_DEBUG("step = ", step, " ortho = ", ortho);
|
||||
|
||||
for (double t = 0; t < line_length; t += 1.0) {
|
||||
for (double ortho_t = 0; ortho_t < width; ortho_t += 0.1) {
|
||||
auto tile_pos = start + step * t + ortho * ortho_t;
|
||||
if (IsTilePosValid(tile_pos)) {
|
||||
size_t row = static_cast<size_t>(tile_pos.x);
|
||||
size_t col = static_cast<size_t>(tile_pos.y);
|
||||
TilePos tile_pos_int{static_cast<int32_t>(tile_pos.x()), static_cast<int32_t>(tile_pos.y())};
|
||||
if (IsTilePosValid(tile_pos_int)) {
|
||||
size_t row = static_cast<size_t>(tile_pos.x());
|
||||
size_t col = static_cast<size_t>(tile_pos.y());
|
||||
m_Tiles[row][col] = &tile_types.at(tile_type);
|
||||
}
|
||||
}
|
||||
@ -116,15 +118,15 @@ void Map::PaintLine(TilePos start_tile, TilePos stop_tile, double width, TileTyp
|
||||
|
||||
void Map::PaintRectangle(TilePos first_corner, TilePos second_corner, TileType tile_type)
|
||||
{
|
||||
std::initializer_list<int> xvals = {first_corner.x, second_corner.x};
|
||||
std::initializer_list<int> yvals = {first_corner.y, second_corner.y};
|
||||
std::initializer_list<int> xvals = {first_corner.x(), second_corner.x()};
|
||||
std::initializer_list<int> yvals = {first_corner.y(), second_corner.y()};
|
||||
for (int x = std::min(xvals); x < std::max(xvals); x++) {
|
||||
for (int y = std::min(yvals); y < std::max(yvals); y++) {
|
||||
TilePos tile_pos{x,y};
|
||||
LOG_DEBUG("tile_pos = ", tile_pos);
|
||||
if (IsTilePosValid(tile_pos)) {
|
||||
size_t row = static_cast<size_t>(tile_pos.x);
|
||||
size_t col = static_cast<size_t>(tile_pos.y);
|
||||
size_t row = static_cast<size_t>(tile_pos.x());
|
||||
size_t col = static_cast<size_t>(tile_pos.y());
|
||||
m_Tiles[row][col] = &tile_types.at(tile_type);
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,15 @@ public:
|
||||
// binary operators
|
||||
//
|
||||
|
||||
friend bool operator==(const vec &a, const vec &b) {
|
||||
friend bool operator==(const vec &a, const vec &b)
|
||||
requires (std::is_integral_v<T>)
|
||||
{
|
||||
return std::ranges::equal(a.m_Array, b.m_Array);
|
||||
}
|
||||
|
||||
friend bool operator==(const vec &a, const vec &b)
|
||||
requires (std::is_floating_point_v<T>)
|
||||
{
|
||||
for (const auto &[u, v] : std::views::zip(a.m_Array, b.m_Array)) {
|
||||
if (!equalEpsilon(u, v)) {
|
||||
return false;
|
||||
@ -72,21 +80,21 @@ public:
|
||||
friend bool operator!=(const vec &a, const vec &b) { return !(a == b); }
|
||||
|
||||
friend vec operator+(const vec &a, const vec &b) {
|
||||
vec<T, N> c;
|
||||
vec<T, N, Tag> c;
|
||||
std::ranges::transform(a.m_Array, b.m_Array, c.m_Array.begin(),
|
||||
std::plus{});
|
||||
return c;
|
||||
}
|
||||
|
||||
friend vec operator-(const vec &a, const vec &b) {
|
||||
vec<T, N> c;
|
||||
vec<T, N, Tag> c;
|
||||
std::ranges::transform(a.m_Array, b.m_Array, c.m_Array.begin(),
|
||||
std::minus{});
|
||||
return c;
|
||||
}
|
||||
|
||||
friend vec operator*(const vec &a, const T &scalar) {
|
||||
vec<T, N> c;
|
||||
vec<T, N, Tag> c;
|
||||
std::ranges::transform(a.m_Array, std::views::repeat(scalar),
|
||||
c.m_Array.begin(), std::multiplies{});
|
||||
return c;
|
||||
@ -95,7 +103,7 @@ public:
|
||||
friend vec operator*(const T &scalar, const vec &a) { return a * scalar; }
|
||||
|
||||
friend vec operator/(const vec &a, const T &scalar) {
|
||||
vec<T, N> c;
|
||||
vec<T, N, Tag> c;
|
||||
std::ranges::transform(a.m_Array, std::views::repeat(scalar),
|
||||
c.m_Array.begin(), std::divides{});
|
||||
return c;
|
||||
@ -124,7 +132,7 @@ public:
|
||||
//
|
||||
|
||||
T LengthSquared() const {
|
||||
return std::transform_reduce(m_Array.begin(), m_Array.end(), T{0.0},
|
||||
return std::transform_reduce(m_Array.begin(), m_Array.end(), T{},
|
||||
std::plus{}, [](T x) { return x * x; });
|
||||
}
|
||||
|
||||
@ -237,7 +245,7 @@ struct TileTag {};
|
||||
// types for each domain
|
||||
using WorldPos = vec<float, 2, WorldTag>;
|
||||
using WindowPos = vec<float, 2, WindowTag>;
|
||||
using TilePos = vec<int32_t, 2, WindowTag>;
|
||||
using TilePos = vec<int32_t, 2, TileTag>;
|
||||
|
||||
//
|
||||
// Utils
|
||||
|
@ -11,7 +11,7 @@ namespace pathfinder {
|
||||
|
||||
float GBFS::Heuristic(const TilePos& a, const TilePos& b)
|
||||
{
|
||||
return static_cast<float>(std::abs(a.x- b.x) + std::abs(a.y - b.y));
|
||||
return static_cast<float>(std::abs(a.x() - b.x()) + std::abs(a.y() - b.y()));
|
||||
}
|
||||
|
||||
Path GBFS::CalculatePath(WorldPos start_world, WorldPos end_world)
|
||||
|
@ -63,7 +63,7 @@ void PathFindingDemo::CreateMap() {
|
||||
}
|
||||
|
||||
WorldPos PathFindingDemo::GetRandomPosition() const {
|
||||
return WorldPos{0.0, 0.0}; // totally random!
|
||||
return WorldPos{0.0f, 0.0f}; // totally random!
|
||||
}
|
||||
|
||||
std::optional<WorldPos> PathFindingDemo::GetMoveTarget() {
|
||||
@ -75,7 +75,7 @@ std::optional<WorldPos> PathFindingDemo::GetMoveTarget() {
|
||||
|
||||
WorldPos next_player_pos = m_Path.front();
|
||||
|
||||
if (current_player_pos.distance(next_player_pos) > 1.0) {
|
||||
if (current_player_pos.DistanceTo(next_player_pos) > 1.0) {
|
||||
// target not reached yet
|
||||
return next_player_pos;
|
||||
}
|
||||
@ -95,7 +95,7 @@ void PathFindingDemo::UpdatePlayerVelocity() {
|
||||
WorldPos velocity = WorldPos{};
|
||||
if (next_pos) {
|
||||
velocity = next_pos.value() - current_pos;
|
||||
velocity.normalize();
|
||||
velocity.Normalize();
|
||||
//LOG_DEBUG("I want to move to: ", next_pos.value(),
|
||||
// ", velocity: ", velocity);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "map.hpp"
|
||||
#include "user_input.hpp"
|
||||
#include "pathfinder/base.hpp"
|
||||
#include "camera.hpp"
|
||||
|
||||
class PathFindingDemo {
|
||||
public:
|
||||
@ -24,6 +25,7 @@ public:
|
||||
std::shared_ptr<Player> GetPlayer() { return m_Player; }
|
||||
std::vector<std::shared_ptr<Entity>>& GetEntities() { return m_Entities; }
|
||||
const Map& GetMap() const { return m_Map; }
|
||||
const Camera& GetCamera() const { return m_Camera; }
|
||||
const pathfinder::Path& GetPath() const { return m_Path; }
|
||||
bool IsExitRequested() const { return m_ExitRequested; }
|
||||
|
||||
@ -37,6 +39,7 @@ public:
|
||||
private:
|
||||
bool m_ExitRequested = false;
|
||||
Map m_Map;
|
||||
Camera m_Camera;
|
||||
std::vector<std::shared_ptr<Entity>> m_Entities;
|
||||
std::shared_ptr<Player> m_Player;
|
||||
pathfinder::Path m_Path;
|
||||
|
@ -12,13 +12,13 @@
|
||||
|
||||
Sprite::Sprite() : m_Texture(nullptr, SDL_DestroyTexture) {}
|
||||
|
||||
Sprite::Sprite(std::string path, Vec2D<float> center) : Sprite() {
|
||||
Sprite::Sprite(std::string path, WorldPos center) : Sprite() {
|
||||
LoadImage(path, center);
|
||||
}
|
||||
|
||||
Sprite::~Sprite() { LOG_DEBUG("."); }
|
||||
|
||||
void Sprite::LoadImage(std::string path, Vec2D<float> image_center) {
|
||||
void Sprite::LoadImage(std::string path, WorldPos image_center) {
|
||||
LOG_INFO("Loading image ", path);
|
||||
assert(m_Renderer != nullptr);
|
||||
|
||||
|
@ -14,7 +14,7 @@ class Sprite {
|
||||
public:
|
||||
Sprite();
|
||||
~Sprite();
|
||||
explicit Sprite(std::string path, WorldPos center = {0, 0});
|
||||
explicit Sprite(std::string path, WorldPos center = WorldPos{});
|
||||
|
||||
Sprite(const Sprite &) = delete;
|
||||
Sprite &operator=(const Sprite &) = delete;
|
||||
@ -28,7 +28,7 @@ public:
|
||||
WorldPos GetSize() const { return m_Size; }
|
||||
WorldPos GetCenter() const { return m_ImageCenter; }
|
||||
|
||||
void LoadImage(std::string path, WorldPos image_center = {0.0, 0.0});
|
||||
void LoadImage(std::string path, WorldPos image_center = WorldPos{});
|
||||
|
||||
private:
|
||||
static std::shared_ptr<SDL_Renderer> m_Renderer;
|
||||
|
@ -11,8 +11,8 @@ class UserAction {
|
||||
public:
|
||||
enum class Type { NONE, EXIT, SET_MOVE_TARGET, SELECT_PATHFINDER };
|
||||
|
||||
UserAction() = default;
|
||||
UserAction(Type t) : type(t) {}
|
||||
UserAction() : type(Type::NONE), Argument{.number = 0} {}
|
||||
UserAction(Type t) : type(t), Argument{.number = 0} {}
|
||||
UserAction(Type t, char key) : type(t), Argument{.key = key} {}
|
||||
UserAction(Type t, WorldPos v) : type(t), Argument{.position = v} {}
|
||||
UserAction(Type t, int arg) : type(t), Argument{.number = arg} {}
|
||||
@ -25,6 +25,9 @@ public:
|
||||
char key;
|
||||
int number;
|
||||
} Argument;
|
||||
|
||||
// TODO use std::variant
|
||||
//std::variant<WorldPos, char, int> Argument;
|
||||
};
|
||||
|
||||
class UserInput {
|
||||
|
@ -76,17 +76,17 @@ Window::~Window() {
|
||||
LOG_DEBUG(".");
|
||||
}
|
||||
|
||||
void Window::DrawSprite(const WorldPos &position, Sprite &s) {
|
||||
void Window::DrawSprite(const WindowPos &position, Sprite &s) {
|
||||
WorldPos size = s.GetSize();
|
||||
WorldPos img_center = s.GetCenter();
|
||||
SDL_FRect rect = {position.x - img_center.x, position.y - img_center.y,
|
||||
size.x, size.y};
|
||||
SDL_FRect rect = {position.x() - img_center.x(), position.y() - img_center.y(),
|
||||
size.x(), size.y()};
|
||||
SDL_RenderTexture(m_Renderer.get(), s.GetTexture(), nullptr, &rect);
|
||||
}
|
||||
|
||||
void Window::DrawRect(const WorldPos &position, const WorldPos size, uint8_t R,
|
||||
void Window::DrawRect(const WindowPos &position, const WindowPos size, uint8_t R,
|
||||
uint8_t G, uint8_t B, uint8_t A) {
|
||||
SDL_FRect rect = {position.x, position.y, size.x, size.y};
|
||||
SDL_FRect rect = {position.x(), position.y(), size.x(), size.y()};
|
||||
SDL_SetRenderDrawColor(m_Renderer.get(), R, G, B, A);
|
||||
SDL_RenderFillRect(m_Renderer.get(), &rect);
|
||||
}
|
||||
@ -98,9 +98,9 @@ void Window::ClearWindow() {
|
||||
|
||||
void Window::Flush() { SDL_RenderPresent(m_Renderer.get()); }
|
||||
|
||||
void Window::DrawCircle(const WorldPos &position, float radius) {
|
||||
int cx = static_cast<int>(position.x);
|
||||
int cy = static_cast<int>(position.y);
|
||||
void Window::DrawCircle(const WindowPos &position, float radius) {
|
||||
int cx = static_cast<int>(position.x());
|
||||
int cy = static_cast<int>(position.y());
|
||||
SDL_SetRenderDrawColor(m_Renderer.get(), 255, 0, 0, 255);
|
||||
for (int i = 0; i < 360; ++i) {
|
||||
double a = i * M_PI / 180.0;
|
||||
@ -110,9 +110,9 @@ void Window::DrawCircle(const WorldPos &position, float radius) {
|
||||
}
|
||||
}
|
||||
|
||||
void Window::DrawLine(const WorldPos &A, const WorldPos &B)
|
||||
void Window::DrawLine(const WindowPos &A, const WindowPos &B)
|
||||
{
|
||||
SDL_SetRenderDrawColor(m_Renderer.get(), 255, 0, 0, 255);
|
||||
SDL_RenderLine(m_Renderer.get(), A.x, A.y, B.x, B.y);
|
||||
SDL_RenderLine(m_Renderer.get(), A.x(), A.y(), B.x(), B.y());
|
||||
}
|
||||
|
||||
|
@ -22,13 +22,13 @@ public:
|
||||
Window &operator=(Window &&) = delete;
|
||||
|
||||
std::expected<void, std::string> Init();
|
||||
void DrawSprite(const WorldPos &position, Sprite &s);
|
||||
void DrawRect(const WorldPos &position, const WorldPos size, uint8_t R,
|
||||
void DrawSprite(const WindowPos &position, Sprite &s);
|
||||
void DrawRect(const WindowPos &position, const WindowPos size, uint8_t R,
|
||||
uint8_t G, uint8_t B, uint8_t A);
|
||||
void ClearWindow();
|
||||
void Flush();
|
||||
void DrawCircle(const WorldPos &position, float radius);
|
||||
void DrawLine(const WorldPos &A, const WorldPos &B);
|
||||
void DrawCircle(const WindowPos &position, float radius);
|
||||
void DrawLine(const WindowPos &A, const WindowPos &B);
|
||||
|
||||
private:
|
||||
uint32_t m_Width;
|
||||
|
@ -37,6 +37,12 @@ TEST(vec, equalEpsilon) {
|
||||
ASSERT_EQ(v1, v2);
|
||||
}
|
||||
|
||||
TEST(vec, equalInt) {
|
||||
ivec2 v1{1,2};
|
||||
ivec2 v2{1,2};
|
||||
ASSERT_EQ(v1, v2);
|
||||
}
|
||||
|
||||
TEST(vec, nonEqualEpsilon) {
|
||||
// Test operator!=
|
||||
vec3 v1{1.0f, 2.0f, 3.0f};
|
||||
|
Loading…
x
Reference in New Issue
Block a user