Rendering player and tiles now works.

This commit is contained in:
Tiberiu Chibici 2016-11-27 13:53:18 +02:00
parent 914ae0de0d
commit 8173937797
35 changed files with 1160 additions and 230 deletions

View File

@ -7,9 +7,7 @@
<extensions> <extensions>
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/> <extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions> </extensions>
</storageModule> </storageModule>
@ -18,7 +16,7 @@
<folderInfo id="cdt.managedbuild.config.gnu.exe.debug.1767279125." name="/" resourcePath=""> <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"> <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"/> <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="cdt.managedbuild.target.gnu.builder.exe.debug.756240966" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.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"/>
<tool id="cdt.managedbuild.tool.gnu.archiver.base.1607221000" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/> <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"> <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.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"/>
@ -66,6 +64,11 @@
</configuration> </configuration>
</storageModule> </storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
<storageModule moduleId="de.marw.cdt.cmake.core.settings">
<options/>
<defs/>
<undefs/>
</storageModule>
</cconfiguration> </cconfiguration>
<cconfiguration id="cdt.managedbuild.config.gnu.exe.release.1609929883"> <cconfiguration id="cdt.managedbuild.config.gnu.exe.release.1609929883">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.release.1609929883" moduleId="org.eclipse.cdt.core.settings" name="Release"> <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.release.1609929883" moduleId="org.eclipse.cdt.core.settings" name="Release">

6
.directory Normal file
View File

@ -0,0 +1,6 @@
[Dolphin]
Timestamp=2016,11,11,20,21,5
Version=3
[Settings]
HiddenFilesShown=true

6
assets/levels/.directory Normal file
View File

@ -0,0 +1,6 @@
[Dolphin]
Timestamp=2016,11,26,16,53,1
Version=3
[Settings]
HiddenFilesShown=true

View File

@ -2,7 +2,7 @@
"cellWidth": 16, "cellWidth": 16,
"cellHeight": 16, "cellHeight": 16,
"layerCount" : 10, "layerCount" : 1,
"width" : 380, "width" : 380,
"height" : 213, "height" : 213,

BIN
assets/player/default.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
assets/ui/cursor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

BIN
assets_original/cursor.xcf Normal file

Binary file not shown.

View File

@ -113,6 +113,9 @@ if __name__ == '__main__':
RdirPrefix += "_" RdirPrefix += "_"
for f in files: for f in files:
if (f[0] == '.'):
continue
# Append to R # Append to R
fResName = RdirPrefix + capitalize(os.path.splitext(f)[0]) fResName = RdirPrefix + capitalize(os.path.splitext(f)[0])
r += " {0} = {1},\n".format(fResName, assetId) r += " {0} = {1},\n".format(fResName, assetId)

View File

@ -1,144 +0,0 @@
/*
* FarmlandsGame.cpp
*
* Created on: Nov 7, 2016
* Author: tibi
*/
#include "FarmlandsGame.h"
#include <resources/Resources.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <unistd.h>
#include <iostream>
namespace farmlands
{
FarmlandsGame::FarmlandsGame() :
m_running(true),
m_sdlWindow(nullptr),
m_sdlRenderer(nullptr)
{
}
bool FarmlandsGame::initialize()
{
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cerr << "Failed to initialize SDL!\n";
return false;
}
int imgFlags = IMG_INIT_PNG;
if (IMG_Init(IMG_INIT_PNG) != imgFlags) {
std::cerr << "Failed to initialize SDL_image!\n";
return false;
}
if (TTF_Init() != 0) {
std::cerr << "Failed to initialize SDL_ttf!\n";
return false;
}
m_sdlWindow = SDL_CreateWindow("Farmlands", 0, 0, 1024, 768, SDL_WINDOW_SHOWN);
if (!m_sdlWindow) {
std::cerr << "Failed to create main window!\n";
return false;
}
m_sdlRenderer = SDL_CreateRenderer(m_sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (!m_sdlRenderer) {
std::cerr << "Failed to create renderer!\n";
return false;
}
// Load resources
m_resourceManager.initialize(m_sdlRenderer);
m_resourceManager.loadLevel(resources::R::Levels::Farm);
return true;
}
void FarmlandsGame::onLogicUpdate()
{
}
void FarmlandsGame::onRender()
{
SDL_RenderClear(m_sdlRenderer);
SDL_Rect dest = { 0, 0, 0, 0};
SDL_QueryTexture(m_resourceManager.texture(resources::R::Tilesets::Ground), NULL, NULL, &dest.w, &dest.h);
dest.w *= 4;
dest.h *= 4;
SDL_RenderCopy(m_sdlRenderer, m_resourceManager.texture(resources::R::Tilesets::Ground), nullptr, &dest);
// Render loading screen
SDL_Delay(10);
SDL_RenderPresent(m_sdlRenderer);
}
void FarmlandsGame::onEvent(SDL_Event& event)
{
switch(event.type)
{
case SDL_QUIT:
stop();
break;
case SDL_KEYDOWN:
if (event.key.keysym.scancode == SDL_Scancode::SDL_SCANCODE_ESCAPE)
stop();
break;
case SDL_WINDOWEVENT_RESIZED:
break;
}
}
void FarmlandsGame::stop()
{
m_running = false;
}
void FarmlandsGame::dispose()
{
if (m_sdlRenderer)
SDL_DestroyRenderer(m_sdlRenderer);
if (m_sdlWindow)
SDL_DestroyWindow(m_sdlWindow);
SDL_Quit();
}
int FarmlandsGame::run()
{
// Initialize game
if (!initialize())
{
dispose();
return 1;
}
// Main loop
while(m_running)
{
SDL_Event event;
while (SDL_PollEvent(&event))
onEvent(event);
onLogicUpdate();
onRender();
}
// Cleanup
dispose();
return 0;
}
}

