Add terrain painting functions
This commit is contained in:
parent
c42a6b647e
commit
b6d24da982
@ -28,7 +28,7 @@ int main() {
|
|||||||
* Initialize the map and run the pathfinding demo
|
* Initialize the map and run the pathfinding demo
|
||||||
*/
|
*/
|
||||||
|
|
||||||
auto demo = std::make_unique<PathFindingDemo>(10, 10);
|
auto demo = std::make_unique<PathFindingDemo>(100, 100);
|
||||||
demo->CreateMap();
|
demo->CreateMap();
|
||||||
|
|
||||||
auto game_loop = GameLoop{};
|
auto game_loop = GameLoop{};
|
||||||
|
@ -6,19 +6,13 @@
|
|||||||
#include "tile.hpp"
|
#include "tile.hpp"
|
||||||
|
|
||||||
Map::Map(int rows, int cols) : m_Cols(cols), m_Rows(rows) {
|
Map::Map(int rows, int cols) : m_Cols(cols), m_Rows(rows) {
|
||||||
bool sw = true;
|
|
||||||
LOG_DEBUG("cols = ", cols, " rows = ", rows);
|
LOG_DEBUG("cols = ", cols, " rows = ", rows);
|
||||||
m_Tiles = std::vector<std::vector<const Tile *>>{};
|
m_Tiles = std::vector<std::vector<const Tile *>>{};
|
||||||
for (size_t row = 0; row < m_Rows; row++) {
|
for (size_t row = 0; row < m_Rows; row++) {
|
||||||
m_Tiles.push_back(std::vector<const Tile *>{});
|
m_Tiles.push_back(std::vector<const Tile *>{});
|
||||||
for (size_t col = 0; col < m_Cols; col++) {
|
for (size_t col = 0; col < m_Cols; col++) {
|
||||||
if (sw)
|
m_Tiles[row].push_back(&tile_types.at(TileType::GRASS));
|
||||||
m_Tiles[row].push_back(&tile_types.at("Grass"));
|
|
||||||
else
|
|
||||||
m_Tiles[row].push_back(&tile_types.at("Water"));
|
|
||||||
sw = !sw;
|
|
||||||
}
|
}
|
||||||
//sw = !sw;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,8 +43,10 @@ const Tile *Map::GetTileAt(WorldPos p) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Map::IsTilePosValid(TilePos p) const {
|
bool Map::IsTilePosValid(TilePos p) const {
|
||||||
size_t row = p.x;
|
if (p.x < 0 || p.y < 0)
|
||||||
size_t col = p.y;
|
return false;
|
||||||
|
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();
|
return row < m_Tiles.size() && col < m_Tiles[0].size();
|
||||||
}
|
}
|
||||||
@ -62,10 +58,10 @@ std::vector<TilePos> Map::GetNeighbors(TilePos center) const
|
|||||||
neighbours.reserve(4);
|
neighbours.reserve(4);
|
||||||
|
|
||||||
std::array<TilePos, 4> candidates = {
|
std::array<TilePos, 4> candidates = {
|
||||||
center + TilePos{1,0},
|
center + TilePos{ 1, 0},
|
||||||
center + TilePos{-1,0},
|
center + TilePos{-1, 0},
|
||||||
center + TilePos{0, 1},
|
center + TilePos{ 0, 1},
|
||||||
center + TilePos{0, -1},
|
center + TilePos{ 0, -1},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto& c : candidates) {
|
for (const auto& c : candidates) {
|
||||||
@ -74,13 +70,46 @@ std::vector<TilePos> Map::GetNeighbors(TilePos center) const
|
|||||||
}
|
}
|
||||||
return neighbours;
|
return neighbours;
|
||||||
}
|
}
|
||||||
// std::vector<TilePos> neighbours;
|
|
||||||
// neighbours.reserve(8);
|
|
||||||
// for (int dx = -1; dx <= 1; ++dx) {
|
void Map::PaintCircle(TilePos center, unsigned radius, TileType tile_type)
|
||||||
// for (int dy = -1; dy <= 1; ++dy) {
|
{
|
||||||
// if (dx == 0 && dy == 0) continue;
|
// get rectangle that wraps the circle
|
||||||
// TilePos p{center.x + dx, center.y + dy};
|
TilePos corner1 = TilePos{center.x - radius, center.y - radius};
|
||||||
// if (IsTilePosValid(p)) neighbours.push_back(std::move(p));
|
TilePos corner2 = TilePos{center.x + radius, center.y + radius};
|
||||||
// }
|
// iterate through all valid points, setting the type
|
||||||
// }
|
const unsigned radius_squared = radius * radius;
|
||||||
// return neighbours;
|
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);
|
||||||
|
if (IsTilePosValid(current_tile) && distance_squared < radius_squared)
|
||||||
|
{
|
||||||
|
// y is row, x is col
|
||||||
|
m_Tiles[y][x] = &tile_types.at(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();
|
||||||
|
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;
|
||||||
|
size_t row = static_cast<size_t>(tile_pos.x);
|
||||||
|
size_t col = static_cast<size_t>(tile_pos.y);
|
||||||
|
if (IsTilePosValid(tile_pos)) {
|
||||||
|
m_Tiles[row][col] = &tile_types.at(tile_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ using TileGrid = std::vector<std::vector<const Tile *>>;
|
|||||||
|
|
||||||
class Map {
|
class Map {
|
||||||
public:
|
public:
|
||||||
static constexpr float TILE_SIZE = 100.0f; // tile size in world
|
static constexpr float TILE_SIZE = 10.0f; // tile size in world
|
||||||
|
|
||||||
Map(int rows, int cols);
|
Map(int rows, int cols);
|
||||||
Map() : Map(0, 0) {}
|
Map() : Map(0, 0) {}
|
||||||
@ -32,6 +32,9 @@ public:
|
|||||||
|
|
||||||
bool IsTilePosValid(TilePos p) const;
|
bool IsTilePosValid(TilePos p) const;
|
||||||
|
|
||||||
|
// methods for drawing on the map
|
||||||
|
void PaintCircle(TilePos center, unsigned radius, TileType tile_type);
|
||||||
|
void PaintLine(TilePos start, TilePos stop, double width, TileType tile_type);
|
||||||
|
|
||||||
std::vector<TilePos> GetNeighbors(TilePos center) const;
|
std::vector<TilePos> GetNeighbors(TilePos center) const;
|
||||||
float GetCost(TilePos pos) const { return GetTileAt(pos)->cost; }
|
float GetCost(TilePos pos) const { return GetTileAt(pos)->cost; }
|
||||||
|
@ -14,12 +14,26 @@ public:
|
|||||||
Vec2D() = default;
|
Vec2D() = default;
|
||||||
~Vec2D() = default;
|
~Vec2D() = default;
|
||||||
|
|
||||||
Vec2D &operator+=(const Vec2D &other) {
|
template <typename U>
|
||||||
|
Vec2D(Vec2D<U> other) {
|
||||||
|
this->x = static_cast<T>(other.x);
|
||||||
|
this->y = static_cast<T>(other.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2D& operator+=(const Vec2D &other) {
|
||||||
x += other.x;
|
x += other.x;
|
||||||
y += other.y;
|
y += other.y;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
requires std::is_arithmetic_v<U>
|
||||||
|
Vec2D& operator/=(U k) {
|
||||||
|
this->x /= static_cast<T>(k);
|
||||||
|
this->y /= static_cast<T>(k);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
friend Vec2D operator+(const Vec2D &a, const Vec2D &b) {
|
friend Vec2D operator+(const Vec2D &a, const Vec2D &b) {
|
||||||
return Vec2D{a.x + b.x, a.y + b.y};
|
return Vec2D{a.x + b.x, a.y + b.y};
|
||||||
}
|
}
|
||||||
@ -28,10 +42,20 @@ public:
|
|||||||
return Vec2D{a.x - b.x, a.y - b.y};
|
return Vec2D{a.x - b.x, a.y - b.y};
|
||||||
}
|
}
|
||||||
|
|
||||||
friend Vec2D operator*(float k, const Vec2D &v) {
|
template <typename U>
|
||||||
|
requires std::is_arithmetic_v<U>
|
||||||
|
friend Vec2D operator*(U k, const Vec2D &v)
|
||||||
|
{
|
||||||
return Vec2D{k * v.x, k * v.y};
|
return Vec2D{k * v.x, k * v.y};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
requires std::is_arithmetic_v<U>
|
||||||
|
friend Vec2D operator/(const Vec2D &v, U k)
|
||||||
|
{
|
||||||
|
return Vec2D{v.x / k, v.y / k};
|
||||||
|
}
|
||||||
|
|
||||||
friend bool operator==(const Vec2D &a, const Vec2D &b) {
|
friend bool operator==(const Vec2D &a, const Vec2D &b) {
|
||||||
if constexpr (std::is_integral_v<T>) {
|
if constexpr (std::is_integral_v<T>) {
|
||||||
return a.x == b.x && a.y == b.y;
|
return a.x == b.x && a.y == b.y;
|
||||||
@ -76,7 +100,7 @@ public:
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2D orthogonal()
|
Vec2D orthogonal() const
|
||||||
{
|
{
|
||||||
Vec2D v(*this);
|
Vec2D v(*this);
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "user_input.hpp"
|
#include "user_input.hpp"
|
||||||
#include "pathfinder/base.hpp"
|
#include "pathfinder/base.hpp"
|
||||||
#include "pathfinder/utils.hpp"
|
#include "pathfinder/utils.hpp"
|
||||||
|
#include "tile.hpp"
|
||||||
|
|
||||||
PathFindingDemo::PathFindingDemo(int width, int height) :
|
PathFindingDemo::PathFindingDemo(int width, int height) :
|
||||||
m_Map(width, height)
|
m_Map(width, height)
|
||||||
@ -28,9 +29,18 @@ void PathFindingDemo::AddEntity(std::shared_ptr<Entity> e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PathFindingDemo::CreateMap() {
|
void PathFindingDemo::CreateMap() {
|
||||||
|
// create the map
|
||||||
|
m_Map.PaintCircle(TilePos{50, 50}, 10, TileType::WATER);
|
||||||
|
m_Map.PaintCircle(TilePos{75, 100}, 50, TileType::WATER);
|
||||||
|
m_Map.PaintLine(TilePos{0,0}, TilePos{100,100}, 3.0, TileType::WATER);
|
||||||
|
m_Map.PaintLine(TilePos{17,6}, TilePos{100,6}, 5.0, TileType::ROAD);
|
||||||
|
m_Map.PaintLine(TilePos{10,17}, TilePos{10,100}, 5.0, TileType::ROAD);
|
||||||
|
m_Map.PaintLine(TilePos{20,10}, TilePos{10,20}, 5.0, TileType::ROAD);
|
||||||
|
|
||||||
|
// add player
|
||||||
m_Entities.clear();
|
m_Entities.clear();
|
||||||
m_Player = std::make_shared<Player>();
|
m_Player = std::make_shared<Player>();
|
||||||
m_Player->SetPosition(WorldPos{200.0f, 200.0f});
|
m_Player->SetPosition(WorldPos{250.0f, 200.0f});
|
||||||
m_Entities.push_back(m_Player);
|
m_Entities.push_back(m_Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +57,7 @@ std::optional<WorldPos> PathFindingDemo::GetMoveTarget() {
|
|||||||
|
|
||||||
WorldPos next_player_pos = m_Path.front();
|
WorldPos next_player_pos = m_Path.front();
|
||||||
|
|
||||||
if (current_player_pos.distance(next_player_pos) > 10.0) {
|
if (current_player_pos.distance(next_player_pos) > 1.0) {
|
||||||
// target not reached yet
|
// target not reached yet
|
||||||
return next_player_pos;
|
return next_player_pos;
|
||||||
}
|
}
|
||||||
@ -68,8 +78,8 @@ void PathFindingDemo::UpdatePlayerVelocity() {
|
|||||||
if (next_pos) {
|
if (next_pos) {
|
||||||
velocity = next_pos.value() - current_pos;
|
velocity = next_pos.value() - current_pos;
|
||||||
velocity.normalize();
|
velocity.normalize();
|
||||||
LOG_DEBUG("I want to move to: ", next_pos.value(),
|
//LOG_DEBUG("I want to move to: ", next_pos.value(),
|
||||||
", velocity: ", velocity);
|
// ", velocity: ", velocity);
|
||||||
}
|
}
|
||||||
player->SetActualVelocity(velocity * tile_velocity_coeff);
|
player->SetActualVelocity(velocity * tile_velocity_coeff);
|
||||||
float time_delta = 1.0f;
|
float time_delta = 1.0f;
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
|
#include <array>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "tile.hpp"
|
#include "tile.hpp"
|
||||||
|
|
||||||
const std::map<std::string_view, Tile> tile_types = {
|
// we could use array here, but this is more explicit,
|
||||||
{"Grass", {1.0, 0, 200, 0, 255}},
|
// and we don't access tile_types that often, so it should be ok
|
||||||
{"Mud", {2.0, 100, 100, 100, 255}},
|
const std::unordered_map<TileType, Tile> tile_types = {
|
||||||
{"Road", {0.5, 200, 200, 200, 255}},
|
{ TileType::GRASS, Tile{1.0, 0, 200, 0, 255}},
|
||||||
{"Water", {10.0, 0, 50, 200, 255}},
|
{ TileType::MUD, Tile{2.0, 100, 100, 100, 255}},
|
||||||
|
{ TileType::ROAD, Tile{0.5, 20, 20, 20, 255}},
|
||||||
|
{ TileType::WATER, Tile{10.0, 0, 50, 200, 255}},
|
||||||
};
|
};
|
||||||
|
@ -3,10 +3,19 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <array>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
struct Tile {
|
struct Tile {
|
||||||
float cost;
|
float cost;
|
||||||
uint8_t R, G, B, A;
|
uint8_t R, G, B, A;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const std::map<std::string_view, Tile> tile_types;
|
enum class TileType {
|
||||||
|
GRASS,
|
||||||
|
MUD,
|
||||||
|
ROAD,
|
||||||
|
WATER,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const std::unordered_map<TileType, Tile> tile_types;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user