diff options
| author | Star Rauchenberger <fefferburbia@gmail.com> | 2022-03-12 12:09:58 -0500 |
|---|---|---|
| committer | Star Rauchenberger <fefferburbia@gmail.com> | 2022-03-12 12:09:58 -0500 |
| commit | be9ccb73bc20b03f62c77f5d529602a10ef4eda9 (patch) | |
| tree | 6f88a9b780a75e52b2f04b6f61167f4ef46590a7 | |
| parent | c1a88a064a0cddbc1df2e716ef2102d22bbf681b (diff) | |
| download | ether-be9ccb73bc20b03f62c77f5d529602a10ef4eda9.tar.gz ether-be9ccb73bc20b03f62c77f5d529602a10ef4eda9.tar.bz2 ether-be9ccb73bc20b03f62c77f5d529602a10ef4eda9.zip | |
player has a sprite now thanks to world of solaria
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rwxr-xr-x | res/player.png | bin | 0 -> 6428 bytes | |||
| -rw-r--r-- | res/player_anim.txt | 12 | ||||
| -rw-r--r-- | src/animation.cpp | 93 | ||||
| -rw-r--r-- | src/animation.h | 39 | ||||
| -rw-r--r-- | src/direction.h | 22 | ||||
| -rw-r--r-- | src/game.h | 2 | ||||
| -rw-r--r-- | src/main.cpp | 11 | ||||
| -rw-r--r-- | src/renderer.cpp | 22 | ||||
| -rw-r--r-- | src/renderer.h | 1 | ||||
| -rw-r--r-- | src/util.h | 35 |
11 files changed, 234 insertions, 4 deletions
| 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 | |||
| 32 | src/main.cpp | 32 | src/main.cpp |
| 33 | src/renderer.cpp | 33 | src/renderer.cpp |
| 34 | src/muxer.cpp | 34 | src/muxer.cpp |
| 35 | src/animation.cpp | ||
| 35 | vendor/fov.c | 36 | vendor/fov.c |
| 36 | ) | 37 | ) |
| 37 | 38 | ||
| diff --git a/res/player.png b/res/player.png new file mode 100755 index 0000000..9f6dbdf --- /dev/null +++ b/res/player.png | |||
| Binary files 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 @@ | |||
| 1 | 16,16 cell size | ||
| 2 | 8 frames per row | ||
| 3 | 128 frames | ||
| 4 | |||
| 5 | still[down]: 0,1,2,3 | ||
| 6 | still[left]: 8,9,10,11 | ||
| 7 | still[right]: 16,17,18,19 | ||
| 8 | still[up]: 24,25,26,27 | ||
| 9 | walk[down]: 32,33,34,35 | ||
| 10 | walk[left]: 40,41,42,43 | ||
| 11 | walk[right]: 48,49,50,51 | ||
| 12 | 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 @@ | |||
| 1 | #include "animation.h" | ||
| 2 | #include <string_view> | ||
| 3 | #include <fstream> | ||
| 4 | #include <stdexcept> | ||
| 5 | #include <string> | ||
| 6 | #include <regex> | ||
| 7 | #include <list> | ||
| 8 | #include "direction.h" | ||
| 9 | #include "util.h" | ||
| 10 | |||
| 11 | Animation::Animation(std::string_view path) { | ||
| 12 | std::ifstream datafile(path.data()); | ||
| 13 | if (!datafile.is_open()) { | ||
| 14 | throw std::invalid_argument(std::string("Could not find sprite datafile: ") + path.data()); | ||
| 15 | } | ||
| 16 | |||
| 17 | std::string animLine; | ||
| 18 | char ch; | ||
| 19 | int cellWidth; | ||
| 20 | int cellHeight; | ||
| 21 | datafile >> cellWidth; | ||
| 22 | datafile >> ch; //, | ||
| 23 | datafile >> cellHeight; | ||
| 24 | std::getline(datafile, animLine); // cell size | ||
| 25 | |||
| 26 | int framesPerRow; | ||
| 27 | datafile >> framesPerRow; | ||
| 28 | std::getline(datafile, animLine); // frames per row | ||
| 29 | |||
| 30 | int numFrames; | ||
| 31 | datafile >> numFrames; | ||
| 32 | std::getline(datafile, animLine); // frames | ||
| 33 | std::getline(datafile, animLine); // blank | ||
| 34 | |||
| 35 | for (int i=0; i<numFrames; i++) { | ||
| 36 | SDL_Rect srcRect; | ||
| 37 | srcRect.x = (i % framesPerRow) * cellWidth; | ||
| 38 | srcRect.y = (i / framesPerRow) * cellHeight; | ||
| 39 | srcRect.w = cellWidth; | ||
| 40 | srcRect.h = cellHeight; | ||
| 41 | frames_.push_back(srcRect); | ||
| 42 | } | ||
| 43 | |||
| 44 | while (std::getline(datafile, animLine)) { | ||
| 45 | std::regex re(R"(([a-z!._]+)\[([a-z_]+)\]: ([0-9,]+))"); | ||
| 46 | std::smatch m; | ||
| 47 | std::regex_match(animLine, m, re); | ||
| 48 | |||
| 49 | std::string animName = m[1]; | ||
| 50 | std::vector<int> anim; | ||
| 51 | auto framestrs = splitStr<std::list<std::string>>(m[3], ","); | ||
| 52 | for (const std::string& f : framestrs) { | ||
| 53 | anim.push_back(std::stoi(f)); | ||
| 54 | } | ||
| 55 | |||
| 56 | int animId = animations_.size(); | ||
| 57 | animations_.push_back(std::move(anim)); | ||
| 58 | |||
| 59 | Direction dir = directionFromString(std::string(m[2])); | ||
| 60 | nameDirToAnim_[animName][dir] = animId; | ||
| 61 | } | ||
| 62 | |||
| 63 | updateAnim(); | ||
| 64 | } | ||
| 65 | |||
| 66 | void Animation::setDirection(Direction dir) { | ||
| 67 | dir_ = dir; | ||
| 68 | updateAnim(); | ||
| 69 | } | ||
| 70 | |||
| 71 | void Animation::setAnimation(std::string_view anim) { | ||
| 72 | animationName_ = anim; | ||
| 73 | updateAnim(); | ||
| 74 | } | ||
| 75 | |||
| 76 | void Animation::update(int dt) { | ||
| 77 | animTimer_.accumulate(dt); | ||
| 78 | |||
| 79 | while (animTimer_.step()) { | ||
| 80 | animationFrame_++; | ||
| 81 | |||
| 82 | if (animationFrame_ >= animations_.at(animationId_).size()) { | ||
| 83 | animationFrame_ = 0; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | void Animation::updateAnim() { | ||
| 89 | if (nameDirToAnim_.at(animationName_).at(dir_) != animationId_) { | ||
| 90 | animationId_ = nameDirToAnim_.at(animationName_).at(dir_); | ||
| 91 | animationFrame_ = 0; | ||
| 92 | } | ||
| 93 | } | ||
| 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 @@ | |||
| 1 | #ifndef ANIMATION_H_332518EB | ||
| 2 | #define ANIMATION_H_332518EB | ||
| 3 | |||
| 4 | #include <string> | ||
| 5 | #include <map> | ||
| 6 | #include <vector> | ||
| 7 | #include <string_view> | ||
| 8 | #include <SDL.h> | ||
| 9 | #include "direction.h" | ||
| 10 | #include "timer.h" | ||
| 11 | |||
| 12 | class Animation { | ||
| 13 | public: | ||
| 14 | explicit Animation(std::string_view path); | ||
| 15 | |||
| 16 | void setDirection(Direction dir); | ||
| 17 | void setAnimation(std::string_view anim); | ||
| 18 | |||
| 19 | const SDL_Rect& getRenderRect() const { | ||
| 20 | return frames_.at(animations_.at(animationId_).at(animationFrame_)); | ||
| 21 | } | ||
| 22 | |||
| 23 | void update(int dt); | ||
| 24 | |||
| 25 | private: | ||
| 26 | |||
| 27 | void updateAnim(); | ||
| 28 | |||
| 29 | std::vector<SDL_Rect> frames_; | ||
| 30 | std::vector<std::vector<int>> animations_; | ||
| 31 | std::map<std::string, std::map<Direction, int>> nameDirToAnim_; | ||
| 32 | Direction dir_ = Direction::down; | ||
| 33 | std::string animationName_ = "still"; | ||
| 34 | int animationId_ = 0; | ||
| 35 | int animationFrame_ = 0; | ||
| 36 | Timer animTimer_ = {1000/5}; | ||
| 37 | }; | ||
| 38 | |||
| 39 | #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 @@ | |||
| 1 | #ifndef DIRECTION_H_42BDAFB9 | ||
| 2 | #define DIRECTION_H_42BDAFB9 | ||
| 3 | |||
| 4 | #include <string_view> | ||
| 5 | #include <stdexcept> | ||
| 6 | |||
| 7 | enum class Direction { | ||
| 8 | up, | ||
| 9 | down, | ||
| 10 | left, | ||
| 11 | right | ||
| 12 | }; | ||
| 13 | |||
| 14 | inline Direction directionFromString(std::string_view str) { | ||
| 15 | if (str == "up") return Direction::up; | ||
| 16 | if (str == "right") return Direction::right; | ||
| 17 | if (str == "down") return Direction::down; | ||
| 18 | if (str == "left") return Direction::left; | ||
| 19 | throw std::invalid_argument("Invalid direction: " + std::string(str)); | ||
| 20 | } | ||
| 21 | |||
| 22 | #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 @@ | |||
| 8 | #include "map.h" | 8 | #include "map.h" |
| 9 | #include "muxer.h" | 9 | #include "muxer.h" |
| 10 | #include "timer.h" | 10 | #include "timer.h" |
| 11 | #include "animation.h" | ||
| 11 | 12 | ||
| 12 | const int GAME_WIDTH = 640*2; | 13 | const int GAME_WIDTH = 640*2; |
| 13 | const int GAME_HEIGHT = 480*2; | 14 | const int GAME_HEIGHT = 480*2; |
| @@ -102,6 +103,7 @@ public: | |||
| 102 | int player_x = 0; | 103 | int player_x = 0; |
| 103 | int player_y = 0; | 104 | int player_y = 0; |
| 104 | bool renderPlayer = true; | 105 | bool renderPlayer = true; |
| 106 | Animation playerAnim {"../res/player_anim.txt"}; | ||
| 105 | 107 | ||
| 106 | int maxZoom = INIT_ZOOM; | 108 | int maxZoom = INIT_ZOOM; |
| 107 | 109 | ||
| 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) | |||
| 207 | { | 207 | { |
| 208 | int px = game.player_x; | 208 | int px = game.player_x; |
| 209 | int py = game.player_y; | 209 | int py = game.player_y; |
| 210 | Direction dir = Direction::up; | ||
| 210 | 211 | ||
| 211 | if (keystate.up) | 212 | if (keystate.up) |
| 212 | { | 213 | { |
| @@ -216,20 +217,26 @@ bool processKeys(Game& game, const Input& keystate) | |||
| 216 | if (keystate.down) | 217 | if (keystate.down) |
| 217 | { | 218 | { |
| 218 | py++; | 219 | py++; |
| 220 | dir = Direction::down; | ||
| 219 | } | 221 | } |
| 220 | 222 | ||
| 221 | if (keystate.left) | 223 | if (keystate.left) |
| 222 | { | 224 | { |
| 223 | px--; | 225 | px--; |
| 226 | dir = Direction::left; | ||
| 224 | } | 227 | } |
| 225 | 228 | ||
| 226 | if (keystate.right) | 229 | if (keystate.right) |
| 227 | { | 230 | { |
| 228 | px++; | 231 | px++; |
| 232 | dir = Direction::right; | ||
| 229 | } | 233 | } |
| 230 | 234 | ||
| 231 | if (!(game.player_x == px && game.player_y == py)) | 235 | if (!(game.player_x == px && game.player_y == py)) |
| 232 | { | 236 | { |
| 237 | game.playerAnim.setAnimation("walk"); | ||
| 238 | game.playerAnim.setDirection(dir); | ||
| 239 | |||
| 233 | return movePlayer(game, px, py); | 240 | return movePlayer(game, px, py); |
| 234 | } else { | 241 | } else { |
| 235 | return false; | 242 | return false; |
| @@ -614,6 +621,8 @@ int main(int, char**) | |||
| 614 | { | 621 | { |
| 615 | game.firstInput = true; | 622 | game.firstInput = true; |
| 616 | game.lastInput = keystate; | 623 | game.lastInput = keystate; |
| 624 | } else if (losing == LoseState::None) { | ||
| 625 | game.playerAnim.setAnimation("still"); | ||
| 617 | } | 626 | } |
| 618 | 627 | ||
| 619 | dustAcc += frameTime; | 628 | dustAcc += frameTime; |
| @@ -767,6 +776,8 @@ int main(int, char**) | |||
| 767 | zoomAcc -= zoomDt; | 776 | zoomAcc -= zoomDt; |
| 768 | } | 777 | } |
| 769 | 778 | ||
| 779 | game.playerAnim.update(frameTime); | ||
| 780 | |||
| 770 | game.muxer.update(); | 781 | game.muxer.update(); |
| 771 | renderer.render(game, true); | 782 | renderer.render(game, true); |
| 772 | } | 783 | } |
| 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() | |||
| 110 | 110 | ||
| 111 | SDL_SetRenderDrawColor(ren_.get(), 100, 100, 100, 255); | 111 | SDL_SetRenderDrawColor(ren_.get(), 100, 100, 100, 255); |
| 112 | SDL_RenderFillRect(ren_.get(), nullptr); | 112 | SDL_RenderFillRect(ren_.get(), nullptr); |
| 113 | |||
| 114 | { | ||
| 115 | surface_ptr pfs(IMG_Load("../res/player.png")); | ||
| 116 | if (!pfs) | ||
| 117 | { | ||
| 118 | throw img_error(); | ||
| 119 | } | ||
| 120 | |||
| 121 | playerSheet_ = texture_ptr(SDL_CreateTextureFromSurface(ren_.get(), pfs.get())); | ||
| 122 | } | ||
| 123 | |||
| 124 | SDL_SetTextureBlendMode(playerSheet_.get(), SDL_BLENDMODE_BLEND); | ||
| 113 | } | 125 | } |
| 114 | 126 | ||
| 115 | void Renderer::render( | 127 | void Renderer::render( |
| @@ -140,10 +152,7 @@ void Renderer::render( | |||
| 140 | { | 152 | { |
| 141 | bool draw = true; | 153 | bool draw = true; |
| 142 | 154 | ||
| 143 | if ((game.player_x == x && game.player_y == y) && game.renderPlayer) | 155 | if (!game.map.at(x,y).lit) |
| 144 | { | ||
| 145 | SDL_SetRenderDrawColor(ren_.get(), 255, 255, 0, 255); | ||
| 146 | } else if (!game.map.at(x,y).lit) | ||
| 147 | { | 156 | { |
| 148 | if (drawDark) | 157 | if (drawDark) |
| 149 | { | 158 | { |
| @@ -191,6 +200,11 @@ void Renderer::render( | |||
| 191 | TILE_HEIGHT}; | 200 | TILE_HEIGHT}; |
| 192 | 201 | ||
| 193 | SDL_RenderFillRect(ren_.get(), &rect); | 202 | SDL_RenderFillRect(ren_.get(), &rect); |
| 203 | |||
| 204 | if ((game.player_x == x && game.player_y == y) && game.renderPlayer) | ||
| 205 | { | ||
| 206 | SDL_RenderCopy(ren_.get(), playerSheet_.get(), &game.playerAnim.getRenderRect(), &rect); | ||
| 207 | } | ||
| 194 | } | 208 | } |
| 195 | } | 209 | } |
| 196 | } | 210 | } |
| 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: | |||
| 129 | texture_ptr playerFade_; | 129 | texture_ptr playerFade_; |
| 130 | texture_ptr lampFade_; | 130 | texture_ptr lampFade_; |
| 131 | texture_ptr dustFade_; | 131 | texture_ptr dustFade_; |
| 132 | texture_ptr playerSheet_; | ||
| 132 | }; | 133 | }; |
| 133 | 134 | ||
| 134 | #endif /* end of include guard: RENDERER_H_6A58EC30 */ | 135 | #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 @@ | |||
| 1 | #ifndef UTIL_H_E9110D4C | 1 | #ifndef UTIL_H_E9110D4C |
| 2 | #define UTIL_H_E9110D4C | 2 | #define UTIL_H_E9110D4C |
| 3 | 3 | ||
| 4 | #include <string> | ||
| 5 | #include <iterator> | ||
| 6 | |||
| 4 | template <typename Container, typename Predicate> | 7 | template <typename Container, typename Predicate> |
| 5 | void erase_if(Container& items, const Predicate& predicate) | 8 | void erase_if(Container& items, const Predicate& predicate) |
| 6 | { | 9 | { |
| @@ -17,4 +20,36 @@ void erase_if(Container& items, const Predicate& predicate) | |||
| 17 | } | 20 | } |
| 18 | }; | 21 | }; |
| 19 | 22 | ||
| 23 | template <class OutputIterator> | ||
| 24 | void splitStr( | ||
| 25 | std::string input, | ||
| 26 | std::string delimiter, | ||
| 27 | OutputIterator out) { | ||
| 28 | while (!input.empty()) { | ||
| 29 | int divider = input.find(delimiter); | ||
| 30 | if (divider == std::string::npos) { | ||
| 31 | *out = input; | ||
| 32 | out++; | ||
| 33 | |||
| 34 | input = ""; | ||
| 35 | } else { | ||
| 36 | *out = input.substr(0, divider); | ||
| 37 | out++; | ||
| 38 | |||
| 39 | input = input.substr(divider+delimiter.length()); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | template <class Container> | ||
| 45 | Container splitStr( | ||
| 46 | std::string input, | ||
| 47 | std::string delimiter) { | ||
| 48 | Container result; | ||
| 49 | |||
| 50 | splitStr(input, delimiter, std::back_inserter(result)); | ||
| 51 | |||
| 52 | return result; | ||
| 53 | } | ||
| 54 | |||
| 20 | #endif /* end of include guard: UTIL_H_E9110D4C */ | 55 | #endif /* end of include guard: UTIL_H_E9110D4C */ |