View File

@ -1,49 +0,0 @@
/*
* FarmlandsGame.h
*
* Created on: Nov 7, 2016
* Author: tibi
*/
#ifndef FARMLANDSGAME_H_
#define FARMLANDSGAME_H_
#include "resources/ResourceManager.h"
#include <SDL2/SDL.h>
namespace farmlands
{
enum GameState
{
Splash,
MainMenu,
Playing
};
class FarmlandsGame {
public:
int run();
FarmlandsGame();
protected:
bool initialize();
void onLogicUpdate();
void onRender();
void onEvent(SDL_Event& event);
void stop();
void dispose();
private:
bool m_running;
SDL_Window* m_sdlWindow;
SDL_Renderer* m_sdlRenderer;
//enum GameState m_state;
resources::ResourceManager m_resourceManager;
};
}
#endif /* FARMLANDSGAME_H_ */

68
src/GameState.h Normal file
View File

@ -0,0 +1,68 @@
/*
* GameState.h
*
* Created on: Nov 13, 2016
* Author: tibi
*/
#ifndef MODEL_GAMESTATE_H_
#define MODEL_GAMESTATE_H_
#include <model/Level.h>
#include <model/Player.h>
#include <model/GameConfig.h>
#include <graphics/SdlRenderer.h>
#include <graphics/GameRenderer.h>
#include <graphics/GuiRenderer.h>
#include <resources/ResourceManager.h>
#include <memory>
namespace farmlands {
struct ViewportState
{
bool initialized;
int width, height;
};
struct Camera
{
float posX, posY;
float scale;
};
struct GuiState
{
};
struct GameState
{
// Resource layer
resources::ResourceManager resManager;
// Graphics layer
graphics::SdlRenderer sdlRenderer;
graphics::GuiRenderer guiRenderer;
graphics::GameRenderer gameRenderer;
// Gui
GuiState gui;
// Settings
model::GameConfig gameConfig;
// Current game
ViewportState viewport;
Camera camera;
model::Player player;
model::Level* currentLevel;
float elapsedTime;
};
}
#endif /* MODEL_GAMESTATE_H_ */

View File

@ -1,7 +1,8 @@
#include "FarmlandsGame.h" #include <controller/FarmlandsGame.h>
using namespace farmlands; using namespace farmlands;
int main() int main()
{ {
return FarmlandsGame().run(); return controller::FarmlandsGame().run();
} }

View File

@ -0,0 +1,126 @@
/*
* FarmlandsGame.cpp
*
* Created on: Nov 7, 2016
* Author: tibi
*/
#include "FarmlandsGame.h"
#include <resources/Resources.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <unistd.h>
#include <iostream>
namespace farmlands {
namespace controller {
FarmlandsGame::FarmlandsGame() :
m_running(true),
m_gameState(),
m_time(0),
m_guiController(),
m_playerController()
{
}
bool FarmlandsGame::initialize()
{
// Initialize game state
m_gameState.viewport.initialized = false;
m_gameState.camera.scale = 4;
// Initialize render system
if (!m_gameState.sdlRenderer.initialize(&m_gameState))
return false;
m_gameState.gameRenderer.initialize(&m_gameState);
m_gameState.guiRenderer.initialize(&m_gameState);
// Initialize controllers
m_guiController.initialize(&m_gameState);
m_playerController.initialize(&m_gameState);
// Initialize & load resources
m_gameState.resManager.initialize(&m_gameState);
m_gameState.resManager.loadGameAssets();
m_gameState.resManager.loadLevel(resources::R::Levels::Farm);
m_gameState.currentLevel = m_gameState.resManager.level(resources::R::Levels::Farm);
return true;
}
void FarmlandsGame::onUpdateLogic()
{
m_playerController.updateLogic();
}
void FarmlandsGame::onRender()
{
m_gameState.sdlRenderer.renderBegin();
m_gameState.gameRenderer.render();
m_gameState.guiRenderer.render();
m_gameState.sdlRenderer.renderEnd();
}
void FarmlandsGame::onEvent(SDL_Event& event)
{
// Let controllers handle event
if (m_guiController.processEvent(event))
return;
if (m_playerController.processEvent(event))
return;
// Nobody? Handle global events
switch(event.type)
{
case SDL_QUIT:
stop();
break;
case SDL_KEYDOWN:
if (event.key.keysym.scancode == SDL_Scancode::SDL_SCANCODE_ESCAPE)
stop();
break;
case SDL_WINDOWEVENT_RESIZED:
break;
}
}
void FarmlandsGame::stop()
{
m_running = false;
}
int FarmlandsGame::run()
{
// Initialize game
if (!initialize())
return 1;
// Main loop
while(m_running)
{
// Update elapsed time
Uint32 now = SDL_GetTicks();
m_gameState.elapsedTime = (now - m_time) * 0.001f;
m_time = now;
SDL_Event event;
while (SDL_PollEvent(&event))
onEvent(event);
onUpdateLogic();
onRender();
}
// Cleanup
return 0;
}
}
}

