From 44324ba5d6cac01048cc5cbecbff255ee56f2fc0 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sat, 14 Mar 2015 16:13:11 -0400 Subject: Wrote simple factory to read map and entity data from XML files --- src/components.cpp | 12 ++-- src/components.h | 4 +- src/entity.cpp | 3 + src/entity.h | 1 + src/entityfactory.cpp | 101 ++++++++++++++++++++++++++++++++ src/entityfactory.h | 15 +++++ src/game.cpp | 34 ++--------- src/game.h | 6 +- src/map.cpp | 158 +++++++++++++++++++++++++++++++++++++++----------- src/map.h | 31 +++++++--- src/renderer.cpp | 2 +- src/renderer.h | 2 +- 12 files changed, 284 insertions(+), 85 deletions(-) create mode 100644 src/entityfactory.cpp create mode 100644 src/entityfactory.h (limited to 'src') diff --git a/src/components.cpp b/src/components.cpp index 26aa5d2..ba4fe72 100644 --- a/src/components.cpp +++ b/src/components.cpp @@ -309,7 +309,7 @@ MapRenderComponent::MapRenderComponent(const Map& map) for (int i=0; i 0) && (tile < 28) && (!((tile >= 5) && (tile <= 7)))) { @@ -600,15 +600,15 @@ void StaticImageComponent::render(Game&, Entity& entity, Texture& buffer) // Simple collision -SimpleColliderComponent::SimpleColliderComponent(std::function callback) : callback(callback) +SimpleColliderComponent::SimpleColliderComponent(std::function callback) : callback(callback) { } -void SimpleColliderComponent::receive(Game&, Entity&, const Message& msg) +void SimpleColliderComponent::receive(Game& game, Entity&, const Message& msg) { if (msg.type == Message::Type::collision) { - callback(*(msg.collisionEntity)); + callback(game, *(msg.collisionEntity)); } } diff --git a/src/components.h b/src/components.h index f5c66d4..3d80d1a 100644 --- a/src/components.h +++ b/src/components.h @@ -111,11 +111,11 @@ class StaticImageComponent : public Component { class SimpleColliderComponent : public Component { public: - SimpleColliderComponent(std::function callback); + SimpleColliderComponent(std::function callback); void receive(Game& game, Entity& entity, const Message& msg); private: - std::function callback; + std::function callback; }; #endif diff --git a/src/entity.cpp b/src/entity.cpp index 2b6cd7f..0ede567 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -1,4 +1,7 @@ #include "entity.h" +#include +#include "components.h" +#include "muxer.h" void Entity::addComponent(std::shared_ptr c) { diff --git a/src/entity.h b/src/entity.h index e22fd10..44ce973 100644 --- a/src/entity.h +++ b/src/entity.h @@ -7,6 +7,7 @@ class Component; #include #include "renderer.h" #include "game.h" +#include "map.h" class Message { public: diff --git a/src/entityfactory.cpp b/src/entityfactory.cpp new file mode 100644 index 0000000..acf9b8e --- /dev/null +++ b/src/entityfactory.cpp @@ -0,0 +1,101 @@ +#include "entityfactory.h" +#include +#include "components.h" +#include "muxer.h" +#include + +struct EntityData { + char* sprite; + char* action; + bool hasPhysics; + int width; + int height; +}; + +static std::map factories; + +std::shared_ptr EntityFactory::createNamedEntity(const std::string name, const Map& map) +{ + auto it = factories.find(name); + EntityData data = factories[name]; + if (it == factories.end()) + { + xmlDocPtr doc = xmlParseFile(("../entities/" + name + ".xml").c_str()); + if (doc == nullptr) + { + fprintf(stderr, "Error reading entity %s\n", name.c_str()); + exit(-1); + } + + xmlNodePtr top = xmlDocGetRootElement(doc); + if (top == nullptr) + { + fprintf(stderr, "Empty entity %s\n", name.c_str()); + exit(-1); + } + + if (xmlStrcmp(top->name, (const xmlChar*) "entity-def")) + { + fprintf(stderr, "Invalid entity definition %s\n", name.c_str()); + exit(-1); + } + + for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) + { + if (!xmlStrcmp(node->name, (const xmlChar*) "sprite")) + { + xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + data.sprite = (char*) calloc(xmlStrlen(key)+1, sizeof(char)); + strcpy(data.sprite, (char*) key); + xmlFree(key); + } else if (!xmlStrcmp(node->name, (const xmlChar*) "action")) + { + xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + data.action = (char*) calloc(xmlStrlen(key)+1, sizeof(char)); + strcpy(data.action, (char*) key); + xmlFree(key); + } else if (!xmlStrcmp(node->name, (const xmlChar*) "size")) + { + xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + data.hasPhysics = true; + sscanf((char*) key, "%d,%d", &(data.width), &(data.height)); + xmlFree(key); + } + } + + xmlFreeDoc(doc); + + factories[name] = data; + } + + auto entity = std::make_shared(); + + if (data.sprite) + { + auto component = std::make_shared(data.sprite); + entity->addComponent(component); + } + + if (data.action) + { + if (!strcmp(data.action, "save")) + { + auto component = std::make_shared([&] (Game& game, Entity& collider) { + playSound("../res/Pickup_Coin23.wav", 0.25); + + game.saveGame(map, collider.position); + }); + entity->addComponent(component); + } + } + + if (data.hasPhysics) + { + auto component = std::make_shared(); + entity->addComponent(component); + + entity->size = std::make_pair(data.width, data.height); + } + + return entity; +} diff --git a/src/entityfactory.h b/src/entityfactory.h new file mode 100644 index 0000000..a35b5f7 --- /dev/null +++ b/src/entityfactory.h @@ -0,0 +1,15 @@ +#ifndef ENTITYFACTORY_H +#define ENTITYFACTORY_H + +#include "entity.h" +#include +#include +#include +#include "map.h" + +class EntityFactory { + public: + static std::shared_ptr createNamedEntity(const std::string name, const Map& map); +}; + +#endif diff --git a/src/game.cpp b/src/game.cpp index b149392..7ec4460 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2,12 +2,10 @@ #include "renderer.h" #include "components.h" #include "muxer.h" +#include "entityfactory.h" Game::Game() { - m.setLeftMap(&m2); - m2.setRightMap(&m); - player = std::make_shared(); player->position = std::make_pair(100.0,100.0); player->size = std::make_pair(10.0,12.0); @@ -116,32 +114,10 @@ void Game::loadMap(const Map& map) auto map_collision = std::make_shared(map); mapEn->addComponent(map_collision); + // Map in the back, player on top, rest of entities in between nextEntities.clear(); nextEntities.push_back(mapEn); - - // this is cheating but is just for testing - if (&map == &m2) - { - auto saveEn = std::make_shared(); - saveEn->position = std::make_pair(257.0, 160.0); - saveEn->size = std::make_pair(8.0, 11.0); - - auto save_render = std::make_shared("../res/keyring.png"); - saveEn->addComponent(save_render); - - auto save_physics = std::make_shared(); - saveEn->addComponent(save_physics); - - auto save_collide = std::make_shared([&] (Entity& collider) { - playSound("../res/Pickup_Coin23.wav", 0.25); - - saveGame(map, collider.position); - }); - saveEn->addComponent(save_collide); - - nextEntities.push_back(saveEn); - } - + map.createEntities(nextEntities); nextEntities.push_back(player); newWorld = true; @@ -160,9 +136,9 @@ void Game::saveGame(const Map& map, std::pair position) save = {&map, position}; } -void Game::schedule(double time, std::function&& callback) +void Game::schedule(double time, std::function callback) { - scheduled.emplace_front(time, callback); + scheduled.emplace_front(time, std::move(callback)); } void Game::playerDie(Entity& player, const Map& curMap) diff --git a/src/game.h b/src/game.h index c7c2625..33d1965 100644 --- a/src/game.h +++ b/src/game.h @@ -30,7 +30,7 @@ class Game { void loadMap(const Map& map); void detectCollision(Entity& collider, std::pair old_position); void saveGame(const Map& map, std::pair position); - void schedule(double time, std::function&& callback); + void schedule(double time, std::function callback); void playerDie(Entity& player, const Map& curMap); private: @@ -40,8 +40,8 @@ class Game { std::list> nextEntities; bool newWorld; std::shared_ptr player; - Map m{"../maps/embarass.txt"}; - Map m2{"../maps/second.txt"}; + Map m {Map::getNamedMap("embarass")}; + Map m2 {Map::getNamedMap("second")}; Savefile save; std::list>> scheduled; bool shouldQuit = false; diff --git a/src/map.cpp b/src/map.cpp index 3976b63..8c1c6f0 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2,43 +2,111 @@ #include "game.h" #include #include +#include +#include +#include "entityfactory.h" + +static std::map maps; Map::Map() { - + title = (char*) calloc(1, sizeof(char)); + mapdata = (int*) calloc(1, sizeof(int)); } -Map::Map(const char* filename) +Map::Map(const std::string name) { - FILE* f = fopen(filename, "r"); + xmlDocPtr doc = xmlParseFile(("../maps/" + name + ".xml").c_str()); + if (doc == nullptr) + { + fprintf(stderr, "Error reading map %s\n", name.c_str()); + exit(-1); + } - m_mapdata = (int*) malloc(MAP_WIDTH*(MAP_HEIGHT-1)*sizeof(int)); - for (int i=0; iname, (const xmlChar*) "map-def")) + { + fprintf(stderr, "Invalid map definition %s\n", name.c_str()); + exit(-1); + } + + for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) + { + if (!xmlStrcmp(node->name, (const xmlChar*) "name")) + { + xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + title = (char*) calloc(xmlStrlen(key) + 1, sizeof(char)); + strcpy(title, (char*) key); + xmlFree(key); + } else if (!xmlStrcmp(node->name, (const xmlChar*) "environment")) + { + xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + mapdata = (int*) malloc(MAP_WIDTH*(MAP_HEIGHT-1)*sizeof(int)); + mapdata[0] = atoi(strtok((char*) key, ",\n")); + for (int i=1; i<(MAP_WIDTH*(MAP_HEIGHT-1)); i++) + { + mapdata[i] = atoi(strtok(NULL, ",\n")); + } + xmlFree(key); + } else if (!xmlStrcmp(node->name, (const xmlChar*) "entities")) { - fscanf(f, "%d,", &(m_mapdata[i*MAP_WIDTH + j])); + for (xmlNodePtr entityNode = node->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next) + { + if (!xmlStrcmp(entityNode->name, (const xmlChar*) "entity")) + { + EntityData data; + for (xmlNodePtr entityDataNode = entityNode->xmlChildrenNode; entityDataNode != NULL; entityDataNode = entityDataNode->next) + { + if (!xmlStrcmp(entityDataNode->name, (const xmlChar*) "entity-type")) + { + xmlChar* key = xmlNodeListGetString(doc, entityDataNode->xmlChildrenNode, 1); + data.name = std::string((char*) key); + xmlFree(key); + } else if (!xmlStrcmp(entityDataNode->name, (const xmlChar*) "entity-position")) + { + xmlChar* key = xmlNodeListGetString(doc, entityDataNode->xmlChildrenNode, 1); + sscanf((char*) key, "%lf,%lf", &(data.position.first), &(data.position.second)); + xmlFree(key); + } + } + + entities.push_back(data); + } + } + } else if (!xmlStrcmp(node->name, (const xmlChar*) "leftmap")) + { + xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + leftMap = &Map::getNamedMap(std::string((char*) key)); + xmlFree(key); + } else if (!xmlStrcmp(node->name, (const xmlChar*) "rightmap")) + { + xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + rightMap = &Map::getNamedMap(std::string((char*) key)); + xmlFree(key); } - - fgetc(f); } - m_title = (char*) calloc(41, sizeof(char)); - fgets(m_title, 41, f); - - fclose(f); + xmlFreeDoc(doc); } -Map::Map(Map& map) +Map::Map(const Map& map) { - m_mapdata = (int*) malloc(MAP_WIDTH*(MAP_HEIGHT-1)*sizeof(int)); - memcpy(m_mapdata, map.m_mapdata, MAP_WIDTH*(MAP_HEIGHT-1)*sizeof(int)); + mapdata = (int*) malloc(MAP_WIDTH*(MAP_HEIGHT-1)*sizeof(int)); + memcpy(mapdata, map.mapdata, MAP_WIDTH*(MAP_HEIGHT-1)*sizeof(int)); + + title = (char*) malloc((MAP_WIDTH+1)*sizeof(char)); + strncpy(title, map.title, MAP_WIDTH+1); - m_title = (char*) malloc((MAP_WIDTH+1)*sizeof(char)); - strncpy(m_title, map.m_title, MAP_WIDTH+1); + leftMap = map.leftMap; + rightMap = map.rightMap; - m_leftMap = map.m_leftMap; - m_rightMap = map.m_rightMap; + entities = map.entities; } Map::Map(Map&& map) : Map() @@ -48,8 +116,8 @@ Map::Map(Map&& map) : Map() Map::~Map() { - free(m_mapdata); - free(m_title); + free(mapdata); + free(title); } Map& Map::operator= (Map map) @@ -61,38 +129,60 @@ Map& Map::operator= (Map map) void swap(Map& first, Map& second) { - std::swap(first.m_mapdata, second.m_mapdata); - std::swap(first.m_title, second.m_title); - std::swap(first.m_leftMap, second.m_leftMap); - std::swap(first.m_rightMap, second.m_rightMap); + std::swap(first.mapdata, second.mapdata); + std::swap(first.title, second.title); + std::swap(first.leftMap, second.leftMap); + std::swap(first.rightMap, second.rightMap); + std::swap(first.entities, second.entities); } -const int* Map::mapdata() const +const int* Map::getMapdata() const { - return m_mapdata; + return mapdata; } -const char* Map::title() const +const char* Map::getTitle() const { - return m_title; + return title; } const Map* Map::getLeftMap() const { - return m_leftMap; + return leftMap; } const Map* Map::getRightMap() const { - return m_rightMap; + return rightMap; } void Map::setLeftMap(const Map* m) { - m_leftMap = m; + leftMap = m; } void Map::setRightMap(const Map* m) { - m_rightMap = m; + rightMap = m; +} + +void Map::createEntities(std::list>& entities) const +{ + for (auto data : this->entities) + { + auto entity = EntityFactory::createNamedEntity(data.name, *this); + entity->position = data.position; + + entities.push_back(entity); + } +} + +Map& Map::getNamedMap(const std::string name) +{ + if (maps.count(name) == 0) + { + maps[name] = Map {name}; + } + + return maps[name]; } diff --git a/src/map.h b/src/map.h index 071b6f2..fa2edcc 100644 --- a/src/map.h +++ b/src/map.h @@ -1,28 +1,41 @@ #ifndef MAP_H #define MAP_H +#include +#include + +class Entity; + class Map { public: - Map(const char* filename); - Map(Map& map); + Map(); + Map(const std::string name); + Map(const Map& map); Map(Map&& map); ~Map(); Map& operator= (Map other); friend void swap(Map& first, Map& second); - const int* mapdata() const; - const char* title() const; + static Map& getNamedMap(const std::string name); + + const int* getMapdata() const; + const char* getTitle() const; const Map* getLeftMap() const; const Map* getRightMap() const; void setLeftMap(const Map* m); void setRightMap(const Map* m); + void createEntities(std::list>& entities) const; private: - Map(); + struct EntityData { + std::string name; + std::pair position; + }; - int* m_mapdata; - char* m_title; - const Map* m_leftMap = nullptr; - const Map* m_rightMap = nullptr; + int* mapdata; + char* title; + const Map* leftMap = nullptr; + const Map* rightMap = nullptr; + std::list entities; }; #endif diff --git a/src/renderer.cpp b/src/renderer.cpp index 64c9fd0..c2b37d2 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -513,7 +513,7 @@ Texture::Texture(const char* filename) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } -Texture::Texture(Texture& tex) +Texture::Texture(const Texture& tex) { if (!rendererInitialized) { diff --git a/src/renderer.h b/src/renderer.h index 90ec101..84ad688 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -15,7 +15,7 @@ class Texture { public: Texture(int width, int height); Texture(const char* file); - Texture(Texture& tex); + Texture(const Texture& tex); Texture(Texture&& tex); ~Texture(); Texture& operator= (Texture tex); -- cgit 1.4.1