Entities are now constructable

Added utility function to display error window
Added textures
Added font
Added a way to choose resources location
This commit is contained in:
Teo-CD 2019-06-07 22:20:34 +02:00
parent 46d26b6e61
commit 3666b9e7e9
17 changed files with 155 additions and 39 deletions

View file

@ -13,11 +13,11 @@ This game is aimed to be a puzzle game in which the player sets different laws f
- [ ] Level - [ ] Level
- [x] Structure - [x] Structure
- [ ] Parsing from XML - [x] Parsing from XML
- [ ] A* - [ ] A*
- [ ] Entities - [ ] Entities
- [x] Structure - [x] Structure
- [ ] Parsing from XML - [x] Parsing from XML
- [ ] Moving - [ ] Moving
- [ ] Decorators (Rules) - [ ] Decorators (Rules)
- [ ] Rules - [ ] Rules
@ -25,7 +25,7 @@ This game is aimed to be a puzzle game in which the player sets different laws f
- [ ] Interaction with entities - [ ] Interaction with entities
- [ ] Parsing of rules and creation of subsequent decorators - [ ] Parsing of rules and creation of subsequent decorators
- [ ] Graphics - [ ] Graphics
- [ ] Scene rendering - [x] Scene rendering
- [ ] UI - [ ] UI
- [ ] Menu ? - [ ] Menu ?
- [ ] Gameloop - [ ] Gameloop

BIN
resources/Building.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

BIN
resources/Head_Boy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 770 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

View file

@ -2,5 +2,6 @@
<Level w="10" h="10" textureId="0"> <Level w="10" h="10" textureId="0">
<Entity x="0" y="0" type="Citizen"/> <Entity x="0" y="0" type="Citizen"/>
<Entity x="0" y="1" type="Citizen"/> <Entity x="0" y="1" type="Citizen"/>
<Entity x="1" y="1" type="House"/> <Entity x="10" y="10" type="Significant" textureId="1"/>
<Entity x="1" y="1" w="8" h="8" type="House" textureId="2"/>
</Level> </Level>

BIN
resources/verdana.ttf Normal file

Binary file not shown.

View file

@ -4,9 +4,10 @@ project(project_maat)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules" ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules" ${CMAKE_MODULE_PATH})
add_library(engine Level.cpp Level.h Entity.cpp Entity.h Game.cpp Game.h Utils.h Utils.h) add_library(engine Level.cpp Level.h Entity.cpp Entity.h Game.cpp Game.h Utils.h Utils.h Utils.cpp)
target_link_libraries(engine target_link_libraries(engine
sfml-window sfml-window
sfml-graphics sfml-graphics
sfml-system) sfml-system
pugixml)

View file

@ -6,28 +6,37 @@
const std::map<std::string,EntityType> Entity::entityTypeLookup = { const std::map<std::string,EntityType> Entity::entityTypeLookup = {
{"Citizen",EntityType::Citizen}, {"Citizen",EntityType::Citizen},
{"Player",EntityType::Player}, {"Significant",EntityType::Significant},
{"House",EntityType::House}, {"House",EntityType::House},
{"Car",EntityType::Car}}; {"Car",EntityType::Car}};
Entity::Entity(int x, int y, EntityType type, int width, int height) Entity::Entity(int x, int y, EntityType type, sf::Texture* texture, int width, int height) : type(type)
{ {
shape = sf::RectangleShape(sf::Vector2f(width*pro_maat::pixelsPerUnit,height*pro_maat::pixelsPerUnit));
// Sets the origin at the center of the entity
shape.setOrigin(shape.getSize()/2.0f);
// Adjust position for offset origin
shape.setPosition((x+0.5*width)*pro_maat::pixelsPerUnit,(y+0.5*width)*pro_maat::pixelsPerUnit);
shape.setTexture(texture);
currentState = State::Idle;
nextState = State::Idle;
target = sf::Vector2i(shape.getPosition());
nextTarget = target;
} }
Entity::Entity(const pugi::xml_node& entityNode) Entity::Entity(const pugi::xml_node& entityNode, sf::Texture* texture)
{ : Entity(entityNode.attribute("x").as_int(),
entityNode.attribute("y").as_int(),
} entityTypeLookup.at(entityNode.attribute("type").as_string()),
texture,
void Entity::render(sf::RenderWindow& renderWindow) const entityNode.attribute("w").as_int(1),
{ entityNode.attribute("h").as_int(1)) {}
}
void Entity::move() void Entity::move()
{ {
// FIXME : Testing purposes
shape.setRotation(shape.getRotation()+90);
} }
void Entity::update() void Entity::update()