View File

@ -0,0 +1,49 @@
/*
* FarmlandsGame.h
*
* Created on: Nov 7, 2016
* Author: tibi
*/
#ifndef FARMLANDSGAME_H_
#define FARMLANDSGAME_H_
#include <GameState.h>
#include <controller/GuiController.h>
#include <controller/PlayerController.h>
#include <graphics/GameRenderer.h>
#include <graphics/SdlRenderer.h>
#include <resources/ResourceManager.h>
#include <SDL2/SDL.h>
namespace farmlands {
namespace controller {
class FarmlandsGame {
public:
int run();
FarmlandsGame();
protected:
bool initialize();
void onUpdateLogic();
void onRender();
void onEvent(SDL_Event& event);
void stop();
private:
bool m_running;
GameState m_gameState;
Uint32 m_time;
GuiController m_guiController;
PlayerController m_playerController;
};
}
}
#endif /* FARMLANDSGAME_H_ */

View File

@ -0,0 +1,39 @@
/*
* GuiController.cpp
*
* Created on: Nov 26, 2016
* Author: tibi
*/
#include <controller/GuiController.h>
#include <cassert>
namespace farmlands
{
namespace controller
{
GuiController::GuiController()
: m_gameState(nullptr)
{
}
GuiController::~GuiController()
{
}
void GuiController::initialize(GameState* gameState)
{
assert(gameState != nullptr);
m_gameState = gameState;
}
bool GuiController::processEvent(SDL_Event& event)
{
return false;
}
} /* namespace controller */
} /* namespace farmlands */

View File

@ -0,0 +1,43 @@
/*
* GuiController.h
*
* Created on: Nov 26, 2016
* Author: tibi
*/
#ifndef CONTROLLER_GUICONTROLLER_H_
#define CONTROLLER_GUICONTROLLER_H_
#include <SDL2/SDL.h>
namespace farmlands {
// Forward declarations
struct GameState;
namespace controller {
class GuiController
{
public:
GuiController();
virtual ~GuiController();
/**
* Initializes game renderer
*/
void initialize(GameState* gameState);
/**
* Processes an UI event
*/
bool processEvent(SDL_Event& event);
private:
GameState* m_gameState;
};
} /* namespace controller */
} /* namespace farmlands */
#endif /* CONTROLLER_GUICONTROLLER_H_ */

View File

@ -0,0 +1,88 @@
/*
* PlayerController.cpp
*
* Created on: Nov 27, 2016
* Author: tibi
*/
#include <GameState.h>
#include <controller/PlayerController.h>
#include <cassert>
namespace farmlands
{
namespace controller
{
PlayerController::PlayerController()
: m_gameState(nullptr)
{
}
PlayerController::~PlayerController()
{
}
void PlayerController::initialize(GameState* gameState)
{
assert(gameState != nullptr);
m_gameState = gameState;
}
bool PlayerController::processEvent(SDL_Event& event)
{
return false;
}
void PlayerController::updateLogic()
{
// Get keyboard status
const Uint8* keys = SDL_GetKeyboardState(NULL);
const SDL_Keymod mods = SDL_GetModState();
float deltaX = 0;
float deltaY = 0;
// Compute movement delta multiplier
float deltaMultiplier = 5.0f * m_gameState->elapsedTime; // Equivalent to units per second
if ((mods & KMOD_LSHIFT) || (mods & KMOD_RSHIFT))
deltaMultiplier *= 5;
// Handle scale changes (debugging only)
if (keys[SDL_SCANCODE_KP_MINUS])
m_gameState->camera.scale *= 1.0f - 0.05f * deltaMultiplier;
if (keys[SDL_SCANCODE_KP_PLUS])
m_gameState->camera.scale *= 1.0f + 0.05f * deltaMultiplier;
// Handle movement
if (keys[SDL_SCANCODE_UP])
deltaY -= 1;
if (keys[SDL_SCANCODE_DOWN])
deltaY += 1;
if (keys[SDL_SCANCODE_LEFT])
deltaX -= 1;
if (keys[SDL_SCANCODE_RIGHT])
deltaX += 1;
float newX = m_gameState->player.posX + deltaX * deltaMultiplier;
float newY = m_gameState->player.posY + deltaY * deltaMultiplier;
if (canMove(newX, newY))
{
m_gameState->player.posX = newX;
m_gameState->player.posY = newY;
m_gameState->camera.posX = m_gameState->player.posX;
m_gameState->camera.posY = m_gameState->player.posY - 1;
}
}
bool PlayerController::canMove(float x, float y)
{
// TODO: check collisions & stuff. For now, nothing
return true;
}
} /* namespace controller */
} /* namespace farmlands */

View File

