From 753f71536339b78c49468ba6452c96d6b3c345b2 Mon Sep 17 00:00:00 2001 From: Paweł Redman Date: Tue, 10 Oct 2017 19:33:33 +0200 Subject: Finish work on world entities, start experimenting with world generation. --- Makefile | 2 +- src/common.hpp | 24 ++++++---- src/game.cpp | 16 ++++--- src/interface.cpp | 12 ++++- src/procgen.cpp | 5 ++- src/render.cpp | 69 ++++++++++++++--------------- src/world.cpp | 128 +++++++++++++++++++++++++++++++++++++++++++----------- 7 files changed, 177 insertions(+), 79 deletions(-) diff --git a/Makefile b/Makefile index df63398..69c8d29 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC ?= gcc -CFLAGS += -g3 -O3 -Wall -std=gnu++11 +CFLAGS += -g3 -O0 -Wall -std=gnu++11 CPPFLAGS += -MMD LDFLAGS += -lstdc++ -lm -lsfml-system -lsfml-window -lsfml-graphics diff --git a/src/common.hpp b/src/common.hpp index 6a30f9e..06e9d9f 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -1,7 +1,9 @@ #include #include #include +#include #include +#include #include #include @@ -45,6 +47,7 @@ namespace world { sector_index_t (); sector_index_t (int64_t x_, int64_t y_); + sector_index_t (float x_, float y_); bool operator<(sector_index_t B) const; }; @@ -52,6 +55,7 @@ namespace world { class sector_t { public: + sector_index_t index; sf::FloatRect bounds; std::unordered_set ents; @@ -64,6 +68,7 @@ namespace world { procgen::perlin_noise_t perlin; std::map sectors; + void generate_tile(ssize_t lx, ssize_t ly, tile_t *tile); void generate(sector_t *sector, sector_index_t index); public: @@ -71,7 +76,13 @@ namespace world { sector_t *get_sector(sector_index_t index); tile_t *get_tile(ssize_t x, ssize_t y); + // FIXME: iterators instead of returning std::lists + std::list get_sectors(sf::FloatRect rect); + std::list get_entities(sf::FloatRect rect); + void render(sf::RenderWindow *window); + + void debug_point(sf::Vector2f point); }; class entity_t { @@ -80,6 +91,10 @@ namespace world { void link_to_sector(sector_t *sector); + protected: + friend world_t; + size_t cookie = 0; + public: sf::FloatRect bounds; @@ -92,9 +107,9 @@ namespace world { namespace game { class state_t { + public: world::world_t world; - public: void start(void); void tick(void); void render(sf::RenderWindow *window_); @@ -142,13 +157,6 @@ T divide_rmi(T x, T y, T *rem) return rv; } -// Modulo operation. y is expected to be positive. -template -T mod(T x, T y) -{ - return (x % y) + (x < 0 ? y : 0); -} - // Linear interpolation. template T lerp(T a, T b, T x) diff --git a/src/game.cpp b/src/game.cpp index 6fff821..6416f93 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2,20 +2,24 @@ namespace game { +static human_t *human; + void state_t::start(void) { - human_t *human; - human = new human_t; - human->bounds.left = 0.2f; - human->bounds.top = 0.2f; - human->bounds.width = 1.0f; - human->bounds.height = 1.0f; + human->bounds.left = -0.2f; + human->bounds.top = -0.2f; + human->bounds.width = 3.0f; + human->bounds.height = 3.0f; human->link(&world); } void state_t::tick(void) { + human->unlink(); + human->bounds.left += 0.05f; + human->bounds.top += 0.05f; + human->link(&world); } } //namespace game diff --git a/src/interface.cpp b/src/interface.cpp index 16fc77d..17c1727 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -68,8 +68,16 @@ void state_t::tick(void) camera.target_zoom -= event.mouseWheelScroll.delta; if (camera.target_zoom < 0) camera.target_zoom = 0; - if (camera.target_zoom > 10) - camera.target_zoom = 10; + if (camera.target_zoom > 11) + camera.target_zoom = 11; + break; + + case sf::Event::KeyPressed: + if (event.key.code == sf::Keyboard::Key::I) { + sf::Vector2i mouse = sf::Mouse::getPosition(*window); + sf::Vector2f vmouse = window->mapPixelToCoords(mouse); + game->world.debug_point(vmouse); + } break; default:; diff --git a/src/procgen.cpp b/src/procgen.cpp index 09ccae5..b5e1d6f 100644 --- a/src/procgen.cpp +++ b/src/procgen.cpp @@ -63,8 +63,9 @@ float perlin_noise_t::get(float x, float y, float scale) x /= scale; y /= scale; - nx = mod(floor(x), size); - ny = mod(floor(y), size); + nx = (ssize_t)floor(x) & (size - 1); + ny = (ssize_t)floor(y) & (size - 1); + nx1 = (nx == size - 1 ? 0 : nx + 1); ny1 = (ny == size - 1 ? 0 : ny + 1); diff --git a/src/render.cpp b/src/render.cpp index d63ca6f..1baf0e0 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -6,9 +6,32 @@ static sf::RectangleShape wot_rect; static void draw_tile(sf::RenderWindow *window, float x, float y, world::tile_t *tile) { + sf::Color color; + wot_rect.setSize(sf::Vector2f(1.0f, 1.0f)); wot_rect.setPosition(sf::Vector2f(x, y)); - wot_rect.setFillColor(sf::Color(tile->type, tile->type, tile->type)); + + switch (tile->type) { + case -1: + color = sf::Color(30, 30, 150); + break; + case 0: + color = sf::Color(50, 70, 200); + break; + case 1: + color = sf::Color(255, 255, 90); + break; + case 2: + color = sf::Color(30, 210, 40); + break; + case 3: + color = sf::Color(29, 190, 45); + break; + default: + ; + } + + wot_rect.setFillColor(color); wot_rect.setOutlineColor(sf::Color::Transparent); window->draw(wot_rect); } @@ -21,18 +44,12 @@ static void draw_sector(sf::RenderWindow *window, world::sector_t *sector) sector->bounds.left + x, sector->bounds.top + y, sector->tiles + y * SECTOR_SIZE + x); - wot_rect.setSize(sf::Vector2f(SECTOR_SIZE, SECTOR_SIZE)); - wot_rect.setPosition(sf::Vector2f(sector->bounds.left, sector->bounds.top)); - wot_rect.setOutlineColor(sf::Color::Yellow); - wot_rect.setOutlineThickness(0.06f); - wot_rect.setFillColor(sf::Color::Transparent); - window->draw(wot_rect); -} - -static void draw_sector_entities(sf::RenderWindow *window, world::sector_t *sector) -{ - for (world::entity_t *ent : sector->ents) - ent->render(window); + if ((sector->index.x & 2) ^ (sector->index.y & 2)) { + wot_rect.setSize(sf::Vector2f(SECTOR_SIZE, SECTOR_SIZE)); + wot_rect.setPosition(sf::Vector2f(sector->bounds.left, sector->bounds.top)); + wot_rect.setFillColor(sf::Color(0, 0, 0, 50)); + window->draw(wot_rect); + } } void game::state_t::render(sf::RenderWindow *window) @@ -40,8 +57,6 @@ void game::state_t::render(sf::RenderWindow *window) sf::Vector2u size = window->getSize(); sf::Vector2f A, B, C, D; sf::Rect bbox; - sf::Rect index_box; - std::list sectors; A = window->mapPixelToCoords(sf::Vector2i(0, 0)); B = window->mapPixelToCoords(sf::Vector2i(size.x, 0)); @@ -50,28 +65,14 @@ void game::state_t::render(sf::RenderWindow *window) bbox.left = std::min({A.x, B.x, C.x, D.x}); bbox.top = std::min({A.y, B.y, C.y, D.y}); - bbox.width = std::max({A.x, B.x, C.x, D.x}); - bbox.height = std::max({A.y, B.y, C.y, D.y}); - - index_box.left = floor(bbox.left / SECTOR_SIZE); - index_box.top = floor(bbox.top / SECTOR_SIZE); - index_box.width = ceil(bbox.width / SECTOR_SIZE); - index_box.height = ceil(bbox.height / SECTOR_SIZE); - - for (ssize_t y = index_box.top; y < index_box.height; y++) - for (ssize_t x = index_box.left; x < index_box.width; x++) { - world::sector_index_t index(x, y); - world::sector_t *sector; + bbox.width = std::max({A.x, B.x, C.x, D.x}) - bbox.left; + bbox.height = std::max({A.y, B.y, C.y, D.y}) - bbox.top; - sector = world.get_sector(index); - sectors.push_back(sector); - } - - for (auto *sector : sectors) + for (world::sector_t *sector : world.get_sectors(bbox)) draw_sector(window, sector); - for (auto *sector : sectors) - draw_sector_entities(window, sector); + for (world::entity_t *ent : world.get_entities(bbox)) + ent->render(window); } void game::human_t::render(sf::RenderWindow *window) diff --git a/src/world.cpp b/src/world.cpp index 9d9b97d..9085b16 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -12,6 +12,12 @@ sector_index_t::sector_index_t (int64_t x_, int64_t y_) y = y_; } +sector_index_t::sector_index_t (float x_, float y_) +{ + x = (int64_t)floor(x_ / SECTOR_SIZE); + y = (int64_t)floor(y_ / SECTOR_SIZE); +} + bool sector_index_t::operator<(sector_index_t B) const { if (x < B.x) @@ -29,31 +35,47 @@ world_t::world_t(void) perlin.generate(&prng, 32); } +void world_t::generate_tile(ssize_t x, ssize_t y, tile_t *tile) +{ + float waterlevel, height; + + waterlevel = perlin.get(x, y, 100.0f) * 0.3f + + perlin.get(x, y, 50.0f) * 0.1f; + + height = perlin.get(x, y, 30.0f) * 0.6f + + perlin.get(x, y, 15.0f) * 0.25f + + perlin.get(x, y, 7.0f) * 0.1f + + perlin.get(x, y, 3.0f) * 0.05f; + + if (height < waterlevel - 0.2f) + tile->type = -1; + else if (height < waterlevel) + tile->type = 0; + else if (height < waterlevel + 0.05f) + tile->type = 1; + else { + if (perlin.get(x, y, 5.0f) > 0.0f) + tile->type = 3; + else + tile->type = 2; + } +} + void world_t::generate(sector_t *sector, sector_index_t index) { + sector->index = index; sector->bounds.left = index.x * SECTOR_SIZE; sector->bounds.top = index.y * SECTOR_SIZE; sector->bounds.width = SECTOR_SIZE; sector->bounds.height = SECTOR_SIZE; - + std::cout << "generating (" << index.x << ", " << index.y << ")\n"; for (ssize_t ly = 0; ly < SECTOR_SIZE; ly++) - for (ssize_t lx = 0; lx < SECTOR_SIZE; lx++) { - ssize_t x, y; - float noise; - - x = index.x * SECTOR_SIZE + lx; - y = index.y * SECTOR_SIZE + ly; - - noise = perlin.get(x, y, 30.0f) * 0.6f + - perlin.get(x, y, 15.0f) * 0.25f + - perlin.get(x, y, 7.0f) * 0.1f + - perlin.get(x, y, 3.0f) * 0.05f; - - sector->tiles[ly * SECTOR_SIZE + lx].type = - (noise + 1) * 100; - } + for (ssize_t lx = 0; lx < SECTOR_SIZE; lx++) + generate_tile(index.x * SECTOR_SIZE + lx, + index.y * SECTOR_SIZE + ly, + sector->tiles + ly * SECTOR_SIZE + lx); sector->empty = false; } @@ -83,9 +105,44 @@ tile_t *world_t::get_tile(ssize_t x, ssize_t y) return sector->tiles + ty * SECTOR_SIZE + tx; } -static sector_index_t get_index(float x, float y) +std::list world_t::get_sectors(sf::FloatRect rect) { - return sector_index_t(floor(x), floor(y)); + sector_index_t base(rect.left, rect.top), + upper(rect.left + rect.width, rect.top + rect.height); + std::list list; + + for (int64_t y = base.y; y <= upper.y; y++) + for (int64_t x = base.x; x <= upper.x; x++) { + sector_index_t index(x, y); + list.push_back(get_sector(index)); + } + + return list; +} + +std::list world_t::get_entities(sf::FloatRect rect) +{ + static size_t cookie = 0; + std::list list; + + cookie++; + + for (sector_t *sector : get_sectors(rect)) + for (entity_t *ent : sector->ents) { + if (ent->cookie == cookie) + continue; + ent->cookie = cookie; + + list.push_back(ent); + } + + return list; +} + +void world_t::debug_point(sf::Vector2f point) +{ + sector_index_t index(point.x, point.y); + printf("sector (%zd, %zd)\n", index.x, index.y); } void entity_t::link_to_sector(sector_t *sector) @@ -96,17 +153,36 @@ void entity_t::link_to_sector(sector_t *sector) void entity_t::link(world_t *world) { + float fx, fy; sector_index_t base; - sector_t *sector; - ssize_t dx, dy; + float xlip, ylip; + size_t xsecs, ysecs; + + fx = floor(bounds.left); + fy = floor(bounds.top); + + base = sector_index_t(fx, fy); + xlip = bounds.left + bounds.width - (base.x + 1) * SECTOR_SIZE; + ylip = bounds.top + bounds.height - (base.y + 1) * SECTOR_SIZE; - // An entity gets linked to at least one sector. - base = get_index(bounds.left, bounds.top); - sector = world->get_sector(base); - link_to_sector(sector); + if (xlip > 0.0f) + xsecs = ceil(xlip / SECTOR_SIZE) + 1; + else + xsecs = 1; - // There might be more, though. - //for (dy = 0; dy < + if (ylip > 0.0f) + ysecs = ceil(ylip / SECTOR_SIZE) + 1; + else + ysecs = 1; + + for (int64_t y = 0; y < (int64_t)ysecs; y++) + for (int64_t x = 0; x < (int64_t)xsecs; x++) { + sector_index_t index(base.x + x, base.y + y); + sector_t *sector; + + sector = world->get_sector(index); + link_to_sector(sector); + } } void entity_t::unlink(void) -- cgit