From f3166702d7dd30312b5a401f52941aad43ac51c3 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sat, 30 Jan 2021 13:01:01 -0500 Subject: Added standing/walking animations --- res/lucas.png | Bin 1663 -> 5334 bytes res/lucas_anim.txt | 18 ++++++++++++ src/direction.h | 30 ++++++++++++++++++++ src/game.h | 14 ++++++++++ src/main.cpp | 18 ++++++++++-- src/party.cpp | 33 ++++++++++++++++++++++ src/party.h | 1 + src/renderer.cpp | 5 ++-- src/sprite.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++-- src/sprite.h | 24 +++++++++++++++- src/util.h | 39 ++++++++++++++++++++++++++ 11 files changed, 252 insertions(+), 9 deletions(-) create mode 100644 res/lucas_anim.txt create mode 100644 src/direction.h create mode 100644 src/util.h diff --git a/res/lucas.png b/res/lucas.png index 9c5a067..4ac7157 100644 Binary files a/res/lucas.png and b/res/lucas.png differ diff --git a/res/lucas_anim.txt b/res/lucas_anim.txt new file mode 100644 index 0000000..ff37580 --- /dev/null +++ b/res/lucas_anim.txt @@ -0,0 +1,18 @@ +../res/lucas.png +17,26 +still[down]: 1 +still[left]: 4 +still[down_left]: 7 +still[down_right]: 10 +still[up]: 13 +still[right]: 16 +still[up_left]: 19 +still[up_right]: 22 +walk[down]: 0,1,2 +walk[left]: 3,4,5 +walk[down_left]: 6,7,8 +walk[down_right]: 9,10,11 +walk[up]: 12,13,14 +walk[right]: 15,16,17 +walk[up_left]: 18,19,20 +walk[up_right]: 21,22,23 \ No newline at end of file diff --git a/src/direction.h b/src/direction.h new file mode 100644 index 0000000..0679a00 --- /dev/null +++ b/src/direction.h @@ -0,0 +1,30 @@ +#ifndef DIRECTION_H_AB66A90E +#define DIRECTION_H_AB66A90E + +#include +#include + +enum class Direction { + up, + up_right, + right, + down_right, + down, + down_left, + left, + up_left +}; + +inline Direction directionFromString(std::string_view str) { + if (str == "up") return Direction::up; + if (str == "up_right") return Direction::up_right; + if (str == "right") return Direction::right; + if (str == "down_right") return Direction::down_right; + if (str == "down") return Direction::down; + if (str == "down_left") return Direction::down_left; + if (str == "left") return Direction::left; + if (str == "up_left") return Direction::up_left; + throw std::invalid_argument("Invalid direction: " + std::string(str)); +} + +#endif /* end of include guard: DIRECTION_H_AB66A90E */ diff --git a/src/game.h b/src/game.h index abb70ce..a8626fa 100644 --- a/src/game.h +++ b/src/game.h @@ -40,6 +40,20 @@ public: void moveSprite(int id, vec2i newLoc); + void setSpriteWalking(int id, bool walking) { + sprites_[id].setWalking(walking); + } + + void setSpriteDirection(int id, Direction dir) { + sprites_[id].setDirection(dir); + } + + void tickSpriteAnim() { + for (Sprite& sprite : sprites_) { + sprite.tickAnim(); + } + } + private: std::vector sprites_; diff --git a/src/main.cpp b/src/main.cpp index 5a4373b..1d3d58e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,18 +7,23 @@ void loop(Renderer& renderer) { Game game; Input keystate; - int kumaSprite = game.addSprite(Sprite("../res/kumatora.png", renderer, 17, 31)); - int lucasSprite = game.addSprite(Sprite("../res/lucas.png", renderer, 17, 27)); + //int kumaSprite = game.addSprite(Sprite("../res/kumatora.png", renderer, 17, 31)); + int lucasSprite = game.addSprite(Sprite("../res/lucas_anim.txt", renderer)); + int lucasSprite2 = game.addSprite(Sprite("../res/lucas_anim.txt", renderer)); Party party; party.addMember(game, lucasSprite); - party.addMember(game, kumaSprite); + party.addMember(game, lucasSprite2); + //party.addMember(game, kumaSprite); renderer.render(game); size_t inputDt = 50; size_t inputAcc = 0; + size_t animDt = 1000/5;//30fps * 1000 t/s; + size_t animAcc = 0; + size_t lastTime = SDL_GetTicks(); for (;;) { @@ -46,6 +51,13 @@ void loop(Renderer& renderer) { party.move(game, keystate); } + animAcc += frameTime; + while (animAcc > animDt) { + animAcc -= animDt; + + game.tickSpriteAnim(); + } + renderer.render(game); } } diff --git a/src/party.cpp b/src/party.cpp index 1ff4bb4..19b9557 100644 --- a/src/party.cpp +++ b/src/party.cpp @@ -12,6 +12,7 @@ void Party::addMember(Game& game, int spriteId) { for (int i = 0; i < PARTY_FRAME_DELAY * index; i++) { newMember.nextPosition.push_back(sprite.loc()); + newMember.nextDirection.push_back(sprite.getDirection()); } } @@ -25,35 +26,67 @@ void Party::move(Game& game, const Input& keystate) { const Sprite& p1 = game.getSprite(members_[0].spriteId); vec2i pLoc = p1.loc(); + Direction dir = Direction::left; if (keystate.up) { pLoc.y() -= MOVEMENT_SPEED; + dir = Direction::up; } if (keystate.down) { pLoc.y() += MOVEMENT_SPEED; + dir = Direction::down; } if (keystate.left) { pLoc.x() -= MOVEMENT_SPEED; + + if (dir == Direction::up) { + dir = Direction::up_left; + } else if (dir == Direction::down) { + dir = Direction::down_left; + } else { + dir = Direction::left; + } } if (keystate.right) { pLoc.x() += MOVEMENT_SPEED; + + if (dir == Direction::up) { + dir = Direction::up_right; + } else if (dir == Direction::down) { + dir = Direction::down_right; + } else { + dir = Direction::right; + } } if (keystate.up || keystate.down || keystate.left || keystate.right) { + for (int i = 0; i < members_.size(); i++) { + game.setSpriteWalking(members_[i].spriteId, true); + } + game.moveSprite(members_[0].spriteId, pLoc); + game.setSpriteDirection(members_[0].spriteId, dir); for (int i = 1; i < members_.size(); i++) { const Sprite& pNext = game.getSprite(members_[i].spriteId); members_[i].nextPosition.push_back(pLoc); game.moveSprite(members_[i].spriteId, members_[i].nextPosition.front()); members_[i].nextPosition.pop_front(); + + members_[i].nextDirection.push_back(dir); + game.setSpriteDirection(members_[i].spriteId, members_[i].nextDirection.front()); + members_[i].nextDirection.pop_front(); + } + } else { + for (int i = 0; i < members_.size(); i++) { + game.setSpriteWalking(members_[i].spriteId, false); } } } \ No newline at end of file diff --git a/src/party.h b/src/party.h index 2a6ffc9..9b0aa89 100644 --- a/src/party.h +++ b/src/party.h @@ -17,6 +17,7 @@ private: struct PartyMember { int spriteId; std::deque nextPosition; + std::deque nextDirection; }; std::vector members_; diff --git a/src/renderer.cpp b/src/renderer.cpp index 8053de0..77f0a0c 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -49,8 +49,9 @@ void Renderer::render(Game& game) { SDL_RenderClear(ren_.get()); for (const Sprite& sprite : game.getSpritesByY() | game.spriteView()) { - SDL_Rect dest { sprite.loc().x(), sprite.loc().y(), sprite.size().w(), sprite.size().h() }; - SDL_RenderCopy(ren_.get(), textures_.at(sprite.getTextureId()).get(), nullptr, &dest); + SDL_Rect src { sprite.getFrame() * sprite.size().w(), 0, sprite.size().w(), sprite.size().h() }; + SDL_Rect dest { sprite.loc().x(), sprite.loc().y(), sprite.size().w() * 4, sprite.size().h() * 4 }; + SDL_RenderCopy(ren_.get(), textures_.at(sprite.getTextureId()).get(), &src, &dest); } SDL_SetRenderTarget(ren_.get(), nullptr); diff --git a/src/sprite.cpp b/src/sprite.cpp index c8c4656..cc196ae 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -1,7 +1,80 @@ #include "sprite.h" #include +#include +#include +#include +#include "util.h" -Sprite::Sprite(std::string_view filename, Renderer& renderer, int width, int height) { - textureId_ = renderer.loadImageFromFile(filename); - size_ = { width*4, height*4 }; +Sprite::Sprite(std::string_view filename, Renderer& renderer) { + std::ifstream datafile(filename.data()); + if (!datafile.is_open()) { + throw std::invalid_argument(std::string("Could not find sprite datafile: ") + std::string(filename)); + } + + char ch; + + std::string imagename; + datafile >> imagename; + textureId_ = renderer.loadImageFromFile(imagename); + + datafile >> size_.w(); + datafile >> ch; //, + datafile >> size_.h(); + + std::string animLine; + std::getline(datafile, animLine); // blank + while (std::getline(datafile, animLine)) { + std::regex re(R"(([a-z]+)\[([a-z_]+)\]: ([0-9,]+))"); + std::smatch m; + std::regex_match(animLine, m, re); + + std::vector frames; + auto framestrs = splitStr>(m[3], ","); + for (const std::string& f : framestrs) { + frames.push_back(std::stoi(f)); + } + + int animId = animations_.size(); + animations_.push_back(std::move(frames)); + + Direction dir = directionFromString(std::string(m[2])); + + if (m[1] == "still") { + stillAnims_[dir] = animId; + } else { + walkingAnims_[dir] = animId; + } + } + + updateAnimation(); +} + +void Sprite::setDirection(Direction dir) { + if (curDir_ != dir) { + curDir_ = dir; + updateAnimation(); + } +} + +void Sprite::setWalking(bool walking) { + if (isWalking_ != walking) { + isWalking_ = walking; + updateAnimation(); + } +} + +void Sprite::updateAnimation() { + if (isWalking_) { + curAnim_ = walkingAnims_[curDir_]; + } else { + curAnim_ = stillAnims_[curDir_]; + } + curFrame_ = 0; +} + +void Sprite::tickAnim() { + curFrame_++; + if (curFrame_ >= animations_[curAnim_].size()) { + curFrame_ = 0; + } } \ No newline at end of file diff --git a/src/sprite.h b/src/sprite.h index 1f917d9..5e8003b 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -1,14 +1,17 @@ #ifndef SPRITE_H_70503825 #define SPRITE_H_70503825 +#include #include +#include +#include "direction.h" #include "renderer.h" #include "vector.h" class Sprite { public: - Sprite(std::string_view filename, Renderer& renderer, int width, int height); + Sprite(std::string_view filename, Renderer& renderer); int getTextureId() const { return textureId_; @@ -22,11 +25,30 @@ public: vec2i& size() { return size_; } + int getFrame() const { return animations_[curAnim_][curFrame_]; } + + void setDirection(Direction dir); + + Direction getDirection() const { return curDir_; } + + void setWalking(bool walking); + + void tickAnim(); + private: + void updateAnimation(); + int textureId_; vec2i loc_ { 0, 0 }; vec2i size_; + Direction curDir_ = Direction::down; + bool isWalking_ = false; + int curAnim_ = 0; + int curFrame_ = 0; + std::vector> animations_; + std::map stillAnims_; + std::map walkingAnims_; }; #endif /* end of include guard: SPRITE_H_70503825 */ diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..8cdad3d --- /dev/null +++ b/src/util.h @@ -0,0 +1,39 @@ +#ifndef UTIL_H_4AC35025 +#define UTIL_H_4AC35025 + +#include +#include + +template +void splitStr( + std::string input, + std::string delimiter, + OutputIterator out) { + while (!input.empty()) { + int divider = input.find(delimiter); + if (divider == std::string::npos) { + *out = input; + out++; + + input = ""; + } else { + *out = input.substr(0, divider); + out++; + + input = input.substr(divider+delimiter.length()); + } + } +} + +template +Container splitStr( + std::string input, + std::string delimiter) { + Container result; + + splitStr(input, delimiter, std::back_inserter(result)); + + return result; +} + +#endif /* end of include guard: UTIL_H_4AC35025 */ -- cgit 1.4.1