From 26fbd8c1edaf94513d9750681edbe449b699efe4 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 22 Feb 2019 17:25:59 -0500 Subject: Trains move on tracks to the beat Small implementation changes in various places, biggest thing is now we're using ranges, which is experimental and will be included for real in C++20. --- CMakeLists.txt | 1 + src/direction.cpp | 25 ++++++++++++ src/direction.h | 18 +++++++++ src/entity.h | 7 ++++ src/enums.h | 9 ++--- src/schedule.h | 22 +++++++++-- src/simulation.cpp | 114 ++++++++++++++++++++++++++++++++++++++++------------- src/simulation.h | 4 +- 8 files changed, 160 insertions(+), 40 deletions(-) create mode 100644 src/direction.cpp create mode 100644 src/direction.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8800db7..6fabbf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ add_executable(dispatcher src/main.cpp src/renderer.cpp src/simulation.cpp + src/direction.cpp ) set_property(TARGET dispatcher PROPERTY CXX_STANDARD 17) diff --git a/src/direction.cpp b/src/direction.cpp new file mode 100644 index 0000000..cf6409e --- /dev/null +++ b/src/direction.cpp @@ -0,0 +1,25 @@ +#include "direction.h" + +vec2s posInDir(vec2s orig, Direction dir) +{ + switch (dir) + { + case Direction::left: return orig - vec2s { 1, 0 }; + case Direction::right: return orig + vec2s { 1, 0 }; + case Direction::up: return orig - vec2s { 0, 1 }; + case Direction::down: return orig + vec2s { 0, 1 }; + case Direction::none: return orig; + } +} + +Direction oppositeDir(Direction dir) +{ + switch (dir) + { + case Direction::left: return Direction::right; + case Direction::right: return Direction::left; + case Direction::up: return Direction::down; + case Direction::down: return Direction::up; + case Direction::none: return Direction::none; + } +} diff --git a/src/direction.h b/src/direction.h new file mode 100644 index 0000000..8108505 --- /dev/null +++ b/src/direction.h @@ -0,0 +1,18 @@ +#ifndef DIRECTION_H_2B40D968 +#define DIRECTION_H_2B40D968 + +#include "vector.h" + +enum class Direction { + none, + left, + right, + up, + down +}; + +vec2s posInDir(vec2s orig, Direction dir); + +Direction oppositeDir(Direction dir); + +#endif /* end of include guard: DIRECTION_H_2B40D968 */ diff --git a/src/entity.h b/src/entity.h index a69c612..c47f1e7 100644 --- a/src/entity.h +++ b/src/entity.h @@ -4,6 +4,7 @@ #include #include "vector.h" #include "enums.h" +#include "direction.h" class Entity { public: @@ -14,6 +15,7 @@ public: // Grid placement vec2s gridPos; + Layer layer = Layer::object; // Movement Direction shouldMoveTo = Direction::none; @@ -35,6 +37,11 @@ public: bool scheduled = false; + // Track + bool isTrack = false; + Direction trackDir1 = Direction::none; + Direction trackDir2 = Direction::none; + }; #endif /* end of include guard: ENTITY_H_0D6CB29A */ diff --git a/src/enums.h b/src/enums.h index 9821da1..e2056f5 100644 --- a/src/enums.h +++ b/src/enums.h @@ -8,12 +8,9 @@ enum class ColliderType { other }; -enum class Direction { - none, - left, - right, - up, - down +enum class Layer { + track, + object }; #endif /* end of include guard: ENUMS_H_CD0A75E4 */ diff --git a/src/schedule.h b/src/schedule.h index 5d77761..f7c5543 100644 --- a/src/schedule.h +++ b/src/schedule.h @@ -5,17 +5,23 @@ class Schedule { public: explicit Schedule( - size_t bpm) : + double bpm) : bpm_(bpm), - tick_(60.0 / static_cast(bpm_)) + bps_(bpm_ / 60.0), + tick_(1.0 / bps_) { } - size_t getBPM() const + double getBPM() const { return bpm_; } + double getBPS() const + { + return bps_; + } + void accumulate(double dt) { accum_ += dt; @@ -26,6 +32,7 @@ public: if (accum_ > tick_) { accum_ -= tick_; + beats_++; return true; } else { @@ -33,11 +40,18 @@ public: } } + size_t getBeat() const + { + return beats_; + } + private: - size_t bpm_; + double bpm_; + double bps_; double tick_; double accum_ = 0.0; + size_t beats_ = 0; }; diff --git a/src/simulation.cpp b/src/simulation.cpp index 1379c34..77a9a3e 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -1,5 +1,6 @@ #include "simulation.h" +#include #include "consts.h" #include "level.h" @@ -7,6 +8,59 @@ Simulation::Simulation( const Level& level) : level_(level) { + + + id_type trackId = emplaceEntity(); + Entity& track = getEntity(trackId); + track.size = TILE_SIZE; + track.layer = Layer::track; + track.isTrack = true; + track.trackDir1 = Direction::right; + track.trackDir2 = Direction::down; + track.colorVal = 130; + track.gridPos = vec2s { 6, 1 }; + + id_type trackId2 = emplaceEntity(); + Entity& track2 = getEntity(trackId2); + track2.size = TILE_SIZE; + track2.layer = Layer::track; + track2.isTrack = true; + track2.trackDir1 = Direction::right; + track2.trackDir2 = Direction::up; + track2.colorVal = 130; + track2.gridPos = vec2s { 6, 2 }; + + id_type trackId3 = emplaceEntity(); + Entity& track3 = getEntity(trackId3); + track3.size = TILE_SIZE; + track3.layer = Layer::track; + track3.isTrack = true; + track3.trackDir1 = Direction::up; + track3.trackDir2 = Direction::left; + track3.colorVal = 130; + track3.gridPos = vec2s { 7, 2 }; + + id_type trackId4 = emplaceEntity(); + Entity& track4 = getEntity(trackId4); + track4.size = TILE_SIZE; + track4.layer = Layer::track; + track4.isTrack = true; + track4.trackDir1 = Direction::left; + track4.trackDir2 = Direction::down; + track4.colorVal = 130; + track4.gridPos = vec2s { 7, 1 }; + + + id_type trainId = emplaceEntity(); + Entity& train = getEntity(trainId); + train.size = TILE_SIZE; + train.speed = schedule_.getBPS() * 2.0; + train.colliderType = ColliderType::train; + train.scheduled = true; + train.colorVal = 90; + train.gridPos = vec2s { 6, 1 }; + train.moveDir = Direction::left; + id_type player = emplaceEntity(); Entity& entity = getEntity(player); entity.size = TILE_SIZE; @@ -19,7 +73,7 @@ Simulation::Simulation( id_type crateId = emplaceEntity(); Entity& crate = getEntity(crateId); crate.size = TILE_SIZE; - crate.speed = static_cast(schedule_.getBPM()) / 30.0; + crate.speed = schedule_.getBPS() * 2.0; crate.colliderType = ColliderType::crate; crate.canBePushedBy.insert(ColliderType::player); crate.canBePushedBy.insert(ColliderType::crate); @@ -29,24 +83,13 @@ Simulation::Simulation( id_type crateId2 = emplaceEntity(); Entity& crate2 = getEntity(crateId2); crate2.size = TILE_SIZE; - crate2.speed = static_cast(schedule_.getBPM()) / 30.0; + crate2.speed = schedule_.getBPS() * 2.0; crate2.colliderType = ColliderType::crate; crate2.canBePushedBy.insert(ColliderType::player); crate2.canBePushedBy.insert(ColliderType::crate); crate2.canBePushedBy.insert(ColliderType::train); crate2.gridPos = vec2s { 6, 7 }; - id_type trainId = emplaceEntity(); - Entity& train = getEntity(trainId); - train.size = TILE_SIZE; - train.speed = static_cast(schedule_.getBPM()) / 30.0; - train.colliderType = ColliderType::train; - train.scheduled = true; - train.colorVal = 90; - train.gridPos = vec2s { 6, 1 }; - - - for (id_type id : active_) { @@ -145,7 +188,28 @@ void Simulation::tick( if (entity.scheduled && !entity.moving) { - moveEntityOnGrid(id, Direction::down); + auto tracks = + posCache_.at(entity.gridPos) | + ranges::view::transform([&] (id_type id) -> Entity& { return entities_.at(id); }) | + ranges::view::filter([&] (Entity& other) { return other.isTrack; }); + + if (!ranges::empty(tracks)) + { + Entity& track = ranges::front(tracks); + + Direction dir = Direction::none; + Direction from = oppositeDir(entity.moveDir); + + if (from == track.trackDir1) + { + dir = track.trackDir2; + } else if (from == track.trackDir2) + { + dir = track.trackDir1; + } + + moveEntityOnGrid(id, dir); + } } } } @@ -282,7 +346,10 @@ bool Simulation::moveEntityOnGrid( } // Can't move into a space that something else is already moving into. - if (!moveToCache_.at(shouldMoveTo).empty()) + if (!ranges::empty( + moveToCache_.at(shouldMoveTo) | + ranges::view::transform([&] (id_type id) -> Entity& { return entities_.at(id); }) | + ranges::view::filter([&] (Entity& other) { return other.layer == entity.layer; }))) { return false; } @@ -291,6 +358,11 @@ bool Simulation::moveEntityOnGrid( { Entity& block = entities_.at(blockId); + if (block.layer != entity.layer) + { + continue; + } + if (!block.moving) { if (!block.canBePushedBy.count(entity.colliderType)) @@ -334,15 +406,3 @@ bool Simulation::moveEntityOnGrid( return true; } - -vec2s Simulation::posInDir(vec2s orig, Direction dir) -{ - switch (dir) - { - case Direction::left: return orig - vec2s { 1, 0 }; - case Direction::right: return orig + vec2s { 1, 0 }; - case Direction::up: return orig - vec2s { 0, 1 }; - case Direction::down: return orig + vec2s { 0, 1 }; - case Direction::none: return orig; - } -} diff --git a/src/simulation.h b/src/simulation.h index f86d513..fbe0a43 100644 --- a/src/simulation.h +++ b/src/simulation.h @@ -47,8 +47,6 @@ public: return level_; } - static vec2s posInDir(vec2s orig, Direction dir); - private: @@ -60,7 +58,7 @@ private: bool validate = false); const Level& level_; - Schedule schedule_ { 120 }; + Schedule schedule_ { 90 }; std::vector entities_; std::deque available_; -- cgit 1.4.1