@ -0,0 +1,52 @@
/*
* PlayerController.h
*
* Created on: Nov 27, 2016
* Author: tibi
*/
#ifndef CONTROLLER_PLAYERCONTROLLER_H_
#define CONTROLLER_PLAYERCONTROLLER_H_
#include <SDL2/SDL.h>
namespace farmlands {
// Forward declarations
struct GameState;
namespace controller {
class PlayerController
{
public:
PlayerController();
virtual ~PlayerController();
/**
* Initializes game renderer
*/
void initialize(GameState* gameState);
/**
* Processes an event.
*
* @returns true if the event was handled, or false otherwise.
*/
bool processEvent(SDL_Event& event);
/**
* Called at the update logic step for every frame
*/
void updateLogic();
private:
bool canMove(float x, float y);
GameState* m_gameState;
};
} /* namespace controller */
} /* namespace farmlands */
#endif /* CONTROLLER_PLAYERCONTROLLER_H_ */

View File

@ -0,0 +1,146 @@
/*
* GameRenderer.cpp
*
* Created on: Nov 13, 2016
* Author: tibi
*/
#include <GameState.h>
#include <graphics/GameRenderer.h>
#include <math/GameMath.h>
#include <resources/Resources.h>
namespace farmlands {
namespace graphics {
GameRenderer::GameRenderer()
: m_gameState(nullptr)
{
}
GameRenderer::~GameRenderer()
{
}
void GameRenderer::initialize(GameState* gameState)
{
m_gameState = gameState;
}
void GameRenderer::render()
{
prepareRender();
renderTileLayers();
renderPlayer();
}
void GameRenderer::prepareRender()
{
m_cellW = m_gameState->currentLevel->m_cellWidth * m_gameState->camera.scale;
m_cellH = m_gameState->currentLevel->m_cellHeight * m_gameState->camera.scale;
}
void GameRenderer::renderTileLayers()
{
// Compute how many cells fit on the screen
float cellsOnScreenX = m_gameState->viewport.width / m_cellW;
float cellsOnScreenY = m_gameState->viewport.height / m_cellH;
int minCellX = floorf(m_gameState->camera.posX - cellsOnScreenX / 2);
int minCellY = floorf(m_gameState->camera.posY - cellsOnScreenY / 2);
int maxCellX = ceilf(m_gameState->camera.posX + cellsOnScreenX / 2);
int maxCellY = ceilf(m_gameState->camera.posY + cellsOnScreenY / 2);
// Clamp cell positions
minCellX = clamp(minCellX, 0, (int)m_gameState->currentLevel->columnCount() - 1);
minCellY = clamp(minCellY, 0, (int)m_gameState->currentLevel->rowCount() - 1);
maxCellX = clamp(maxCellX, 0, (int)m_gameState->currentLevel->columnCount() - 1);
maxCellY = clamp(maxCellY, 0, (int)m_gameState->currentLevel->rowCount() - 1);
// Draw each layer
for (size_t i = 0; i < m_gameState->currentLevel->layerCount(); i++)
{
int textureId = m_gameState->currentLevel->texture(i);
// Render only visible tiles
for (int y = minCellY; y <= maxCellY; y++)
for (int x = minCellX; x <= maxCellX; x++)
{
int cellId = m_gameState->currentLevel->cell(i, y, x);
// Obtain texture
int texWidth, texHeight;
SDL_Texture* texture = m_gameState->resManager.texture(textureId);
SDL_QueryTexture(texture, NULL, NULL, &texWidth, &texHeight);
// Compute texture coordinates
int cellCol = (cellId * m_gameState->currentLevel->m_cellWidth) % texWidth;
int cellRow = ((cellId * m_gameState->currentLevel->m_cellWidth) / texWidth) * m_gameState->currentLevel->m_cellHeight;
// Calculate source position
SDL_Rect src =
{
cellCol,
cellRow,
(int) m_gameState->currentLevel->m_cellWidth,
(int) m_gameState->currentLevel->m_cellHeight
};
// Calculate destination position
SDL_Rect dest =
{
(int) xToScreen(x),
(int) yToScreen(y),
(int) ceilf(m_cellW),
(int) ceilf(m_cellH)
};
// Blit
SDL_RenderCopy(m_gameState->sdlRenderer.internalRenderer(), texture, &src, &dest);
}
}
}
void GameRenderer::renderPlayer()
{
float posX = xToScreen(m_gameState->player.posX);
float posY = yToScreen(m_gameState->player.posY);
// Obtain texture
int texWidth, texHeight;
SDL_Texture* playerTexture = m_gameState->resManager.texture(resources::R::Player::Default);
SDL_QueryTexture(playerTexture, NULL, NULL, &texWidth, &texHeight);
// Draw using bottom center of texture as anchor point
SDL_Rect dest =
{
(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),
};
SDL_RenderCopy(m_gameState->sdlRenderer.internalRenderer(), playerTexture, NULL, &dest);
}
float GameRenderer::xToWorld(float x)
{
return (x - m_gameState->viewport.width / 2) / m_cellW + m_gameState->camera.posX;
}
float GameRenderer::yToWorld(float y)
{
return (y - m_gameState->viewport.height / 2) / m_cellH + m_gameState->camera.posY;
}
float GameRenderer::xToScreen(float x)
{
return (x - m_gameState->camera.posX) * m_cellW + m_gameState->viewport.width / 2;
}
float GameRenderer::yToScreen(float y)
{
return (y - m_gameState->camera.posY) * m_cellH + m_gameState->viewport.height / 2;
}
} /* namespace graphics */
} /* namespace farmlands */

View File

