From 470b1d43fb6f8e17624ee90f87270de5bd6ff77e Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sat, 13 Feb 2021 20:50:21 -0500 Subject: Added lightning sprite to mailbox event Sprites can be destroyed now, which really just means that their index is removed from the list of active sprites. The actual memory is not freed until all sprites are deleted on map change. Sprite layers are introduced. All sprites by default are on layer 0 (Normal) which renders them in between the lower and upper map layers. There is also a layer 1 (Above) that renders above the upper map layer, and the sprite for the lightning strike uses this layer in order to not be hidden by the trees. Fixed a bug where waiting for the end of a non-looping animation would trip the flag immediately upon the final frame activating, instead of waiting the length of the last frame. --- src/animation_system.cpp | 13 ++++++------- src/camera_system.cpp | 6 ++++++ src/camera_system.h | 2 ++ src/character_system.cpp | 7 +++++++ src/character_system.h | 2 ++ src/consts.h | 2 ++ src/game.cpp | 12 +++++++++++- src/game.h | 7 +++++-- src/main.cpp | 2 +- src/renderer.cpp | 34 +++++++++++++++++++++------------- src/renderer.h | 4 ++++ src/script_system.cpp | 33 +++++++++++++++++++++++++++++++++ src/sprite.h | 8 ++++++++ src/system.h | 2 ++ src/transform_system.cpp | 22 +++++++++++++++++----- src/transform_system.h | 12 ++++++++---- 16 files changed, 135 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/animation_system.cpp b/src/animation_system.cpp index 3f3f22a..c43d0ca 100644 --- a/src/animation_system.cpp +++ b/src/animation_system.cpp @@ -65,7 +65,7 @@ void AnimationSystem::initSprite(int spriteId, std::string_view filename) { std::string animLine; std::getline(datafile, animLine); // blank while (std::getline(datafile, animLine)) { - std::regex re(R"(([a-z!]+)\[([a-z_]+)\]: ([0-9,]+))"); + std::regex re(R"(([a-z!_]+)\[([a-z_]+)\]: ([0-9,]+))"); std::smatch m; std::regex_match(animLine, m, re); @@ -96,14 +96,13 @@ void AnimationSystem::tick(double dt) { for (Sprite& sprite : game_.getSprites() | game_.spriteView()) { if (sprite.isAnimated && !sprite.animFinished) { sprite.animationFrame++; - if (sprite.animations[sprite.animationId].looping) { - if (sprite.animationFrame >= sprite.animations[sprite.animationId].frameIndices.size()) { + + if (sprite.animationFrame >= sprite.animations[sprite.animationId].frameIndices.size()) { + if (sprite.animations[sprite.animationId].looping) { sprite.animationFrame = 0; - } - } else { - if (sprite.animationFrame >= sprite.animations[sprite.animationId].frameIndices.size() - 1) { - sprite.animationFrame = sprite.animations[sprite.animationId].frameIndices.size() - 1; + } else { sprite.animFinished = true; + sprite.animationFrame = sprite.animations[sprite.animationId].frameIndices.size() - 1; } } } diff --git a/src/camera_system.cpp b/src/camera_system.cpp index a6e8fca..b7627b1 100644 --- a/src/camera_system.cpp +++ b/src/camera_system.cpp @@ -26,6 +26,12 @@ void CameraSystem::tick(double dt) { } } +void CameraSystem::destroySprite(int spriteId) { + if (followingSprite_ == spriteId) { + followingSprite_ = -1; + } +} + void CameraSystem::clearSpriteCache() { followingSprite_ = -1; } diff --git a/src/camera_system.h b/src/camera_system.h index 77d813f..37ff8b4 100644 --- a/src/camera_system.h +++ b/src/camera_system.h @@ -26,6 +26,8 @@ public: void tick(double dt) override; + void destroySprite(int spriteId) override; + void clearSpriteCache() override; private: diff --git a/src/character_system.cpp b/src/character_system.cpp index a0572b0..d0c416e 100644 --- a/src/character_system.cpp +++ b/src/character_system.cpp @@ -260,6 +260,13 @@ void CharacterSystem::halt(int spriteId) { } } +void CharacterSystem::destroySprite(int spriteId) { + Sprite& sprite = game_.getSprite(spriteId); + if (sprite.runningSfxChannel != -1) { + stopRunningSound(sprite); + } +} + void CharacterSystem::clearSpriteCache() { for (Sprite& sprite : game_.getSprites() | game_.spriteView()) { if (sprite.runningSfxChannel != -1) { diff --git a/src/character_system.h b/src/character_system.h index c6d4e6d..72a2585 100644 --- a/src/character_system.h +++ b/src/character_system.h @@ -35,6 +35,8 @@ public: void halt(int spriteId); + void destroySprite(int spriteId) override; + void clearSpriteCache() override; private: diff --git a/src/consts.h b/src/consts.h index 12b9e8f..38e0ef8 100644 --- a/src/consts.h +++ b/src/consts.h @@ -12,4 +12,6 @@ const int PARTY_FRAME_DELAY = 10;// / MOVEMENT_SPEED; const int MESSAGE_TEXT_WIDTH = 196; +const int NUM_SPRITE_LAYERS = 2; + #endif /* end of include guard: CONSTS_H_9561E49C */ diff --git a/src/game.cpp b/src/game.cpp index d1e5b8e..b7ca869 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -7,11 +7,21 @@ int Game::emplaceSprite(std::string alias) { int id = sprites_.size(); sprites_.emplace_back(); - spriteIds_.push_back(id); + sprites_.back().alias = alias; + spriteIds_.insert(id); spritesByAlias_[alias] = id; return id; } +void Game::destroySprite(int id) { + for (std::unique_ptr& system : systems_) { + system->destroySprite(id); + } + + spriteIds_.erase(id); + spritesByAlias_.erase(sprites_.at(id).alias); +} + void Game::clearSprites() { for (std::unique_ptr& system : systems_) { system->clearSpriteCache(); diff --git a/src/game.h b/src/game.h index 84114ca..c7926bf 100644 --- a/src/game.h +++ b/src/game.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "sprite.h" #include "map.h" #include "consts.h" @@ -45,6 +46,8 @@ public: int emplaceSprite(std::string alias); + void destroySprite(int id); + const Sprite& getSprite(int id) const { return sprites_.at(id); } @@ -53,7 +56,7 @@ public: return sprites_.at(id); } - const std::vector& getSprites() { + const std::set& getSprites() { return spriteIds_; } @@ -93,7 +96,7 @@ private: std::list> systems_; std::map systemByKey_; - std::vector spriteIds_; + std::set spriteIds_; std::vector sprites_; std::map spritesByAlias_; std::unique_ptr map_; diff --git a/src/main.cpp b/src/main.cpp index c9bfaf1..592b3be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,7 +22,7 @@ void loop(Renderer& renderer) { game.emplaceSystem(); game.emplaceSystem(); - game.loadMap("map1", "spawn", Direction::down); + game.loadMap("map2", "debugWarp_mailboxes", Direction::down); game.getSprite(game.getSpriteByAlias("lucas")).controllable = true; renderer.render(game); diff --git a/src/renderer.cpp b/src/renderer.cpp index a7169e9..0e5f8f1 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -94,6 +94,21 @@ texture_ptr Renderer::renderMapLayer(const Map& map, int layer) { return canvas; } +void Renderer::renderSprite(const Sprite& sprite) { + if (sprite.isAnimated) { + if (sprite.hasShadow) { + int shadowTexId = loadImageFromFile("../res/shadow.png"); + const SDL_Rect shadowDest { sprite.loc.x() - 8, sprite.loc.y() - 8, 16, 8 }; + SDL_RenderCopy(ren_.get(), textures_.at(shadowTexId).get(), nullptr, &shadowDest); + } + + const SpriteFrame& frame = sprite.frames.at(sprite.animations.at(sprite.animationId).frameIndices.at(sprite.animationFrame)); + const SDL_Rect& src = frame.srcRect; + SDL_Rect dest { sprite.loc.x() - frame.center.x(), sprite.loc.y() - frame.center.y(), frame.size.w(), frame.size.h() }; + SDL_RenderCopy(ren_.get(), textures_.at(loadImageFromFile(sprite.spritesheet)).get(), &src, &dest); + } +} + void Renderer::render(Game& game) { if (cachedMapName_ != game.getMap().getName()) { cachedMapName_ = game.getMap().getName(); @@ -122,23 +137,16 @@ void Renderer::render(Game& game) { SDL_RenderCopy(ren_.get(), renLay1_.get(), nullptr, nullptr); - int shadowTexId = loadImageFromFile("../res/shadow.png"); - for (const Sprite& sprite : game.getSystem().getSpritesByY() | game.spriteView()) { - if (sprite.isAnimated) { - if (sprite.hasShadow) { - const SDL_Rect shadowDest { sprite.loc.x() - 8, sprite.loc.y() - 8, 16, 8 }; - SDL_RenderCopy(ren_.get(), textures_.at(shadowTexId).get(), nullptr, &shadowDest); - } - - const SpriteFrame& frame = sprite.frames.at(sprite.animations.at(sprite.animationId).frameIndices.at(sprite.animationFrame)); - const SDL_Rect& src = frame.srcRect; - SDL_Rect dest { sprite.loc.x() - frame.center.x(), sprite.loc.y() - frame.center.y(), frame.size.w(), frame.size.h() }; - SDL_RenderCopy(ren_.get(), textures_.at(loadImageFromFile(sprite.spritesheet)).get(), &src, &dest); - } + for (const Sprite& sprite : game.getSystem().getSpritesByY(SpriteLayer::Normal) | game.spriteView()) { + renderSprite(sprite); } SDL_RenderCopy(ren_.get(), renLay0_.get(), nullptr, nullptr); + for (const Sprite& sprite : game.getSystem().getSpritesByY(SpriteLayer::Above) | game.spriteView()) { + renderSprite(sprite); + } + SDL_Rect cameraField { game.getSystem().getCameraPosition().x(), game.getSystem().getCameraPosition().y(), diff --git a/src/renderer.h b/src/renderer.h index 1684a0c..54dae1c 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -11,6 +11,7 @@ class Game; class Map; +class Sprite; class sdl_error : public std::logic_error { public: @@ -133,6 +134,9 @@ private: std::vector textures_; std::map filenameToTexId_; + // Sprite rendering + void renderSprite(const Sprite& sprite); + // Map rendering texture_ptr renderMapLayer(const Map& map, int layer); diff --git a/src/script_system.cpp b/src/script_system.cpp index 3f89290..08d66d4 100644 --- a/src/script_system.cpp +++ b/src/script_system.cpp @@ -4,6 +4,8 @@ #include "message_system.h" #include "animation_system.h" #include "character_system.h" +#include "transform_system.h" +#include "vector.h" ScriptSystem::ScriptSystem(Game& game) : game_(game) { engine_.open_libraries( @@ -11,8 +13,14 @@ ScriptSystem::ScriptSystem(Game& game) : game_(game) { sol::lib::coroutine, sol::lib::math); + engine_.new_usertype( + "vec2i", + "x", [] (const vec2i& v) { return v.x(); }, + "y", [] (const vec2i& v) { return v.y(); }); + engine_.new_usertype( "sprite", + "loc", &Sprite::loc, "dir", &Sprite::dir, "followers", &Sprite::followers, "characterState", &Sprite::characterState, @@ -29,6 +37,7 @@ ScriptSystem::ScriptSystem(Game& game) : game_(game) { engine_.new_usertype( "animation", + "initSprite", &AnimationSystem::initSprite, "setSpriteAnimation", &AnimationSystem::setSpriteAnimation, "setSpriteDirection", &AnimationSystem::setSpriteDirection); @@ -37,6 +46,12 @@ ScriptSystem::ScriptSystem(Game& game) : game_(game) { "startRunning", &CharacterSystem::startRunning, "halt", &CharacterSystem::halt); + engine_.new_usertype( + "transform", + "initSprite", [] (TransformSystem& transform, int spriteId, int x, int y, SpriteLayer layer) { + transform.initSprite(spriteId, vec2i{x, y}, layer); + }); + engine_.new_usertype( "mixer", "playSound", &Mixer::playSound, @@ -61,12 +76,30 @@ ScriptSystem::ScriptSystem(Game& game) : game_(game) { return game_.getSystem(); }); + engine_.set_function( + "transform", + [&] () -> TransformSystem& { + return game_.getSystem(); + }); + engine_.set_function( "mixer", [&] () -> Mixer& { return game_.getMixer(); }); + engine_.set_function( + "emplaceSprite", + [&] (std::string alias) -> int { + return game_.emplaceSprite(alias); + }); + + engine_.set_function( + "destroySprite", + [&] (int spriteId) { + game_.destroySprite(spriteId); + }); + engine_.set_function( "getSpriteByAlias", [&] (std::string alias) -> int { diff --git a/src/sprite.h b/src/sprite.h index fcf7e1d..84b161f 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -10,6 +10,11 @@ #include "vector.h" #include "step_type.h" +enum class SpriteLayer { + Normal, + Above +}; + struct SpriteFrame { SDL_Rect srcRect; vec2i center; @@ -36,8 +41,11 @@ struct Movement { class Sprite { public: + std::string alias; + // Transform vec2i loc { 0, 0 }; + SpriteLayer layer = SpriteLayer::Normal; bool collidable = false; bool solid = false; vec2i collisionOffset; diff --git a/src/system.h b/src/system.h index 93b903e..3e84537 100644 --- a/src/system.h +++ b/src/system.h @@ -16,6 +16,8 @@ public: virtual void tick(double dt) {} + virtual void destroySprite(int spriteId) {} + virtual void clearSpriteCache() {} }; diff --git a/src/transform_system.cpp b/src/transform_system.cpp index e5b0363..6e04d70 100644 --- a/src/transform_system.cpp +++ b/src/transform_system.cpp @@ -2,10 +2,11 @@ #include "game.h" #include "map.h" -void TransformSystem::initSprite(int spriteId, vec2i loc) { +void TransformSystem::initSprite(int spriteId, vec2i loc, SpriteLayer layer) { Sprite& sprite = game_.getSprite(spriteId); sprite.loc = loc; - spritesByY_.emplace(loc.y(), spriteId); + sprite.layer = layer; + spritesByY_[static_cast(layer)].emplace(loc.y(), spriteId); } void TransformSystem::setUpCollision(int spriteId, vec2i offset, vec2i size, bool solid) { @@ -26,11 +27,11 @@ void TransformSystem::moveSprite(int spriteId, vec2i newLoc) { bool changedY = (sprite.loc.y() != newLoc.y()); if (changedY) { - spritesByY_.erase(std::make_tuple(sprite.loc.y(), spriteId)); + spritesByY_[static_cast(sprite.layer)].erase(std::make_tuple(sprite.loc.y(), spriteId)); } sprite.loc = newLoc; if (changedY) { - spritesByY_.emplace(newLoc.y(), spriteId); + spritesByY_[static_cast(sprite.layer)].emplace(newLoc.y(), spriteId); } if (sprite.collidable) { addCollidable(spriteId); @@ -216,8 +217,19 @@ void TransformSystem::removeCollidable(int spriteId) { downCollidables_.erase({ colUL.y(), spriteId }); } +void TransformSystem::destroySprite(int spriteId) { + Sprite& sprite = game_.getSprite(spriteId); + spritesByY_[static_cast(sprite.layer)].erase(std::make_tuple(sprite.loc.y(), spriteId)); + + if (sprite.collidable) { + removeCollidable(spriteId); + } +} + void TransformSystem::clearSpriteCache() { - spritesByY_.clear(); + for (auto& layer : spritesByY_) { + layer.clear(); + } leftCollidables_.clear(); rightCollidables_.clear(); upCollidables_.clear(); diff --git a/src/transform_system.h b/src/transform_system.h index 46b6877..a21b93b 100644 --- a/src/transform_system.h +++ b/src/transform_system.h @@ -8,6 +8,8 @@ #include "direction.h" #include "system.h" #include "vector.h" +#include "sprite.h" +#include "consts.h" class Game; @@ -29,26 +31,28 @@ public: TransformSystem(Game& game) : game_(game) {} - void initSprite(int spriteId, vec2i loc); + void initSprite(int spriteId, vec2i loc, SpriteLayer layer = SpriteLayer::Normal); void setUpCollision(int spriteId, vec2i offset, vec2i size, bool solid); void moveSprite(int spriteId, vec2i newLoc); - auto getSpritesByY() const { - return spritesByY_ | ranges::views::transform([] (const std::tuple& val) { + auto getSpritesByY(SpriteLayer layer) const { + return spritesByY_[static_cast(layer)] | ranges::views::transform([] (const std::tuple& val) { return std::get<1>(val); }); } CollisionResult checkCollision(int spriteId, vec2i newLoc, Direction dir); + void destroySprite(int spriteId) override; + void clearSpriteCache() override; private: Game& game_; - std::set> spritesByY_; + std::set> spritesByY_[NUM_SPRITE_LAYERS]; struct Collidable { int lower; -- cgit 1.4.1