View file

@ -14,7 +14,7 @@
enum class EntityType enum class EntityType
{ {
Citizen, Citizen,
Player, Significant,
House, House,
Car, Car,
}; };
@ -40,10 +40,9 @@ class Entity
{ {
public: public:
/// x,y, width and height are in grid coordinates /// x,y, width and height are in grid coordinates
Entity(int x, int y, EntityType type, int width = 1, int height = 1); Entity(int x, int y, EntityType type, sf::Texture* texture, int width = 1, int height = 1);
Entity(const pugi::xml_node& entityNode); explicit Entity(const pugi::xml_node& entityNode, sf::Texture* texture);
void render(sf::RenderWindow& renderWindow) const;
void move(); void move();
void update(); void update();
@ -54,6 +53,8 @@ public:
private: private:
static const std::map<std::string,EntityType> entityTypeLookup; static const std::map<std::string,EntityType> entityTypeLookup;
EntityType type;
// As it contains position, size and orientation, we do not need anything more // As it contains position, size and orientation, we do not need anything more
sf::RectangleShape shape; sf::RectangleShape shape;

View file

@ -7,22 +7,22 @@
#include "Game.h" #include "Game.h"
Game::Game(const std::vector<std::string>& levels, const std::vector<std::string>& textures) Game::Game(std::vector<std::string>& levels, std::vector<std::string>& textures) : levelFiles(std::move(levels)),
textureFiles(std::move(textures))
{ {
loadTextures(); loadTextures();
} }
void Game::loadLevel(int levelId) void Game::loadLevel(int levelId)
{ {
pugi::xml_document document; pugi::xml_document document;
pugi::xml_parse_result result = document.load_file(levelFiles.at(levelId).c_str()); pugi::xml_parse_result result = document.load_file((pro_maat::levelFolder+levelFiles.at(levelId)).c_str());
if(!result) if(!result)
{ {
std::cerr << "Error while loading level :\n" << "\t" << result.description() << std::endl; // std::cerr << "Error while loading level :\n" << "\t" << result.description() << std::endl;
exit(-1); // exit(-1);
pro_maat::errorWindow(result.description());
} }
currentLevel = std::make_unique<Level>(document,textures); currentLevel = std::make_unique<Level>(document,textures);
@ -34,11 +34,37 @@ void Game::loadTextures()
for(const std::string& filePath : textureFiles) for(const std::string& filePath : textureFiles)
{ {
textures.emplace_back(std::make_unique<sf::Texture>()); textures.emplace_back(std::make_unique<sf::Texture>());
textures.back()->loadFromFile(filePath); textures.back()->loadFromFile(pro_maat::textureFolder+filePath);
} }
} }
void Game::runGame() void Game::runGame()
{ {
sf::RenderWindow window(sf::VideoMode(1280,1024),"Project Maat");
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close();
}
// FIXME : For testing purposes
if (event.type == sf::Event::KeyPressed)
{
currentLevel->runStep();
}
}
window.clear(sf::Color::White);
// TODO : Consider drawing in a sf::RenderTexture to allow positioning the level at a fixed position ?
currentLevel->render(window);
window.display();
}
}
Game::operator bool() const
{
return (currentLevel ? true : false);
} }

View file

