From 8016a7146fec3f6f43ca05723441750e5aae3d4d Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sat, 28 Apr 2018 09:22:44 -0400 Subject: Restructured the way the world is loaded The World class was removed and replaced by the RealizingSystem and RealizableComponent. The realizable entity is intended to be a singleton and to represent the world. The Map class was also removed and integrated into the MappableComponent. These changes are to facilitate implementation of map objects without needing special intermediary objects (including the Map class). Now, map entities are created as soon as the world is created, and map object entities will be as well. They will simply be deactivated while the map is not active. Multiple players are now slightly better supported, which will be important in the future. This will likely become inefficient as the world becomes bigger, and some sort of sector-loading process will have to be designed. This also reduces the usefulness of EntityManager's entity-searching capabilities (which are not the most efficiently implemented currently anyway), and will likely in the future require some added functionality to better search subsets of entities. A lot of the components were also rewritten to use bare member variables instead of accessor methods, as they never had special functionality and just took up space. These components were also documented. --- src/systems/animating.cpp | 93 +++++++----- src/systems/animating.h | 2 + src/systems/mapping.cpp | 127 ++++++++--------- src/systems/mapping.h | 2 +- src/systems/orienting.cpp | 22 +-- src/systems/playing.cpp | 220 +++++++++++++--------------- src/systems/playing.h | 9 +- src/systems/pondering.cpp | 354 ++++++++++++++++++++++++++-------------------- src/systems/pondering.h | 2 + src/systems/realizing.cpp | 321 +++++++++++++++++++++++++++++++++++++++++ src/systems/realizing.h | 43 ++++++ 11 files changed, 800 insertions(+), 395 deletions(-) create mode 100644 src/systems/realizing.cpp create mode 100644 src/systems/realizing.h (limited to 'src/systems') diff --git a/src/systems/animating.cpp b/src/systems/animating.cpp index 634af67..8543ba2 100644 --- a/src/systems/animating.cpp +++ b/src/systems/animating.cpp @@ -13,26 +13,29 @@ void AnimatingSystem::tick(double) auto& sprite = game_.getEntityManager(). getComponent(entity); - if (!sprite.isFrozen()) + if (sprite.active) { - sprite.setCountdown(sprite.getCountdown() + 1); - } - - const Animation& anim = sprite.getAnimation(); - if (sprite.getCountdown() >= anim.getDelay()) - { - sprite.setFrame(sprite.getFrame() + 1); - sprite.setCountdown(0); + if (!sprite.frozen) + { + sprite.countdown++; + } - if (sprite.getFrame() >= anim.getFirstFrame() + anim.getNumFrames()) + const Animation& anim = sprite.getAnimation(); + if (sprite.countdown >= anim.getDelay()) { - sprite.setFrame(anim.getFirstFrame()); + sprite.frame++; + sprite.countdown = 0; + + if (sprite.frame >= anim.getFirstFrame() + anim.getNumFrames()) + { + sprite.frame = anim.getFirstFrame(); + } } - } - if (sprite.isFlickering()) - { - sprite.setFlickerTimer((sprite.getFlickerTimer() + 1) % 6); + if (sprite.flickering) + { + sprite.flickerTimer = (sprite.flickerTimer + 1) % 6; + } } } } @@ -49,36 +52,52 @@ void AnimatingSystem::render(Texture& texture) auto& sprite = game_.getEntityManager(). getComponent(entity); - auto& transform = game_.getEntityManager(). - getComponent(entity); - - double alpha = 1.0; - if (sprite.isFlickering() && (sprite.getFlickerTimer() < 3)) + if (sprite.active) { - alpha = 0.0; - } + auto& transform = game_.getEntityManager(). + getComponent(entity); - Rectangle dstrect { - static_cast(transform.getX()), - static_cast(transform.getY()), - transform.getW(), - transform.getH()}; - - const AnimationSet& aset = sprite.getAnimationSet(); - game_.getRenderer().blit( - aset.getTexture(), - texture, - aset.getFrameRect(sprite.getFrame()), - dstrect, - alpha); + double alpha = 1.0; + if (sprite.flickering && (sprite.flickerTimer < 3)) + { + alpha = 0.0; + } + + Rectangle dstrect { + static_cast(transform.x), + static_cast(transform.y), + transform.w, + transform.h}; + + const AnimationSet& aset = sprite.animationSet; + game_.getRenderer().blit( + aset.getTexture(), + texture, + aset.getFrameRect(sprite.frame), + dstrect, + alpha); + } } } +void AnimatingSystem::initPrototype(id_type entity) +{ + auto& sprite = game_.getEntityManager(). + getComponent(entity); + + startAnimation(entity, sprite.origAnimation); + + sprite.countdown = 0; + sprite.flickering = false; + sprite.flickerTimer = 0; + sprite.frozen = false; +} + void AnimatingSystem::startAnimation(id_type entity, std::string animation) { auto& sprite = game_.getEntityManager(). getComponent(entity); - sprite.setAnimation(animation); - sprite.setFrame(sprite.getAnimation().getFirstFrame()); + sprite.animation = std::move(animation); + sprite.frame = sprite.getAnimation().getFirstFrame(); } diff --git a/src/systems/animating.h b/src/systems/animating.h index 548bff1..acc6191 100644 --- a/src/systems/animating.h +++ b/src/systems/animating.h @@ -16,6 +16,8 @@ public: void render(Texture& texture); + void initPrototype(id_type entity); + void startAnimation(id_type entity, std::string animation); }; diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp index a3a17ec..af67aed 100644 --- a/src/systems/mapping.cpp +++ b/src/systems/mapping.cpp @@ -1,5 +1,7 @@ #include "mapping.h" #include "components/mappable.h" +#include "components/realizable.h" +#include "systems/realizing.h" #include "game.h" #include "consts.h" @@ -18,104 +20,95 @@ inline void addBoundary( void MappingSystem::render(Texture& texture) { - auto entities = game_.getEntityManager().getEntitiesWithComponents< - MappableComponent>(); + auto& realizable = game_.getEntityManager(). + getComponent( + game_.getSystemManager().getSystem().getSingleton()); - for (id_type entity : entities) - { - auto& mappable = game_.getEntityManager(). - getComponent(entity); + id_type map = realizable.activeMap; - const Map& map = game_.getWorld().getMap(mappable.getMapId()); + auto& mappable = game_.getEntityManager(). + getComponent(map); - for (int i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++) - { - int x = i % MAP_WIDTH; - int y = i / MAP_WIDTH; - int tile = map.getTiles()[i]; - - if (tile > 0) - { - Rectangle dst { - x * TILE_WIDTH, - y * TILE_HEIGHT, - TILE_WIDTH, - TILE_HEIGHT}; - - Rectangle src { - (tile % TILESET_COLS) * TILE_WIDTH, - (tile / TILESET_COLS) * TILE_HEIGHT, - TILE_WIDTH, - TILE_HEIGHT}; - - game_.getRenderer().blit( - mappable.getTileset(), - texture, - std::move(src), - std::move(dst)); - } - } + for (int i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++) + { + int x = i % MAP_WIDTH; + int y = i / MAP_WIDTH; + int tile = mappable.tiles[i]; - int startX = ((GAME_WIDTH / TILE_WIDTH) / 2) - (map.getTitle().size() / 2); - for (size_t i = 0; i < map.getTitle().size(); i++) + if (tile > 0) { - Rectangle src { - (map.getTitle()[i] % FONT_COLS) * TILE_WIDTH, - (map.getTitle()[i] / FONT_COLS) * TILE_HEIGHT, + Rectangle dst { + x * TILE_WIDTH, + y * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; - Rectangle dst { - (startX + static_cast(i)) * TILE_WIDTH, - 24 * TILE_HEIGHT, + Rectangle src { + (tile % TILESET_COLS) * TILE_WIDTH, + (tile / TILESET_COLS) * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; game_.getRenderer().blit( - mappable.getFont(), + mappable.tileset, texture, std::move(src), std::move(dst)); } } + + int startX = ((GAME_WIDTH / TILE_WIDTH) / 2) - (mappable.title.size() / 2); + + for (size_t i = 0; i < mappable.title.size(); i++) + { + Rectangle src { + (mappable.title[i] % FONT_COLS) * TILE_WIDTH, + (mappable.title[i] / FONT_COLS) * TILE_HEIGHT, + TILE_WIDTH, + TILE_HEIGHT}; + + Rectangle dst { + (startX + static_cast(i)) * TILE_WIDTH, + 24 * TILE_HEIGHT, + TILE_WIDTH, + TILE_HEIGHT}; + + game_.getRenderer().blit( + mappable.font, + texture, + std::move(src), + std::move(dst)); + } } -void MappingSystem::loadMap(size_t mapId) +void MappingSystem::generateBoundaries(id_type mapEntity) { - id_type mapEntity = game_.getEntityManager().emplaceEntity(); - auto& mappable = game_.getEntityManager(). - emplaceComponent(mapEntity, - Texture("res/tiles.png"), - Texture("res/font.bmp")); - - mappable.setMapId(mapId); - - const Map& map = game_.getWorld().getMap(mappable.getMapId()); + getComponent(mapEntity); addBoundary( - mappable.getLeftBoundaries(), + mappable.leftBoundaries, -WALL_GAP, 0, MAP_HEIGHT * TILE_HEIGHT, MappableComponent::Boundary::Type::adjacency); addBoundary( - mappable.getRightBoundaries(), + mappable.rightBoundaries, GAME_WIDTH + WALL_GAP, 0, MAP_HEIGHT * TILE_HEIGHT, MappableComponent::Boundary::Type::adjacency); addBoundary( - mappable.getUpBoundaries(), + mappable.upBoundaries, -WALL_GAP, 0, GAME_WIDTH, MappableComponent::Boundary::Type::adjacency); addBoundary( - mappable.getDownBoundaries(), + mappable.downBoundaries, MAP_HEIGHT * TILE_HEIGHT + WALL_GAP, 0, GAME_WIDTH, @@ -125,12 +118,12 @@ void MappingSystem::loadMap(size_t mapId) { size_t x = i % MAP_WIDTH; size_t y = i / MAP_WIDTH; - int tile = map.getTiles()[i]; + int tile = mappable.tiles[i]; if ((tile >= 5) && (tile <= 7)) { addBoundary( - mappable.getDownBoundaries(), + mappable.downBoundaries, y * TILE_HEIGHT, x * TILE_WIDTH, (x + 1) * TILE_WIDTH, @@ -138,28 +131,28 @@ void MappingSystem::loadMap(size_t mapId) } else if ((tile > 0) && (tile < 28)) { addBoundary( - mappable.getRightBoundaries(), + mappable.rightBoundaries, x * TILE_WIDTH, y * TILE_HEIGHT, (y+1) * TILE_HEIGHT, MappableComponent::Boundary::Type::wall); addBoundary( - mappable.getLeftBoundaries(), + mappable.leftBoundaries, (x+1) * TILE_WIDTH, y * TILE_HEIGHT, (y+1) * TILE_HEIGHT, MappableComponent::Boundary::Type::wall); addBoundary( - mappable.getDownBoundaries(), + mappable.downBoundaries, y * TILE_HEIGHT, x * TILE_WIDTH, (x+1) * TILE_WIDTH, MappableComponent::Boundary::Type::wall); addBoundary( - mappable.getUpBoundaries(), + mappable.upBoundaries, (y+1) * TILE_HEIGHT, x * TILE_WIDTH, (x+1) * TILE_WIDTH, @@ -167,28 +160,28 @@ void MappingSystem::loadMap(size_t mapId) } else if (tile == 42) { addBoundary( - mappable.getRightBoundaries(), + mappable.rightBoundaries, x * TILE_WIDTH, y * TILE_HEIGHT, (y+1) * TILE_HEIGHT, MappableComponent::Boundary::Type::danger); addBoundary( - mappable.getLeftBoundaries(), + mappable.leftBoundaries, (x+1) * TILE_WIDTH, y * TILE_HEIGHT, (y+1) * TILE_HEIGHT, MappableComponent::Boundary::Type::danger); addBoundary( - mappable.getDownBoundaries(), + mappable.downBoundaries, y * TILE_HEIGHT, x * TILE_WIDTH, (x+1) * TILE_WIDTH, MappableComponent::Boundary::Type::danger); addBoundary( - mappable.getUpBoundaries(), + mappable.upBoundaries, (y+1) * TILE_HEIGHT, x * TILE_WIDTH, (x+1) * TILE_WIDTH, diff --git a/src/systems/mapping.h b/src/systems/mapping.h index 53d054b..3c47419 100644 --- a/src/systems/mapping.h +++ b/src/systems/mapping.h @@ -12,7 +12,7 @@ public: void render(Texture& texture); - void loadMap(size_t mapId); + void generateBoundaries(id_type mapEntity); }; diff --git a/src/systems/orienting.cpp b/src/systems/orienting.cpp index 2df8f87..206ebf6 100644 --- a/src/systems/orienting.cpp +++ b/src/systems/orienting.cpp @@ -24,27 +24,27 @@ void OrientingSystem::tick(double) { case OrientableComponent::WalkState::still: { - ponderable.setVelocityX(0); + ponderable.velX = 0.0; break; } case OrientableComponent::WalkState::left: { - ponderable.setVelocityX(-WALK_SPEED); + ponderable.velX = -WALK_SPEED; break; } case OrientableComponent::WalkState::right: { - ponderable.setVelocityX(WALK_SPEED); + ponderable.velX = WALK_SPEED; break; } } - if (orientable.isJumping() && (ponderable.getVelocityY() > 0)) + if (orientable.isJumping() && (ponderable.velY > 0)) { orientable.setJumping(false); } @@ -63,7 +63,7 @@ void OrientingSystem::moveLeft(id_type entity) orientable.setWalkState(OrientableComponent::WalkState::left); auto& animating = game_.getSystemManager().getSystem(); - if (ponderable.isGrounded()) + if (ponderable.grounded) { animating.startAnimation(entity, "walkingLeft"); } else { @@ -83,7 +83,7 @@ void OrientingSystem::moveRight(id_type entity) orientable.setWalkState(OrientableComponent::WalkState::right); auto& animating = game_.getSystemManager().getSystem(); - if (ponderable.isGrounded()) + if (ponderable.grounded) { animating.startAnimation(entity, "walkingRight"); } else { @@ -113,7 +113,7 @@ void OrientingSystem::jump(id_type entity) auto& ponderable = game_.getEntityManager(). getComponent(entity); - if (ponderable.isGrounded()) + if (ponderable.grounded) { auto& orientable = game_.getEntityManager(). getComponent(entity); @@ -122,8 +122,8 @@ void OrientingSystem::jump(id_type entity) playSound("res/Randomize87.wav", 0.25); - ponderable.setVelocityY(JUMP_VELOCITY); - ponderable.setAccelY(JUMP_GRAVITY); + ponderable.velY = JUMP_VELOCITY; + ponderable.accelY = JUMP_GRAVITY; auto& animating = game_.getSystemManager().getSystem(); if (orientable.isFacingRight()) @@ -147,7 +147,7 @@ void OrientingSystem::stopJumping(id_type entity) auto& ponderable = game_.getEntityManager(). getComponent(entity); - ponderable.setAccelY(NORMAL_GRAVITY); + ponderable.accelY = NORMAL_GRAVITY; } } @@ -211,7 +211,7 @@ void OrientingSystem::drop(id_type entity) auto& ponderable = game_.getEntityManager(). getComponent(entity); - if (ponderable.isGrounded() + if (ponderable.grounded && (orientable.getDropState() == OrientableComponent::DropState::none)) { orientable.setDropState(OrientableComponent::DropState::ready); diff --git a/src/systems/playing.cpp b/src/systems/playing.cpp index 40d9706..b04f0cb 100644 --- a/src/systems/playing.cpp +++ b/src/systems/playing.cpp @@ -5,61 +5,17 @@ #include "components/playable.h" #include "components/controllable.h" #include "components/orientable.h" +#include "components/realizable.h" #include "systems/mapping.h" #include "systems/pondering.h" #include "systems/orienting.h" #include "systems/scheduling.h" #include "systems/controlling.h" +#include "systems/animating.h" +#include "systems/realizing.h" #include "animation.h" #include "muxer.h" -void PlayingSystem::tick(double) -{ - // Check if we need to change the map - auto players = game_.getEntityManager().getEntitiesWithComponents< - PlayableComponent, - TransformableComponent>(); - - for (id_type player : players) - { - auto& playable = game_.getEntityManager(). - getComponent(player); - - if (playable.changingMap) - { - // Change the map! - auto entities = game_.getEntityManager().getEntities(); - - for (id_type entity : entities) - { - if (entity != player) - { - game_.getEntityManager().deleteEntity(entity); - } - } - - game_.getSystemManager().getSystem(). - loadMap(playable.newMapId); - - auto& transformable = game_.getEntityManager(). - getComponent(player); - - transformable.setX(playable.newMapX); - transformable.setY(playable.newMapY); - - playable.changingMap = false; - - if (playable.newMapCallback) - { - playable.newMapCallback(); - playable.newMapCallback = nullptr; - } - - break; - } - } -} - void PlayingSystem::initPlayer() { id_type player = game_.getEntityManager().emplaceEntity(); @@ -72,15 +28,24 @@ void PlayingSystem::initPlayer() game_.getEntityManager().emplaceComponent( player, - std::move(playerGraphics), - "stillLeft"); + std::move(playerGraphics)); - game_.getEntityManager().emplaceComponent( + game_.getSystemManager().getSystem().startAnimation( player, - game_.getWorld().getStartingX(), - game_.getWorld().getStartingY(), - 10, - 12); + "stillLeft"); + + auto& realizing = game_.getSystemManager().getSystem(); + + auto& realizable = game_.getEntityManager(). + getComponent(realizing.getSingleton()); + + auto& transformable = game_.getEntityManager(). + emplaceComponent(player); + + transformable.x = realizable.startingX; + transformable.y = realizable.startingY; + transformable.w = 10; + transformable.h = 12; game_.getSystemManager().getSystem().initializeBody( player, @@ -92,84 +57,103 @@ void PlayingSystem::initPlayer() auto& playable = game_.getEntityManager(). emplaceComponent(player); - playable.checkpointMapId = game_.getWorld().getStartingMapId(); - playable.checkpointX = game_.getWorld().getStartingX(); - playable.checkpointY = game_.getWorld().getStartingY(); + playable.mapId = realizable.activeMap; + playable.checkpointMapId = realizable.startingMapId; + playable.checkpointX = realizable.startingX; + playable.checkpointY = realizable.startingY; + + realizing.enterActiveMap(player); + + realizable.activePlayer = player; } void PlayingSystem::changeMap( + id_type player, size_t mapId, double x, - double y, - PlayableComponent::MapChangeCallback callback) + double y) { - auto players = game_.getEntityManager().getEntitiesWithComponents< - PlayableComponent>(); + auto& playable = game_.getEntityManager(). + getComponent(player); - for (id_type player : players) + auto& transformable = game_.getEntityManager(). + getComponent(player); + + auto& animatable = game_.getEntityManager(). + getComponent(player); + + auto& ponderable = game_.getEntityManager(). + getComponent(player); + + auto& realizing = game_.getSystemManager().getSystem(); + + auto& realizable = game_.getEntityManager(). + getComponent(realizing.getSingleton()); + + id_type newMapEntity = realizable.entityByMapId[mapId]; + + if (playable.mapId != newMapEntity) { - auto& playable = game_.getEntityManager(). - getComponent(player); + if (playable.mapId == realizable.activeMap) + { + realizing.leaveActiveMap(player); + } else if (newMapEntity == realizable.activeMap) + { + realizing.enterActiveMap(player); + } - playable.changingMap = true; - playable.newMapId = mapId; - playable.newMapX = x; - playable.newMapY = y; - playable.newMapCallback = std::move(callback); + playable.mapId = newMapEntity; + } + + transformable.x = x; + transformable.y = y; + + if (realizable.activePlayer == player) + { + realizing.loadMap(newMapEntity); } } -void PlayingSystem::die() +void PlayingSystem::die(id_type player) { playSound("res/Hit_Hurt5.wav", 0.25); - auto players = game_.getEntityManager().getEntitiesWithComponents< - OrientableComponent, - ControllableComponent, - AnimatableComponent, - PonderableComponent, - PlayableComponent>(); + auto& animatable = game_.getEntityManager(). + getComponent(player); - for (id_type player : players) - { - auto& animatable = game_.getEntityManager(). - getComponent(player); - - auto& ponderable = game_.getEntityManager(). - getComponent(player); - - auto& controlling = game_.getSystemManager().getSystem(); - controlling.freeze(player); - - animatable.setFrozen(true); - animatable.setFlickering(true); - ponderable.setFrozen(true); - ponderable.setCollidable(false); - - auto& scheduling = game_.getSystemManager().getSystem(); - - scheduling.schedule(player, 0.75, [&] (id_type player) { - auto& playable = game_.getEntityManager(). - getComponent(player); - - changeMap( - playable.checkpointMapId, - playable.checkpointX, - playable.checkpointY, - [&, player] () { - animatable.setFrozen(false); - animatable.setFlickering(false); - ponderable.setFrozen(false); - ponderable.setCollidable(true); - - // Reset the walk state, and then potentially let the - // ControllingSystem set it again. - auto& orienting = game_.getSystemManager(). - getSystem(); - orienting.stopWalking(player); - - controlling.unfreeze(player); - }); - }); - } + auto& ponderable = game_.getEntityManager(). + getComponent(player); + + auto& controlling = game_.getSystemManager().getSystem(); + controlling.freeze(player); + + animatable.frozen = true; + animatable.flickering = true; + ponderable.frozen = true; + ponderable.collidable = false; + + auto& scheduling = game_.getSystemManager().getSystem(); + + scheduling.schedule(player, 0.75, [&] (id_type player) { + auto& playable = game_.getEntityManager(). + getComponent(player); + + changeMap( + player, + playable.checkpointMapId, + playable.checkpointX, + playable.checkpointY); + + animatable.frozen = false; + animatable.flickering = false; + ponderable.frozen = false; + ponderable.collidable = true; + + // Reset the walk state, and then potentially let the + // ControllingSystem set it again. + auto& orienting = game_.getSystemManager().getSystem(); + orienting.stopWalking(player); + + controlling.unfreeze(player); + }); } diff --git a/src/systems/playing.h b/src/systems/playing.h index ff16808..9ba403b 100644 --- a/src/systems/playing.h +++ b/src/systems/playing.h @@ -2,7 +2,6 @@ #define PLAYING_H_70A54F7D #include "system.h" -#include "components/playable.h" class PlayingSystem : public System { public: @@ -11,17 +10,15 @@ public: { } - void tick(double dt); - void initPlayer(); void changeMap( + id_type player, size_t mapId, double x, - double y, - PlayableComponent::MapChangeCallback callback = nullptr); + double y); - void die(); + void die(id_type player); }; diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 02d5cfc..4ae6176 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -5,149 +5,153 @@ #include "components/transformable.h" #include "components/orientable.h" #include "components/mappable.h" +#include "components/realizable.h" +#include "components/playable.h" #include "systems/orienting.h" #include "systems/playing.h" +#include "systems/realizing.h" #include "consts.h" #include "collision.h" void PonderingSystem::tick(double dt) { + auto& realizable = game_.getEntityManager(). + getComponent( + game_.getSystemManager().getSystem().getSingleton()); + + id_type mapEntity = realizable.activeMap; + + auto& mappable = game_.getEntityManager(). + getComponent(mapEntity); + auto entities = game_.getEntityManager().getEntitiesWithComponents< PonderableComponent, TransformableComponent>(); - auto maps = game_.getEntityManager().getEntitiesWithComponents< - MappableComponent>(); - for (id_type entity : entities) { - auto& transformable = game_.getEntityManager(). - getComponent(entity); - auto& ponderable = game_.getEntityManager(). getComponent(entity); - if (ponderable.isFrozen()) + if (!ponderable.active || ponderable.frozen) { continue; } - // Accelerate - ponderable.setVelocityX( - ponderable.getVelocityX() + ponderable.getAccelX() * dt); + auto& transformable = game_.getEntityManager(). + getComponent(entity); - ponderable.setVelocityY( - ponderable.getVelocityY() + ponderable.getAccelY() * dt); + // Accelerate + ponderable.velX += ponderable.accelX * dt; + ponderable.velY += ponderable.accelY * dt; - if ((ponderable.getType() == PonderableComponent::Type::freefalling) - && (ponderable.getVelocityY() > TERMINAL_VELOCITY)) + if ((ponderable.type == PonderableComponent::Type::freefalling) + && (ponderable.velY > TERMINAL_VELOCITY)) { - ponderable.setVelocityY(TERMINAL_VELOCITY); + ponderable.velY = TERMINAL_VELOCITY; } - const double oldX = transformable.getX(); - const double oldY = transformable.getY(); - const double oldRight = oldX + transformable.getW(); - const double oldBottom = oldY + transformable.getH(); + const double oldX = transformable.x; + const double oldY = transformable.y; + const double oldRight = oldX + transformable.w; + const double oldBottom = oldY + transformable.h; - double newX = oldX + ponderable.getVelocityX() * dt; - double newY = oldY + ponderable.getVelocityY() * dt; + double newX = oldX + ponderable.velX * dt; + double newY = oldY + ponderable.velY * dt; - bool oldGrounded = ponderable.isGrounded(); - ponderable.setGrounded(false); + bool oldGrounded = ponderable.grounded; + ponderable.grounded = false; std::priority_queue collisions; // Find collisions - for (id_type mapEntity : maps) + if (newX < oldX) { - auto& mappable = game_.getEntityManager(). - getComponent(mapEntity); - - if (newX < oldX) + for (auto it = mappable.leftBoundaries.lower_bound(oldX); + (it != std::end(mappable.leftBoundaries)) && (it->first >= newX); + it++) { - for (auto it = mappable.getLeftBoundaries().lower_bound(oldX); - (it != std::end(mappable.getLeftBoundaries())) && (it->first >= newX); - it++) + if ((oldBottom > it->second.lower) + && (oldY < it->second.upper)) { - if ((oldBottom > it->second.getLower()) - && (oldY < it->second.getUpper())) - { - // We have a collision! - collisions.emplace( - mapEntity, - Direction::left, - it->second.getType(), - it->first, - it->second.getLower(), - it->second.getUpper()); - } + // We have a collision! + collisions.emplace( + mapEntity, + Direction::left, + it->second.type, + it->first, + it->second.lower, + it->second.upper); } - } else if (newX > oldX) + } + } else if (newX > oldX) + { + for (auto it = mappable.rightBoundaries.lower_bound(oldRight); + (it != std::end(mappable.rightBoundaries)) + && (it->first <= (newX + transformable.w)); + it++) { - for (auto it = mappable.getRightBoundaries().lower_bound(oldRight); - (it != std::end(mappable.getRightBoundaries())) - && (it->first <= (newX + transformable.getW())); - it++) + if ((oldBottom > it->second.lower) + && (oldY < it->second.upper)) { - if ((oldBottom > it->second.getLower()) - && (oldY < it->second.getUpper())) - { - // We have a collision! - collisions.emplace( - mapEntity, - Direction::right, - it->second.getType(), - it->first, - it->second.getLower(), - it->second.getUpper()); - } + // We have a collision! + collisions.emplace( + mapEntity, + Direction::right, + it->second.type, + it->first, + it->second.lower, + it->second.upper); } } + } - if (newY < oldY) + if (newY < oldY) + { + for (auto it = mappable.upBoundaries.lower_bound(oldY); + (it != std::end(mappable.upBoundaries)) && (it->first >= newY); + it++) { - for (auto it = mappable.getUpBoundaries().lower_bound(oldY); - (it != std::end(mappable.getUpBoundaries())) && (it->first >= newY); - it++) + if ((oldRight > it->second.lower) + && (oldX < it->second.upper)) { - if ((oldRight > it->second.getLower()) - && (oldX < it->second.getUpper())) - { - // We have a collision! - collisions.emplace( - mapEntity, - Direction::up, - it->second.getType(), - it->first, - it->second.getLower(), - it->second.getUpper()); - } + // We have a collision! + collisions.emplace( + mapEntity, + Direction::up, + it->second.type, + it->first, + it->second.lower, + it->second.upper); } - } else if (newY > oldY) + } + } else if (newY > oldY) + { + for (auto it = mappable.downBoundaries.lower_bound(oldBottom); + (it != std::end(mappable.downBoundaries)) + && (it->first <= (newY + transformable.h)); + it++) { - for (auto it = mappable.getDownBoundaries().lower_bound(oldBottom); - (it != std::end(mappable.getDownBoundaries())) - && (it->first <= (newY + transformable.getH())); - it++) + if ((oldRight > it->second.lower) + && (oldX < it->second.upper)) { - if ((oldRight > it->second.getLower()) - && (oldX < it->second.getUpper())) - { - // We have a collision! - collisions.emplace( - mapEntity, - Direction::down, - it->second.getType(), - it->first, - it->second.getLower(), - it->second.getUpper()); - } + // We have a collision! + collisions.emplace( + mapEntity, + Direction::down, + it->second.type, + it->first, + it->second.lower, + it->second.upper); } } } // Process collisions in order of priority + bool adjacentlyWarping = false; + Direction adjWarpDir; + size_t adjWarpMapId; + while (!collisions.empty()) { Collision collision = collisions.top(); @@ -157,8 +161,8 @@ void PonderingSystem::tick(double dt) if (!collision.isColliding( newX, newY, - transformable.getW(), - transformable.getH())) + transformable.w, + transformable.h)) { continue; } @@ -201,33 +205,33 @@ void PonderingSystem::tick(double dt) { auto& mappable = game_.getEntityManager(). getComponent(collision.getCollider()); - const Map& map = game_.getWorld().getMap(mappable.getMapId()); - auto& adj = [&] () -> const Map::Adjacent& { + + auto& adj = [&] () -> const MappableComponent::Adjacent& { switch (collision.getDirection()) { - case Direction::left: return map.getLeftAdjacent(); - case Direction::right: return map.getRightAdjacent(); - case Direction::up: return map.getUpAdjacent(); - case Direction::down: return map.getDownAdjacent(); + case Direction::left: return mappable.leftAdjacent; + case Direction::right: return mappable.rightAdjacent; + case Direction::up: return mappable.upAdjacent; + case Direction::down: return mappable.downAdjacent; } }(); - switch (adj.getType()) + switch (adj.type) { - case Map::Adjacent::Type::wall: + case MappableComponent::Adjacent::Type::wall: { touchedWall = true; break; } - case Map::Adjacent::Type::wrap: + case MappableComponent::Adjacent::Type::wrap: { switch (collision.getDirection()) { case Direction::left: { - newX = GAME_WIDTH + WALL_GAP - transformable.getW(); + newX = GAME_WIDTH + WALL_GAP - transformable.w; break; } @@ -241,8 +245,7 @@ void PonderingSystem::tick(double dt) case Direction::up: { - newY = MAP_HEIGHT * TILE_HEIGHT + WALL_GAP - - transformable.getH(); + newY = MAP_HEIGHT * TILE_HEIGHT + WALL_GAP - transformable.h; break; } @@ -256,46 +259,22 @@ void PonderingSystem::tick(double dt) } } - case Map::Adjacent::Type::warp: + case MappableComponent::Adjacent::Type::warp: { - double warpX = newX; - double warpY = newY; - - switch (collision.getDirection()) + if (game_.getEntityManager(). + hasComponent(entity)) { - case Direction::left: - { - warpX = GAME_WIDTH + WALL_GAP - transformable.getW(); - - break; - } - - case Direction::right: - { - warpX = -WALL_GAP; - - break; - } - - case Direction::up: - { - warpY = MAP_HEIGHT * TILE_HEIGHT - transformable.getH(); - - break; - } - - case Direction::down: - { - warpY = -WALL_GAP; - - break; - } + adjacentlyWarping = true; + adjWarpDir = collision.getDirection(); + adjWarpMapId = adj.mapId; } - game_.getSystemManager().getSystem(). - changeMap(adj.getMapId(), warpX, warpY); + break; + } - stopProcessing = true; + case MappableComponent::Adjacent::Type::reverse: + { + // TODO: not yet implemented. break; } @@ -306,7 +285,13 @@ void PonderingSystem::tick(double dt) case Collision::Type::danger: { - game_.getSystemManager().getSystem().die(); + if (game_.getEntityManager(). + hasComponent(entity)) + { + game_.getSystemManager().getSystem().die(entity); + + adjacentlyWarping = false; + } stopProcessing = true; @@ -333,15 +318,15 @@ void PonderingSystem::tick(double dt) case Direction::left: { newX = collision.getAxis(); - ponderable.setVelocityX(0.0); + ponderable.velX = 0.0; break; } case Direction::right: { - newX = collision.getAxis() - transformable.getW(); - ponderable.setVelocityX(0.0); + newX = collision.getAxis() - transformable.w; + ponderable.velX = 0.0; break; } @@ -349,16 +334,16 @@ void PonderingSystem::tick(double dt) case Direction::up: { newY = collision.getAxis(); - ponderable.setVelocityY(0.0); + ponderable.velY = 0.0; break; } case Direction::down: { - newY = collision.getAxis() - transformable.getH(); - ponderable.setVelocityY(0.0); - ponderable.setGrounded(true); + newY = collision.getAxis() - transformable.h; + ponderable.velY = 0.0; + ponderable.grounded = true; break; } @@ -367,8 +352,8 @@ void PonderingSystem::tick(double dt) } // Move - transformable.setX(newX); - transformable.setY(newY); + transformable.x = newX; + transformable.y = newY; // Perform cleanup for orientable entites if (game_.getEntityManager().hasComponent(entity)) @@ -377,9 +362,9 @@ void PonderingSystem::tick(double dt) getComponent(entity); // Handle changes in groundedness - if (ponderable.isGrounded() != oldGrounded) + if (ponderable.grounded != oldGrounded) { - if (ponderable.isGrounded()) + if (ponderable.grounded) { game_.getSystemManager().getSystem().land(entity); } else { @@ -394,6 +379,51 @@ void PonderingSystem::tick(double dt) orientable.setDropState(OrientableComponent::DropState::none); } } + + // Move to an adjacent map, if necessary + if (adjacentlyWarping) + { + double warpX = newX; + double warpY = newY; + + switch (adjWarpDir) + { + case Direction::left: + { + warpX = GAME_WIDTH + WALL_GAP - transformable.w; + + break; + } + + case Direction::right: + { + warpX = -WALL_GAP; + + break; + } + + case Direction::up: + { + warpY = MAP_HEIGHT * TILE_HEIGHT - transformable.h; + + break; + } + + case Direction::down: + { + warpY = -WALL_GAP; + + break; + } + } + + game_.getSystemManager().getSystem(). + changeMap( + entity, + adjWarpMapId, + warpX, + warpY); + } } } @@ -406,6 +436,20 @@ void PonderingSystem::initializeBody( if (type == PonderableComponent::Type::freefalling) { - ponderable.setAccelY(NORMAL_GRAVITY); + ponderable.accelY = NORMAL_GRAVITY; } } + +void PonderingSystem::initPrototype(id_type prototype) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(prototype); + + ponderable.velX = 0.0; + ponderable.velY = 0.0; + ponderable.accelX = 0.0; + ponderable.accelY = 0.0; + ponderable.grounded = false; + ponderable.frozen = false; + ponderable.collidable = true; +} diff --git a/src/systems/pondering.h b/src/systems/pondering.h index d70525b..58e6496 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -16,6 +16,8 @@ public: void initializeBody(id_type entity, PonderableComponent::Type type); + void initPrototype(id_type prototype); + }; #endif /* end of include guard: PONDERING_H_F2530E0E */ diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp new file mode 100644 index 0000000..09c38f3 --- /dev/null +++ b/src/systems/realizing.cpp @@ -0,0 +1,321 @@ +#include "realizing.h" +#include +#include +#include +#include "game.h" +#include "consts.h" +#include "components/realizable.h" +#include "components/mappable.h" +#include "components/animatable.h" +#include "components/playable.h" +#include "components/ponderable.h" +#include "components/transformable.h" +#include "systems/mapping.h" +#include "systems/animating.h" +#include "systems/pondering.h" + +inline xmlChar* getProp(xmlNodePtr node, const char* attr) +{ + xmlChar* key = xmlGetProp(node, reinterpret_cast(attr)); + if (key == nullptr) + { + throw std::invalid_argument("Error parsing world file"); + } + + return key; +} + +// TODO: neither the XML doc nor any of the emplaced entities are properly +// destroyed if this method throws an exception. +EntityManager::id_type RealizingSystem::initSingleton(std::string filename) +{ + id_type world = game_.getEntityManager().emplaceEntity(); + + auto& realizable = game_.getEntityManager(). + emplaceComponent(world); + + auto& mapping = game_.getSystemManager().getSystem(); + + xmlDocPtr doc = xmlParseFile(filename.c_str()); + if (doc == nullptr) + { + throw std::invalid_argument("Cannot find world file"); + } + + xmlNodePtr top = xmlDocGetRootElement(doc); + if (top == nullptr) + { + throw std::invalid_argument("Error parsing world file"); + } + + if (xmlStrcmp(top->name, reinterpret_cast("world"))) + { + throw std::invalid_argument("Error parsing world file"); + } + + xmlChar* key = nullptr; + + key = getProp(top, "startx"); + realizable.startingX = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(top, "starty"); + realizable.startingY = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(top, "startmap"); + realizable.startingMapId = atoi(reinterpret_cast(key)); + xmlFree(key); + + for (xmlNodePtr node = top->xmlChildrenNode; + node != nullptr; + node = node->next) + { + if (!xmlStrcmp(node->name, reinterpret_cast("map"))) + { + id_type map = game_.getEntityManager().emplaceEntity(); + + auto& mappable = game_.getEntityManager(). + emplaceComponent(map, + Texture("res/tiles.png"), + Texture("res/font.bmp")); + + key = getProp(node, "id"); + mappable.mapId = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(node, "title"); + mappable.title = reinterpret_cast(key); + xmlFree(key); + + for (xmlNodePtr mapNode = node->xmlChildrenNode; + mapNode != nullptr; + mapNode = mapNode->next) + { + if (!xmlStrcmp( + mapNode->name, + reinterpret_cast("environment"))) + { + key = xmlNodeGetContent(mapNode); + if (key == nullptr) + { + throw std::invalid_argument("Error parsing world file"); + } + + mappable.tiles.clear(); + mappable.tiles.push_back(atoi(strtok( + reinterpret_cast(key), + ",\n"))); + + for (size_t i = 1; i < (MAP_WIDTH * MAP_HEIGHT); i++) + { + mappable.tiles.push_back(atoi(strtok(nullptr, ",\n"))); + } + + xmlFree(key); + } else if (!xmlStrcmp( + mapNode->name, + reinterpret_cast("adjacent"))) + { + key = getProp(mapNode, "type"); + std::string adjTypeStr(reinterpret_cast(key)); + xmlFree(key); + + MappableComponent::Adjacent::Type adjType; + if (adjTypeStr == "wall") + { + adjType = MappableComponent::Adjacent::Type::wall; + } else if (adjTypeStr == "wrap") + { + adjType = MappableComponent::Adjacent::Type::wrap; + } else if (adjTypeStr == "warp") + { + adjType = MappableComponent::Adjacent::Type::warp; + } else if (adjTypeStr == "reverseWarp") + { + adjType = MappableComponent::Adjacent::Type::reverse; + } else { + throw std::logic_error("Invalid adjacency type"); + } + + key = getProp(mapNode, "map"); + size_t adjMapId = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(mapNode, "dir"); + std::string adjDir(reinterpret_cast(key)); + xmlFree(key); + + if (adjDir == "left") + { + mappable.leftAdjacent = {adjType, adjMapId}; + } else if (adjDir == "right") + { + mappable.rightAdjacent = {adjType, adjMapId}; + } else if (adjDir == "up") + { + mappable.upAdjacent = {adjType, adjMapId}; + } else if (adjDir == "down") + { + mappable.downAdjacent = {adjType, adjMapId}; + } else { + throw std::logic_error("Invalid adjacency direction"); + } + } + } + + mapping.generateBoundaries(map); + + realizable.maps.insert(map); + realizable.entityByMapId[mappable.mapId] = map; + } + } + + xmlFreeDoc(doc); + + loadMap(realizable.entityByMapId[realizable.startingMapId]); + + return world; +} + +EntityManager::id_type RealizingSystem::getSingleton() const +{ + std::set result = + game_.getEntityManager().getEntitiesWithComponents< + RealizableComponent>(); + + if (result.empty()) + { + throw std::logic_error("No realizable entity found"); + } else if (result.size() > 1) + { + throw std::logic_error("Multiple realizable entities found"); + } + + return *std::begin(result); +} + +void RealizingSystem::loadMap(id_type mapEntity) +{ + id_type world = getSingleton(); + + auto& realizable = game_.getEntityManager(). + getComponent(world); + + auto& animating = game_.getSystemManager().getSystem(); + auto& pondering = game_.getSystemManager().getSystem(); + + std::set players = + game_.getEntityManager().getEntitiesWithComponents< + PlayableComponent>(); + + if (realizable.hasActiveMap) + { + id_type oldMap = realizable.activeMap; + + auto& oldMappable = game_.getEntityManager(). + getComponent(oldMap); + + // Deactivate any map objects from the old map. + for (id_type prototype : oldMappable.objects) + { + leaveActiveMap(prototype); + } + + // Deactivate players that were on the old map. + for (id_type player : players) + { + auto& playable = game_.getEntityManager(). + getComponent(player); + + if (playable.mapId == oldMap) + { + leaveActiveMap(player); + } + } + } + + realizable.hasActiveMap = true; + realizable.activeMap = mapEntity; + + auto& mappable = game_.getEntityManager(). + getComponent(mapEntity); + + // Initialize the new map's objects. + for (id_type prototype : mappable.objects) + { + if (game_.getEntityManager(). + hasComponent(prototype)) + { + auto& transformable = game_.getEntityManager(). + getComponent(prototype); + + transformable.x = transformable.origX; + transformable.y = transformable.origY; + transformable.w = transformable.origW; + transformable.h = transformable.origH; + } + + if (game_.getEntityManager().hasComponent(prototype)) + { + animating.initPrototype(prototype); + } + + if (game_.getEntityManager().hasComponent(prototype)) + { + pondering.initPrototype(prototype); + } + + enterActiveMap(prototype); + } + + // Activate any players on the map. + for (id_type player : players) + { + auto& playable = game_.getEntityManager(). + getComponent(player); + + if (playable.mapId == mapEntity) + { + enterActiveMap(player); + } + } +} + +void RealizingSystem::enterActiveMap(id_type entity) +{ + if (game_.getEntityManager().hasComponent(entity)) + { + auto& animatable = game_.getEntityManager(). + getComponent(entity); + + animatable.active = true; + } + + if (game_.getEntityManager().hasComponent(entity)) + { + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + ponderable.active = true; + } +} + +void RealizingSystem::leaveActiveMap(id_type entity) +{ + if (game_.getEntityManager().hasComponent(entity)) + { + auto& animatable = game_.getEntityManager(). + getComponent(entity); + + animatable.active = false; + } + + if (game_.getEntityManager().hasComponent(entity)) + { + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + ponderable.active = false; + } +} diff --git a/src/systems/realizing.h b/src/systems/realizing.h new file mode 100644 index 0000000..c681892 --- /dev/null +++ b/src/systems/realizing.h @@ -0,0 +1,43 @@ +#ifndef REALIZING_H_6853748C +#define REALIZING_H_6853748C + +#include "system.h" + +class RealizingSystem : public System { +public: + + RealizingSystem(Game& game) : System(game) + { + } + + /** + * Creates the singleton realizable entity and initializes it with the + * provided world definition. + */ + id_type initSingleton(std::string filename); + + /** + * Helper method that returns the entity ID of the (assumed) singleton entity + * with a RealizableComponent. Throws an exception if the number of realizable + * entities is not exactly one. + */ + id_type getSingleton() const; + + /** + * Loads the given map. + */ + void loadMap(id_type mapEntity); + + /** + * Treats the given entity as part of the active map. + */ + void enterActiveMap(id_type entity); + + /** + * Stops treating the given entity as part of the active map. + */ + void leaveActiveMap(id_type entity); + +}; + +#endif /* end of include guard: REALIZING_H_6853748C */ -- cgit 1.4.1