@ -0,0 +1,60 @@
/*
* GameRenderer.h
*
* Created on: Nov 13, 2016
* Author: tibi
*/
#ifndef GRAPHICS_GAMERENDERER_H_
#define GRAPHICS_GAMERENDERER_H_
#include <graphics/SdlRenderer.h>
#include <resources/ResourceManager.h>
#include <memory>
#include <SDL2/SDL.h>
namespace farmlands {
// Forward declarations
struct GameState;
namespace graphics {
class GameRenderer
{
public:
GameRenderer();
virtual ~GameRenderer();
/**
* Initializes game renderer
*/
void initialize(GameState* gameState);
/**
* Renders everything
*/
void render();
private:
void prepareRender();
void renderTileLayers();
void renderPlayer();
float xToWorld(float x);
float yToWorld(float y);
float xToScreen(float x);
float yToScreen(float y);
GameState* m_gameState;
// Size of a cell (scaled)
float m_cellW, m_cellH;
};
} /* namespace graphics */
} /* namespace farmlands */
#endif /* GRAPHICS_GAMERENDERER_H_ */

View File

@ -0,0 +1,72 @@
/*
* GuiRenderer.cpp
*
* Created on: Nov 13, 2016
* Author: tibi
*/
#include <GameState.h>
#include <graphics/GuiRenderer.h>
#include <resources/Resources.h>
#include <sstream>
#include <SDL2/SDL.h>
namespace farmlands
{
namespace graphics
{
GuiRenderer::GuiRenderer()
: m_gameState(nullptr),
m_fps(0),
m_fpsIndex(0)
{
}
GuiRenderer::~GuiRenderer()
{
}
void GuiRenderer::initialize(GameState* gameState)
{
m_gameState = gameState;
}
void GuiRenderer::render()
{
computeFps();
// Prepare stuff
TTF_Font* font = m_gameState->resManager.font(resources::R::Fonts::DejaVuSans, 10);
SDL_Color white = { 255, 255, 255, 255 };
SDL_Rect dest = { 10, 10, 0, 0 };
// Figure out what text to print
std::stringstream textStream;
textStream << "FPS: " << m_fps;
// Render text
SDL_Texture* fpsText = m_gameState->sdlRenderer.renderText(textStream.str(), font, white);
SDL_QueryTexture(fpsText, NULL, NULL, &dest.w, &dest.h);
SDL_RenderCopy(m_gameState->sdlRenderer.internalRenderer(), fpsText, NULL, &dest);
}
void GuiRenderer::computeFps()
{
// Compute FPS
m_fpsVals[m_fpsIndex++] = 1.0f / m_gameState->elapsedTime;
if (m_fpsIndex >= GUIRENDERER_FPS_VALS)
{
m_fpsIndex = 0;
m_fps = 0;
for (int i = 0; i < GUIRENDERER_FPS_VALS; i++)
m_fps += m_fpsVals[i];
m_fps /= GUIRENDERER_FPS_VALS;
}
}
} /* namespace graphics */
} /* namespace farmlands */

View File

@ -0,0 +1,48 @@
/*
* GuiRenderer.h
*
* Created on: Nov 13, 2016
* Author: tibi
*/
#ifndef GRAPHICS_GUIRENDERER_H_
#define GRAPHICS_GUIRENDERER_H_
#define GUIRENDERER_FPS_VALS 30
namespace farmlands {
// Forward declarations
struct GameState;
namespace graphics {
class GuiRenderer
{
public:
GuiRenderer();
virtual ~GuiRenderer();
/**
* Initializes game renderer
*/
void initialize(GameState* gameState);
/**
* Renders the GUI
*/
void render();
private:
void computeFps();
GameState* m_gameState;
float m_fpsVals[GUIRENDERER_FPS_VALS];
float m_fps;
int m_fpsIndex;
};
} /* namespace graphics */
} /* namespace farmlands */
#endif /* GRAPHICS_GUIRENDERER_H_ */

View File

@ -0,0 +1,105 @@
/*
* SdlRenderer.cpp
*
* Created on: Nov 13, 2016
* Author: tibi
*/
#include <GameState.h>
#include <graphics/SdlRenderer.h>
#include <iostream>
#include <cassert>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
namespace farmlands
{
namespace graphics
{
SdlRenderer::SdlRenderer()
: m_sdlWindow(nullptr),
m_sdlRenderer(nullptr),
m_gameState(nullptr)
{
}
SdlRenderer::~SdlRenderer()
{
if (m_sdlRenderer)
SDL_DestroyRenderer(m_sdlRenderer);
if (m_sdlWindow)
SDL_DestroyWindow(m_sdlWindow);
SDL_Quit();
}
bool SdlRenderer::initialize(GameState* gameState)
{
m_gameState = gameState;
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cerr << "Failed to initialize SDL!\n";
return false;
}
int imgFlags = IMG_INIT_PNG;
if (IMG_Init(IMG_INIT_PNG) != imgFlags) {
std::cerr << "Failed to initialize SDL_image!\n";
return false;
}
if (TTF_Init() != 0) {
std::cerr << "Failed to initialize SDL_ttf!\n";
return false;
}
m_gameState->viewport.width = 1024;
m_gameState->viewport.height = 768;
m_sdlWindow = SDL_CreateWindow("Farmlands", 0, 0, m_gameState->viewport.width, m_gameState->viewport.height, SDL_WINDOW_SHOWN);
if (!m_sdlWindow) {
std::cerr << "Failed to create main window!\n";
return false;
}
m_sdlRenderer = SDL_CreateRenderer(m_sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (!m_sdlRenderer) {
std::cerr << "Failed to create renderer!\n";
return false;
}
return true;
}
void SdlRenderer::renderBegin()
{
SDL_RenderClear(m_sdlRenderer);
}
void SdlRenderer::renderEnd()
{
SDL_RenderPresent(m_sdlRenderer);
}
SDL_Texture* SdlRenderer::renderText(const std::string& text, TTF_Font* font, SDL_Color color)
{
assert(font != nullptr);
SDL_Surface* surface = TTF_RenderText_Blended(font, text.c_str(), color);
if (surface == nullptr)
return nullptr;
SDL_Texture* texture = SDL_CreateTextureFromSurface(m_sdlRenderer, surface);
SDL_FreeSurface(surface);
return texture;
}
} /* namespace graphics */
} /* namespace farmlands */

