From bcd0a359fc0a99595c5c54e8a720d7c2cd178976 Mon Sep 17 00:00:00 2001 From: Tiberiu Chibici Date: Wed, 30 Nov 2016 00:34:36 +0200 Subject: [PATCH] Implemented sprite & added player animation. --- .cproject | 16 +- assets/sprites/player.sprite | 148 ++++++++++++++++++ .../default.png => tilesets/PlayerTiles.png} | Bin 3415 -> 5241 bytes assets_original/player.xcf | Bin 0 -> 14903 bytes build/prepareAssets.py | 3 +- src/Main.cpp | 14 +- src/controller/GuiController.cpp | 6 +- src/controller/PlayerController.cpp | 31 +++- src/controller/PlayerController.h | 1 + src/graphics/GameRenderer.cpp | 81 ++++++++-- src/graphics/GameRenderer.h | 4 + src/model/Player.h | 5 + src/model/Sprite.cpp | 102 ++++++++++++ src/model/Sprite.h | 88 +++++++++++ src/resources/ResourceInfo.h | 1 + src/resources/ResourceManager.h | 15 +- .../ResourceManager/ResourceManager.cpp | 28 +--- .../ResourceManager/ResourceManager_Fonts.cpp | 37 +++++ .../ResourceManager_Levels.cpp | 19 ++- .../ResourceManager_Sprites.cpp | 91 +++++++++++ .../ResourceManager_Textures.cpp | 18 ++- src/resources/Resources.g.h | 30 ++-- src/utils/Assert.cpp | 39 +++++ src/utils/Assert.h | 30 ++++ src/utils/Exceptions.cpp | 45 ++++++ src/utils/Exceptions.h | 77 +++++++++ 26 files changed, 843 insertions(+), 86 deletions(-) create mode 100644 assets/sprites/player.sprite rename assets/{player/default.png => tilesets/PlayerTiles.png} (50%) create mode 100644 assets_original/player.xcf create mode 100644 src/model/Sprite.cpp create mode 100644 src/model/Sprite.h create mode 100644 src/resources/ResourceManager/ResourceManager_Fonts.cpp create mode 100644 src/resources/ResourceManager/ResourceManager_Sprites.cpp create mode 100644 src/utils/Assert.cpp create mode 100644 src/utils/Assert.h create mode 100644 src/utils/Exceptions.cpp create mode 100644 src/utils/Exceptions.h diff --git a/.cproject b/.cproject index 7f24998..21efad7 100644 --- a/.cproject +++ b/.cproject @@ -16,13 +16,15 @@ - + + @@ -93,7 +98,9 @@ + diff --git a/assets/sprites/player.sprite b/assets/sprites/player.sprite new file mode 100644 index 0000000..fa65df7 --- /dev/null +++ b/assets/sprites/player.sprite @@ -0,0 +1,148 @@ +{ + "name" : "Player", + "anchorX" : 0.5, + "anchorY" : 1, + + "states" : + [ + { + "name" : "Idle right", + "frames" : + [ + { + "tileSet" : "tilesets/PlayerTiles.png", + "cell" : 0, + "width" : 1, + "height" : 2, + "duration" : 1 + } + ] + }, + + { + "name" : "Idle up", + "frames" : + [ + { + "tileSet" : "tilesets/PlayerTiles.png", + "cell" : 2, + "width" : 1, + "height" : 2, + "duration" : 1 + } + ] + }, + + { + "name" : "Idle left", + "frames" : + [ + { + "tileSet" : "tilesets/PlayerTiles.png", + "cell" : 4, + "width" : 1, + "height" : 2, + "duration" : 1 + } + ] + }, + + { + "name" : "Idle down", + "frames" : + [ + { + "tileSet" : "tilesets/PlayerTiles.png", + "cell" : 6, + "width" : 1, + "height" : 2, + "duration" : 1 + } + ] + }, + + { + "name" : "Walking right", + "frames" : + [ + { + "tileSet" : "tilesets/PlayerTiles.png", + "cell" : 0, + "width" : 1, + "height" : 2, + "duration" : 7 + }, + { + "tileSet" : "tilesets/PlayerTiles.png", + "cell" : 1, + "width" : 1, + "height" : 2, + "duration" : 7 + } + ] + }, + + { + "name" : "Walking up", + "frames" : + [ + { + "tileSet" : "tilesets/PlayerTiles.png", + "cell" : 2, + "width" : 1, + "height" : 2, + "duration" : 7 + }, + { + "tileSet" : "tilesets/PlayerTiles.png", + "cell" : 3, + "width" : 1, + "height" : 2, + "duration" : 7 + } + ] + }, + + { + "name" : "Walking left", + "frames" : + [ + { + "tileSet" : "tilesets/PlayerTiles.png", + "cell" : 4, + "width" : 1, + "height" : 2, + "duration" : 7 + }, + { + "tileSet" : "tilesets/PlayerTiles.png", + "cell" : 5, + "width" : 1, + "height" : 2, + "duration" : 7 + } + ] + }, + + { + "name" : "Walking down", + "frames" : + [ + { + "tileSet" : "tilesets/PlayerTiles.png", + "cell" : 6, + "width" : 1, + "height" : 2, + "duration" : 7 + }, + { + "tileSet" : "tilesets/PlayerTiles.png", + "cell" : 7, + "width" : 1, + "height" : 2, + "duration" : 7 + } + ] + } + ] +} \ No newline at end of file diff --git a/assets/player/default.png b/assets/tilesets/PlayerTiles.png similarity index 50% rename from assets/player/default.png rename to assets/tilesets/PlayerTiles.png index 04fa9e40c50f1749fa8a71fa6d83979678e82f3b..ec53233dff7f32c7fbb39f84fa5b45c382ef82ab 100644 GIT binary patch delta 2591 zcmV+)3gGqE8u=(8iBL{Q4GJ0x0000DNk~Le0001h0000W2nGNE0NNsOC9xr13X_ov z9e*7ZE*9(0xS#+43B5@~K~#9!)mm?C6XzX%-m@E{vA8kU6D> zCXItcSE|vqgK1*Rx=6F8AcPQzibd6elz!;st{Orq9g|>uz@|=%Tbwx1G7#y95w?zj zU`t2|1PlS<`0TrV$b0UaH}9R#_A!s2bbpG^zUO^^&+~iUKX(@bF1D?$c?Q640223; z3SfKlk@nB<03+Z23ypu+_&Wt{>;dq!LHm0EJoA7B%&Y%G;~zHuA_J%t;ND+HLl`Y$y8VSnbY z&j29+Pg-22o~Fk#08eF^z_Z)d)_f)qFt7d#jenT=6aCwFe&+ezv437|N?-NJBjb>o z27F^m3ds~{`PCo8TNnrbHH!rFINf}t{VAjV&0_Uqv&Qsq7vAa6nr_~4fDpm3>FqVd z+r{6ke>45_!KW{+ud2{^z-G4#gnx_z0l*;vsnJ#BP zZ6Mln$1eQQ9Y6R8z#4{Qn)`blH^wy(i1rY>48-dH#wr(_(r9Jk%II&!be>jHfdBXn z0O$v>E)eZGl`r0DrqX*IH?Z05N}uoeXjGY-rH+tpd}pnI)4D)%3}1m zx#H)Ar%|@+Sejqju%hCNV&1I85&)Q6u4FV2)oKf0yv=SGloYVNT?HY)Z)+r|8qnIQ zVkiM@aZC8Q+l4=L+_)wxelB=tHgnd_)e*sB7hcMiB^4-^i$XhBOW3tW5>2N+ z%(AJ+?ZnfFFmnnpr;I?=fX!}~ zW*1&!*887`_5f^rdO^dd7c>AkkgG^020EKXGo23re}Lg1j=d>_CG3qt)R zFu!wy-T1mIhd-!XIH`~2DvI@0bKC3s-ra9zAQo@MKypJ!s(Z8Z{g_(Xo6^4Sf7PP| zs~#n3{RZvK&|7;ij>-lQ$B5mVf<2uiZibJBry^B;Vm_HMn1{>$0%{A_c zQYHiGi5MA(7I7tjyC%gu5vtg;9&Ij7ZU_-u@og@3(_rJg1@mXZyGRup*|VbJ(8j^W zb=bQ|Gc%CRH46jHmK#Fyk9UXW{5v%RHIJ#N`8FA&op+Indw<0<5}O7a7swM&C*_8a zYzLljP9lm{G}$wu`c02G zCwgAy4K&f2LQi}ae782qNq{@8$Q4fnjZ6U$OKJ{i^k)JMPLkRN;4J_|@z<&*1<2Y!azm&@ z@z=)b=jQ;toYWk@;QIdrKn*if@{k49ln#KAd@6ylGKy&0GL5VhTIS;VfxkE zyk%h%7o;PV*oD`*&~}C>S7C@WVz@XcM~{HNZlH2On+4-9F;kzFn8b9dS`jBp1GQSn zp`Z5cvPP4oWR7n1kQ85kTKDS?hoqq_qU!}XtqHGLQ)bOE{@V}@6_|2TeS1)BC z@P7`UL%w*9zu5!b>6eVf&)GnQle)rCR@GL=Kw4gz=_TcTIl-J&lTAsMC>M^hl2YV}qh7Zv~J{j{EL z5k7-+?{e1;>FX(gUOVuDd^7;0)myD`ny}Xx-A208d?!x8WXIULw0f(L`+||@bj=FQ zU!MW^y+A3Kw5b6YF~&UsV~Vejkbl>+d~h+BGn?E}?~yG&_RJYC;9SbJGj9LHbK|+Q z8krdAf68B?$?%)AZti?qh8e)gjTSxT^Ix2d7q=~2zEU%2hX~AdfnPG|Z6>iBpMi5X z*X|h2mMveYos1W^S<#@?Tdj!x{tAEzg5M@{Tr=Wz7ix6f)5*t{Enhjt-2iar zR2QKbg^r*!=D_vQ0kL7a^M6OaVB||9QD`_?>OF+*v!&icg0c8yqXM!cGaBu>CUU6*M31=`C7vXg-P5|k`=$t6`m~MckKv-+3_l(K?;6U5~`dXIfOK*Pzt={S{4_r_F z!(jHCWRd>{Z&}G1jQ(#wi^{;l$RCL1>)J{s+MJR0p<8jW@>72%r#VU==HGCV}lSPW|*%E@8CS)@%r z)lP5kE`Tc*__qPL-V_MOcn;BM*HARtMfAf8{=YLbhR?m>OY;B#002ovPDHLkV1ikG B_+J13 delta 749 zcmV>qTZJ}U* za5Q$gYfp{aQ*N{yrr>m_lE4TFn~QAjRCODmudp2@ujhAfWSi9 z3gyhUI&FYqb)g9$9Dj}dHiZg+_;bbRON9tr3TT)LdPhyZr=X)=qj4jstZ&IN?%yFC zs1*Q`8PEg{?b1kRAZ;o{1f@#v!B>EcX`Ni^uM<#Jo*x>fTJ+8D!Oe5~00sd*e9IC7 z$;5H|t}*sHpWrS_0x)Gd8JuY#KHrQksa*LDC8wZEijjpz?#%B*SqUO2 z>|zu?Uh!+R2!Aoww9guUiT?uGDF})!sgL=wt%f<9iz&NjQQ%1822DSotvRYgrRm#n z*nE@|*q(eho)LR}fzJ%^G+Uwx)B&CxX^4%=Ork%ZL7ADXFA6f=Jrr-x8Iex^-NN6w zLg<(s^^L%r<(g<)#kO?*?L}J4LP(*&ts-)u$S$=c6D|M}>Gab*6kj$>j*oQuTe1NK fnCKpgPXqh{>6X%dm>Oxz00000NkvXXu0mjf469Kq diff --git a/assets_original/player.xcf b/assets_original/player.xcf new file mode 100644 index 0000000000000000000000000000000000000000..d04c3606a2aff8b2add04687b0c24f52dfe39635 GIT binary patch literal 14903 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 D3F(tL literal 0 HcmV?d00001 diff --git a/build/prepareAssets.py b/build/prepareAssets.py index cd0dc09..505d704 100755 --- a/build/prepareAssets.py +++ b/build/prepareAssets.py @@ -47,7 +47,8 @@ FILE_TYPES = [ ([".png", ".bmp"], "Texture"), ([".level"], "Level"), ([".csv"], "LevelLayer"), - ([".ttf"], "Font"), + ([".ttf"], "Font"), + ([".sprite"], "Sprite"), ] diff --git a/src/Main.cpp b/src/Main.cpp index 71a0f0d..087f8ef 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,8 +1,20 @@ #include +#include + +#include using namespace farmlands; int main() { - return controller::FarmlandsGame().run(); + try + { + return controller::FarmlandsGame().run(); + } + catch (utils::Exception& ex) + { + std::cerr << "Panic: Caught unhandled exception!\n"; + std::cerr << typeid(ex).name() << " : " << ex.message() << "\n"; + std::cerr << "Source: file " << ex.file() << " line " << ex.line() << "\n"; + } } diff --git a/src/controller/GuiController.cpp b/src/controller/GuiController.cpp index 9bd30e9..0346602 100644 --- a/src/controller/GuiController.cpp +++ b/src/controller/GuiController.cpp @@ -38,13 +38,13 @@ void GuiController::initialize(GameState* gameState) // Add a text element auto text = new gui::widgets::TextArea(); - text->setText("Hello world!\nMy name is Tibi!\nThis is a really really long long long, even the longest ever, line.\nThis is a very loooooooooooooooooong word."); - text->setSize(200, 200); + text->setText("Hello world!"); + text->setSize(50, 5); text->setPosition(100, 10); text->setColor(0, 1, 0); text->setBackColor(0.5f, 0, 0, 0.5f); text->setTextSize(11); - text->setHorizontalWrap(gui::widgets::TextHorizontalWrapping::Wrap); + text->setHorizontalWrap(gui::widgets::TextHorizontalWrapping::Ellipsis); text->setVerticalWrap(gui::widgets::TextVerticalWrapping::Trim); text->setAlignment(gui::widgets::TextAlign::BottomRight); m_canvas.addChild(text); diff --git a/src/controller/PlayerController.cpp b/src/controller/PlayerController.cpp index 987c300..9b0f23b 100644 --- a/src/controller/PlayerController.cpp +++ b/src/controller/PlayerController.cpp @@ -7,13 +7,10 @@ #include #include +#include -#include - -namespace farmlands -{ -namespace controller -{ +namespace farmlands { +namespace controller { PlayerController::PlayerController() : m_gameState(nullptr) @@ -26,7 +23,8 @@ PlayerController::~PlayerController() void PlayerController::initialize(GameState* gameState) { - assert(gameState != nullptr); + Assert(gameState != nullptr, "Game state must not be NULL!"); + m_gameState = gameState; } @@ -71,6 +69,9 @@ void PlayerController::updateLogic() { m_gameState->player.posX = newX; m_gameState->player.posY = newY; + m_gameState->player.lastDeltaX = deltaX * deltaMultiplier; + m_gameState->player.lastDeltaY = deltaY * deltaMultiplier; + setDirection(deltaX, deltaY); m_gameState->camera.posX = m_gameState->player.posX; m_gameState->camera.posY = m_gameState->player.posY - 1; @@ -83,5 +84,21 @@ bool PlayerController::canMove(float x, float y) return true; } +static const model::Direction directions[3][3] = +{ + { model::Direction::NorthWest, model::Direction::West, model::Direction::SouthWest }, + { model::Direction::North, model::Direction::South, model::Direction::South }, + { model::Direction::NorthEast, model::Direction::East, model::Direction::SouthEast }, +}; + +void PlayerController::setDirection(float dx, float dy) +{ + int xx = (0 < dx) - (dx < 0); + int yy = (0 < dy) - (dy < 0); + + if (xx != 0 || yy != 0) + m_gameState->player.direction = directions[xx + 1][yy + 1]; +} + } /* namespace controller */ } /* namespace farmlands */ diff --git a/src/controller/PlayerController.h b/src/controller/PlayerController.h index d81712d..0530ff8 100644 --- a/src/controller/PlayerController.h +++ b/src/controller/PlayerController.h @@ -42,6 +42,7 @@ namespace controller { private: bool canMove(float x, float y); + void setDirection(float dx, float dy); GameState* m_gameState; }; diff --git a/src/graphics/GameRenderer.cpp b/src/graphics/GameRenderer.cpp index e769c3f..33feb36 100644 --- a/src/graphics/GameRenderer.cpp +++ b/src/graphics/GameRenderer.cpp @@ -100,26 +100,79 @@ void GameRenderer::renderTileLayers() } } -void GameRenderer::renderPlayer() +void GameRenderer::renderSprite(model::Sprite* sprite, float destX, float destY) { - float posX = xToScreen(m_gameState->player.posX); - float posY = yToScreen(m_gameState->player.posY); + float posX = xToScreen(destX); + float posY = yToScreen(destY); // Obtain texture - int texWidth, texHeight; - SDL_Texture* playerTexture = m_gameState->resManager.texture(resources::R::Player::Default); - SDL_QueryTexture(playerTexture, NULL, NULL, &texWidth, &texHeight); + int texId = sprite->currentFrame().tileSetId; + SDL_Texture* texture = m_gameState->resManager.texture(texId); - // Draw using bottom center of texture as anchor point - SDL_Rect dest = + // Compute src rectangle + SDL_Rect src; + getCell(texture, sprite->currentFrame().tileSetCell, &src.x, &src.y); + src.w = sprite->currentFrame().width * m_gameState->currentLevel->m_cellWidth; + src.h = sprite->currentFrame().height * m_gameState->currentLevel->m_cellHeight; + + // Compute destination rectangle + SDL_Rect dest; + dest.x = posX - sprite->anchorX * src.w * m_gameState->camera.scale; + dest.y = posY - sprite->anchorY * src.h * m_gameState->camera.scale; + dest.w = src.w * m_gameState->camera.scale; + dest.h = src.h * m_gameState->camera.scale; + + // Draw + SDL_RenderCopy(m_gameState->sdlRenderer.internalRenderer(), texture, &src, &dest); + + // Advance animation frame + sprite->advanceTime(1); +} + +void GameRenderer::renderPlayer() +{ + // Compute current state + model::Sprite* sprite = m_gameState->resManager.sprite(resources::R::Sprites::Player); + + bool walking = (m_gameState->player.lastDeltaX != 0 || m_gameState->player.lastDeltaY != 0); + std::string stateName = (walking) ? "Walking " : "Idle "; + + switch(m_gameState->player.direction) { - (int) (posX - texWidth * m_gameState->camera.scale / 2), - (int) (posY - texHeight * m_gameState->camera.scale), - (int) (texWidth * m_gameState->camera.scale), - (int) (texHeight * m_gameState->camera.scale), - }; + case model::Direction::SouthEast: + case model::Direction::East: + case model::Direction::NorthEast: + stateName += "right"; + break; - SDL_RenderCopy(m_gameState->sdlRenderer.internalRenderer(), playerTexture, NULL, &dest); + case model::Direction::North: + stateName += "up"; + break; + + case model::Direction::NorthWest: + case model::Direction::West: + case model::Direction::SouthWest: + stateName += "left"; + break; + + case model::Direction::South: + stateName += "down"; + break; + } + sprite->setState(stateName); + + // Draw + renderSprite(sprite, m_gameState->player.posX, m_gameState->player.posY); +} + +void GameRenderer::getCell(SDL_Texture* texture, int cell, int* outX, int* outY) +{ + int texWidth, texHeight; + SDL_QueryTexture(texture, NULL, NULL, &texWidth, &texHeight); + + // Compute texture coordinates + *outX = (cell * m_gameState->currentLevel->m_cellWidth) % texWidth; + *outY = ((cell * m_gameState->currentLevel->m_cellWidth) / texWidth) * m_gameState->currentLevel->m_cellHeight; } float GameRenderer::xToWorld(float x) diff --git a/src/graphics/GameRenderer.h b/src/graphics/GameRenderer.h index 8af3623..bb4eb05 100644 --- a/src/graphics/GameRenderer.h +++ b/src/graphics/GameRenderer.h @@ -8,6 +8,7 @@ #ifndef GRAPHICS_GAMERENDERER_H_ #define GRAPHICS_GAMERENDERER_H_ +#include #include #include @@ -42,12 +43,15 @@ namespace graphics { void prepareRender(); void renderTileLayers(); void renderPlayer(); + void renderSprite(model::Sprite* sprite, float destX, float destY); float xToWorld(float x); float yToWorld(float y); float xToScreen(float x); float yToScreen(float y); + void getCell(SDL_Texture* texture, int cell, int* outX, int* outY); + GameState* m_gameState; // Size of a cell (scaled) diff --git a/src/model/Player.h b/src/model/Player.h index 38ccff2..92e3582 100644 --- a/src/model/Player.h +++ b/src/model/Player.h @@ -8,6 +8,8 @@ #ifndef MODEL_PLAYER_H_ #define MODEL_PLAYER_H_ +#include + namespace farmlands { namespace model { @@ -16,6 +18,9 @@ namespace model { struct Player { float posX, posY; + float lastDeltaX, lastDeltaY; + Direction direction; + int inventorySelection = -1; int inventory[PLAYER_INVENTORY_SIZE]; diff --git a/src/model/Sprite.cpp b/src/model/Sprite.cpp new file mode 100644 index 0000000..3d57a74 --- /dev/null +++ b/src/model/Sprite.cpp @@ -0,0 +1,102 @@ +/* + * Sprite.cpp + * + * Created on: Nov 29, 2016 + * Author: tibi + */ + +#include +#include + +#include + +namespace farmlands { +namespace model { + +Sprite::Sprite() + : anchorX(0), anchorY(0), + m_states(), + m_currentState(0), + m_currentFrame(0), + m_currentFrameTimeLeft(0) +{ +} + +Sprite::~Sprite() +{ +} + +void Sprite::addState(const SpriteState& state) +{ + Assert(state.frames.size() > 0, "State must have at least one frame!"); +#ifdef BUILD_DEBUG + uint32_t totalDuration = 0; + for (auto frame : state.frames) + totalDuration += frame.duration; + + Assert(totalDuration > 0, "State must have a frame which last at least one tick."); +#endif + Assert(m_stateNames.count(state.name) == 0, "A state with the same name already added!"); + + m_states.push_back(state); + m_stateNames.emplace(state.name, m_states.size() - 1); +} + +void Sprite::setState(size_t stateId) +{ + Assert(stateId < m_states.size(), "Inexistent state."); + + // Avoid resetting state + if (stateId == m_currentState) + return; + + m_currentState = stateId; + m_currentFrame = 0; + m_currentFrameTimeLeft = currentFrame().duration * 1; +} + +void Sprite::setState(const std::string& name) +{ + Assert(m_stateNames.count(name) > 0, "Inexistent state."); + setState(m_stateNames.at(name)); +} + +void Sprite::advanceTime(uint32_t steps) +{ + Assert(m_states.size() > 0, "Sprite must have at least one state!"); + + while (steps > 0) + { + // There is time left in the current frame? + if (m_currentFrameTimeLeft > 0) + { + uint32_t sub = std::min(steps, m_currentFrameTimeLeft); + m_currentFrameTimeLeft -= sub; + steps -= sub; + } + + if (m_currentFrameTimeLeft == 0) + { + // Move to the next frame + if (++m_currentFrame >= currentState().frames.size()) + m_currentFrame = 0; + + m_currentFrameTimeLeft = currentFrame().duration * 1; + } + } +} + +SpriteState& Sprite::currentState() +{ + Assert(m_states.size() > 0, "Sprite must have at least one state!"); + return m_states.at(m_currentState); +} + +Frame& Sprite::currentFrame() +{ + Assert(currentState().frames.size() > 0, "State must have at least one frame!"); + return currentState().frames.at(m_currentFrame); +} + +} /* namespace model */ +} /* namespace farmlands */ diff --git a/src/model/Sprite.h b/src/model/Sprite.h new file mode 100644 index 0000000..3cb3588 --- /dev/null +++ b/src/model/Sprite.h @@ -0,0 +1,88 @@ +/* + * Sprite.h + * + * Created on: Nov 29, 2016 + * Author: tibi + */ + +#ifndef MODEL_SPRITE_H_ +#define MODEL_SPRITE_H_ + +#include + +#include +#include + +namespace farmlands { +namespace model { + + /** + * Defines an animation frame + */ + struct Frame + { + uint32_t tileSetId; + uint32_t tileSetCell; + uint32_t width, height; + uint32_t duration; + }; + + /** + * Defines a sprite state (aka an animation). + */ + struct SpriteState + { + std::string name; + std::vector frames; + }; + + /** + * Defines a sprite + */ + class Sprite + { + public: + Sprite(); + virtual ~Sprite(); + + /** + * Adds a state to the sprite. + */ + void addState(const SpriteState& state); + + /** + * Sets the current state. + */ + void setState(size_t stateId); + + /** + * Sets the current state. + */ + void setState(const std::string& name); + + /** + * Advances the current frame + */ + void advanceTime(uint32_t steps); + + + // Getters + SpriteState& currentState(); + Frame& currentFrame(); + + // Public fields + float anchorX, anchorY; + + private: + std::vector m_states; + std::unordered_map m_stateNames; + + size_t m_currentState; + size_t m_currentFrame; + uint32_t m_currentFrameTimeLeft; + }; + +} /* namespace model */ +} /* namespace farmlands */ + +#endif /* MODEL_SPRITE_H_ */ diff --git a/src/resources/ResourceInfo.h b/src/resources/ResourceInfo.h index 0f1ee24..61e44ae 100644 --- a/src/resources/ResourceInfo.h +++ b/src/resources/ResourceInfo.h @@ -15,6 +15,7 @@ namespace resources { { None, Texture, + Sprite, Level, LevelLayer, Font, diff --git a/src/resources/ResourceManager.h b/src/resources/ResourceManager.h index 5fac075..f4c2469 100644 --- a/src/resources/ResourceManager.h +++ b/src/resources/ResourceManager.h @@ -9,6 +9,7 @@ #define STORAGE_RESOURCEMANAGER_H_ #include +#include #include #include @@ -39,6 +40,7 @@ namespace resources { } texture; model::Level* level; + model::Sprite* sprite; }; }; @@ -57,6 +59,7 @@ namespace resources { TTF_Font* font(int id, int pointSize); SDL_Texture* texture(int id); model::Level* level(int id); + model::Sprite* sprite(int id); private: /** @@ -70,16 +73,10 @@ namespace resources { */ int getId(std::string resourcePath); - /** - * Loads the cell data for a level tile layer. - */ - void loadLevelLayer(model::Level* level, size_t layerNumber, int resourceId); - - /** - * Loads a texture into memory. - */ - void loadTexture(int textureId); void loadFont(int fontId, int pointSize); + void loadTexture(int textureId); + void loadSprite(int spriteId); + void loadLevelLayer(model::Level* level, size_t layerNumber, int resourceId); // State GameState* m_gameState; diff --git a/src/resources/ResourceManager/ResourceManager.cpp b/src/resources/ResourceManager/ResourceManager.cpp index 6215fa5..7f7a30e 100644 --- a/src/resources/ResourceManager/ResourceManager.cpp +++ b/src/resources/ResourceManager/ResourceManager.cpp @@ -7,13 +7,10 @@ #include #include +#include #include -#define FONTID(id,size) (id * 1000 + size) -#define FONTID_SIZE(fontid) (fontid % 1000) -#define FONTID_ID(fontid) (fontid / 1000) - namespace farmlands { namespace resources { @@ -43,8 +40,11 @@ ResourceManager::~ResourceManager() SDL_FreeSurface(m_loadedResources[i].texture.surface); break; + case ResourceType::Sprite: + delete m_loadedResources[i].sprite; + default: - assert(false); + Assert(false, "Cannot free resources!"); break; } } @@ -64,25 +64,13 @@ void ResourceManager::loadMainMenu() void ResourceManager::loadGameAssets() { - loadTexture(R::Player::Default); -} - -TTF_Font* ResourceManager::font(int id, int pointSize) -{ - // Open from cache - auto it = m_fontCache.find(FONTID(id, pointSize)); - if (it != m_fontCache.end()) - return it->second; - - // Open font - TTF_Font* font = TTF_OpenFont(getPath(id).c_str(), pointSize); - m_fontCache.emplace(FONTID(id, pointSize), font); - - return font; + loadSprite(R::Sprites::Player); } std::string ResourceManager::getPath(int resourceId) { + Assert(resourceId >= 0 && resourceId < sizeof(RInfo) / sizeof(RInfo[0]), "Resource id out of bounds."); + boost::filesystem::path resPath(ASSETS_DIR); resPath.append(RInfo[resourceId].path); diff --git a/src/resources/ResourceManager/ResourceManager_Fonts.cpp b/src/resources/ResourceManager/ResourceManager_Fonts.cpp new file mode 100644 index 0000000..d91932f --- /dev/null +++ b/src/resources/ResourceManager/ResourceManager_Fonts.cpp @@ -0,0 +1,37 @@ +/* + * ResourceManager_Fonts.cpp + * + * Created on: Nov 29, 2016 + * Author: tibi + */ +#include +#include + +#define FONTID(id,size) (id * 1000 + size) +#define FONTID_SIZE(fontid) (fontid % 1000) +#define FONTID_ID(fontid) (fontid / 1000) + +namespace farmlands { +namespace resources { + +TTF_Font* ResourceManager::font(int id, int pointSize) +{ + // Open from cache + auto it = m_fontCache.find(FONTID(id, pointSize)); + if (it != m_fontCache.end()) + return it->second; + + // Open font + std::string fontPath = getPath(id); + TTF_Font* font = TTF_OpenFont(fontPath.c_str(), pointSize); + if (!font) + THROW(utils::ResourceLoadException, "Could not load font " + fontPath); + + // Cache it + m_fontCache.emplace(FONTID(id, pointSize), font); + + return font; +} + +} +} diff --git a/src/resources/ResourceManager/ResourceManager_Levels.cpp b/src/resources/ResourceManager/ResourceManager_Levels.cpp index 1b8d112..ffb9a19 100644 --- a/src/resources/ResourceManager/ResourceManager_Levels.cpp +++ b/src/resources/ResourceManager/ResourceManager_Levels.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -20,14 +21,15 @@ namespace resources { void ResourceManager::loadLevelLayer(model::Level* level, size_t layer, int resourceId) { - assert(RInfo[resourceId].type == ResourceType::LevelLayer); + Assert(RInfo[resourceId].type == ResourceType::LevelLayer, "Resource must be a level layer."); char buffer[1024 * 10]; // Open file - std::ifstream in(getPath(resourceId)); + std::string pathIn = getPath(resourceId); + std::ifstream in(pathIn); if (!in) - throw 0; // TODO: replace with exception type + THROW(utils::ResourceLoadException, "Could not load level layer " + pathIn); // Read CSV file line by line for (size_t row = 0; row < level->rowCount(); row++) @@ -35,7 +37,7 @@ void ResourceManager::loadLevelLayer(model::Level* level, size_t layer, int reso in.getline(buffer, sizeof(buffer)); if (in.eof()) - throw 0; // TODO: replace with exception type + THROW(utils::ResourceLoadException, "Unexpected end of file " + pathIn); // Separated by comma (or maybe semicolon) char* nextNum = strtok(buffer, ",;"); @@ -55,12 +57,15 @@ void ResourceManager::loadLevelLayer(model::Level* level, size_t layer, int reso void ResourceManager::loadLevel(int levelId) { // Sanity checks - assert(RInfo[levelId].type == ResourceType::Level); + Assert(RInfo[levelId].type == ResourceType::Level, "Resource must be a level!"); + if (m_loadedResources[levelId].loaded) + return; // Open file + std::string levelPath = getPath(levelId); std::ifstream levelIn(getPath(levelId)); if (!levelIn) - throw 0; // TODO: replace with exception type + THROW(utils::ResourceLoadException, "Failed to load level " + levelPath); // Parse file json levelJs; @@ -97,7 +102,7 @@ void ResourceManager::loadLevel(int levelId) model::Level* ResourceManager::level(int id) { - assert(RInfo[id].type == ResourceType::Level); + Assert(RInfo[id].type == ResourceType::Level, "Resource must be a level!"); return m_loadedResources[id].level; } diff --git a/src/resources/ResourceManager/ResourceManager_Sprites.cpp b/src/resources/ResourceManager/ResourceManager_Sprites.cpp new file mode 100644 index 0000000..36609a9 --- /dev/null +++ b/src/resources/ResourceManager/ResourceManager_Sprites.cpp @@ -0,0 +1,91 @@ +/* + * ResourceManager_Sprites.cpp + * + * Created on: Nov 29, 2016 + * Author: tibi + */ +#include +#include +#include +#include + +#include +#include + +#include + +using namespace nlohmann; + +namespace farmlands { +namespace resources { + + +void ResourceManager::loadSprite(int spriteId) +{ + Assert(RInfo[spriteId].type == ResourceType::Sprite, "Resource must be a sprite!"); + if (m_loadedResources[spriteId].loaded) + return; + + // Open file + std::string spritePath = getPath(spriteId); + std::ifstream spriteIn(spritePath); + if (!spriteIn) + THROW(utils::ResourceLoadException, "Could not load " + spritePath); + + // Parse file + json spriteJs; + spriteIn >> spriteJs; + + model::Sprite* sprite = new model::Sprite(); + sprite->anchorX = spriteJs.value("anchorX", 0.0f); + sprite->anchorY = spriteJs.value("anchorY", 0.0f); + + json statesJs = spriteJs.at("states"); + + for (auto state : statesJs) + { + model::SpriteState spriteState; + spriteState.name = state.value("name", std::string()); + + // Obtain frames + json framesJs = state.at("frames"); + for (auto frame : framesJs) + { + model::Frame spriteFrame; + spriteFrame.tileSetCell = frame.value("cell", 0u); + spriteFrame.width = frame.value("width", 0u); + spriteFrame.height = frame.value("height", 0u); + spriteFrame.duration = frame.value("duration", 0u); + + // Obtain tile set id + std::string tileSetPath = frame.value("tileSet", std::string()); + spriteFrame.tileSetId = getId(tileSetPath); + loadTexture(spriteFrame.tileSetId); + + // Add frame + spriteState.frames.push_back(spriteFrame); + } + + // Add state + sprite->addState(spriteState); + } + + m_loadedResources[spriteId].loaded = true; + m_loadedResources[spriteId].sprite = sprite; +} + +model::Sprite* ResourceManager::sprite(int id) +{ + Assert(RInfo[id].type == ResourceType::Sprite, "Resource must be a sprite!"); + + return m_loadedResources[id].sprite; +} + +} +} + + + + + + diff --git a/src/resources/ResourceManager/ResourceManager_Textures.cpp b/src/resources/ResourceManager/ResourceManager_Textures.cpp index 985ba62..16f6b9d 100644 --- a/src/resources/ResourceManager/ResourceManager_Textures.cpp +++ b/src/resources/ResourceManager/ResourceManager_Textures.cpp @@ -7,25 +7,28 @@ #include #include #include - -#include +#include namespace farmlands { namespace resources { void ResourceManager::loadTexture(int resourceId) { - assert(RInfo[resourceId].type == ResourceType::Texture); + Assert(RInfo[resourceId].type == ResourceType::Texture, "Resource must be a texture!"); + if (m_loadedResources[resourceId].loaded) + return; // Open file - SDL_Surface* surface = IMG_Load(getPath(resourceId).c_str()); + std::string texturePath = getPath(resourceId); + SDL_Surface* surface = IMG_Load(texturePath.c_str()); if (surface == NULL) - throw 0; // TODO: error handling + THROW(utils::ResourceLoadException, "Failed to load texture " + texturePath); SDL_Texture* texture = SDL_CreateTextureFromSurface(m_gameState->sdlRenderer.internalRenderer(), surface); if (texture == NULL) - throw 0; // TODO: error handling + THROW(utils::ResourceLoadException, "Failed to create texture " + texturePath); + // Add to loaded resources m_loadedResources[resourceId].loaded = true; m_loadedResources[resourceId].texture.surface = surface; m_loadedResources[resourceId].texture.texture = texture; @@ -33,7 +36,8 @@ void ResourceManager::loadTexture(int resourceId) SDL_Texture* ResourceManager::texture(int id) { - assert(RInfo[id].type == ResourceType::Texture); + Assert(RInfo[id].type == ResourceType::Texture, "Resource must be a texture!"); + return m_loadedResources[id].texture.texture; } diff --git a/src/resources/Resources.g.h b/src/resources/Resources.g.h index dd2ea3b..208a291 100644 --- a/src/resources/Resources.g.h +++ b/src/resources/Resources.g.h @@ -12,41 +12,43 @@ namespace resources { * The IDs are generated at build time by the 'prepareAssets.py' script. */ namespace R { + enum Sprites + { + Player = 0, + }; enum Fonts { - DejaVuSans = 0, - }; - enum Player - { - Default = 1, + DejaVuSans = 1, }; enum Tilesets { - Ground = 2, + PlayerTiles = 2, + Ground = 3, }; enum Ui { - Cursor = 3, + Cursor = 4, }; enum Levels { - Farm_Background = 4, - Farm = 5, + Farm_Background = 5, + Farm = 6, }; } - const int RInfo_Fonts_Begin = 0; - const int RInfo_Player_Begin = 1; + const int RInfo_Sprites_Begin = 0; + const int RInfo_Fonts_Begin = 1; const int RInfo_Tilesets_Begin = 2; - const int RInfo_Ui_Begin = 3; - const int RInfo_Levels_Begin = 4; + const int RInfo_Ui_Begin = 4; + const int RInfo_Levels_Begin = 5; /** * This array contains the names of all the files, and the corresponding file type. */ const ResourceInfo RInfo[] = { + { "sprites/player.sprite", ResourceType::Sprite }, { "fonts/DejaVuSans.ttf", ResourceType::Font }, - { "player/default.png", ResourceType::Texture }, + { "tilesets/PlayerTiles.png", ResourceType::Texture }, { "tilesets/Ground.png", ResourceType::Texture }, { "ui/cursor.png", ResourceType::Texture }, { "levels/Farm_Background.csv", ResourceType::LevelLayer }, diff --git a/src/utils/Assert.cpp b/src/utils/Assert.cpp new file mode 100644 index 0000000..1311bf9 --- /dev/null +++ b/src/utils/Assert.cpp @@ -0,0 +1,39 @@ +/* + * Assert.cpp + * + * Created on: Nov 29, 2016 + * Author: tibi + */ + +#include +#include + +namespace farmlands { +namespace utils { + +DEFINE_EXCEPTION_CPP(AssertionFailedException, Exception) + +void _AssertInternal(bool condition, const std::string& msg, + const std::string& lineText, const std::string& file, int line) +{ + if (!condition) + { + throw AssertionFailedException("Assertion failed: " + msg + "\n" + lineText, file, line); + } +} + +void _AssertInternalLog(bool condition, const std::string& msg, + const std::string& lineText, const std::string& file, int line) +{ + if (!condition) + { + std::cerr << "In file " << file << ":" << line << ": "; + std::cerr << "Assertion failed: " << msg << "\n"; + std::cerr << lineText << "\n"; + } +} + +} /* namespace utils */ +} /* namespace farmlands */ + + diff --git a/src/utils/Assert.h b/src/utils/Assert.h new file mode 100644 index 0000000..46e88e2 --- /dev/null +++ b/src/utils/Assert.h @@ -0,0 +1,30 @@ +/* + * Assert.h + * + * Created on: Nov 29, 2016 + * Author: tibi + */ + +#ifndef UTILS_ASSERT_H_ +#define UTILS_ASSERT_H_ + +#include + +namespace farmlands { +namespace utils { + + DEFINE_EXCEPTION_CLASS(AssertionFailedException, Exception) + + void _AssertInternal(bool condition, const std::string& msg, const std::string& lineText, const std::string& file, int line); + void _AssertInternalLog(bool condition, const std::string& msg, const std::string& lineText, const std::string& file, int line); + +#ifdef BUILD_DEBUG +#define Assert(condition, message) farmlands::utils::_AssertInternal(condition, message, #condition, __FILE__, __LINE__) +#else +#define Assert(condition, message) farmlands::utils::_AssertInternalLog(condition, message, #condition, __FILE__, __LINE__) +#endif + +} /* namespace utils */ +} /* namespace farmlands */ + +#endif /* UTILS_ASSERT_H_ */ diff --git a/src/utils/Exceptions.cpp b/src/utils/Exceptions.cpp new file mode 100644 index 0000000..eb7ef47 --- /dev/null +++ b/src/utils/Exceptions.cpp @@ -0,0 +1,45 @@ +/* + * Exceptions.cpp + * + * Created on: Nov 29, 2016 + * Author: tibi + */ + +#include + +namespace farmlands { +namespace utils { + +Exception::Exception() + : m_message(), + m_file(), + m_line() +{ +} + +Exception::Exception(const std::string& msg) + : m_message(msg), + m_file(), + m_line() +{ +} + +Exception::Exception(const std::string& msg, const std::string& file, int line) + : m_message(msg), + m_file(file), + m_line(line) +{ +} + +Exception::~Exception() +{ +} + + +DEFINE_EXCEPTION_CPP(InvalidArgumentException, Exception) +DEFINE_EXCEPTION_CPP(IOException, Exception); +DEFINE_EXCEPTION_CPP(ResourceLoadException, IOException); + +} /* namespace utils */ +} /* namespace farmlands */ + diff --git a/src/utils/Exceptions.h b/src/utils/Exceptions.h new file mode 100644 index 0000000..16a6ae7 --- /dev/null +++ b/src/utils/Exceptions.h @@ -0,0 +1,77 @@ +/* + * Exceptions.h + * + * Created on: Nov 29, 2016 + * Author: tibi + */ + +#ifndef UTILS_EXCEPTIONS_H_ +#define UTILS_EXCEPTIONS_H_ + +#include + +namespace farmlands { +namespace utils { + + class Exception + { + public: + Exception(); + Exception(const std::string& msg); + Exception(const std::string& msg, const std::string& file, int line); + virtual ~Exception(); + + inline std::string message() const { return m_message; } + inline std::string file() const { return m_file; } + inline int line() const { return m_line; } + + private: + std::string m_message; + std::string m_file; + int m_line; + }; + +/** + * Defines an exception class + */ +#define DEFINE_EXCEPTION_CLASS(className, baseClass) \ + class className : public baseClass \ + { \ + public: \ + className(); \ + className(const std::string& msg); \ + className(const std::string& msg, const std::string& file, int line); \ + virtual ~className(); \ + }; \ + + +/** + * Defines the implementation for an exception class + */ +#define DEFINE_EXCEPTION_CPP(className, baseClass) \ + className::className() \ + : baseClass() { } \ + className::className(const std::string& msg) \ + : baseClass(msg) { } \ + className::className(const std::string& msg, const std::string& file, int line) \ + : baseClass(msg, file, line) { } \ + className::~className() { } \ + + +/** + * Throws an exception; also adds file and line. + */ +#define THROW(exceptionClass, message) throw exceptionClass(message, __FILE__, __LINE__) + + + // Common exceptions + + DEFINE_EXCEPTION_CLASS(InvalidArgumentException, Exception); + DEFINE_EXCEPTION_CLASS(IOException, Exception); + DEFINE_EXCEPTION_CLASS(ResourceLoadException, IOException); + + +} /* namespace utils */ +} /* namespace farmlands */ + +#endif /* UTILS_EXCEPTIONS_H_ */