From 1fd33b69f7cef5f9dfe1da417717545f34c673d0 Mon Sep 17 00:00:00 2001 From: Paweł Redman Date: Tue, 12 Dec 2017 14:57:52 +0100 Subject: Start moving game logic to src/game. --- Makefile | 6 +- src/assets.cpp | 20 ---- src/common.hpp | 9 -- src/game.cpp | 270 ------------------------------------------------- src/game/assets.cpp | 20 ++++ src/game/game.cpp | 270 +++++++++++++++++++++++++++++++++++++++++++++++++ src/game/game.hpp | 14 +++ src/game/interface.cpp | 134 ++++++++++++++++++++++++ src/interface.cpp | 134 ------------------------ src/render.cpp | 4 +- 10 files changed, 443 insertions(+), 438 deletions(-) delete mode 100644 src/assets.cpp delete mode 100644 src/game.cpp create mode 100644 src/game/assets.cpp create mode 100644 src/game/game.cpp create mode 100644 src/game/game.hpp create mode 100644 src/game/interface.cpp delete mode 100644 src/interface.cpp diff --git a/Makefile b/Makefile index 74c2486..7ddca74 100644 --- a/Makefile +++ b/Makefile @@ -9,9 +9,9 @@ PP_CC := $(PP_BOLD)$(shell tput setf 6)CC$(PP_RESET) PP_LD := $(PP_BOLD)$(shell tput setf 2)LD$(PP_RESET) PP_RM := $(PP_BOLD)$(shell tput setf 4)RM$(PP_RESET) -SRC := src/assets.cpp \ - src/game.cpp \ - src/interface.cpp \ +SRC := src/game/assets.cpp \ + src/game/game.cpp \ + src/game/interface.cpp \ src/main.cpp \ src/path_finder.cpp \ src/procgen.cpp \ diff --git a/src/assets.cpp b/src/assets.cpp deleted file mode 100644 index 94651c6..0000000 --- a/src/assets.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "common.hpp" - -namespace assets { - -human_assets_t human; -sf::Texture tile_dirt; -sf::Texture tile_wall; - -void load(void) -{ - human.head_idle.load("assets/units/human/head_idle", 1, 1, 1); - human.body_idle.load("assets/units/human/body_idle", 2, 2, 2); - human.legs_idle.load("assets/units/human/legs_idle", 2, 2); - human.legs_walking.load("assets/units/human/legs_walking", 2, 2); - - tile_dirt.loadFromFile("assets/tiles/dirt.png"); - tile_wall.loadFromFile("assets/tiles/wall.png"); -} - -} // namespace assets diff --git a/src/common.hpp b/src/common.hpp index 259c458..e3bd19c 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -292,15 +292,6 @@ namespace render { extern render::state_t *debug_render; namespace assets { - typedef struct { - render::oriented_sprite_4M_t head_idle, body_idle; - render::oriented_sprite_4M2_t legs_idle, legs_walking; - } human_assets_t; - - extern human_assets_t human; - extern sf::Texture tile_dirt; - extern sf::Texture tile_wall; - void load(void); }; diff --git a/src/game.cpp b/src/game.cpp deleted file mode 100644 index fd119f8..0000000 --- a/src/game.cpp +++ /dev/null @@ -1,270 +0,0 @@ -#include "common.hpp" - -namespace game { - -static size_t selection_cookie = 1; - -enum { - ET_UNIT -}; - -class unit_t : public world::entity_t { -protected: - world::world_t *world; - - world::cmodel_t make_cmodel(v2f_t at) - { - world::cmodel_t cmodel; - - cmodel.bounds[0] = at + size[0]; - cmodel.bounds[1] = at + size[1]; - cmodel.cflags = cflags; - - return cmodel; - } - - void compute_bounds() - { - render_bounds[0] = x + render_size[0]; - render_bounds[1] = x + render_size[1]; - } - -public: - v2f_t x; - rectf_t size, render_size; - world::cflags_t cflags; - size_t selected = 0; - - unit_t() : entity_t(ET_UNIT) - { - } - - struct { - bool moving = false; - v2f_t dst; - float angle = 0.0f; - - std::list path; - - bool blocked; - size_t attempts_left; - float next_attempt; - } move; - - const wchar_t *say_text; - double say_time = -INFINITY; - - void say(const wchar_t *wstr, double now) - { - say_text = wstr; - say_time = now; - std::cout << (void*)this << ": " << wstr << "\n"; - } - - void place(world::world_t *world_, v2f_t x_) - { - world = world_; - x = x_; - move.moving = false; - cflags = 1; - - unlink(); - cmodel = make_cmodel(x); - compute_bounds(); - link(world); - } - - void keep_moving(double now, double dt) - { - float time; - - if (!move.moving) - return; - - if (move.blocked && now < move.next_attempt) - return; - - time = dt * 10; - - while (time > 0.0f) { - v2f_t delta, next, x_new; - world::cmodel_t cmodel_next; - - if (!move.path.size()) { - move.moving = false; - break; - } - - next = *move.path.begin(); - delta = next - x; - move.angle = delta.angle(); - - if (delta.len() >= time) { - x_new = x + delta * time / delta.len(); - time -= delta.len(); - } else { - x_new = next; - time -= delta.len(); - move.path.pop_front(); - } - - cmodel_next = make_cmodel(x_new); - if (!world->test_rect(&cmodel_next, this)) { - x = x_new; - cmodel = cmodel_next; - continue; - } - - if (move.attempts_left) { - move.blocked = true; - move.attempts_left--; - move.next_attempt = now + 0.2f; - } else { - if ((x - move.dst).len() > 1.5f) - say(text::unit_blocked, now); - move.moving = false; - } - break; - } - - - unlink(); - compute_bounds(); - link(world); - } - - bool start_moving(v2f_t dst_, double now) - { - if (!world) { - printf("unit_t::start_moving: entity is not linked\n"); - return false; - } - - move.dst = dst_; - move.path.clear(); - - if (!world->find_path(x, move.dst, &cmodel, this, &move.path)) { - say(text::unit_no_path, now); - move.moving = false; - return false; - } - - move.moving = true; - - move.blocked = false; - move.attempts_left = 10; - move.next_attempt = -INFINITY; - - return true; - } -}; - -class human_t : public unit_t { -public: - human_t() - { - size[0] = v2f_t(-0.4f, -0.4f); - size[1] = v2f_t(+0.4f, +0.4f); - render_size[0] = v2f_t(-0.5f, -1.0f); - render_size[1] = v2f_t(+0.5f, +0.5f); - } - - void render_to(render::state_t *render) - { - bool moving; - - if (selected == selection_cookie) - render->render_hlrect(render_bounds, sf::Color::Blue); - - moving = move.moving && !move.blocked; - - render->render((moving ? &assets::human.legs_walking : - &assets::human.legs_idle), render_bounds, move.angle); - render->render(&assets::human.body_idle, render_bounds, move.angle); - render->render(&assets::human.head_idle, render_bounds, move.angle); - - { - v2f_t x1; - static float t = 0; - world::trace_t trace; - - t += 0.02f; - - x1[0] = x[0] + cos(t) * 5; - x1[1] = x[1] + sin(t) * 5; - trace = world->trace(x, x1, 1); - render->render_arrow(x, trace.end, sf::Color::Green); - } - - if (move.moving && debug_draw_paths) - render->debug_path(&move.path); - - if (say_time + 5.0 > render->now) { - v2f_t text_pos; - float height; - - text_pos = render_bounds[0] + v2f_t(render_bounds.dim(0) / 2, -render_bounds.dim(1) * 0.1); - height = size.dim_min() * 0.20f; - render->render_text(text_pos, height, say_text, - render::ALIGN_CENTER_BOTTOM, - sf::Color::White); - } - } -}; - -void state_t::start(void) -{ - human_t *human; - - human = new human_t; - human->place(&world, v2f_t(0.5, 0.5)); - units.insert(human); -} - -void state_t::stop(void) -{ - // FIXME - /* - for (unit_t *unit : units) - delete unit; - */ -} - -void state_t::select(rectf_t x) -{ - selection_cookie++; - selected_units.clear(); - - for (world::entity_t *ent : world.get_render_entities(x)) { - unit_t *unit; - - if (ent->type != ET_UNIT) - continue; - - unit = (unit_t*)ent; - unit->selected = selection_cookie; - selected_units.insert(unit); - } -} - -void state_t::command(v2f_t x) -{ - v2f_t snap; - - snap[0] = std::round(x[0] - 0.5f) + 0.5f; - snap[1] = std::round(x[1] - 0.5f) + 0.5f; - - for (unit_t *unit : selected_units) - unit->start_moving(snap, now); -} - -void state_t::tick(double now_, double dt_) -{ - now = now_; - dt = dt_; - - for (unit_t *unit : units) - unit->keep_moving(now, dt); -} - -} //namespace game diff --git a/src/game/assets.cpp b/src/game/assets.cpp new file mode 100644 index 0000000..32eff81 --- /dev/null +++ b/src/game/assets.cpp @@ -0,0 +1,20 @@ +#include "game.hpp" + +namespace assets { + +human_assets_t human; +sf::Texture tile_dirt; +sf::Texture tile_wall; + +void load(void) +{ + human.head_idle.load("assets/units/human/head_idle", 1, 1, 1); + human.body_idle.load("assets/units/human/body_idle", 2, 2, 2); + human.legs_idle.load("assets/units/human/legs_idle", 2, 2); + human.legs_walking.load("assets/units/human/legs_walking", 2, 2); + + tile_dirt.loadFromFile("assets/tiles/dirt.png"); + tile_wall.loadFromFile("assets/tiles/wall.png"); +} + +} // namespace assets diff --git a/src/game/game.cpp b/src/game/game.cpp new file mode 100644 index 0000000..eb3966d --- /dev/null +++ b/src/game/game.cpp @@ -0,0 +1,270 @@ +#include "game.hpp" + +namespace game { + +static size_t selection_cookie = 1; + +enum { + ET_UNIT +}; + +class unit_t : public world::entity_t { +protected: + world::world_t *world; + + world::cmodel_t make_cmodel(v2f_t at) + { + world::cmodel_t cmodel; + + cmodel.bounds[0] = at + size[0]; + cmodel.bounds[1] = at + size[1]; + cmodel.cflags = cflags; + + return cmodel; + } + + void compute_bounds() + { + render_bounds[0] = x + render_size[0]; + render_bounds[1] = x + render_size[1]; + } + +public: + v2f_t x; + rectf_t size, render_size; + world::cflags_t cflags; + size_t selected = 0; + + unit_t() : entity_t(ET_UNIT) + { + } + + struct { + bool moving = false; + v2f_t dst; + float angle = 0.0f; + + std::list path; + + bool blocked; + size_t attempts_left; + float next_attempt; + } move; + + const wchar_t *say_text; + double say_time = -INFINITY; + + void say(const wchar_t *wstr, double now) + { + say_text = wstr; + say_time = now; + std::cout << (void*)this << ": " << wstr << "\n"; + } + + void place(world::world_t *world_, v2f_t x_) + { + world = world_; + x = x_; + move.moving = false; + cflags = 1; + + unlink(); + cmodel = make_cmodel(x); + compute_bounds(); + link(world); + } + + void keep_moving(double now, double dt) + { + float time; + + if (!move.moving) + return; + + if (move.blocked && now < move.next_attempt) + return; + + time = dt * 10; + + while (time > 0.0f) { + v2f_t delta, next, x_new; + world::cmodel_t cmodel_next; + + if (!move.path.size()) { + move.moving = false; + break; + } + + next = *move.path.begin(); + delta = next - x; + move.angle = delta.angle(); + + if (delta.len() >= time) { + x_new = x + delta * time / delta.len(); + time -= delta.len(); + } else { + x_new = next; + time -= delta.len(); + move.path.pop_front(); + } + + cmodel_next = make_cmodel(x_new); + if (!world->test_rect(&cmodel_next, this)) { + x = x_new; + cmodel = cmodel_next; + continue; + } + + if (move.attempts_left) { + move.blocked = true; + move.attempts_left--; + move.next_attempt = now + 0.2f; + } else { + if ((x - move.dst).len() > 1.5f) + say(text::unit_blocked, now); + move.moving = false; + } + break; + } + + + unlink(); + compute_bounds(); + link(world); + } + + bool start_moving(v2f_t dst_, double now) + { + if (!world) { + printf("unit_t::start_moving: entity is not linked\n"); + return false; + } + + move.dst = dst_; + move.path.clear(); + + if (!world->find_path(x, move.dst, &cmodel, this, &move.path)) { + say(text::unit_no_path, now); + move.moving = false; + return false; + } + + move.moving = true; + + move.blocked = false; + move.attempts_left = 10; + move.next_attempt = -INFINITY; + + return true; + } +}; + +class human_t : public unit_t { +public: + human_t() + { + size[0] = v2f_t(-0.4f, -0.4f); + size[1] = v2f_t(+0.4f, +0.4f); + render_size[0] = v2f_t(-0.5f, -1.0f); + render_size[1] = v2f_t(+0.5f, +0.5f); + } + + void render_to(render::state_t *render) + { + bool moving; + + if (selected == selection_cookie) + render->render_hlrect(render_bounds, sf::Color::Blue); + + moving = move.moving && !move.blocked; + + render->render((moving ? &assets::human.legs_walking : + &assets::human.legs_idle), render_bounds, move.angle); + render->render(&assets::human.body_idle, render_bounds, move.angle); + render->render(&assets::human.head_idle, render_bounds, move.angle); + + { + v2f_t x1; + static float t = 0; + world::trace_t trace; + + t += 0.02f; + + x1[0] = x[0] + cos(t) * 5; + x1[1] = x[1] + sin(t) * 5; + trace = world->trace(x, x1, 1); + render->render_arrow(x, trace.end, sf::Color::Green); + } + + if (move.moving && debug_draw_paths) + render->debug_path(&move.path); + + if (say_time + 5.0 > render->now) { + v2f_t text_pos; + float height; + + text_pos = render_bounds[0] + v2f_t(render_bounds.dim(0) / 2, -render_bounds.dim(1) * 0.1); + height = size.dim_min() * 0.20f; + render->render_text(text_pos, height, say_text, + render::ALIGN_CENTER_BOTTOM, + sf::Color::White); + } + } +}; + +void state_t::start(void) +{ + human_t *human; + + human = new human_t; + human->place(&world, v2f_t(0.5, 0.5)); + units.insert(human); +} + +void state_t::stop(void) +{ + // FIXME + /* + for (unit_t *unit : units) + delete unit; + */ +} + +void state_t::select(rectf_t x) +{ + selection_cookie++; + selected_units.clear(); + + for (world::entity_t *ent : world.get_render_entities(x)) { + unit_t *unit; + + if (ent->type != ET_UNIT) + continue; + + unit = (unit_t*)ent; + unit->selected = selection_cookie; + selected_units.insert(unit); + } +} + +void state_t::command(v2f_t x) +{ + v2f_t snap; + + snap[0] = std::round(x[0] - 0.5f) + 0.5f; + snap[1] = std::round(x[1] - 0.5f) + 0.5f; + + for (unit_t *unit : selected_units) + unit->start_moving(snap, now); +} + +void state_t::tick(double now_, double dt_) +{ + now = now_; + dt = dt_; + + for (unit_t *unit : units) + unit->keep_moving(now, dt); +} + +} //namespace game diff --git a/src/game/game.hpp b/src/game/game.hpp new file mode 100644 index 0000000..3e10bbb --- /dev/null +++ b/src/game/game.hpp @@ -0,0 +1,14 @@ +#include "../common.hpp" + +namespace assets { + typedef struct { + render::oriented_sprite_4M_t head_idle, body_idle; + render::oriented_sprite_4M2_t legs_idle, legs_walking; + } human_assets_t; + + extern human_assets_t human; + extern sf::Texture tile_dirt; + extern sf::Texture tile_wall; + + void load(void); +}; diff --git a/src/game/interface.cpp b/src/game/interface.cpp new file mode 100644 index 0000000..c89cdad --- /dev/null +++ b/src/game/interface.cpp @@ -0,0 +1,134 @@ +#include "game.hpp" + +namespace interface { + +state_t::state_t(sf::RenderWindow *window_, game::state_t *game_) +{ + window = window_; + game = game_; +} + +static sf::Vector2f compute_pan(sf::RenderWindow *window, sf::Vector2f pan_ref) +{ + sf::Vector2i mouse = sf::Mouse::getPosition(*window); + sf::Vector2f vmouse = window->mapPixelToCoords(mouse); + return -(vmouse - pan_ref); +} + +void state_t::tick(double dt) +{ + sf::Vector2u size; + sf::Event event; + sf::Vector2f view_size; + v2f_t wmouse; // Mouse position in world space; + + size = window->getSize(); + + camera.zoom = expfade(camera.zoom, camera.target_zoom, 15, dt); + + { + float view_scale; + + view_scale = 3 * exp(camera.zoom * 0.3); + if (size.x > size.y) { + view_size.y = view_scale; + view_size.x = view_scale * size.x / size.y; + } else { + view_size.x = view_scale; + view_size.y = view_scale * size.y / size.x; + } + + window->setView(sf::View(camera.center, view_size)); + } + + + while (window->pollEvent(event)) { + // FIXME: refactor this nested switch clusterfuck + switch (event.type) { + case sf::Event::Closed: + window->close(); + return; + + case sf::Event::MouseButtonPressed: + wmouse = window->mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y)); + + switch (event.mouseButton.button) { + case sf::Mouse::Button::Left: + select.selecting = true; + select.rect[0] = wmouse; + select.rect[1] = wmouse; + break; + + case sf::Mouse::Button::Right: + game->command(wmouse); + break; + + case sf::Mouse::Button::Middle: + camera.panning = true; + camera.pan_ref = wmouse; + break; + + default:; + } + break; + + case sf::Event::MouseButtonReleased: + switch (event.mouseButton.button) { + case sf::Mouse::Button::Left: + if (select.selecting) + game->select(select.rect); + select.selecting = false; + break; + + case sf::Mouse::Button::Middle: + if (camera.panning) + camera.center += compute_pan(window, camera.pan_ref); + camera.panning = false; + break; + + default:; + } + break; + + case sf::Event::MouseWheelScrolled: + camera.target_zoom -= event.mouseWheelScroll.delta; + if (camera.target_zoom < 0) + camera.target_zoom = 0; + if (camera.target_zoom > 11) + camera.target_zoom = 11; + break; + + case sf::Event::KeyPressed: + switch (event.key.code) { + case sf::Keyboard::Key::F1: + debug_draw_cmodels ^= 1; + break; + + case sf::Keyboard::Key::F2: + debug_draw_paths ^= 1; + break; + + case sf::Keyboard::Key::F3: + debug_draw_tile_coords ^= 1; + break; + + default:; + } + default:; + } + } + + if (camera.panning) { + sf::Vector2f delta = compute_pan(window, camera.pan_ref); + window->setView(sf::View(camera.center + delta, view_size)); + } else + window->setView(sf::View(camera.center, view_size)); + + // Compute this _after_ the setView above. + wmouse = window->mapPixelToCoords(sf::Mouse::getPosition(*window)); + + if (select.selecting) + select.rect[1] = wmouse; +} + +} // namespace interface diff --git a/src/interface.cpp b/src/interface.cpp deleted file mode 100644 index 3a6a294..0000000 --- a/src/interface.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "common.hpp" - -namespace interface { - -state_t::state_t(sf::RenderWindow *window_, game::state_t *game_) -{ - window = window_; - game = game_; -} - -static sf::Vector2f compute_pan(sf::RenderWindow *window, sf::Vector2f pan_ref) -{ - sf::Vector2i mouse = sf::Mouse::getPosition(*window); - sf::Vector2f vmouse = window->mapPixelToCoords(mouse); - return -(vmouse - pan_ref); -} - -void state_t::tick(double dt) -{ - sf::Vector2u size; - sf::Event event; - sf::Vector2f view_size; - v2f_t wmouse; // Mouse position in world space; - - size = window->getSize(); - - camera.zoom = expfade(camera.zoom, camera.target_zoom, 15, dt); - - { - float view_scale; - - view_scale = 3 * exp(camera.zoom * 0.3); - if (size.x > size.y) { - view_size.y = view_scale; - view_size.x = view_scale * size.x / size.y; - } else { - view_size.x = view_scale; - view_size.y = view_scale * size.y / size.x; - } - - window->setView(sf::View(camera.center, view_size)); - } - - - while (window->pollEvent(event)) { - // FIXME: refactor this nested switch clusterfuck - switch (event.type) { - case sf::Event::Closed: - window->close(); - return; - - case sf::Event::MouseButtonPressed: - wmouse = window->mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y)); - - switch (event.mouseButton.button) { - case sf::Mouse::Button::Left: - select.selecting = true; - select.rect[0] = wmouse; - select.rect[1] = wmouse; - break; - - case sf::Mouse::Button::Right: - game->command(wmouse); - break; - - case sf::Mouse::Button::Middle: - camera.panning = true; - camera.pan_ref = wmouse; - break; - - default:; - } - break; - - case sf::Event::MouseButtonReleased: - switch (event.mouseButton.button) { - case sf::Mouse::Button::Left: - if (select.selecting) - game->select(select.rect); - select.selecting = false; - break; - - case sf::Mouse::Button::Middle: - if (camera.panning) - camera.center += compute_pan(window, camera.pan_ref); - camera.panning = false; - break; - - default:; - } - break; - - case sf::Event::MouseWheelScrolled: - camera.target_zoom -= event.mouseWheelScroll.delta; - if (camera.target_zoom < 0) - camera.target_zoom = 0; - if (camera.target_zoom > 11) - camera.target_zoom = 11; - break; - - case sf::Event::KeyPressed: - switch (event.key.code) { - case sf::Keyboard::Key::F1: - debug_draw_cmodels ^= 1; - break; - - case sf::Keyboard::Key::F2: - debug_draw_paths ^= 1; - break; - - case sf::Keyboard::Key::F3: - debug_draw_tile_coords ^= 1; - break; - - default:; - } - default:; - } - } - - if (camera.panning) { - sf::Vector2f delta = compute_pan(window, camera.pan_ref); - window->setView(sf::View(camera.center + delta, view_size)); - } else - window->setView(sf::View(camera.center, view_size)); - - // Compute this _after_ the setView above. - wmouse = window->mapPixelToCoords(sf::Mouse::getPosition(*window)); - - if (select.selecting) - select.rect[1] = wmouse; -} - -} // namespace interface diff --git a/src/render.cpp b/src/render.cpp index 7e90190..0952343 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -14,13 +14,13 @@ static void draw_tile(sf::RenderWindow *window, v2f_t x, world::tile_t *tile, default: return; - case world::TILE_DIRT: + /*case world::TILE_DIRT: texture = &assets::tile_dirt; break; case world::TILE_WALL: texture = &assets::tile_wall; - break; + break;*/ } wot_rect.setTexture(texture, true); -- cgit