View File

@ -0,0 +1,68 @@
/*
* SdlRenderer.h
*
* Created on: Nov 13, 2016
* Author: tibi
*/
#ifndef GRAPHICS_SDLRENDERER_H_
#define GRAPHICS_SDLRENDERER_H_
#include <string>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
namespace farmlands {
// Forward declarations
struct GameState;
namespace graphics {
class SdlRenderer
{
public:
SdlRenderer();
virtual ~SdlRenderer();
/**
* Initializes the game renderer.
*
* @returns true if successful, false otherwise.
*/
bool initialize(GameState* gameState);
/**
* Performs steps for beginning to render.
*/
void renderBegin();
/**
* Performs steps for ending a render.
*/
void renderEnd();
/**
* Renders given text to a texture
*/
SDL_Texture* renderText(const std::string& text, TTF_Font* font, SDL_Color color);
// Getters
/**
* Gets the internal SDL renderer object;
*/
SDL_Renderer* internalRenderer() { return m_sdlRenderer; }
private:
SDL_Window* m_sdlWindow;
SDL_Renderer* m_sdlRenderer;
GameState* m_gameState;
};
} /* namespace graphics */
} /* namespace farmlands */
#endif /* GRAPHICS_SDLRENDERER_H_ */

10
src/math/GameMath.cpp Normal file
View File

@ -0,0 +1,10 @@
/*
* Math.cpp
*
* Created on: Nov 26, 2016
* Author: tibi
*/
#include <math/GameMath.h>

25
src/math/GameMath.h Normal file
View File

@ -0,0 +1,25 @@
/*
* Math.h
*
* Created on: Nov 26, 2016
* Author: tibi
*/
#ifndef MATH_GAMEMATH_H_
#define MATH_GAMEMATH_H_
template<typename TVal, typename TMin, typename TMax>
TVal clamp (TVal value, TMin min, TMax max)
{
if (value < min)
return min;
if (value > max)
return max;
return value;
}
#endif /* MATH_GAMEMATH_H_ */

18
src/model/GameConfig.h Normal file
View File

@ -0,0 +1,18 @@
/*
* Settings.h
*
* Created on: Nov 13, 2016
* Author: tibi
*/
namespace farmlands {
namespace model {
struct GameConfig
{
float graphics_Scale;
float graphics_UiScale;
};
}
}

View File

@ -12,7 +12,10 @@ namespace farmlands {
namespace model { namespace model {
Level::Level(size_t layerCount, size_t rowCount, size_t columnCount) Level::Level(size_t layerCount, size_t rowCount, size_t columnCount)
: m_cells(new Cell[layerCount * rowCount * columnCount]), : m_cellWidth(0),
m_cellHeight(0),
m_cells(new Cell[layerCount * rowCount * columnCount]),
m_textures(new int[layerCount]),
m_layers(layerCount), m_layers(layerCount),
m_rows(rowCount), m_rows(rowCount),
m_columns(columnCount) m_columns(columnCount)
@ -22,6 +25,7 @@ Level::Level(size_t layerCount, size_t rowCount, size_t columnCount)
Level::~Level() Level::~Level()
{ {
delete[] m_cells; delete[] m_cells;
delete[] m_textures;
} }
@ -43,6 +47,16 @@ void Level::setCell(size_t layer, size_t row, size_t col, Cell value)
m_cells[layer * m_rows * m_columns + row * m_columns + col] = value; m_cells[layer * m_rows * m_columns + row * m_columns + col] = value;
} }
int Level::texture(size_t layer) const
{
return m_textures[layer];
}
void Level::setTexture(size_t layer, int textureId) const
{
m_textures[layer] = textureId;
}
} /* namespace model */ } /* namespace model */
} /* namespace farmlands */ } /* namespace farmlands */

View File

