Implemented sprite & added player animation.
This commit is contained in:
parent
d2c335bfa5
commit
bcd0a359fc
16
.cproject
16
.cproject
@ -16,13 +16,15 @@
|
||||
<folderInfo id="cdt.managedbuild.config.gnu.exe.debug.1767279125." name="/" resourcePath="">
|
||||
<toolChain id="cdt.managedbuild.toolchain.gnu.exe.debug.263074825" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.debug">
|
||||
<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.debug.361182110" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.debug"/>
|
||||
<builder buildPath="${workspace_loc:/Farmlands}/Debug" id="org.eclipse.cdt.build.core.internal.builder.1184678368" superClass="org.eclipse.cdt.build.core.internal.builder"/>
|
||||
<builder buildPath="${workspace_loc:/Farmlands}/Debug" id="org.eclipse.cdt.build.core.internal.builder.1184678368" keepEnvironmentInBuildfile="false" name="CDT Internal Builder" superClass="org.eclipse.cdt.build.core.internal.builder"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.archiver.base.1607221000" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
|
||||
<tool command="g++" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.1808198807" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug">
|
||||
<option id="gnu.cpp.compiler.exe.debug.option.optimization.level.593370343" name="Optimization Level" superClass="gnu.cpp.compiler.exe.debug.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
|
||||
<option id="gnu.cpp.compiler.exe.debug.option.debugging.level.1975874858" name="Debug Level" superClass="gnu.cpp.compiler.exe.debug.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
|
||||
<option id="gnu.cpp.compiler.option.dialect.std.2087263669" name="Language standard" superClass="gnu.cpp.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.cpp.compiler.dialect.c++11" valueType="enumerated"/>
|
||||
<option id="gnu.cpp.compiler.option.preprocessor.def.954705469" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false"/>
|
||||
<option id="gnu.cpp.compiler.option.preprocessor.def.954705469" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false" valueType="definedSymbols">
|
||||
<listOptionValue builtIn="false" value="BUILD_DEBUG"/>
|
||||
</option>
|
||||
<option id="gnu.cpp.compiler.option.include.paths.1179839838" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/src}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/import/include}""/>
|
||||
@ -37,6 +39,9 @@
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/src}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/import/include}""/>
|
||||
</option>
|
||||
<option id="gnu.c.compiler.option.preprocessor.def.symbols.1611927348" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" useByScannerDiscovery="false" valueType="definedSymbols">
|
||||
<listOptionValue builtIn="false" value="BUILD_DEBUG"/>
|
||||
</option>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1905365757" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.debug.1471902586" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.debug"/>
|
||||
@ -93,7 +98,9 @@
|
||||
<option id="gnu.cpp.compiler.exe.release.option.optimization.level.1342166702" name="Optimization Level" superClass="gnu.cpp.compiler.exe.release.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
|
||||
<option id="gnu.cpp.compiler.exe.release.option.debugging.level.1515472655" name="Debug Level" superClass="gnu.cpp.compiler.exe.release.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
|
||||
<option id="gnu.cpp.compiler.option.dialect.std.1039507910" name="Language standard" superClass="gnu.cpp.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.cpp.compiler.dialect.c++11" valueType="enumerated"/>
|
||||
<option id="gnu.cpp.compiler.option.preprocessor.def.317772284" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false"/>
|
||||
<option id="gnu.cpp.compiler.option.preprocessor.def.317772284" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false" valueType="definedSymbols">
|
||||
<listOptionValue builtIn="false" value="BUILD_RELEASE"/>
|
||||
</option>
|
||||
<option id="gnu.cpp.compiler.option.include.paths.664997027" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/src}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/import/include}""/>
|
||||
@ -108,6 +115,9 @@
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/src}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Farmlands/import/include}""/>
|
||||
</option>
|
||||
<option id="gnu.c.compiler.option.preprocessor.def.symbols.252229749" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" useByScannerDiscovery="false" valueType="definedSymbols">
|
||||
<listOptionValue builtIn="false" value="BUILD_RELEASE"/>
|
||||
</option>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1918347020" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.release.1752295375" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.release"/>
|
||||
|
148
assets/sprites/player.sprite
Normal file
148
assets/sprites/player.sprite
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 5.1 KiB |
BIN
assets_original/player.xcf
Normal file
BIN
assets_original/player.xcf
Normal file
Binary file not shown.
@ -48,6 +48,7 @@ FILE_TYPES = [
|
||||
([".level"], "Level"),
|
||||
([".csv"], "LevelLayer"),
|
||||
([".ttf"], "Font"),
|
||||
([".sprite"], "Sprite"),
|
||||
]
|
||||
|
||||
|
||||
|
12
src/Main.cpp
12
src/Main.cpp
@ -1,8 +1,20 @@
|
||||
#include <controller/FarmlandsGame.h>
|
||||
#include <utils/Exceptions.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace farmlands;
|
||||
|
||||
int main()
|
||||
{
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -7,13 +7,10 @@
|
||||
|
||||
#include <GameState.h>
|
||||
#include <controller/PlayerController.h>
|
||||
#include <utils/Assert.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
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 */
|
||||
|
@ -42,6 +42,7 @@ namespace controller {
|
||||
|
||||
private:
|
||||
bool canMove(float x, float y);
|
||||
void setDirection(float dx, float dy);
|
||||
|
||||
GameState* m_gameState;
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -8,6 +8,7 @@
|
||||
#ifndef GRAPHICS_GAMERENDERER_H_
|
||||
#define GRAPHICS_GAMERENDERER_H_
|
||||
|
||||
#include <model/Sprite.h>
|
||||
#include <graphics/SdlRenderer.h>
|
||||
#include <resources/ResourceManager.h>
|
||||
|
||||
@ -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)
|
||||
|
@ -8,6 +8,8 @@
|
||||
#ifndef MODEL_PLAYER_H_
|
||||
#define MODEL_PLAYER_H_
|
||||
|
||||
#include <model/Direction.h>
|
||||
|
||||
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];
|
||||
|
102
src/model/Sprite.cpp
Normal file
102
src/model/Sprite.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Sprite.cpp
|
||||
*
|
||||
* Created on: Nov 29, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#include <model/Sprite.h>
|
||||
#include <utils/Assert.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
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 */
|
88
src/model/Sprite.h
Normal file
88
src/model/Sprite.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Sprite.h
|
||||
*
|
||||
* Created on: Nov 29, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef MODEL_SPRITE_H_
|
||||
#define MODEL_SPRITE_H_
|
||||
|
||||
#include <utils/Exceptions.h>
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
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<Frame> 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<SpriteState> m_states;
|
||||
std::unordered_map<std::string, size_t> m_stateNames;
|
||||
|
||||
size_t m_currentState;
|
||||
size_t m_currentFrame;
|
||||
uint32_t m_currentFrameTimeLeft;
|
||||
};
|
||||
|
||||
} /* namespace model */
|
||||
} /* namespace farmlands */
|
||||
|
||||
#endif /* MODEL_SPRITE_H_ */
|
@ -15,6 +15,7 @@ namespace resources {
|
||||
{
|
||||
None,
|
||||
Texture,
|
||||
Sprite,
|
||||
Level,
|
||||
LevelLayer,
|
||||
Font,
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define STORAGE_RESOURCEMANAGER_H_
|
||||
|
||||
#include <model/Level.h>
|
||||
#include <model/Sprite.h>
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
@ -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;
|
||||
|
@ -7,13 +7,10 @@
|
||||
|
||||
#include <resources/ResourceManager.h>
|
||||
#include <resources/Resources.h>
|
||||
#include <utils/Assert.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#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);
|
||||
|
||||
|
37
src/resources/ResourceManager/ResourceManager_Fonts.cpp
Normal file
37
src/resources/ResourceManager/ResourceManager_Fonts.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* ResourceManager_Fonts.cpp
|
||||
*
|
||||
* Created on: Nov 29, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
#include <resources/ResourceManager.h>
|
||||
#include <resources/Resources.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <resources/ResourceManager.h>
|
||||
#include <resources/Resources.h>
|
||||
#include <utils/Assert.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
@ -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;
|
||||
}
|
||||
|
91
src/resources/ResourceManager/ResourceManager_Sprites.cpp
Normal file
91
src/resources/ResourceManager/ResourceManager_Sprites.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* ResourceManager_Sprites.cpp
|
||||
*
|
||||
* Created on: Nov 29, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
#include <model/Sprite.h>
|
||||
#include <resources/ResourceManager.h>
|
||||
#include <resources/Resources.h>
|
||||
#include <utils/Assert.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include <json.hpp>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -7,25 +7,28 @@
|
||||
#include <GameState.h>
|
||||
#include <resources/ResourceManager.h>
|
||||
#include <resources/Resources.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <utils/Assert.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 },
|
||||
|
39
src/utils/Assert.cpp
Normal file
39
src/utils/Assert.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Assert.cpp
|
||||
*
|
||||
* Created on: Nov 29, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#include <utils/Assert.h>
|
||||
#include <iostream>
|
||||
|
||||
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 */
|
||||
|
||||
|
30
src/utils/Assert.h
Normal file
30
src/utils/Assert.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Assert.h
|
||||
*
|
||||
* Created on: Nov 29, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef UTILS_ASSERT_H_
|
||||
#define UTILS_ASSERT_H_
|
||||
|
||||
#include <utils/Exceptions.h>
|
||||
|
||||
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_ */
|
45
src/utils/Exceptions.cpp
Normal file
45
src/utils/Exceptions.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Exceptions.cpp
|
||||
*
|
||||
* Created on: Nov 29, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#include <utils/Exceptions.h>
|
||||
|
||||
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 */
|
||||
|
77
src/utils/Exceptions.h
Normal file
77
src/utils/Exceptions.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Exceptions.h
|
||||
*
|
||||
* Created on: Nov 29, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef UTILS_EXCEPTIONS_H_
|
||||
#define UTILS_EXCEPTIONS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
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_ */
|
Loading…
Reference in New Issue
Block a user