From b06b259c54e09f1a4026191d6eec9684599bd370 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Tue, 23 Feb 2021 22:22:49 -0500 Subject: Started working on ladders TODO: * all the animations are weird. we will need to have an adjustable framerate bc the climbing animation does not look right at the current rate. (also remove the manual animation stuff ig) * does the medium stuff seem good and right? i am kinda not satisfied with it. * running onto a ladder causes the characters to bunch up bc the movement speed is slowed down but the trails are not doubled * no ladder running sound * shadows should vanish while on a ladder * uhh if you end a cutscene while on a ladder it resets the animation to "still" which is wrong. will this ever happen? idk * adding a sprite to your party while you are on a ladder?? --- res/maps/hallucination.tsx | 30 +++++++++++ res/sprites/boney_anim.txt | 4 +- res/sprites/duster_anim.txt | 4 +- res/sprites/kuma_anim.txt | 4 +- res/sprites/lucas_anim.txt | 4 +- src/animation_system.cpp | 20 +++++++- src/animation_system.h | 3 ++ src/character_system.cpp | 122 +++++++++++++++++++++++++++++++++----------- src/character_system.h | 3 ++ src/map.cpp | 22 ++++++++ src/map.h | 4 ++ src/sprite.h | 10 ++++ src/transform_system.cpp | 31 +++++++++-- src/transform_system.h | 2 + 14 files changed, 224 insertions(+), 39 deletions(-) diff --git a/res/maps/hallucination.tsx b/res/maps/hallucination.tsx index 82edada..e06dab1 100644 --- a/res/maps/hallucination.tsx +++ b/res/maps/hallucination.tsx @@ -1096,6 +1096,16 @@ + + + + + + + + + + @@ -1151,6 +1161,11 @@ + + + + + @@ -1281,6 +1296,16 @@ + + + + + + + + + + @@ -1311,6 +1336,11 @@ + + + + + diff --git a/res/sprites/boney_anim.txt b/res/sprites/boney_anim.txt index a8b036c..5dfb65f 100644 --- a/res/sprites/boney_anim.txt +++ b/res/sprites/boney_anim.txt @@ -47,4 +47,6 @@ barking[up_left]: 3,35,43,35,43,35,43 barking[up]: 4,36,44,36,44,36,44 barking[up_right]: 5,37,45,37,45,37,45 barking[right]: 6,38,46,38,46,38,46 -barking[down_right]: 7,39,47,39,47,39,47 \ No newline at end of file +barking[down_right]: 7,39,47,39,47,39,47 +climb.[up]: 240,241,242,243,244,245,246,247,248,249,250,251,252 +climb.[down]: 253,254,255,256,257,258,259,260,261,262,263,264,265 \ No newline at end of file diff --git a/res/sprites/duster_anim.txt b/res/sprites/duster_anim.txt index 57c470c..538ddd1 100644 --- a/res/sprites/duster_anim.txt +++ b/res/sprites/duster_anim.txt @@ -39,4 +39,6 @@ run[up_left]: 75,83,91,99,107 run[up]: 76,84,92,100,108 run[up_right]: 77,85,93,101,109 run[right]: 78,86,94,102,110 -run[down_right]: 79,87,95,103,111 \ No newline at end of file +run[down_right]: 79,87,95,103,111 +climb.[up]: 200,201,202,206,207,208,203,204,205,206,207,208 +climb.[down]: 200,201,202,206,207,208,203,204,205,206,207,208 \ No newline at end of file diff --git a/res/sprites/kuma_anim.txt b/res/sprites/kuma_anim.txt index 01ca970..a691b7d 100644 --- a/res/sprites/kuma_anim.txt +++ b/res/sprites/kuma_anim.txt @@ -47,4 +47,6 @@ talk[up_left]: 35,43 talk[up]: 36,44 talk[up_right]: 37,45 talk[right]: 38,46 -talk[down_right]: 39,47 \ No newline at end of file +talk[down_right]: 39,47 +climb.[up]: 257,258,259,263,264,265,260,261,262,263,264,265 +climb.[down]: 257,258,259,263,264,265,260,261,262,263,264,265 \ No newline at end of file diff --git a/res/sprites/lucas_anim.txt b/res/sprites/lucas_anim.txt index 1a8b62b..cd5ee9f 100644 --- a/res/sprites/lucas_anim.txt +++ b/res/sprites/lucas_anim.txt @@ -41,4 +41,6 @@ run[up_right]: 72,80,88,96 run[right]: 73,81,89,97 run[down_right]: 74,82,90,98 lightning_electrocute![down]: 116,117,118,116,117,118 -lightning_collapse![down]: 119,120,121,122 \ No newline at end of file +lightning_collapse![down]: 119,120,121,122 +climb.[up]: 123,124,125,128,127,127,129,130,131,128,127,126 +climb.[down]: 123,124,125,128,127,127,129,130,131,128,127,126 \ No newline at end of file diff --git a/src/animation_system.cpp b/src/animation_system.cpp index d23eae2..a280aee 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); @@ -78,6 +78,8 @@ void AnimationSystem::initSprite(int spriteId, std::string_view filename) { if (animName.back() == '!') { anim.looping = false; + } else if (animName.back() == '.') { + anim.manual = true; } int animId = sprite.animations.size(); @@ -96,7 +98,7 @@ void AnimationSystem::tick(double dt) { animTimer_.accumulate(dt); while (animTimer_.step()) { for (Sprite& sprite : game_.getSprites() | game_.spriteView()) { - if (sprite.isAnimated && !sprite.animFinished) { + if (sprite.isAnimated && !sprite.animFinished && !sprite.animPaused) { sprite.animationFrame++; if (sprite.animationFrame >= sprite.animations[sprite.animationId].frameIndices.size()) { @@ -112,6 +114,19 @@ void AnimationSystem::tick(double dt) { } } +void AnimationSystem::advanceAnimation(int spriteId) { + Sprite& sprite = game_.getSprite(spriteId); + Animation& animation = sprite.animations[sprite.animationId]; + + if (animation.manual) { + sprite.animationFrame++; + + if (sprite.animationFrame >= animation.frameIndices.size()) { + sprite.animationFrame = 0; + } + } +} + void AnimationSystem::setSpriteDirection(int spriteId, Direction dir) { Sprite& sprite = game_.getSprite(spriteId); if (sprite.dir != dir) { @@ -133,4 +148,5 @@ void AnimationSystem::updateAnimation(int spriteId) { sprite.animationId = sprite.nameDirToAnim[sprite.animationName][sprite.dir]; sprite.animationFrame = 0; sprite.animFinished = false; + sprite.animPaused = false; } diff --git a/src/animation_system.h b/src/animation_system.h index a116673..8352c19 100644 --- a/src/animation_system.h +++ b/src/animation_system.h @@ -17,6 +17,9 @@ public: void tick(double dt) override; + // Advances animation by a frame. Only to be used on manual animations. + void advanceAnimation(int spriteId); + void initSprite(int spriteId, std::string_view filename); void setSpriteDirection(int spriteId, Direction dir); diff --git a/src/character_system.cpp b/src/character_system.cpp index 99b6929..27c2280 100644 --- a/src/character_system.cpp +++ b/src/character_system.cpp @@ -34,7 +34,7 @@ void CharacterSystem::addSpriteToParty(int leaderId, int followerId) { for (int i=0; i(truePartyDelay) + targetPos; - follower.trail.push_front({.pos = tween, .dir = toFace}); + follower.trail.push_front({.pos = tween, .dir = toFace, .medium = CharacterMedium::Normal}); } leader.followers.push_back(followerId); @@ -70,14 +70,31 @@ void CharacterSystem::transplantParty(int leaderId, vec2i pos, Direction dir) { void CharacterSystem::moveInDirection(int spriteId, Direction dir) { Sprite& sprite = game_.getSprite(spriteId); + sprite.movementDir = dir; - game_.getSystem().setSpriteDirection(spriteId, dir); + switch (sprite.characterMedium) { + case CharacterMedium::Normal: { + game_.getSystem().setSpriteDirection(spriteId, dir); + break; + } + case CharacterMedium::Ladder: { + if (dirHasDir(dir, Direction::up)) { + game_.getSystem().setSpriteDirection(spriteId, Direction::up); + } else if (dirHasDir(dir, Direction::down)) { + game_.getSystem().setSpriteDirection(spriteId, Direction::down); + } + break; + } + } if (sprite.characterState == CharacterState::Still) { setPartyState(spriteId, CharacterState::Walking); } else if (sprite.characterState == CharacterState::Crouching) { for (int followerId : sprite.followers) { - game_.getSystem().setSpriteDirection(followerId, dir); + Sprite& follower = game_.getSprite(followerId); + if (follower.characterMedium == CharacterMedium::Normal) { + game_.getSystem().setSpriteDirection(followerId, dir); + } } } } @@ -107,14 +124,18 @@ void CharacterSystem::tick(double dt) { } int speed = sprite.movementSpeed; - if (sprite.characterState == CharacterState::Running) { + if (sprite.characterState == CharacterState::Running && sprite.characterMedium == CharacterMedium::Normal) { speed *= 2; } - pLoc += (unitVecInDirection(sprite.dir) * speed); + if (sprite.characterMedium == CharacterMedium::Ladder) { + //game_.getSystem().advanceAnimation(spriteId); + } + + pLoc += (unitVecInDirection(sprite.movementDir) * speed); // Check collision. - CollisionResult collision = game_.getSystem().checkCollision(spriteId, pLoc, sprite.dir); + CollisionResult collision = game_.getSystem().checkCollision(spriteId, pLoc, sprite.movementDir); bool blocked = collision.horiz.blocked || collision.vert.blocked; if (collision.horiz.blocked && !sprite.clipping) { @@ -146,6 +167,12 @@ void CharacterSystem::tick(double dt) { if (pLoc != sprite.loc) { game_.getSystem().moveSprite(spriteId, pLoc); + CharacterMedium newMedium = game_.getSystem().getMediumAtPosition(spriteId, pLoc); + if (newMedium != sprite.characterMedium) { + sprite.characterMedium = newMedium; + setAnimationFor(spriteId, sprite.characterState); + } + if (sprite.characterState == CharacterState::Running) { const Map& map = game_.getMap(); @@ -164,12 +191,20 @@ void CharacterSystem::tick(double dt) { for (int followerId : sprite.followers) { Sprite& pNext = game_.getSprite(followerId); + if (pNext.characterMedium == CharacterMedium::Ladder) { + //game_.getSystem().advanceAnimation(followerId); + } + const Movement& posdir = pNext.trail.front(); game_.getSystem().moveSprite(followerId, posdir.pos); game_.getSystem().setSpriteDirection(followerId, posdir.dir); + if (posdir.medium != pNext.characterMedium) { + pNext.characterMedium = posdir.medium; + setAnimationFor(followerId, sprite.characterState); + } pNext.trail.pop_front(); - pNext.trail.push_back({.pos = pLoc, .dir = sprite.dir}); + pNext.trail.push_back({.pos = pLoc, .dir = sprite.dir, .medium = sprite.characterMedium}); } } } @@ -180,6 +215,10 @@ void CharacterSystem::tick(double dt) { void CharacterSystem::beginCrouch(int spriteId) { Sprite& sprite = game_.getSprite(spriteId); + if (sprite.characterMedium == CharacterMedium::Ladder) { + return; + } + if (sprite.characterState == CharacterState::Running) { stopRunning(spriteId); } else { @@ -242,32 +281,12 @@ void CharacterSystem::stopRunning(int spriteId) { } void CharacterSystem::setPartyState(int spriteId, CharacterState state) { - std::string animName; - switch (state) { - case CharacterState::Still: { - animName = "still"; - break; - } - case CharacterState::Walking: { - animName = "walk"; - break; - } - case CharacterState::Crouching: { - animName = "crouch"; - break; - } - case CharacterState::Running: { - animName = "run"; - break; - } - } - Sprite& sprite = game_.getSprite(spriteId); sprite.characterState = state; - game_.getSystem().setSpriteAnimation(spriteId, animName); + setAnimationFor(spriteId, state); for (int followerId : sprite.followers) { - game_.getSystem().setSpriteAnimation(followerId, animName); + setAnimationFor(followerId, state); } } @@ -297,3 +316,48 @@ void CharacterSystem::destroySprite(int spriteId) { stopRunningSound(sprite); } } + +void CharacterSystem::setAnimationFor(int spriteId, CharacterState state) { + Sprite& sprite = game_.getSprite(spriteId); + std::string animName; + + switch (sprite.characterMedium) { + case CharacterMedium::Normal: { + std::string animName; + + switch (state) { + case CharacterState::Still: { + animName = "still"; + break; + } + case CharacterState::Walking: { + animName = "walk"; + break; + } + case CharacterState::Crouching: { + animName = "crouch"; + break; + } + case CharacterState::Running: { + animName = "run"; + break; + } + } + + game_.getSystem().setSpriteAnimation(spriteId, animName); + + break; + } + case CharacterMedium::Ladder: { + game_.getSystem().setSpriteAnimation(spriteId, "climb."); + + if (state == CharacterState::Still || state == CharacterState::Crouching) { + sprite.animPaused = true; + } else { + sprite.animPaused = false; + } + + break; + } + } +} diff --git a/src/character_system.h b/src/character_system.h index 79c1710..ef49d0e 100644 --- a/src/character_system.h +++ b/src/character_system.h @@ -47,6 +47,9 @@ private: void stopRunningSound(Sprite& sprite); + // state should be the party leader's state + void setAnimationFor(int spriteId, CharacterState state); + Game& game_; Timer inputTimer_ {33}; }; diff --git a/src/map.cpp b/src/map.cpp index 4781231..0425962 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -44,6 +44,10 @@ Map::Map(std::string_view name) : name_(name) { tile.blocked = true; } else if (property.getName() == "runSound") { tile.step = stepTypeFromString(property.getStringValue()); + } else if (property.getName() == "medium") { + if (property.getStringValue() == "ladder") { + tile.medium = CharacterMedium::Ladder; + } } } @@ -178,3 +182,21 @@ StepType Map::getStepType(int x, int y) const { return StepType::none; } + +CharacterMedium Map::getMedium(int x, int y) const { + CharacterMedium ret = CharacterMedium::Normal; + + if (x < 0 || y < 0 || x >= mapSize_.w() || y >= mapSize_.h()) { + return ret; + } + + int i = x + y * mapSize_.w(); + + for (const std::vector& layer : lowerLayers_) { + if (layer.at(i).medium > ret) { + ret = layer.at(i).medium; + } + } + + return ret; +} diff --git a/src/map.h b/src/map.h index 9467d75..1a88cc8 100644 --- a/src/map.h +++ b/src/map.h @@ -7,6 +7,7 @@ #include #include "vector.h" #include "step_type.h" +#include "sprite.h" struct Tile { unsigned int id = 0; @@ -14,6 +15,7 @@ struct Tile { bool flipVertical = false; bool blocked = false; StepType step = StepType::none; + CharacterMedium medium = CharacterMedium::Normal; }; struct Prototype { @@ -64,6 +66,8 @@ public: StepType getStepType(int x, int y) const; + CharacterMedium getMedium(int x, int y) const; + const std::vector& getPrototypes() const { return prototypes_; } const vec2i& getWarpPoint(const std::string& name) const { return warpPoints_.at(name); } diff --git a/src/sprite.h b/src/sprite.h index 3d2e9df..59d2caf 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -23,6 +23,7 @@ struct SpriteFrame { struct Animation { bool looping = true; + bool manual = false; std::vector frameIndices; }; @@ -33,9 +34,15 @@ enum class CharacterState { Running }; +enum class CharacterMedium { + Normal, + Ladder +}; + struct Movement { vec2i pos; Direction dir; + CharacterMedium medium; }; class Sprite { @@ -68,6 +75,7 @@ public: std::map> nameDirToAnim; bool animFinished = false; bool hasShadow = false; + bool animPaused = false; // Character bool orientable = false; @@ -75,6 +83,8 @@ public: std::vector followers; std::deque trail; CharacterState characterState = CharacterState::Still; + CharacterMedium characterMedium = CharacterMedium::Normal; + Direction movementDir = Direction::down; StepType stepType = StepType::none; int runningSfxChannel = -1; bool clipping = false; diff --git a/src/transform_system.cpp b/src/transform_system.cpp index ee392f1..4056f46 100644 --- a/src/transform_system.cpp +++ b/src/transform_system.cpp @@ -72,7 +72,7 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i newLoc, Dire enclosureZone = &map.getZone(sprite.enclosureZone); } - if (dirHasDir(sprite.dir, Direction::right)) { + if (dirHasDir(dir, Direction::right)) { if (newTileDR.x() > oldTileDR.x() && newColDR.x() < mapBounds.w()) { for (int y = newTileUL.y(); y <= newTileDR.y(); y++) { @@ -113,7 +113,7 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i newLoc, Dire } } - if (dirHasDir(sprite.dir, Direction::left)) { + if (dirHasDir(dir, Direction::left)) { if (newTileUL.x() < oldTileUL.x() && newColUL.x() >= 0) { for (int y = newTileUL.y(); y <= newTileDR.y(); y++) { @@ -154,7 +154,7 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i newLoc, Dire } } - if (dirHasDir(sprite.dir, Direction::down)) { + if (dirHasDir(dir, Direction::down)) { if (newTileDR.y() > oldTileDR.y() && newColDR.y() < mapBounds.h()) { for (int x = newTileUL.x(); x <= newTileDR.x(); x++) { @@ -195,7 +195,7 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i newLoc, Dire } } - if (dirHasDir(sprite.dir, Direction::up)) { + if (dirHasDir(dir, Direction::up)) { if (newTileUL.y() < oldTileUL.y() && newColUL.y() >= 0) { for (int x = newTileUL.x(); x <= newTileDR.x(); x++) { @@ -239,6 +239,29 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i newLoc, Dire return result; } +CharacterMedium TransformSystem::getMediumAtPosition(int spriteId, vec2i newLoc) { + Sprite& sprite = game_.getSprite(spriteId); + + const Map& map = game_.getMap(); + + vec2i newColUL = newLoc + sprite.collisionOffset; + vec2i newColDR = newColUL + sprite.collisionSize; + vec2i newTileUL = newColUL / map.getTileSize(); + vec2i newTileDR = newColDR / map.getTileSize(); + + CharacterMedium result = CharacterMedium::Normal; + for (int y=newTileUL.y(); y<=newTileDR.y(); y++) { + for (int x=newTileUL.x(); x<=newTileDR.x(); x++) { + CharacterMedium tileMedium = map.getMedium(x, y); + if (tileMedium > result) { + result = tileMedium; + } + } + } + + return result; +} + void TransformSystem::addCollidable(int spriteId) { Sprite& sprite = game_.getSprite(spriteId); diff --git a/src/transform_system.h b/src/transform_system.h index d894b30..a07447c 100644 --- a/src/transform_system.h +++ b/src/transform_system.h @@ -47,6 +47,8 @@ public: CollisionResult checkCollision(int spriteId, vec2i newLoc, Direction dir); + CharacterMedium getMediumAtPosition(int spriteId, vec2i newLoc); + void destroySprite(int spriteId) override; private: -- cgit 1.4.1