@ -32,10 +32,14 @@ namespace model {
Cell cell(size_t layer, size_t row, size_t col) const; Cell cell(size_t layer, size_t row, size_t col) const;
void setCell(size_t layer, size_t row, size_t col, Cell value); void setCell(size_t layer, size_t row, size_t col, Cell value);
int texture(size_t layer) const;
void setTexture(size_t layer, int textureId) const;
size_t m_cellWidth, m_cellHeight; size_t m_cellWidth, m_cellHeight;
private: private:
Cell* m_cells; Cell* m_cells;
int* m_textures;
size_t m_layers; size_t m_layers;
size_t m_rows; size_t m_rows;
size_t m_columns; size_t m_columns;

View File

@ -1,7 +1,7 @@
/* /*
* Player.h * Player.h
* *
* Created on: Nov 12, 2016 * Created on: Nov 26, 2016
* Author: tibi * Author: tibi
*/ */
@ -11,9 +11,12 @@
namespace farmlands { namespace farmlands {
namespace model { namespace model {
#define PLAYER_INVENTORY_SIZE 3*12
struct Player struct Player
{ {
float posX, posY; float posX, posY;
int inventory[PLAYER_INVENTORY_SIZE];
}; };
} }

View File

@ -20,15 +20,26 @@
#include <SDL2/SDL_ttf.h> #include <SDL2/SDL_ttf.h>
namespace farmlands { namespace farmlands {
// Forward declaration
struct GameState;
namespace resources { namespace resources {
union LoadedResource struct LoadedResource
{
bool loaded;
union
{ {
struct struct
{ {
SDL_Surface* m_surface; SDL_Surface* surface;
SDL_Texture* m_texture; SDL_Texture* texture;
} texture; } texture;
model::Level* level;
};
}; };
class ResourceManager class ResourceManager
@ -36,14 +47,16 @@ namespace resources {
public: public:
ResourceManager(); ResourceManager();
virtual ~ResourceManager(); virtual ~ResourceManager();
void initialize(SDL_Renderer* renderer); void initialize(GameState* gameState);
// Loading routines // Loading routines
void loadMainMenu(); void loadMainMenu();
void loadGameAssets();
void loadLevel(int levelId); void loadLevel(int levelId);
TTF_Font* font(int id, int pointSize); TTF_Font* font(int id, int pointSize);
SDL_Texture* texture(int id); SDL_Texture* texture(int id);
model::Level* level(int id);
private: private:
/** /**
@ -60,7 +73,7 @@ namespace resources {
/** /**
* Loads the cell data for a level tile layer. * Loads the cell data for a level tile layer.
*/ */
void loadLevelLayer(std::shared_ptr<model::Level> level, size_t layerNumber, int resourceId); void loadLevelLayer(model::Level* level, size_t layerNumber, int resourceId);
/** /**
* Loads a texture into memory. * Loads a texture into memory.
@ -68,11 +81,10 @@ namespace resources {
void loadTexture(int textureId); void loadTexture(int textureId);
void loadFont(int fontId, int pointSize); void loadFont(int fontId, int pointSize);
// SDL Renderer // State
SDL_Renderer* m_renderer; GameState* m_gameState;
// Loaded resources // Loaded resources
std::shared_ptr<model::Level> m_loadedLevel;
LoadedResource* m_loadedResources; LoadedResource* m_loadedResources;
typedef int FontId; typedef int FontId;

View File

@ -18,26 +18,55 @@ namespace farmlands {
namespace resources { namespace resources {
ResourceManager::ResourceManager() ResourceManager::ResourceManager()
: m_renderer(nullptr), : m_gameState(nullptr),
m_loadedLevel(nullptr),
m_loadedResources(new LoadedResource[sizeof(RInfo) / sizeof(RInfo[0])]) m_loadedResources(new LoadedResource[sizeof(RInfo) / sizeof(RInfo[0])])
{ {
for(size_t i = 0; i < sizeof(RInfo) / sizeof(RInfo[0]); i++)
m_loadedResources[i].loaded = false;
} }
ResourceManager::~ResourceManager() ResourceManager::~ResourceManager()
{ {
// Unload resources
for(size_t i = 0; i < sizeof(RInfo) / sizeof(RInfo[0]); i++)
{
if (m_loadedResources[i].loaded)
{
switch(RInfo[i].type)
{
case ResourceType::Level:
delete m_loadedResources[i].level;
break;
case ResourceType::Texture:
SDL_DestroyTexture(m_loadedResources[i].texture.texture);
SDL_FreeSurface(m_loadedResources[i].texture.surface);
break;
default:
assert(false);
break;
}
}
}
delete[] m_loadedResources; delete[] m_loadedResources;
} }
void ResourceManager::initialize(SDL_Renderer* renderer) void ResourceManager::initialize(GameState* gameState)
{ {
m_renderer = renderer; m_gameState = gameState;
} }
void ResourceManager::loadMainMenu() void ResourceManager::loadMainMenu()
{ {
} }
void ResourceManager::loadGameAssets()
{
loadTexture(R::Player::Default);
}
TTF_Font* ResourceManager::font(int id, int pointSize) TTF_Font* ResourceManager::font(int id, int pointSize)
{ {
// Open from cache // Open from cache
@ -46,7 +75,7 @@ TTF_Font* ResourceManager::font(int id, int pointSize)
return it->second; return it->second;
// Open font // Open font
TTF_Font* font = TTF_OpenFont(RInfo[id].path, pointSize); TTF_Font* font = TTF_OpenFont(getPath(id).c_str(), pointSize);
m_fontCache.emplace(FONTID(id, pointSize), font); m_fontCache.emplace(FONTID(id, pointSize), font);
return font; return font;
@ -76,3 +105,5 @@ int ResourceManager::getId(std::string resPathStr)
} /* namespace storage */ } /* namespace storage */
} /* namespace farmlands */ } /* namespace farmlands */

View File

@ -18,7 +18,7 @@ using namespace nlohmann;
namespace farmlands { namespace farmlands {
namespace resources { namespace resources {
void ResourceManager::loadLevelLayer(std::shared_ptr<model::Level> level, size_t layer, int resourceId) void ResourceManager::loadLevelLayer(model::Level* level, size_t layer, int resourceId)
{ {
assert(RInfo[resourceId].type == ResourceType::LevelLayer); assert(RInfo[resourceId].type == ResourceType::LevelLayer);
@ -71,7 +71,7 @@ void ResourceManager::loadLevel(int levelId)
size_t colCount = levelJs.value("width", 0u); size_t colCount = levelJs.value("width", 0u);
assert(layerCount > 0 && rowCount > 0 && colCount > 0); assert(layerCount > 0 && rowCount > 0 && colCount > 0);
std::shared_ptr<model::Level> level(new model::Level(layerCount, rowCount, colCount)); model::Level* level = new model::Level(layerCount, rowCount, colCount);
level->m_cellWidth = levelJs.value("cellWidth", 0u); level->m_cellWidth = levelJs.value("cellWidth", 0u);
level->m_cellHeight = levelJs.value("cellHeight", 0u); level->m_cellHeight = levelJs.value("cellHeight", 0u);
@ -86,10 +86,20 @@ void ResourceManager::loadLevel(int levelId)
loadLevelLayer(level, layer, getId(cellsFileName)); loadLevelLayer(level, layer, getId(cellsFileName));
std::string textureFileName = it->value("textureFile", std::string()); std::string textureFileName = it->value("textureFile", std::string());
loadTexture(getId(textureFileName)); int textureId = getId(textureFileName);
level->setTexture(layer, textureId);
loadTexture(textureId);
} }
m_loadedLevel = level; m_loadedResources[levelId].loaded = true;
m_loadedResources[levelId].level = level;
}
model::Level* ResourceManager::level(int id)
{
assert(RInfo[id].type == ResourceType::Level);
return m_loadedResources[id].level;
} }
} }

View File

@ -4,7 +4,7 @@
* Created on: Nov 12, 2016 * Created on: Nov 12, 2016
* Author: tibi * Author: tibi
*/ */
#include <GameState.h>
#include <resources/ResourceManager.h> #include <resources/ResourceManager.h>
#include <resources/Resources.h> #include <resources/Resources.h>
@ -22,18 +22,19 @@ void ResourceManager::loadTexture(int resourceId)
if (surface == NULL) if (surface == NULL)
throw 0; // TODO: error handling throw 0; // TODO: error handling
SDL_Texture* texture = SDL_CreateTextureFromSurface(m_renderer, surface); SDL_Texture* texture = SDL_CreateTextureFromSurface(m_gameState->sdlRenderer.internalRenderer(), surface);
if (texture == NULL) if (texture == NULL)
throw 0; // TODO: error handling throw 0; // TODO: error handling
m_loadedResources[resourceId].texture.m_surface = surface; m_loadedResources[resourceId].loaded = true;
m_loadedResources[resourceId].texture.m_texture = texture; m_loadedResources[resourceId].texture.surface = surface;
m_loadedResources[resourceId].texture.texture = texture;
} }
SDL_Texture* ResourceManager::texture(int id) SDL_Texture* ResourceManager::texture(int id)
{ {
assert(RInfo[id].type == ResourceType::Texture); assert(RInfo[id].type == ResourceType::Texture);
return m_loadedResources[id].texture.m_texture; return m_loadedResources[id].texture.texture;
} }
} }

View File

@ -16,27 +16,39 @@ namespace resources {
{ {
DejaVuSans = 0, DejaVuSans = 0,
}; };
enum Player
{
Default = 1,
};
enum Tilesets enum Tilesets
{ {
Ground = 1, Ground = 2,
};
enum Ui
{
Cursor = 3,
}; };
enum Levels enum Levels
{ {
Farm_Background = 2, Farm_Background = 4,
Farm = 3, Farm = 5,
}; };
} }
const int RInfo_Fonts_Begin = 0; const int RInfo_Fonts_Begin = 0;
const int RInfo_Tilesets_Begin = 1; const int RInfo_Player_Begin = 1;
const int RInfo_Levels_Begin = 2; const int RInfo_Tilesets_Begin = 2;
const int RInfo_Ui_Begin = 3;
const int RInfo_Levels_Begin = 4;
/** /**
* This array contains the names of all the files, and the corresponding file type. * This array contains the names of all the files, and the corresponding file type.
*/ */
const ResourceInfo RInfo[] = { const ResourceInfo RInfo[] = {
{ "fonts/DejaVuSans.ttf", ResourceType::Font }, { "fonts/DejaVuSans.ttf", ResourceType::Font },
{ "player/default.png", ResourceType::Texture },
{ "tilesets/Ground.png", ResourceType::Texture }, { "tilesets/Ground.png", ResourceType::Texture },
{ "ui/cursor.png", ResourceType::Texture },
{ "levels/Farm_Background.csv", ResourceType::LevelLayer }, { "levels/Farm_Background.csv", ResourceType::LevelLayer },
{ "levels/Farm.level", ResourceType::Level }, { "levels/Farm.level", ResourceType::Level },
}; };