@ -11,14 +11,14 @@
#include "Level.h" #include "Level.h"
#include "Entity.h" #include "Entity.h"
#include "Utils.h"
// Used for convenience // Used for convenience
using TextureStore = std::vector<std::unique_ptr<sf::Texture>>; using TextureStore = std::vector<std::unique_ptr<sf::Texture>>;
class Game { class Game {
public: public:
Game(const std::vector<std::string>& levels, const std::vector<std::string>& textures); Game(std::vector<std::string>& levels, std::vector<std::string>& textures);
/// Loads the level of corresponding ID from Game::levelFiles /// Loads the level of corresponding ID from Game::levelFiles
/// Closes the program if there is a fatal error (Missing file, bad file...) /// Closes the program if there is a fatal error (Missing file, bad file...)
@ -29,6 +29,8 @@ public:
// This should not be called before a level has been loaded // This should not be called before a level has been loaded
void runGame(); void runGame();
explicit operator bool() const;
private: private:
/// Store the paths to level files /// Store the paths to level files
const std::vector<std::string> levelFiles; const std::vector<std::string> levelFiles;

View file

@ -14,17 +14,24 @@ Level::Level(const pugi::xml_document& xmlDoc, const TextureStore& textureStore)
{ {
if(!strncmp(child.name(),"Entity",6)) if(!strncmp(child.name(),"Entity",6))
{ {
entities.emplace_back(child); entities.emplace_back(child,textures.at(child.attribute("textureId").as_int(0)).get());
} }
} }
} }
void Level::render(sf::RenderWindow& renderWindow) const void Level::render(sf::RenderWindow& renderWindow) const
{ {
for(const Entity& entity : entities)
{
renderWindow.draw(entity.getShape());
}
} }
void Level::runStep() const void Level::runStep()
{ {
for(Entity& entity: entities)
{
// FIXME : For testing purposes
entity.move();
}
} }

View file

@ -20,7 +20,7 @@ public:
Level(const pugi::xml_document& xmlDoc, const TextureStore& textureStore); Level(const pugi::xml_document& xmlDoc, const TextureStore& textureStore);
void render(sf::RenderWindow& renderWindow) const; void render(sf::RenderWindow& renderWindow) const;
void runStep() const; void runStep();
private: private:
const sf::Vector2i size; const sf::Vector2i size;

39
src/Utils.cpp Normal file
View file

@ -0,0 +1,39 @@
//
// Created by trotfunky on 07/06/19.
//
#include "Utils.h"
namespace pro_maat
{
void errorWindow(const std::string& error)
{
sf::Font font;
if(!font.loadFromFile(std::string(pro_maat::fontFolder)+"verdana.ttf"))
{
std::cerr << "Error while loading font for error :" << std::endl;
std::cerr << error << std::endl;
}
sf::Text errorMessage(error,font);
errorMessage.setFillColor(sf::Color::Red);
sf::Rect errorArea = errorMessage.getGlobalBounds();
errorMessage.setPosition(errorArea.width*(1.5/2-0.5),errorArea.height*(0.5));
sf::RenderWindow window(sf::VideoMode(errorArea.width*1.5,errorArea.height*2),"ERROR");
while (window.isOpen())
{
sf::Event event;
while(window.pollEvent(event))
{
if (event.type == sf::Event::Closed || event.type == sf::Event::KeyPressed || event.type == sf::Event::MouseButtonPressed)
{
window.close();
exit(-1);
}
}
window.clear(sf::Color::White);
window.draw(errorMessage);
window.display();
}
}
}

View file

@ -6,12 +6,19 @@
#define PROJECT_MAAT_UTILS_H #define PROJECT_MAAT_UTILS_H
#include <cstdint> #include <cstdint>
#include <string>
#include <SFML/Graphics.hpp>
#include <iostream>
namespace pro_maat namespace pro_maat
{ {
static constexpr uint8_t pixelsPerUnit = 20; static constexpr uint8_t pixelsPerUnit = 25;
static constexpr char levelFolder[] = "resources/";
static constexpr char textureFolder[] = "resources/";
static constexpr char fontFolder[] = "resources/";
void errorWindow(const std::string& error);
} }

View file

@ -6,7 +6,13 @@ set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules" ${CMAKE_MODULE_PATH})
add_executable(gTests gTests.cpp gTests.cpp) add_executable(gTests gTests.cpp gTests.cpp)
target_include_directories(gTests PRIVATE ${PROJECT_SOURCE_DIR}/../src)
target_link_libraries(gTests target_link_libraries(gTests
engine engine
gtest gtest
pthread) pthread
sfml-window
sfml-graphics
sfml-system
pugixml)

View file

@ -3,6 +3,23 @@
// //
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <vector>
#include "Game.h"
TEST(Setup,LevelSetup)
{
// TODO : Think about parsing from file ? Currently cumbersome and error-prone
std::vector<std::string> textures = {"Head_Boy.png","Head_Significant_Boy.png","Building.png"};
std::vector<std::string> levels = {"test_level.xml"};
Game game(levels,textures);
ASSERT_FALSE(game);
game.loadLevel(0);
ASSERT_TRUE(game);
game.runGame();
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {