From be9ccb73bc20b03f62c77f5d529602a10ef4eda9 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Sat, 12 Mar 2022 12:09:58 -0500 Subject: player has a sprite now thanks to world of solaria --- CMakeLists.txt | 1 + res/player.png | Bin 0 -> 6428 bytes res/player_anim.txt | 12 +++++++ src/animation.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/animation.h | 39 ++++++++++++++++++++++ src/direction.h | 22 +++++++++++++ src/game.h | 2 ++ src/main.cpp | 11 +++++++ src/renderer.cpp | 22 ++++++++++--- src/renderer.h | 1 + src/util.h | 35 ++++++++++++++++++++ 11 files changed, 234 insertions(+), 4 deletions(-) create mode 100755 res/player.png create mode 100644 res/player_anim.txt create mode 100644 src/animation.cpp create mode 100644 src/animation.h create mode 100644 src/direction.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e499ef2..360d4a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ add_executable(Ether src/main.cpp src/renderer.cpp src/muxer.cpp + src/animation.cpp vendor/fov.c ) diff --git a/res/player.png b/res/player.png new file mode 100755 index 0000000..9f6dbdf Binary files /dev/null and b/res/player.png differ diff --git a/res/player_anim.txt b/res/player_anim.txt new file mode 100644 index 0000000..e1037a0 --- /dev/null +++ b/res/player_anim.txt @@ -0,0 +1,12 @@ +16,16 cell size +8 frames per row +128 frames + +still[down]: 0,1,2,3 +still[left]: 8,9,10,11 +still[right]: 16,17,18,19 +still[up]: 24,25,26,27 +walk[down]: 32,33,34,35 +walk[left]: 40,41,42,43 +walk[right]: 48,49,50,51 +walk[up]: 56,57,58,59 \ No newline at end of file diff --git a/src/animation.cpp b/src/animation.cpp new file mode 100644 index 0000000..fbf7ccf --- /dev/null +++ b/src/animation.cpp @@ -0,0 +1,93 @@ +#include "animation.h" +#include +#include +#include +#include +#include +#include +#include "direction.h" +#include "util.h" + +Animation::Animation(std::string_view path) { + std::ifstream datafile(path.data()); + if (!datafile.is_open()) { + throw std::invalid_argument(std::string("Could not find sprite datafile: ") + path.data()); + } + + std::string animLine; + char ch; + int cellWidth; + int cellHeight; + datafile >> cellWidth; + datafile >> ch; //, + datafile >> cellHeight; + std::getline(datafile, animLine); // cell size + + int framesPerRow; + datafile >> framesPerRow; + std::getline(datafile, animLine); // frames per row + + int numFrames; + datafile >> numFrames; + std::getline(datafile, animLine); // frames + std::getline(datafile, animLine); // blank + + for (int i=0; i anim; + auto framestrs = splitStr>(m[3], ","); + for (const std::string& f : framestrs) { + anim.push_back(std::stoi(f)); + } + + int animId = animations_.size(); + animations_.push_back(std::move(anim)); + + Direction dir = directionFromString(std::string(m[2])); + nameDirToAnim_[animName][dir] = animId; + } + + updateAnim(); +} + +void Animation::setDirection(Direction dir) { + dir_ = dir; + updateAnim(); +} + +void Animation::setAnimation(std::string_view anim) { + animationName_ = anim; + updateAnim(); +} + +void Animation::update(int dt) { + animTimer_.accumulate(dt); + + while (animTimer_.step()) { + animationFrame_++; + + if (animationFrame_ >= animations_.at(animationId_).size()) { + animationFrame_ = 0; + } + } +} + +void Animation::updateAnim() { + if (nameDirToAnim_.at(animationName_).at(dir_) != animationId_) { + animationId_ = nameDirToAnim_.at(animationName_).at(dir_); + animationFrame_ = 0; + } +} diff --git a/src/animation.h b/src/animation.h new file mode 100644 index 0000000..0108c12 --- /dev/null +++ b/src/animation.h @@ -0,0 +1,39 @@ +#ifndef ANIMATION_H_332518EB +#define ANIMATION_H_332518EB + +#include +#include +#include +#include +#include +#include "direction.h" +#include "timer.h" + +class Animation { +public: + explicit Animation(std::string_view path); + + void setDirection(Direction dir); + void setAnimation(std::string_view anim); + + const SDL_Rect& getRenderRect() const { + return frames_.at(animations_.at(animationId_).at(animationFrame_)); + } + + void update(int dt); + +private: + + void updateAnim(); + + std::vector frames_; + std::vector> animations_; + std::map> nameDirToAnim_; + Direction dir_ = Direction::down; + std::string animationName_ = "still"; + int animationId_ = 0; + int animationFrame_ = 0; + Timer animTimer_ = {1000/5}; +}; + +#endif /* end of include guard: ANIMATION_H_332518EB */ diff --git a/src/direction.h b/src/direction.h new file mode 100644 index 0000000..0fe3e5a --- /dev/null +++ b/src/direction.h @@ -0,0 +1,22 @@ +#ifndef DIRECTION_H_42BDAFB9 +#define DIRECTION_H_42BDAFB9 + +#include +#include + +enum class Direction { + up, + down, + left, + right +}; + +inline Direction directionFromString(std::string_view str) { + if (str == "up") return Direction::up; + if (str == "right") return Direction::right; + if (str == "down") return Direction::down; + if (str == "left") return Direction::left; + throw std::invalid_argument("Invalid direction: " + std::string(str)); +} + +#endif /* end of include guard: DIRECTION_H_42BDAFB9 */ diff --git a/src/game.h b/src/game.h index c489afc..2fd0f05 100644 --- a/src/game.h +++ b/src/game.h @@ -8,6 +8,7 @@ #include "map.h" #include "muxer.h" #include "timer.h" +#include "animation.h" const int GAME_WIDTH = 640*2; const int GAME_HEIGHT = 480*2; @@ -102,6 +103,7 @@ public: int player_x = 0; int player_y = 0; bool renderPlayer = true; + Animation playerAnim {"../res/player_anim.txt"}; int maxZoom = INIT_ZOOM; diff --git a/src/main.cpp b/src/main.cpp index 1805357..5178110 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -207,6 +207,7 @@ bool processKeys(Game& game, const Input& keystate) { int px = game.player_x; int py = game.player_y; + Direction dir = Direction::up; if (keystate.up) { @@ -216,20 +217,26 @@ bool processKeys(Game& game, const Input& keystate) if (keystate.down) { py++; + dir = Direction::down; } if (keystate.left) { px--; + dir = Direction::left; } if (keystate.right) { px++; + dir = Direction::right; } if (!(game.player_x == px && game.player_y == py)) { + game.playerAnim.setAnimation("walk"); + game.playerAnim.setDirection(dir); + return movePlayer(game, px, py); } else { return false; @@ -614,6 +621,8 @@ int main(int, char**) { game.firstInput = true; game.lastInput = keystate; + } else if (losing == LoseState::None) { + game.playerAnim.setAnimation("still"); } dustAcc += frameTime; @@ -767,6 +776,8 @@ int main(int, char**) zoomAcc -= zoomDt; } + game.playerAnim.update(frameTime); + game.muxer.update(); renderer.render(game, true); } diff --git a/src/renderer.cpp b/src/renderer.cpp index 2dac07e..0aaa14a 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -110,6 +110,18 @@ Renderer::Renderer() SDL_SetRenderDrawColor(ren_.get(), 100, 100, 100, 255); SDL_RenderFillRect(ren_.get(), nullptr); + + { + surface_ptr pfs(IMG_Load("../res/player.png")); + if (!pfs) + { + throw img_error(); + } + + playerSheet_ = texture_ptr(SDL_CreateTextureFromSurface(ren_.get(), pfs.get())); + } + + SDL_SetTextureBlendMode(playerSheet_.get(), SDL_BLENDMODE_BLEND); } void Renderer::render( @@ -140,10 +152,7 @@ void Renderer::render( { bool draw = true; - if ((game.player_x == x && game.player_y == y) && game.renderPlayer) - { - SDL_SetRenderDrawColor(ren_.get(), 255, 255, 0, 255); - } else if (!game.map.at(x,y).lit) + if (!game.map.at(x,y).lit) { if (drawDark) { @@ -191,6 +200,11 @@ void Renderer::render( TILE_HEIGHT}; SDL_RenderFillRect(ren_.get(), &rect); + + if ((game.player_x == x && game.player_y == y) && game.renderPlayer) + { + SDL_RenderCopy(ren_.get(), playerSheet_.get(), &game.playerAnim.getRenderRect(), &rect); + } } } } diff --git a/src/renderer.h b/src/renderer.h index a34b231..0416c9e 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -129,6 +129,7 @@ private: texture_ptr playerFade_; texture_ptr lampFade_; texture_ptr dustFade_; + texture_ptr playerSheet_; }; #endif /* end of include guard: RENDERER_H_6A58EC30 */ diff --git a/src/util.h b/src/util.h index 150a6a5..1eb2303 100644 --- a/src/util.h +++ b/src/util.h @@ -1,6 +1,9 @@ #ifndef UTIL_H_E9110D4C #define UTIL_H_E9110D4C +#include +#include + template void erase_if(Container& items, const Predicate& predicate) { @@ -17,4 +20,36 @@ void erase_if(Container& items, const Predicate& predicate) } }; +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_E9110D4C */ -- cgit 1.4.1