Preload scripts on boot and grab by ID for less file io operations + general cleanup
This commit is contained in:
parent
3241eafea0
commit
43bbc9e21d
12 changed files with 1195 additions and 1002 deletions
3
Resources/monsters/shooty_peeps.xml
Normal file
3
Resources/monsters/shooty_peeps.xml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
<monster id="monster/shooty/bighead" anim="character/tmp" weapon="gun/pistol" aggressive="true" behaviour="script/behaviour/grunt" hp="10.0"/>
|
||||||
|
<monster id="monster/shooty/clone" anim="character/player" weapon="gun/shotgun" aggressive="true" behaviour="script/behaviour/grunt" hp="15.0"/>
|
||||||
|
|
@ -3,20 +3,17 @@
|
||||||
<scene type="shooter" id="000" bg="backgrounds/blue_sky.png">
|
<scene type="shooter" id="000" bg="backgrounds/blue_sky.png">
|
||||||
<map name="newmap"/>
|
<map name="newmap"/>
|
||||||
<entities>
|
<entities>
|
||||||
<player x="7" y="5" weapon="gun/machine">
|
<player x="7" y="5" weapon="gun/shotgun">
|
||||||
<animation id="character/player"/>
|
<animation id="character/player"/>
|
||||||
</player>
|
</player>
|
||||||
<entity x="10" y="3" weapon="gun/pistol">
|
<entity x="10" y="3" weapon="gun/pistol">
|
||||||
<animation id="character/player"/>
|
<animation id="character/player"/>
|
||||||
<script file="scripts/ai/grunt_behaviour.lua"/>
|
<script id="script/behaviour/grunt"/>
|
||||||
</entity>
|
</entity>
|
||||||
<entity x="6" y="3" weapon="gun/pistol">
|
<entity x="6" y="3" weapon="gun/pistol">
|
||||||
<animation id="character/tmp"/>
|
<animation id="character/tmp"/>
|
||||||
<script file="scripts/ai/grunt_behaviour.lua"/>
|
<script id="script/behaviour/grunt"/>
|
||||||
</entity>
|
|
||||||
<entity x="5" y="3" weapon="gun/pistol">
|
|
||||||
<animation id="character/tmp"/>
|
|
||||||
<script file="scripts/ai/grunt_behaviour.lua"/>
|
|
||||||
</entity>
|
</entity>
|
||||||
|
<entity x="5" y="3" weapon="gun/pistol" monster_id="monster/shooty/bighead"/>
|
||||||
</entities>
|
</entities>
|
||||||
</scene>
|
</scene>
|
||||||
|
|
|
||||||
4
Resources/scripts/ai_scripts.xml
Normal file
4
Resources/scripts/ai_scripts.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
<!-- Shooter Scripts -->
|
||||||
|
<script id="script/behaviour/grunt" file="scripts/ai/grunt_behaviour.lua"/>
|
||||||
|
<script id="script/behaviour/scared" file="scripts/ai/scared_behaviour.lua"/>
|
||||||
3
Resources/scripts/weapon_scripts.xml
Normal file
3
Resources/scripts/weapon_scripts.xml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
<!-- Ranged weapon scripts -->
|
||||||
|
<script id="script/weapon/shotgun" file="scripts/weapons/shotgun_script.lua"/>
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
|
|
||||||
<weapon id="gun/shotgun" fireSpeed="1750.0" maxAmmo="64" clipSize="4">
|
<weapon id="gun/shotgun" fireSpeed="1750.0" maxAmmo="64" clipSize="4">
|
||||||
<script file="scripts/weapons/shotgun_script.lua"/>
|
<script id="script/weapon/shotgun"/>
|
||||||
<animation>
|
<animation>
|
||||||
<size x="55.0" y="55.0"/>
|
<size x="55.0" y="55.0"/>
|
||||||
<offset x="-30.0" y="0.0"/>
|
<offset x="-30.0" y="0.0"/>
|
||||||
|
|
@ -1,57 +1,60 @@
|
||||||
#ifndef _H_RESOURCEMANAGER_H
|
#ifndef _H_RESOURCEMANAGER_H
|
||||||
#define _H_RESOURCEMANAGER_H
|
#define _H_RESOURCEMANAGER_H
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "sound/soundeffect.h"
|
#include "graphics/background.h"
|
||||||
#include "utility/xmlloader.h"
|
|
||||||
#include "graphics/shader.h"
|
#include "graphics/shader.h"
|
||||||
#include "graphics/sprite.h"
|
#include "graphics/sprite.h"
|
||||||
#include "graphics/background.h"
|
#include "sound/soundeffect.h"
|
||||||
|
#include "utility/script.h"
|
||||||
|
#include "utility/xmlloader.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
class Weapon;
|
class Weapon;
|
||||||
class Script;
|
|
||||||
class AnimationSet;
|
class AnimationSet;
|
||||||
class AIScript;
|
|
||||||
class WeaponScript;
|
|
||||||
class SpriteComponent;
|
class SpriteComponent;
|
||||||
|
|
||||||
class ResourceManager
|
class ResourceManager {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
ResourceManager() :
|
ResourceManager() : xmlLoader(std::make_shared<XMLLoader>()) {
|
||||||
xmlLoader(std::make_shared<XMLLoader>())
|
|
||||||
{
|
|
||||||
xmlLoader->loadWeapons("weapons");
|
xmlLoader->loadWeapons("weapons");
|
||||||
xmlLoader->loadAnimations("animations");
|
xmlLoader->loadAnimations("animations");
|
||||||
|
xmlLoader->loadMonsters("monsters");
|
||||||
xmlLoader->loadTileSets("maps/tilesets");
|
xmlLoader->loadTileSets("maps/tilesets");
|
||||||
xmlLoader->loadMaps("maps");
|
xmlLoader->loadMaps("maps");
|
||||||
|
xmlLoader->loadScripts("scripts", loadLuaString);
|
||||||
xmlLoader->loadScenes("scenes");
|
xmlLoader->loadScenes("scenes");
|
||||||
xmlLoader->loadSoundEffects("sounds");
|
xmlLoader->loadSoundEffects("sounds");
|
||||||
shaders["__fallback__"] = std::make_unique<GenericShader>();
|
shaders["__fallback__"] = std::make_unique<GenericShader>();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a NON-OWNING pointer to a sprite atlas
|
// Returns a NON-OWNING pointer to a sprite atlas
|
||||||
SpriteAtlas* loadSpriteAtlas (const std::string& path, float frameSize, bool isDirectional = false);
|
SpriteAtlas *loadSpriteAtlas(const std::string &path, float frameSize,
|
||||||
|
bool isDirectional = false);
|
||||||
// Returns a NON-OWNING pointer to a static sprite
|
// Returns a NON-OWNING pointer to a static sprite
|
||||||
Sprite* loadSpriteStatic (const std::string& path);
|
Sprite *loadSpriteStatic(const std::string &path);
|
||||||
// Returns a NON-OWNING pointer to a background
|
// Returns a NON-OWNING pointer to a background
|
||||||
Background* loadBackground (const std::string& path);
|
Background *loadBackground(const std::string &path);
|
||||||
const unsigned loadSoundEffect (const std::string& id);
|
const unsigned loadSoundEffect(const std::string &id);
|
||||||
std::unique_ptr<AIScript> loadAIScript (const std::string& path);
|
template <typename T = Script>
|
||||||
std::unique_ptr<WeaponScript> loadWeaponScript (const std::string& path);
|
std::unique_ptr<T> loadScript(const std::string &id);
|
||||||
std::unique_ptr<Weapon> loadWeapon (const std::string& name, const unsigned weaponShaderID, const unsigned bulletShaderID);
|
std::unique_ptr<Weapon> loadWeapon(const std::string &name,
|
||||||
std::shared_ptr<AnimationSet> loadAnimationSet (const std::string& name, int entityid = 0);
|
const unsigned weaponShaderID,
|
||||||
|
const unsigned bulletShaderID);
|
||||||
|
std::shared_ptr<AnimationSet> loadAnimationSet(const std::string &name,
|
||||||
|
int entityid = 0);
|
||||||
|
|
||||||
const unsigned loadShader (const std::string& name, const std::string& vertexPath, const std::string& fragPath);
|
const unsigned loadShader(const std::string &name,
|
||||||
const SceneData* loadScene (const std::string& id);
|
const std::string &vertexPath,
|
||||||
const TileSetData* loadTileSet (const std::string& name);
|
const std::string &fragPath);
|
||||||
|
const SceneData *loadScene(const std::string &id);
|
||||||
|
const TileSetData *loadTileSet(const std::string &name);
|
||||||
|
|
||||||
// Returns a NON-OWNING pointer to a shader by ID
|
// Returns a NON-OWNING pointer to a shader by ID
|
||||||
Shader* getShaderByID(unsigned int ID);
|
Shader *getShaderByID(unsigned int ID);
|
||||||
|
|
||||||
void clearResources();
|
void clearResources();
|
||||||
|
|
||||||
|
|
@ -59,19 +62,29 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, std::unique_ptr<Shader>> shaders;
|
std::unordered_map<std::string, std::unique_ptr<Shader>> shaders;
|
||||||
std::unordered_map<unsigned, Shader*> shaderIDs;
|
std::unordered_map<unsigned, Shader *> shaderIDs;
|
||||||
std::unordered_map<std::string, std::unique_ptr<SoundEffect>> sounds;
|
std::unordered_map<std::string, std::unique_ptr<SoundEffect>> sounds;
|
||||||
std::unordered_map<std::string, std::unique_ptr<Sprite>> sprites;
|
std::unordered_map<std::string, std::unique_ptr<Sprite>> sprites;
|
||||||
//std::unordered_map<std::string, std::unique_ptr<Weapon>> weapons;
|
|
||||||
//std::unordered_map<std::string, std::string> scripts;
|
|
||||||
std::unordered_map<std::string, std::unique_ptr<Background>> backgrounds;
|
std::unordered_map<std::string, std::unique_ptr<Background>> backgrounds;
|
||||||
std::unordered_map<std::string, std::shared_ptr<TileSetData>> tileSets;
|
std::unordered_map<std::string, std::shared_ptr<TileSetData>> tileSets;
|
||||||
//std::unordered_map<std::string, std::shared_ptr<EntityData>> entityData;
|
|
||||||
//std::unordered_map<std::string, std::shared_ptr<SceneData>> scenes;
|
|
||||||
//std::unordered_map<std::string, std::shared_ptr<MapData>> maps;
|
|
||||||
//std::unordered_map<std::string, std::shared_ptr<TileType>> tiles;
|
|
||||||
|
|
||||||
std::shared_ptr<XMLLoader> xmlLoader;
|
std::shared_ptr<XMLLoader> xmlLoader;
|
||||||
|
|
||||||
|
static bool loadLuaString(ScriptData *script);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::unique_ptr<T> ResourceManager::loadScript(const std::string &id) {
|
||||||
|
const ScriptData *data = xmlLoader->getScriptData(id);
|
||||||
|
if (data == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
try {
|
||||||
|
std::unique_ptr<T> script = std::make_unique<T>(data->script);
|
||||||
|
return std::move(script);
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
LOG(ERROR, "Failed to load script '{}'", data->fileName);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // _H_RESOURCEMANAGER_H
|
#endif // _H_RESOURCEMANAGER_H
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,22 @@
|
||||||
|
|
||||||
#define SOL_ALL_SAFETIES_ON 1
|
#define SOL_ALL_SAFETIES_ON 1
|
||||||
|
|
||||||
#include <sol/sol.hpp>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
class Script {
|
class Script {
|
||||||
public:
|
public:
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
Script(const std::string& path);
|
Script(const std::string &str);
|
||||||
~Script();
|
~Script();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool loadScript(const std::string& path) {
|
bool loadScript(const std::string &str) {
|
||||||
auto result = lua.script_file(path);
|
auto result = lua.script(str);
|
||||||
if (!result.valid())
|
if (!result.valid()) {
|
||||||
{
|
|
||||||
sol::error err = result;
|
sol::error err = result;
|
||||||
std::cerr << "Failed to load script ( " << path << " ) Error: " << err.what() << std::endl;
|
std::cerr << "Failed to load script. Error: " << err.what() << std::endl;
|
||||||
}
|
}
|
||||||
return result.valid();
|
return result.valid();
|
||||||
}
|
}
|
||||||
|
|
@ -27,21 +27,21 @@ private:
|
||||||
|
|
||||||
class AIScript : public Script {
|
class AIScript : public Script {
|
||||||
public:
|
public:
|
||||||
AIScript(const std::string& path) : Script(path) { registerUserTypes(); }
|
AIScript(const std::string &str) : Script(str) { registerUserTypes(); }
|
||||||
|
|
||||||
~AIScript();
|
~AIScript();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void registerUserTypes();
|
||||||
void registerUserTypes() ;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class WeaponScript : public Script {
|
class WeaponScript : public Script {
|
||||||
public:
|
public:
|
||||||
WeaponScript(const std::string& path) : Script(path) { registerUserTypes(); }
|
WeaponScript(const std::string &str) : Script(str) { registerUserTypes(); }
|
||||||
~WeaponScript();
|
~WeaponScript();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void registerUserTypes() ;
|
void registerUserTypes();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _H_SCRIPT_H
|
#endif // _H_SCRIPT_H
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,30 @@
|
||||||
#ifndef _H_XMLLOADER_H
|
#ifndef _H_XMLLOADER_H
|
||||||
#define _H_XMLLOADER_H
|
#define _H_XMLLOADER_H
|
||||||
|
|
||||||
#include <vector>
|
#include <functional>
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
#include <tinyxml2.h>
|
#include <tinyxml2.h>
|
||||||
|
|
||||||
struct Tile;
|
struct Tile;
|
||||||
|
|
||||||
|
// Except for the player, these definitions are mostly overrides of the monster
|
||||||
|
// data
|
||||||
struct EntityData {
|
struct EntityData {
|
||||||
bool isPlayer;
|
bool isPlayer;
|
||||||
bool animated;
|
bool animated;
|
||||||
int x = 0, y = 0;
|
int x = 0, y = 0;
|
||||||
|
float hp;
|
||||||
|
std::string monsterDef;
|
||||||
std::string graphic;
|
std::string graphic;
|
||||||
std::string weapon = "pistol";
|
std::string weapon = "gun/pistol";
|
||||||
std::string script;
|
std::string script;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -67,10 +72,17 @@ struct SceneData {
|
||||||
std::string type;
|
std::string type;
|
||||||
std::string bgFile;
|
std::string bgFile;
|
||||||
|
|
||||||
const MapData* map;
|
const MapData *map;
|
||||||
std::vector<EntityData> entities;
|
std::vector<EntityData> entities;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Store our script as a string so we only need to read the file at boot
|
||||||
|
struct ScriptData {
|
||||||
|
std::string id;
|
||||||
|
std::string fileName;
|
||||||
|
std::string script;
|
||||||
|
};
|
||||||
|
|
||||||
struct WeaponData {
|
struct WeaponData {
|
||||||
std::string id;
|
std::string id;
|
||||||
float fireSpeed = 250.0f;
|
float fireSpeed = 250.0f;
|
||||||
|
|
@ -102,100 +114,130 @@ struct AnimationData {
|
||||||
float frameSize;
|
float frameSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This holds a lot of defaults, but the scene can
|
||||||
|
// override a large portion of the definitions here
|
||||||
|
struct MonsterData {
|
||||||
|
std::string id;
|
||||||
|
std::string anim;
|
||||||
|
std::string weapon;
|
||||||
|
bool aggressive = false;
|
||||||
|
std::string behaviour;
|
||||||
|
float hp;
|
||||||
|
};
|
||||||
|
|
||||||
struct SoundData {
|
struct SoundData {
|
||||||
std::string id; // <type>/<object>/<state>
|
std::string id; // <type>/<object>/<state>
|
||||||
std::string path;
|
std::string path;
|
||||||
bool spatial;
|
bool spatial;
|
||||||
};
|
};
|
||||||
|
|
||||||
class XMLLoader
|
class XMLLoader {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
XMLLoader() {}
|
XMLLoader() {}
|
||||||
bool loadScenes(const char* sceneFolder);
|
bool loadScenes(const char *sceneFolder);
|
||||||
bool loadWeapons(const char* weaponFolder);
|
bool loadWeapons(const char *weaponFolder);
|
||||||
bool loadAnimations(const char* animationFolder);
|
bool loadAnimations(const char *animationFolder);
|
||||||
bool loadTileSets(const char* tileSetFolder);
|
bool loadTileSets(const char *tileSetFolder);
|
||||||
bool loadMaps(const char* mapFolder);
|
bool loadMaps(const char *mapFolder);
|
||||||
bool loadSoundEffects(const char* soundFolder);
|
bool loadMonsters(const char *monsterFolder);
|
||||||
|
// luaLoader is the function we use to load the lua file.
|
||||||
|
// This will be defined in our resource manager
|
||||||
|
bool loadScripts(const char *scriptFolder,
|
||||||
|
std::function<bool(ScriptData *)> luaLoader);
|
||||||
|
bool loadSoundEffects(const char *soundFolder);
|
||||||
|
|
||||||
const SceneData* getSceneData(const std::string& id) const {
|
const SceneData *getSceneData(const std::string &id) const {
|
||||||
try {
|
try {
|
||||||
return scenes.at(id).get();
|
return scenes.at(id).get();
|
||||||
}
|
} catch (std::exception &) {
|
||||||
catch (std::exception&) {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MapData* getMapData(const std::string& name) const {
|
const ScriptData *getScriptData(const std::string &id) const {
|
||||||
|
try {
|
||||||
|
return scripts.at(id).get();
|
||||||
|
} catch (std::exception &) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MapData *getMapData(const std::string &name) const {
|
||||||
try {
|
try {
|
||||||
return maps.at(name).get();
|
return maps.at(name).get();
|
||||||
}
|
} catch (std::exception &) {
|
||||||
catch (std::exception&) {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const WeaponData* getWeaponData(const std::string& id) const {
|
const WeaponData *getWeaponData(const std::string &id) const {
|
||||||
try {
|
try {
|
||||||
return weapons.at(id).get();
|
return weapons.at(id).get();
|
||||||
}
|
} catch (std::exception &) {
|
||||||
catch (std::exception&) {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AnimationData* getAnimationData(const std::string& id) const {
|
const AnimationData *getAnimationData(const std::string &id) const {
|
||||||
try {
|
try {
|
||||||
return animations.at(id).get();
|
return animations.at(id).get();
|
||||||
}
|
} catch (std::exception &) {
|
||||||
catch (std::exception&) {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TileSetData* getTileSetData(const std::string& name) const {
|
const TileSetData *getTileSetData(const std::string &name) const {
|
||||||
try {
|
try {
|
||||||
return tileSets.at(name).get();
|
return tileSets.at(name).get();
|
||||||
}
|
} catch (std::exception &) {
|
||||||
catch (std::exception&) {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SoundData* getSoundData(const std::string& id) const {
|
const SoundData *getSoundData(const std::string &id) const {
|
||||||
try {
|
try {
|
||||||
return sounds.at(id).get();
|
return sounds.at(id).get();
|
||||||
}
|
} catch (std::exception &) {
|
||||||
catch (std::exception&) {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return a full set of animations, may need further optimization.
|
// return a full set of animations, may need further optimization.
|
||||||
// one idea is when loading animations we create a seperate map that holds each set by their reference, so we can just do a simple,
|
// one idea is when loading animations we create a seperate map that holds
|
||||||
// hash table lookup.
|
// each set by their reference, so we can just do a simple, hash table lookup.
|
||||||
std::vector<AnimationData*> getAnimationSet(const std::string& prefix) const {
|
std::vector<AnimationData *>
|
||||||
std::vector<AnimationData*> animSet;
|
getAnimationSet(const std::string &prefix) const {
|
||||||
|
std::vector<AnimationData *> animSet;
|
||||||
animSet.reserve(animations.size());
|
animSet.reserve(animations.size());
|
||||||
for (const auto& [id, anim] : animations) {
|
for (const auto &[id, anim] : animations) {
|
||||||
if (id.starts_with(prefix)) animSet.push_back(anim.get());
|
if (id.starts_with(prefix))
|
||||||
|
animSet.push_back(anim.get());
|
||||||
}
|
}
|
||||||
animSet.shrink_to_fit();
|
animSet.shrink_to_fit();
|
||||||
return animSet;
|
return animSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearData() { scenes.clear(); weapons.clear(); animations.clear(); maps.clear(); tileSets.clear(); }
|
void clearData() {
|
||||||
|
scenes.clear();
|
||||||
|
weapons.clear();
|
||||||
|
animations.clear();
|
||||||
|
maps.clear();
|
||||||
|
tileSets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool loadXmlScene(const char* xmlFile, SceneData* out);
|
bool loadXmlScene(const char *xmlFile, SceneData *out);
|
||||||
bool loadEntityData(const char* xmlFile, SceneData* out);
|
bool loadEntityData(const char *xmlFile, SceneData *out);
|
||||||
bool loadTile(tinyxml2::XMLElement* tileElement, TileSetData::TileData* out);
|
bool loadTile(tinyxml2::XMLElement *tileElement, TileSetData::TileData *out);
|
||||||
bool loadObject(tinyxml2::XMLElement* objectElement, TileSetData::TileData::ObjectData* out);
|
bool loadObject(tinyxml2::XMLElement *objectElement,
|
||||||
|
TileSetData::TileData::ObjectData *out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, std::unique_ptr<SceneData>> scenes;
|
std::unordered_map<std::string, std::unique_ptr<SceneData>> scenes;
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<ScriptData>> scripts;
|
||||||
std::unordered_map<std::string, std::unique_ptr<WeaponData>> weapons;
|
std::unordered_map<std::string, std::unique_ptr<WeaponData>> weapons;
|
||||||
std::unordered_map<std::string, std::unique_ptr<AnimationData>> animations;
|
std::unordered_map<std::string, std::unique_ptr<AnimationData>> animations;
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<MonsterData>> monsters;
|
||||||
std::unordered_map<std::string, std::unique_ptr<MapData>> maps;
|
std::unordered_map<std::string, std::unique_ptr<MapData>> maps;
|
||||||
std::unordered_map<std::string, std::unique_ptr<TileSetData>> tileSets;
|
std::unordered_map<std::string, std::unique_ptr<TileSetData>> tileSets;
|
||||||
std::unordered_map<std::string, std::unique_ptr<SoundData>> sounds;
|
std::unordered_map<std::string, std::unique_ptr<SoundData>> sounds;
|
||||||
|
|
|
||||||
|
|
@ -101,11 +101,13 @@ void Scene::loadDebugShooterScene() {
|
||||||
} else {
|
} else {
|
||||||
// attach ai
|
// attach ai
|
||||||
if (!entityData.script.empty()) {
|
if (!entityData.script.empty()) {
|
||||||
auto behaviour = resourceManager->loadAIScript(entityData.script);
|
auto behaviour =
|
||||||
|
resourceManager->loadScript<AIScript>(entityData.script);
|
||||||
auto rayCaster = std::make_unique<Raycaster>(
|
auto rayCaster = std::make_unique<Raycaster>(
|
||||||
40.f, 300.f, map->getCollisionMap(), mapData->tileSize);
|
40.f, 300.f, map->getCollisionMap(), mapData->tileSize);
|
||||||
auto ai = std::make_shared<AI>(entity.get(), std::move(rayCaster));
|
auto ai = std::make_shared<AI>(entity.get(), std::move(rayCaster));
|
||||||
ai->setTarget(player.get());
|
ai->setTarget(player.get());
|
||||||
|
if (behaviour != nullptr)
|
||||||
ai->attachBehaviourScript(std::move(behaviour));
|
ai->attachBehaviourScript(std::move(behaviour));
|
||||||
entity->addComponent(std::make_unique<AIComponent>(ai));
|
entity->addComponent(std::make_unique<AIComponent>(ai));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
#include "graphics/texture.h"
|
#include "graphics/texture.h"
|
||||||
#include "utility/logger.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "utility/logger.h"
|
||||||
|
|
||||||
bool Texture::loadTexture(const char* imagePath)
|
bool Texture::loadTexture(const char *imagePath) {
|
||||||
{
|
SDL_Surface *buffer = IMG_Load(imagePath);
|
||||||
SDL_Surface* buffer = IMG_Load(imagePath);
|
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
ERROR_LOG("Failed to load image file: {}", imagePath);
|
ERROR_LOG("Failed to load image file: {}", imagePath);
|
||||||
//UTIL::flip_surface(buffer);
|
// UTIL::flip_surface(buffer);
|
||||||
|
|
||||||
glGenTextures(1, &ID);
|
glGenTextures(1, &ID);
|
||||||
/*
|
/*
|
||||||
|
|
@ -19,12 +18,13 @@ bool Texture::loadTexture(const char* imagePath)
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, ID);
|
glBindTexture(GL_TEXTURE_2D, ID);
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, buffer->w, buffer->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer->pixels);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, buffer->w, buffer->h, 0, GL_RGBA,
|
||||||
|
GL_UNSIGNED_BYTE, buffer->pixels);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glGenerateMipmap(ID);
|
glGenerateMipmap(ID);
|
||||||
|
|
||||||
textureWidth = buffer->w;
|
textureWidth = buffer->w;
|
||||||
|
|
@ -35,31 +35,27 @@ bool Texture::loadTexture(const char* imagePath)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::bind()
|
void Texture::bind() {
|
||||||
{
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, ID);
|
glBindTexture(GL_TEXTURE_2D, ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Texture::~Texture() { glDeleteTextures(1, &ID); }
|
||||||
|
|
||||||
Texture::~Texture()
|
bool TextureArray::loadTextures(std::vector<const char *> imagePaths) {
|
||||||
{
|
std::vector<SDL_Surface *> surfaces;
|
||||||
glDeleteTextures(1, &ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextureArray::loadTextures(std::vector<const char*> imagePaths)
|
|
||||||
{
|
|
||||||
std::vector<SDL_Surface*> surfaces;
|
|
||||||
surfaces.resize(imagePaths.size());
|
surfaces.resize(imagePaths.size());
|
||||||
// Fill surfaces vector
|
// Fill surfaces vector
|
||||||
for (int i = 0; i < imagePaths.size(); ++i)
|
for (int i = 0; i < imagePaths.size(); ++i) {
|
||||||
{
|
|
||||||
surfaces[i] = IMG_Load(imagePaths[i]);
|
surfaces[i] = IMG_Load(imagePaths[i]);
|
||||||
if (!surfaces[i])
|
if (!surfaces[i])
|
||||||
ERROR_LOG("Failed to load image file: {}", imagePaths[i]);
|
ERROR_LOG("Failed to load image file: {}", imagePaths[i]);
|
||||||
}
|
}
|
||||||
if (!adjustCanvasSizes(surfaces))
|
if (!adjustCanvasSizes(surfaces))
|
||||||
ERROR_LOG("Failed to adjust canvas size of images! \n Make sure to check that every tileset has square dimensions! (512x512, 756x756 ... etc)", NULL);
|
ERROR_LOG(
|
||||||
|
"Failed to adjust canvas size of images! \n Make sure to check that "
|
||||||
|
"every tileset has square dimensions! (512x512, 756x756 ... etc)",
|
||||||
|
NULL);
|
||||||
if (surfaces.empty())
|
if (surfaces.empty())
|
||||||
ERROR_LOG("No surfaces created!", NULL);
|
ERROR_LOG("No surfaces created!", NULL);
|
||||||
numOfLayers = imagePaths.size();
|
numOfLayers = imagePaths.size();
|
||||||
|
|
@ -68,29 +64,14 @@ bool TextureArray::loadTextures(std::vector<const char*> imagePaths)
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, ID);
|
glBindTexture(GL_TEXTURE_2D_ARRAY, ID);
|
||||||
|
|
||||||
// Creating the texture array all of our textures will live in.
|
// Creating the texture array all of our textures will live in.
|
||||||
// adjustCanvasSizes makes every image the same size, so we can just use the first
|
// adjustCanvasSizes makes every image the same size, so we can just use the
|
||||||
// surface in the list of surfaces
|
// first surface in the list of surfaces
|
||||||
glTexImage3D(GL_TEXTURE_2D_ARRAY,
|
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, surfaces[0]->w, surfaces[0]->h,
|
||||||
0,
|
(GLsizei)numOfLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
GL_RGBA,
|
|
||||||
surfaces[0]->w,
|
|
||||||
surfaces[0]->h,
|
|
||||||
(GLsizei)numOfLayers,
|
|
||||||
0,
|
|
||||||
GL_RGBA,
|
|
||||||
GL_UNSIGNED_BYTE,
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
for (int layer = 0; layer < numOfLayers; ++layer)
|
for (int layer = 0; layer < numOfLayers; ++layer) {
|
||||||
{
|
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, layer, surfaces[layer]->w,
|
||||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
|
surfaces[layer]->h, 1, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
0,
|
|
||||||
0, 0, layer,
|
|
||||||
surfaces[layer]->w,
|
|
||||||
surfaces[layer]->h,
|
|
||||||
1,
|
|
||||||
GL_RGBA,
|
|
||||||
GL_UNSIGNED_BYTE,
|
|
||||||
surfaces[layer]->pixels);
|
surfaces[layer]->pixels);
|
||||||
}
|
}
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
|
@ -100,40 +81,36 @@ bool TextureArray::loadTextures(std::vector<const char*> imagePaths)
|
||||||
|
|
||||||
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
||||||
|
|
||||||
for (auto& surface : surfaces)
|
for (auto &surface : surfaces)
|
||||||
SDL_FreeSurface(surface);
|
SDL_FreeSurface(surface);
|
||||||
surfaces.clear();
|
surfaces.clear();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureArray::bind()
|
void TextureArray::bind() {
|
||||||
{
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, ID);
|
glBindTexture(GL_TEXTURE_2D_ARRAY, ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureArray::adjustCanvasSizes(std::vector<SDL_Surface*>& surfaces)
|
bool TextureArray::adjustCanvasSizes(std::vector<SDL_Surface *> &surfaces) {
|
||||||
{
|
|
||||||
int maxWidth = 0;
|
int maxWidth = 0;
|
||||||
int maxHeight = 0;
|
int maxHeight = 0;
|
||||||
for (auto& surface : surfaces)
|
for (auto &surface : surfaces) {
|
||||||
{
|
|
||||||
if (surface->w != surface->h)
|
if (surface->w != surface->h)
|
||||||
ERROR_LOG("Image must be a square!", NULL);
|
ERROR_LOG("Image must be a square!", NULL);
|
||||||
|
|
||||||
if (surface->w > maxWidth) maxWidth = surface->w;
|
if (surface->w > maxWidth)
|
||||||
if (surface->h > maxHeight) maxHeight = surface->h;
|
maxWidth = surface->w;
|
||||||
textures.push_back(TextureData({ surface->w, surface->h }));
|
if (surface->h > maxHeight)
|
||||||
|
maxHeight = surface->h;
|
||||||
|
textures.push_back(TextureData({surface->w, surface->h}));
|
||||||
}
|
}
|
||||||
for (int i = 0; i < surfaces.size(); ++i)
|
for (int i = 0; i < surfaces.size(); ++i) {
|
||||||
{
|
SDL_Surface *canvas = SDL_CreateRGBSurface(
|
||||||
SDL_Surface* canvas = SDL_CreateRGBSurface(0, maxWidth, maxHeight,
|
0, maxWidth, maxHeight, surfaces[i]->format->BitsPerPixel,
|
||||||
surfaces[i]->format->BitsPerPixel,
|
surfaces[i]->format->Rmask, surfaces[i]->format->Gmask,
|
||||||
surfaces[i]->format->Rmask,
|
surfaces[i]->format->Bmask, surfaces[i]->format->Amask);
|
||||||
surfaces[i]->format->Gmask,
|
|
||||||
surfaces[i]->format->Bmask,
|
|
||||||
surfaces[i]->format->Amask);
|
|
||||||
|
|
||||||
SDL_FillRect(canvas, NULL, SDL_MapRGBA(canvas->format, 0, 0, 0, 0));
|
SDL_FillRect(canvas, NULL, SDL_MapRGBA(canvas->format, 0, 0, 0, 0));
|
||||||
|
|
||||||
|
|
@ -149,7 +126,4 @@ bool TextureArray::adjustCanvasSizes(std::vector<SDL_Surface*>& surfaces)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureArray::~TextureArray()
|
TextureArray::~TextureArray() { glDeleteTextures(1, &ID); }
|
||||||
{
|
|
||||||
glDeleteTextures(1, &ID);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,26 @@
|
||||||
#include "utility/resourcemanager.h"
|
#include "utility/resourcemanager.h"
|
||||||
|
#include "gameplay/weapons/weapons.h"
|
||||||
|
#include "graphics/animation.h"
|
||||||
|
#include "graphics/background.h"
|
||||||
|
#include "graphics/shader.h"
|
||||||
#include "graphics/sprite.h"
|
#include "graphics/sprite.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utility/script.h"
|
#include "utility/script.h"
|
||||||
#include "graphics/shader.h"
|
|
||||||
#include "graphics/animation.h"
|
|
||||||
#include "graphics/background.h"
|
|
||||||
#include "gameplay/weapons/weapons.h"
|
|
||||||
|
|
||||||
SpriteAtlas* ResourceManager::loadSpriteAtlas(const std::string& path, float frameSize, bool isDirectional)
|
SpriteAtlas *ResourceManager::loadSpriteAtlas(const std::string &path,
|
||||||
{
|
float frameSize,
|
||||||
|
bool isDirectional) {
|
||||||
auto iterator = sprites.find(path);
|
auto iterator = sprites.find(path);
|
||||||
if (iterator != sprites.end())
|
if (iterator != sprites.end())
|
||||||
return static_cast<SpriteAtlas*>(iterator->second.get());
|
return static_cast<SpriteAtlas *>(iterator->second.get());
|
||||||
auto sprite = std::make_unique<SpriteAtlas>(path.c_str(), frameSize, isDirectional);
|
auto sprite =
|
||||||
|
std::make_unique<SpriteAtlas>(path.c_str(), frameSize, isDirectional);
|
||||||
sprites[path] = std::move(sprite);
|
sprites[path] = std::move(sprite);
|
||||||
SpriteAtlas& l = static_cast<SpriteAtlas&>(*sprites[path].get());
|
SpriteAtlas &l = static_cast<SpriteAtlas &>(*sprites[path].get());
|
||||||
return static_cast<SpriteAtlas*>(sprites[path].get());
|
return static_cast<SpriteAtlas *>(sprites[path].get());
|
||||||
}
|
}
|
||||||
|
|
||||||
Sprite* ResourceManager::loadSpriteStatic(const std::string& path)
|
Sprite *ResourceManager::loadSpriteStatic(const std::string &path) {
|
||||||
{
|
|
||||||
auto iterator = sprites.find(path);
|
auto iterator = sprites.find(path);
|
||||||
if (iterator != sprites.end())
|
if (iterator != sprites.end())
|
||||||
return iterator->second.get();
|
return iterator->second.get();
|
||||||
|
|
@ -30,23 +31,13 @@ Sprite* ResourceManager::loadSpriteStatic(const std::string& path)
|
||||||
return sprites[path].get();
|
return sprites[path].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AIScript> ResourceManager::loadAIScript(const std::string& path)
|
const TileSetData *ResourceManager::loadTileSet(const std::string &name) {
|
||||||
{
|
|
||||||
return std::make_unique<AIScript>(path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<WeaponScript> ResourceManager::loadWeaponScript(const std::string& path)
|
|
||||||
{
|
|
||||||
return std::make_unique<WeaponScript>(path.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
const TileSetData* ResourceManager::loadTileSet(const std::string& name)
|
|
||||||
{
|
|
||||||
return xmlLoader->getTileSetData(name);
|
return xmlLoader->getTileSetData(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned ResourceManager::loadShader(const std::string& name, const std::string& vertexPath, const std::string& fragPath)
|
const unsigned ResourceManager::loadShader(const std::string &name,
|
||||||
{
|
const std::string &vertexPath,
|
||||||
|
const std::string &fragPath) {
|
||||||
auto iterator = shaders.find(name);
|
auto iterator = shaders.find(name);
|
||||||
if (iterator != shaders.end())
|
if (iterator != shaders.end())
|
||||||
return iterator->second->ID;
|
return iterator->second->ID;
|
||||||
|
|
@ -60,14 +51,13 @@ const unsigned ResourceManager::loadShader(const std::string& name, const std::s
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader* ResourceManager::getShaderByID(unsigned int ID)
|
Shader *ResourceManager::getShaderByID(unsigned int ID) {
|
||||||
{
|
|
||||||
auto iterator = shaderIDs.find(ID);
|
auto iterator = shaderIDs.find(ID);
|
||||||
return (iterator != shaderIDs.end() ? iterator->second : shaders["__fallback__"].get());
|
return (iterator != shaderIDs.end() ? iterator->second
|
||||||
|
: shaders["__fallback__"].get());
|
||||||
}
|
}
|
||||||
|
|
||||||
Background* ResourceManager::loadBackground(const std::string& path)
|
Background *ResourceManager::loadBackground(const std::string &path) {
|
||||||
{
|
|
||||||
auto iterator = backgrounds.find(path);
|
auto iterator = backgrounds.find(path);
|
||||||
if (iterator != backgrounds.end())
|
if (iterator != backgrounds.end())
|
||||||
return iterator->second.get();
|
return iterator->second.get();
|
||||||
|
|
@ -76,27 +66,31 @@ Background* ResourceManager::loadBackground(const std::string& path)
|
||||||
return backgrounds[path].get();
|
return backgrounds[path].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
// We attach our script after we create our weapon because we are passing a reference to the weapon into the script and we don't want to pass an
|
// We attach our script after we create our weapon because we are passing a
|
||||||
|
// reference to the weapon into the script and we don't want to pass an
|
||||||
// incomplete reference to our script.
|
// incomplete reference to our script.
|
||||||
std::unique_ptr<Weapon> ResourceManager::loadWeapon(const std::string& id, const unsigned weaponShaderID, const unsigned bulletShaderID)
|
std::unique_ptr<Weapon>
|
||||||
{
|
ResourceManager::loadWeapon(const std::string &id,
|
||||||
const WeaponData* data = xmlLoader->getWeaponData(id);
|
const unsigned weaponShaderID,
|
||||||
|
const unsigned bulletShaderID) {
|
||||||
|
const WeaponData *data = xmlLoader->getWeaponData(id);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
LOG(ERROR, "Could not load weapon id '{}', falling back to pistol", id);
|
LOG(ERROR, "Could not load weapon id '{}', falling back to pistol", id);
|
||||||
data = xmlLoader->getWeaponData("gun/pistol");// using this as a fallback for now
|
data = xmlLoader->getWeaponData(
|
||||||
|
"gun/pistol"); // using this as a fallback for now
|
||||||
}
|
}
|
||||||
auto weapon = std::make_unique<Weapon>(data, weaponShaderID, bulletShaderID, this);
|
auto weapon =
|
||||||
|
std::make_unique<Weapon>(data, weaponShaderID, bulletShaderID, this);
|
||||||
if (!data->script.empty())
|
if (!data->script.empty())
|
||||||
weapon->attachScript(loadWeaponScript(data->script));
|
weapon->attachScript(loadScript<WeaponScript>(data->script));
|
||||||
return std::move(weapon);
|
return std::move(weapon);
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned ResourceManager::loadSoundEffect(const std::string& id)
|
const unsigned ResourceManager::loadSoundEffect(const std::string &id) {
|
||||||
{
|
|
||||||
auto iterator = sounds.find(id);
|
auto iterator = sounds.find(id);
|
||||||
if (iterator != sounds.end())
|
if (iterator != sounds.end())
|
||||||
return iterator->second->getBuffer();
|
return iterator->second->getBuffer();
|
||||||
auto soundData = xmlLoader->getSoundData(id) ;
|
auto soundData = xmlLoader->getSoundData(id);
|
||||||
if (!soundData) {
|
if (!soundData) {
|
||||||
soundData = xmlLoader->getSoundData(UTIL::get_generic(id));
|
soundData = xmlLoader->getSoundData(UTIL::get_generic(id));
|
||||||
LOG(WARN, "Could not load sound id: '{}' trying generic", id);
|
LOG(WARN, "Could not load sound id: '{}' trying generic", id);
|
||||||
|
|
@ -108,42 +102,44 @@ const unsigned ResourceManager::loadSoundEffect(const std::string& id)
|
||||||
return sounds[id]->getBuffer();
|
return sounds[id]->getBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
const SceneData* ResourceManager::loadScene(const std::string& id)
|
const SceneData *ResourceManager::loadScene(const std::string &id) {
|
||||||
{
|
|
||||||
return xmlLoader->getSceneData(id);
|
return xmlLoader->getSceneData(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<AnimationSet> ResourceManager::loadAnimationSet(const std::string& prefix, int entityid)
|
std::shared_ptr<AnimationSet>
|
||||||
{
|
ResourceManager::loadAnimationSet(const std::string &prefix, int entityid) {
|
||||||
auto animSetData = xmlLoader->getAnimationSet(prefix);
|
auto animSetData = xmlLoader->getAnimationSet(prefix);
|
||||||
|
|
||||||
return std::make_shared<AnimationSet>(entityid, this, animSetData);
|
return std::make_shared<AnimationSet>(entityid, this, animSetData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this will need some work, but for now where there is only one weapon type we can work with it
|
void ResourceManager::clearResources() {
|
||||||
// TODO: Allow different weapon types!
|
|
||||||
/*
|
|
||||||
template <typename T>
|
|
||||||
std::shared_ptr<T> ResourceManager::loadWeapon(const std::string& name, std::shared_ptr<Shader> shader, std::shared_ptr<SpriteComponent> spriteComponent)
|
|
||||||
{
|
|
||||||
auto iterator = weapons.find(name);
|
|
||||||
if (iterator != weapons.end())
|
|
||||||
return iterator->second;
|
|
||||||
auto weapon = std::make_shared<T>(T(shader, spriteComponent));
|
|
||||||
weapons[name] = weapon;
|
|
||||||
return weapon;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void ResourceManager::clearResources()
|
|
||||||
{
|
|
||||||
sprites.clear();
|
sprites.clear();
|
||||||
shaders.clear();
|
shaders.clear();
|
||||||
shaderIDs.clear();
|
shaderIDs.clear();
|
||||||
tileSets.clear();
|
tileSets.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceManager::~ResourceManager()
|
ResourceManager::~ResourceManager() {
|
||||||
{
|
|
||||||
clearResources();
|
clearResources();
|
||||||
xmlLoader.reset();
|
xmlLoader.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ResourceManager::loadLuaString(ScriptData *scriptData) {
|
||||||
|
std::filesystem::path file(scriptData->fileName);
|
||||||
|
if (file.empty() || !file.has_extension())
|
||||||
|
return false;
|
||||||
|
try {
|
||||||
|
|
||||||
|
std::ifstream fileStream(file);
|
||||||
|
std::ostringstream sstr;
|
||||||
|
sstr << fileStream.rdbuf();
|
||||||
|
scriptData->script = sstr.str().c_str();
|
||||||
|
fileStream.close();
|
||||||
|
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
ERROR_LOG("Failed to read script file: '{}' - '{}'", scriptData->fileName,
|
||||||
|
e.what());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,17 @@
|
||||||
Loading every scene in the scene folder and storing in hashmap scenes
|
Loading every scene in the scene folder and storing in hashmap scenes
|
||||||
hashkey is the id of the scene
|
hashkey is the id of the scene
|
||||||
*/
|
*/
|
||||||
bool XMLLoader::loadScenes(const char* sceneFolder)
|
bool XMLLoader::loadScenes(const char *sceneFolder) {
|
||||||
{
|
|
||||||
std::filesystem::path folder(sceneFolder);
|
std::filesystem::path folder(sceneFolder);
|
||||||
if (!std::filesystem::exists(folder) || !std::filesystem::is_directory(folder))
|
if (!std::filesystem::exists(folder) ||
|
||||||
|
!std::filesystem::is_directory(folder))
|
||||||
ERROR_LOG("'{}' folder not found!", sceneFolder);
|
ERROR_LOG("'{}' folder not found!", sceneFolder);
|
||||||
for (auto& file : std::filesystem::directory_iterator(folder))
|
for (auto &file : std::filesystem::directory_iterator(folder)) {
|
||||||
{
|
if (!file.path().has_extension() || !file.path().has_filename() ||
|
||||||
if (!file.path().has_extension() || !file.path().has_filename() || !file.exists() || file.is_directory())
|
!file.exists() || file.is_directory())
|
||||||
continue;
|
continue;
|
||||||
SceneData scene;
|
SceneData scene;
|
||||||
if (!loadXmlScene((const char*)file.path().string().c_str(), &scene))
|
if (!loadXmlScene((const char *)file.path().string().c_str(), &scene))
|
||||||
continue;
|
continue;
|
||||||
scenes.try_emplace(scene.id, std::make_unique<SceneData>(scene));
|
scenes.try_emplace(scene.id, std::make_unique<SceneData>(scene));
|
||||||
}
|
}
|
||||||
|
|
@ -28,14 +28,13 @@ bool XMLLoader::loadScenes(const char* sceneFolder)
|
||||||
/*
|
/*
|
||||||
Loading scene data
|
Loading scene data
|
||||||
*/
|
*/
|
||||||
bool XMLLoader::loadXmlScene(const char* xmlFile, SceneData* out)
|
bool XMLLoader::loadXmlScene(const char *xmlFile, SceneData *out) {
|
||||||
{
|
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
if (doc.LoadFile(xmlFile) != tinyxml2::XML_SUCCESS)
|
if (doc.LoadFile(xmlFile) != tinyxml2::XML_SUCCESS)
|
||||||
ERROR_LOG("Failed to load file: {}", xmlFile);
|
ERROR_LOG("Failed to load file: {}", xmlFile);
|
||||||
tinyxml2::XMLElement* scene = doc.FirstChildElement("scene");
|
tinyxml2::XMLElement *scene = doc.FirstChildElement("scene");
|
||||||
|
|
||||||
const char* type, * id, * mapName, * bgFile;
|
const char *type, *id, *mapName, *bgFile;
|
||||||
if (scene->QueryStringAttribute("type", &type) != tinyxml2::XML_SUCCESS ||
|
if (scene->QueryStringAttribute("type", &type) != tinyxml2::XML_SUCCESS ||
|
||||||
scene->QueryStringAttribute("id", &id) != tinyxml2::XML_SUCCESS)
|
scene->QueryStringAttribute("id", &id) != tinyxml2::XML_SUCCESS)
|
||||||
ERROR_LOG("Could not read type or id tag in file: {}", xmlFile);
|
ERROR_LOG("Could not read type or id tag in file: {}", xmlFile);
|
||||||
|
|
@ -47,7 +46,7 @@ bool XMLLoader::loadXmlScene(const char* xmlFile, SceneData* out)
|
||||||
else
|
else
|
||||||
out->bgFile = bgFile;
|
out->bgFile = bgFile;
|
||||||
|
|
||||||
tinyxml2::XMLElement* map = scene->FirstChildElement("map");
|
tinyxml2::XMLElement *map = scene->FirstChildElement("map");
|
||||||
if (map == NULL)
|
if (map == NULL)
|
||||||
ERROR_LOG("Could not find 'map' tag in file: {}", xmlFile);
|
ERROR_LOG("Could not find 'map' tag in file: {}", xmlFile);
|
||||||
if (map->QueryStringAttribute("name", &mapName) != tinyxml2::XML_SUCCESS)
|
if (map->QueryStringAttribute("name", &mapName) != tinyxml2::XML_SUCCESS)
|
||||||
|
|
@ -62,43 +61,145 @@ bool XMLLoader::loadXmlScene(const char* xmlFile, SceneData* out)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Load entity data held in the scene file, store inside of the SceneData out parameter
|
* Load monster definitions
|
||||||
|
*/
|
||||||
|
bool XMLLoader::loadMonsters(const char *monsterFolder) {
|
||||||
|
std::filesystem::path folder(monsterFolder);
|
||||||
|
if (!std::filesystem::exists(folder) ||
|
||||||
|
!std::filesystem::is_directory(folder))
|
||||||
|
ERROR_LOG("''{}' folder does not exist!", monsterFolder);
|
||||||
|
|
||||||
|
for (auto &file : std::filesystem::directory_iterator(folder)) {
|
||||||
|
if (!file.path().has_extension() || !file.path().has_filename() ||
|
||||||
|
!file.exists() || file.is_directory())
|
||||||
|
continue;
|
||||||
|
tinyxml2::XMLDocument doc;
|
||||||
|
if (doc.LoadFile(file.path().generic_string().c_str()) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (tinyxml2::XMLElement *e = doc.FirstChildElement("monster");
|
||||||
|
e != nullptr; e = e->NextSiblingElement("monster")) {
|
||||||
|
const char *id, *anim, *weapon, *behaviour;
|
||||||
|
|
||||||
|
MonsterData data;
|
||||||
|
data.aggressive = false;
|
||||||
|
|
||||||
|
// The rules for creating a monster is pretty strict, since we can always
|
||||||
|
// just create entities without creating a definition for them as well.
|
||||||
|
if (e->QueryStringAttribute("id", &id) != tinyxml2::XML_SUCCESS ||
|
||||||
|
e->QueryStringAttribute("anim", &anim) != tinyxml2::XML_SUCCESS ||
|
||||||
|
e->QueryStringAttribute("weapon", &weapon) != tinyxml2::XML_SUCCESS ||
|
||||||
|
e->QueryStringAttribute("behaviour", &behaviour) !=
|
||||||
|
tinyxml2::XML_SUCCESS ||
|
||||||
|
e->QueryFloatAttribute("hp", &data.hp) != tinyxml2::XML_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
e->QueryBoolAttribute("aggressive", &data.aggressive);
|
||||||
|
|
||||||
|
data.id = id;
|
||||||
|
data.anim = anim;
|
||||||
|
data.weapon = weapon;
|
||||||
|
data.behaviour = behaviour;
|
||||||
|
|
||||||
|
monsters.try_emplace(data.id, std::make_unique<MonsterData>(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Loading scripts from the xml file then storing the information inside of the
|
||||||
|
* ScriptData definition struct. This includes storing our script contents. This
|
||||||
|
* is mostly a test, but I feel like it would be faster to hold the scripts as
|
||||||
|
* raw string we store at boot then load based on their ID. It certainly makes
|
||||||
|
* creating definitions easier and cleaner to look at.
|
||||||
|
*
|
||||||
|
* It is the responsibilty of the resource manager to open read read the lua
|
||||||
|
* file via the luaLoader function!
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool XMLLoader::loadScripts(const char *scriptFolder,
|
||||||
|
std::function<bool(ScriptData *)> luaLoader) {
|
||||||
|
std::filesystem::path folder(scriptFolder);
|
||||||
|
if (!std::filesystem::exists(folder) ||
|
||||||
|
!std::filesystem::is_directory(folder))
|
||||||
|
ERROR_LOG("'{}' folder does not exist!", scriptFolder);
|
||||||
|
|
||||||
|
for (auto &file : std::filesystem::directory_iterator(folder)) {
|
||||||
|
if (!file.path().has_extension() || !file.path().has_filename() ||
|
||||||
|
!file.exists() || file.is_directory())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tinyxml2::XMLDocument doc;
|
||||||
|
if (doc.LoadFile(file.path().generic_string().c_str()) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (tinyxml2::XMLElement *e = doc.FirstChildElement("script");
|
||||||
|
e != nullptr; e = e->NextSiblingElement("script")) {
|
||||||
|
ScriptData scriptData;
|
||||||
|
const char *id, *fileName;
|
||||||
|
if (e->QueryStringAttribute("id", &id) != tinyxml2::XML_SUCCESS ||
|
||||||
|
e->QueryStringAttribute("file", &fileName) != tinyxml2::XML_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
scriptData.id = id;
|
||||||
|
scriptData.fileName = fileName;
|
||||||
|
|
||||||
|
if (!luaLoader(&scriptData)) {
|
||||||
|
LOG(ERROR, "Failed to load script '{}'", fileName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
scripts.try_emplace(scriptData.id,
|
||||||
|
std::make_unique<ScriptData>(scriptData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Load entity data held in the scene file, store inside of the SceneData
|
||||||
|
out parameter
|
||||||
*/
|
*/
|
||||||
bool XMLLoader::loadEntityData(const char* xmlFile, SceneData* out)
|
bool XMLLoader::loadEntityData(const char *xmlFile, SceneData *out) {
|
||||||
{
|
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
if (doc.LoadFile(xmlFile) != tinyxml2::XML_SUCCESS)
|
if (doc.LoadFile(xmlFile) != tinyxml2::XML_SUCCESS)
|
||||||
ERROR_LOG("Failed to load file: {}", xmlFile);
|
ERROR_LOG("Failed to load file: {}", xmlFile);
|
||||||
|
|
||||||
tinyxml2::XMLElement* entities = doc.FirstChildElement()->FirstChildElement("entities");
|
tinyxml2::XMLElement *entities =
|
||||||
|
doc.FirstChildElement()->FirstChildElement("entities");
|
||||||
|
|
||||||
// Adding the player. Player must be in the scene or the scene will not load!
|
// Adding the player. Player must be in the scene or the scene will not load!
|
||||||
tinyxml2::XMLElement* playerElement = entities->FirstChildElement("player");
|
tinyxml2::XMLElement *playerElement = entities->FirstChildElement("player");
|
||||||
if (playerElement == NULL)
|
if (playerElement == NULL)
|
||||||
ERROR_LOG("Player element not found in scene! File: {}", xmlFile);
|
ERROR_LOG("Player element not found in scene! File: {}", xmlFile);
|
||||||
|
|
||||||
EntityData playData;
|
EntityData playData;
|
||||||
const char *graphic, *weaponName = "pistol";
|
const char *graphic, *weaponName = "pistol";
|
||||||
|
|
||||||
if (playerElement->QueryIntAttribute("x", &playData.x) != tinyxml2::XML_SUCCESS ||
|
if (playerElement->QueryIntAttribute("x", &playData.x) !=
|
||||||
playerElement->QueryIntAttribute("y", &playData.y) != tinyxml2::XML_SUCCESS)
|
tinyxml2::XML_SUCCESS ||
|
||||||
ERROR_LOG("Failed to find x or y attribute in 'player' tag. File: {}", xmlFile);
|
playerElement->QueryIntAttribute("y", &playData.y) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
|
ERROR_LOG("Failed to find x or y attribute in 'player' tag. File: {}",
|
||||||
|
xmlFile);
|
||||||
playerElement->QueryStringAttribute("weapon", &weaponName);
|
playerElement->QueryStringAttribute("weapon", &weaponName);
|
||||||
tinyxml2::XMLElement* anim = playerElement->FirstChildElement("animation");
|
tinyxml2::XMLElement *anim = playerElement->FirstChildElement("animation");
|
||||||
if (anim == NULL)
|
if (anim == NULL) {
|
||||||
{
|
|
||||||
playData.animated = false;
|
playData.animated = false;
|
||||||
tinyxml2::XMLElement* sprite = playerElement->FirstChildElement("sprite");
|
tinyxml2::XMLElement *sprite = playerElement->FirstChildElement("sprite");
|
||||||
if (sprite == NULL)
|
if (sprite == NULL)
|
||||||
ERROR_LOG("Could not find tag 'sprite' in 'player' tag. File: {}", xmlFile);
|
ERROR_LOG("Could not find tag 'sprite' in 'player' tag. File: {}",
|
||||||
|
xmlFile);
|
||||||
if (sprite->QueryStringAttribute("file", &graphic) != tinyxml2::XML_SUCCESS)
|
if (sprite->QueryStringAttribute("file", &graphic) != tinyxml2::XML_SUCCESS)
|
||||||
ERROR_LOG("Could not find attribute 'file' in 'player' -> 'sprite' tag. File: {}", xmlFile);
|
ERROR_LOG("Could not find attribute 'file' in 'player' -> 'sprite' tag. "
|
||||||
}
|
"File: {}",
|
||||||
else
|
xmlFile);
|
||||||
{
|
} else {
|
||||||
playData.animated = true;
|
playData.animated = true;
|
||||||
if (anim->QueryStringAttribute("id", &graphic) != tinyxml2::XML_SUCCESS)
|
if (anim->QueryStringAttribute("id", &graphic) != tinyxml2::XML_SUCCESS)
|
||||||
ERROR_LOG("Could not find 'name' attribute in 'animation' tag. File: {}", xmlFile);
|
ERROR_LOG("Could not find 'name' attribute in 'animation' tag. File: {}",
|
||||||
|
xmlFile);
|
||||||
}
|
}
|
||||||
playData.isPlayer = true;
|
playData.isPlayer = true;
|
||||||
playData.graphic = graphic;
|
playData.graphic = graphic;
|
||||||
|
|
@ -110,35 +211,59 @@ bool XMLLoader::loadEntityData(const char* xmlFile, SceneData* out)
|
||||||
// Adding every other entity...
|
// Adding every other entity...
|
||||||
// TODO: Add npcs to game and enable their use with XMLLoader
|
// TODO: Add npcs to game and enable their use with XMLLoader
|
||||||
|
|
||||||
for (tinyxml2::XMLElement* e = entities->FirstChildElement("entity"); e != NULL; e = e->NextSiblingElement("entity"))
|
for (tinyxml2::XMLElement *e = entities->FirstChildElement("entity");
|
||||||
{
|
e != NULL; e = e->NextSiblingElement("entity")) {
|
||||||
EntityData data;
|
EntityData data;
|
||||||
const char *graphic, *weaponName = "pistol", *scriptPath;
|
const char *monsterDef, *graphic, *weaponID, *scriptID;
|
||||||
if (e->QueryIntAttribute("x", &data.x) != tinyxml2::XML_SUCCESS ||
|
if (e->QueryIntAttribute("x", &data.x) != tinyxml2::XML_SUCCESS ||
|
||||||
e->QueryIntAttribute("y", &data.y) != tinyxml2::XML_SUCCESS)
|
e->QueryIntAttribute("y", &data.y) != tinyxml2::XML_SUCCESS)
|
||||||
ERROR_LOG("Could not load position coordinates for entity. File: {}", xmlFile);
|
ERROR_LOG("Could not load position coordinates for entity. File: {}",
|
||||||
|
xmlFile);
|
||||||
e->QueryStringAttribute("weapon", &weaponName);
|
e->QueryStringAttribute("weapon", &weaponName);
|
||||||
tinyxml2::XMLElement* anim = e->FirstChildElement("animation");
|
e->QueryStringAttribute("monster_id", &monsterDef);
|
||||||
if (anim == NULL)
|
// If we find that the entity has a monster definition we will fill in the
|
||||||
{
|
// defaults Having a monster definition means we must be animated by default
|
||||||
|
// and we will prefer the animated default for now.
|
||||||
|
if (monsterDef != NULL && monsters[monsterDef] != NULL) {
|
||||||
|
// Setting up the defaults
|
||||||
|
data.animated = true;
|
||||||
|
data.monsterDef = monsterDef;
|
||||||
|
weaponID = monsters[monsterDef]->weapon.c_str();
|
||||||
|
graphic = monsters[monsterDef]->anim.c_str();
|
||||||
|
scriptID = monsters[monsterDef]->behaviour.c_str();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// So if we look for the animation tag and there is no monster definition
|
||||||
|
// only then will we take in a sprite as the graphic
|
||||||
|
tinyxml2::XMLElement *anim = e->FirstChildElement("animation");
|
||||||
|
if (anim == NULL && data.monsterDef.empty()) {
|
||||||
data.animated = false;
|
data.animated = false;
|
||||||
tinyxml2::XMLElement* sprite = e->FirstChildElement("sprite");
|
tinyxml2::XMLElement *sprite = e->FirstChildElement("sprite");
|
||||||
if (sprite == NULL)
|
if (sprite == NULL)
|
||||||
continue;
|
continue;
|
||||||
if (sprite->QueryStringAttribute("file", &graphic) != tinyxml2::XML_SUCCESS)
|
if (sprite->QueryStringAttribute("file", &graphic) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
}
|
} else if (data.monsterDef.empty()) {
|
||||||
else
|
|
||||||
{
|
|
||||||
data.animated = true;
|
data.animated = true;
|
||||||
if (anim->QueryStringAttribute("id", &graphic) != tinyxml2::XML_SUCCESS)
|
if (anim->QueryStringAttribute("id", &graphic) != tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
|
} else if (anim != NULL) {
|
||||||
|
// We will take alternative animation ids if specified
|
||||||
|
data.animated = true;
|
||||||
|
anim->QueryStringAttribute("id", &graphic);
|
||||||
}
|
}
|
||||||
tinyxml2::XMLElement* script = e->FirstChildElement("script");
|
} catch (std::exception &e) {
|
||||||
script->QueryStringAttribute("file", &scriptPath);
|
LOG(ERROR, "Failed to load entity! ''{}'", e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// We just overload the script id if there is an overload given
|
||||||
|
tinyxml2::XMLElement *script = e->FirstChildElement("script");
|
||||||
|
if (script != NULL)
|
||||||
|
script->QueryStringAttribute("id", &scriptID);
|
||||||
data.isPlayer = false;
|
data.isPlayer = false;
|
||||||
data.graphic = graphic;
|
data.graphic = graphic;
|
||||||
data.script = scriptPath;
|
data.script = scriptID;
|
||||||
data.weapon = weaponName;
|
data.weapon = weaponName;
|
||||||
|
|
||||||
out->entities.push_back(data);
|
out->entities.push_back(data);
|
||||||
|
|
@ -147,40 +272,41 @@ bool XMLLoader::loadEntityData(const char* xmlFile, SceneData* out)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getFloatIfExists(tinyxml2::XMLElement* e)
|
float getFloatIfExists(tinyxml2::XMLElement *e) {
|
||||||
{
|
|
||||||
float buf = 0.f;
|
float buf = 0.f;
|
||||||
if (e)
|
if (e) {
|
||||||
{
|
|
||||||
e->QueryFloatText(&buf);
|
e->QueryFloatText(&buf);
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Load every weapon file, weapon nodes can be fit together in one file or placed in seperate files.
|
Load every weapon file, weapon nodes can be fit together in one file or
|
||||||
hash key is the weapon name
|
placed in seperate files. hash key is the weapon id
|
||||||
*/
|
*/
|
||||||
bool XMLLoader::loadWeapons(const char* weaponFolder)
|
bool XMLLoader::loadWeapons(const char *weaponFolder) {
|
||||||
{
|
// We are gonna check every xml file within the weaponFolder, then check every
|
||||||
// We are gonna check every xml file within the weaponFolder, then check every weapon node within each file.
|
// weapon node within each file.
|
||||||
std::filesystem::path folder(weaponFolder);
|
std::filesystem::path folder(weaponFolder);
|
||||||
if (!std::filesystem::exists(folder) || !std::filesystem::is_directory(folder))
|
if (!std::filesystem::exists(folder) ||
|
||||||
|
!std::filesystem::is_directory(folder))
|
||||||
ERROR_LOG("'{}' folder does not exist!", weaponFolder);
|
ERROR_LOG("'{}' folder does not exist!", weaponFolder);
|
||||||
for (auto& file : std::filesystem::directory_iterator(folder))
|
for (auto &file : std::filesystem::directory_iterator(folder)) {
|
||||||
{
|
if (!file.path().has_extension() || !file.path().has_filename() ||
|
||||||
if (!file.path().has_extension() || !file.path().has_filename() || !file.exists() || file.is_directory())
|
!file.exists() || file.is_directory())
|
||||||
continue;
|
continue;
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
if (doc.LoadFile(file.path().generic_string().c_str()) != tinyxml2::XML_SUCCESS)
|
if (doc.LoadFile(file.path().generic_string().c_str()) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
tinyxml2::XMLElement* guns = doc.FirstChildElement("weapons");
|
tinyxml2::XMLElement *guns = doc.FirstChildElement("weapons");
|
||||||
if (guns == NULL)
|
if (guns == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (tinyxml2::XMLElement* weapon = guns->FirstChildElement("weapon"); weapon != NULL; weapon = weapon->NextSiblingElement("weapon"))
|
for (tinyxml2::XMLElement *weapon = guns->FirstChildElement("weapon");
|
||||||
{
|
weapon != NULL; weapon = weapon->NextSiblingElement("weapon")) {
|
||||||
// populate weapon data into this temp buffer, then push it into our list of weapons
|
// populate weapon data into this temp buffer, then push it into our list
|
||||||
|
// of weapons
|
||||||
WeaponData data;
|
WeaponData data;
|
||||||
const char *id, *graphic, *bulletGraphic, *script;
|
const char *id, *graphic, *bulletGraphic, *script;
|
||||||
// Getting top level weapon data, attribs in the weapon Node
|
// Getting top level weapon data, attribs in the weapon Node
|
||||||
|
|
@ -190,86 +316,82 @@ bool XMLLoader::loadWeapons(const char* weaponFolder)
|
||||||
weapon->QueryIntAttribute("maxAmmo", &data.maxAmmo);
|
weapon->QueryIntAttribute("maxAmmo", &data.maxAmmo);
|
||||||
weapon->QueryIntAttribute("clipSize", &data.clipSize);
|
weapon->QueryIntAttribute("clipSize", &data.clipSize);
|
||||||
// Getting script file if Node exists
|
// Getting script file if Node exists
|
||||||
tinyxml2::XMLElement* wepScript = weapon->FirstChildElement("script");
|
tinyxml2::XMLElement *wepScript = weapon->FirstChildElement("script");
|
||||||
if (wepScript)
|
if (wepScript)
|
||||||
wepScript->QueryStringAttribute("file", &script);
|
wepScript->QueryStringAttribute("id", &script);
|
||||||
else
|
else
|
||||||
script = "";
|
script = "";
|
||||||
// Getting weapon sprite information, held in the sprite node
|
// Getting weapon sprite information, held in the sprite node
|
||||||
tinyxml2::XMLElement* anim = weapon->FirstChildElement("animation");
|
tinyxml2::XMLElement *anim = weapon->FirstChildElement("animation");
|
||||||
if (anim)
|
if (anim) {
|
||||||
{
|
|
||||||
data.animated = true;
|
data.animated = true;
|
||||||
if (anim->ChildElementCount() != 0)
|
if (anim->ChildElementCount() != 0) {
|
||||||
{
|
tinyxml2::XMLElement *size = anim->FirstChildElement("size");
|
||||||
tinyxml2::XMLElement* size = anim->FirstChildElement("size");
|
|
||||||
size->QueryFloatAttribute("x", &data.sizeX);
|
size->QueryFloatAttribute("x", &data.sizeX);
|
||||||
size->QueryFloatAttribute("y", &data.sizeY);
|
size->QueryFloatAttribute("y", &data.sizeY);
|
||||||
tinyxml2::XMLElement* offset = anim->FirstChildElement("offset");
|
tinyxml2::XMLElement *offset = anim->FirstChildElement("offset");
|
||||||
offset->QueryFloatAttribute("x", &data.offsetX);
|
offset->QueryFloatAttribute("x", &data.offsetX);
|
||||||
offset->QueryFloatAttribute("y", &data.offsetY);
|
offset->QueryFloatAttribute("y", &data.offsetY);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
tinyxml2::XMLElement *wepSprite = weapon->FirstChildElement("sprite");
|
||||||
{
|
|
||||||
tinyxml2::XMLElement* wepSprite = weapon->FirstChildElement("sprite");
|
|
||||||
if (wepSprite == NULL)
|
if (wepSprite == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
wepSprite->QueryStringAttribute("file", &graphic);
|
wepSprite->QueryStringAttribute("file", &graphic);
|
||||||
data.animated = false;
|
data.animated = false;
|
||||||
if (wepSprite->ChildElementCount() != 0)
|
if (wepSprite->ChildElementCount() != 0) {
|
||||||
{
|
tinyxml2::XMLElement *size = wepSprite->FirstChildElement("size");
|
||||||
tinyxml2::XMLElement* size = wepSprite->FirstChildElement("size");
|
|
||||||
size->QueryFloatAttribute("x", &data.sizeX);
|
size->QueryFloatAttribute("x", &data.sizeX);
|
||||||
size->QueryFloatAttribute("y", &data.sizeY);
|
size->QueryFloatAttribute("y", &data.sizeY);
|
||||||
tinyxml2::XMLElement* offset = wepSprite->FirstChildElement("offset");
|
tinyxml2::XMLElement *offset = wepSprite->FirstChildElement("offset");
|
||||||
offset->QueryFloatAttribute("x", &data.offsetX);
|
offset->QueryFloatAttribute("x", &data.offsetX);
|
||||||
offset->QueryFloatAttribute("y", &data.offsetY);
|
offset->QueryFloatAttribute("y", &data.offsetY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// getting bullet information held in the bullet node and each child node held therein
|
// getting bullet information held in the bullet node and each child node
|
||||||
tinyxml2::XMLElement* bullet = weapon->FirstChildElement("bullet");
|
// held therein
|
||||||
|
tinyxml2::XMLElement *bullet = weapon->FirstChildElement("bullet");
|
||||||
|
|
||||||
if (bullet->FindAttribute("anim"))
|
if (bullet->FindAttribute("anim")) {
|
||||||
{
|
|
||||||
data.bulletAnimated = true;
|
data.bulletAnimated = true;
|
||||||
if (bullet->QueryStringAttribute("anim", &bulletGraphic) != tinyxml2::XML_SUCCESS)
|
if (bullet->QueryStringAttribute("anim", &bulletGraphic) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
data.bulletAnimated = false;
|
data.bulletAnimated = false;
|
||||||
if (bullet->QueryStringAttribute("sprite", &bulletGraphic) != tinyxml2::XML_SUCCESS)
|
if (bullet->QueryStringAttribute("sprite", &bulletGraphic) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bullet->FirstChildElement("size")->QueryFloatAttribute(
|
||||||
if (bullet->FirstChildElement("size")->QueryFloatAttribute("x", &data.bulletSizeX) != tinyxml2::XML_SUCCESS ||
|
"x", &data.bulletSizeX) != tinyxml2::XML_SUCCESS ||
|
||||||
bullet->FirstChildElement("size")->QueryFloatAttribute("y", &data.bulletSizeY) != tinyxml2::XML_SUCCESS)
|
bullet->FirstChildElement("size")->QueryFloatAttribute(
|
||||||
|
"y", &data.bulletSizeY) != tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
data.id = id;
|
data.id = id;
|
||||||
data.script = script;
|
data.script = script;
|
||||||
data.bulletGraphic = bulletGraphic;
|
data.bulletGraphic = bulletGraphic;
|
||||||
|
|
||||||
tinyxml2::XMLElement* spread = bullet->FirstChildElement("spread");
|
tinyxml2::XMLElement *spread = bullet->FirstChildElement("spread");
|
||||||
tinyxml2::XMLElement* speed = bullet->FirstChildElement("speed");
|
tinyxml2::XMLElement *speed = bullet->FirstChildElement("speed");
|
||||||
tinyxml2::XMLElement* drop = bullet->FirstChildElement("drop");
|
tinyxml2::XMLElement *drop = bullet->FirstChildElement("drop");
|
||||||
tinyxml2::XMLElement* modifier = bullet->FirstChildElement("modifier");
|
tinyxml2::XMLElement *modifier = bullet->FirstChildElement("modifier");
|
||||||
if (spread)
|
if (spread)
|
||||||
spread->QueryFloatText(&data.bulletSpread);
|
spread->QueryFloatText(&data.bulletSpread);
|
||||||
if (speed)
|
if (speed)
|
||||||
speed->QueryFloatText(&data.bulletSpeed);
|
speed->QueryFloatText(&data.bulletSpeed);
|
||||||
if (drop)
|
if (drop)
|
||||||
drop->QueryFloatText(&data.bulletDrop);
|
drop->QueryFloatText(&data.bulletDrop);
|
||||||
if (modifier)
|
if (modifier) {
|
||||||
{
|
|
||||||
modifier->QueryFloatAttribute("min", &data.modMin);
|
modifier->QueryFloatAttribute("min", &data.modMin);
|
||||||
modifier->QueryFloatAttribute("max", &data.modMax);
|
modifier->QueryFloatAttribute("max", &data.modMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(DEBUG, "Loaded {} from {}", data.id, file.path().filename().generic_string());
|
LOG(DEBUG, "Loaded {} from {}", data.id,
|
||||||
|
file.path().filename().generic_string());
|
||||||
weapons.try_emplace(data.id, std::make_unique<WeaponData>(data));
|
weapons.try_emplace(data.id, std::make_unique<WeaponData>(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -277,33 +399,37 @@ bool XMLLoader::loadWeapons(const char* weaponFolder)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load each animation node and store inside a hashmap by their id. Each object that needs an animation will be given a prefix <type>/<object>.
|
* Load each animation node and store inside a hashmap by their id. Each object
|
||||||
* Which will be used to look up the corresponding animation
|
* that needs an animation will be given a prefix <type>/<object>. Which will be
|
||||||
*/
|
* used to look up the corresponding animation
|
||||||
bool XMLLoader::loadAnimations(const char* animationFolder)
|
*/
|
||||||
{
|
bool XMLLoader::loadAnimations(const char *animationFolder) {
|
||||||
std::filesystem::path folder(animationFolder);
|
std::filesystem::path folder(animationFolder);
|
||||||
if (!std::filesystem::exists(folder) || !std::filesystem::is_directory(folder))
|
if (!std::filesystem::exists(folder) ||
|
||||||
|
!std::filesystem::is_directory(folder))
|
||||||
ERROR_LOG("'{}' folder does not exist!", animationFolder);
|
ERROR_LOG("'{}' folder does not exist!", animationFolder);
|
||||||
for (auto& file : std::filesystem::directory_iterator(folder))
|
for (auto &file : std::filesystem::directory_iterator(folder)) {
|
||||||
{
|
if (!file.path().has_extension() || !file.path().has_filename() ||
|
||||||
if (!file.path().has_extension() || !file.path().has_filename() || !file.exists() || file.is_directory())
|
!file.exists() || file.is_directory())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
if (doc.LoadFile(file.path().generic_string().c_str()) != tinyxml2::XML_SUCCESS)
|
if (doc.LoadFile(file.path().generic_string().c_str()) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (tinyxml2::XMLElement* e = doc.FirstChildElement("animation"); e != NULL; e = e->NextSiblingElement("animation"))
|
for (tinyxml2::XMLElement *e = doc.FirstChildElement("animation");
|
||||||
{
|
e != NULL; e = e->NextSiblingElement("animation")) {
|
||||||
AnimationData animData;
|
AnimationData animData;
|
||||||
const char *id, *spriteAtlas;
|
const char *id, *spriteAtlas;
|
||||||
|
|
||||||
if (e->QueryStringAttribute("id", &id) != tinyxml2::XML_SUCCESS)
|
if (e->QueryStringAttribute("id", &id) != tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (e->QueryStringAttribute("atlas", &spriteAtlas) != tinyxml2::XML_SUCCESS ||
|
if (e->QueryStringAttribute("atlas", &spriteAtlas) !=
|
||||||
e->QueryFloatAttribute("frameSize", &animData.frameSize) != tinyxml2::XML_SUCCESS)
|
tinyxml2::XML_SUCCESS ||
|
||||||
|
e->QueryFloatAttribute("frameSize", &animData.frameSize) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
e->QueryFloatAttribute("FPS", &animData.FPS);
|
e->QueryFloatAttribute("FPS", &animData.FPS);
|
||||||
|
|
@ -311,7 +437,8 @@ bool XMLLoader::loadAnimations(const char* animationFolder)
|
||||||
|
|
||||||
animData.id = id;
|
animData.id = id;
|
||||||
animData.spriteAtlas = spriteAtlas;
|
animData.spriteAtlas = spriteAtlas;
|
||||||
animations.try_emplace(animData.id, std::make_unique<AnimationData>(animData));
|
animations.try_emplace(animData.id,
|
||||||
|
std::make_unique<AnimationData>(animData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -321,9 +448,8 @@ bool XMLLoader::loadAnimations(const char* animationFolder)
|
||||||
Start of (LoadTileSets)
|
Start of (LoadTileSets)
|
||||||
|
|
||||||
Load every tileset and store them in hashmap tileSets
|
Load every tileset and store them in hashmap tileSets
|
||||||
hashkey is the <parent directory>/<filename>, this is due to the expected
|
hashkey is the <parent directory>/<filename>, this is due to the
|
||||||
file structure, being
|
expected file structure, being Resources
|
||||||
Resources
|
|
||||||
|
|
|
|
||||||
- maps
|
- maps
|
||||||
|
|
|
|
||||||
|
|
@ -332,110 +458,131 @@ bool XMLLoader::loadAnimations(const char* animationFolder)
|
||||||
This makes it easier to import maps from the Tiled program.
|
This makes it easier to import maps from the Tiled program.
|
||||||
Refer to the Tiled project file for the file structure
|
Refer to the Tiled project file for the file structure
|
||||||
*/
|
*/
|
||||||
bool XMLLoader::loadTileSets(const char* tileSetFolder)
|
bool XMLLoader::loadTileSets(const char *tileSetFolder) {
|
||||||
{
|
|
||||||
std::filesystem::path folder(tileSetFolder);
|
std::filesystem::path folder(tileSetFolder);
|
||||||
if (!std::filesystem::exists(folder) || !std::filesystem::is_directory(folder))
|
if (!std::filesystem::exists(folder) ||
|
||||||
|
!std::filesystem::is_directory(folder))
|
||||||
ERROR_LOG("'{}' folder failed to load!", tileSetFolder);
|
ERROR_LOG("'{}' folder failed to load!", tileSetFolder);
|
||||||
|
|
||||||
for (auto& file : std::filesystem::directory_iterator(folder))
|
for (auto &file : std::filesystem::directory_iterator(folder)) {
|
||||||
{
|
if (!file.path().has_extension() || !file.path().has_filename() ||
|
||||||
if (!file.path().has_extension() || !file.path().has_filename() || !file.exists() || file.is_directory())
|
!file.exists() || file.is_directory())
|
||||||
continue;
|
continue;
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
if (doc.LoadFile(file.path().generic_string().c_str()) != tinyxml2::XML_SUCCESS)
|
if (doc.LoadFile(file.path().generic_string().c_str()) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tinyxml2::XMLElement* tileSet = doc.FirstChildElement("tileset");
|
tinyxml2::XMLElement *tileSet = doc.FirstChildElement("tileset");
|
||||||
if (tileSet == NULL)
|
if (tileSet == NULL)
|
||||||
continue;
|
continue;
|
||||||
TileSetData tileSetData;
|
TileSetData tileSetData;
|
||||||
const char* setName, * setType = "shooter", * setFile;
|
const char *setName, *setType = "shooter", *setFile;
|
||||||
|
|
||||||
tileSet->QueryStringAttribute("class", &setType);
|
tileSet->QueryStringAttribute("class", &setType);
|
||||||
|
|
||||||
// Read attributes of tileset element
|
// Read attributes of tileset element
|
||||||
if (tileSet->QueryStringAttribute("name", &setName) != tinyxml2::XML_SUCCESS ||
|
if (tileSet->QueryStringAttribute("name", &setName) !=
|
||||||
tileSet->QueryFloatAttribute("tilewidth", &tileSetData.tileSize) != tinyxml2::XML_SUCCESS ||
|
tinyxml2::XML_SUCCESS ||
|
||||||
tileSet->QueryIntAttribute("tilecount", &tileSetData.tileCount) != tinyxml2::XML_SUCCESS ||
|
tileSet->QueryFloatAttribute("tilewidth", &tileSetData.tileSize) !=
|
||||||
tileSet->QueryIntAttribute("columns", &tileSetData.columns) != tinyxml2::XML_SUCCESS)
|
tinyxml2::XML_SUCCESS ||
|
||||||
|
tileSet->QueryIntAttribute("tilecount", &tileSetData.tileCount) !=
|
||||||
|
tinyxml2::XML_SUCCESS ||
|
||||||
|
tileSet->QueryIntAttribute("columns", &tileSetData.columns) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tinyxml2::XMLElement* image = tileSet->FirstChildElement("image");
|
tinyxml2::XMLElement *image = tileSet->FirstChildElement("image");
|
||||||
if (image == NULL)
|
if (image == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Reading image element attribs
|
// Reading image element attribs
|
||||||
if (image->QueryStringAttribute("source", &setFile) != tinyxml2::XML_SUCCESS ||
|
if (image->QueryStringAttribute("source", &setFile) !=
|
||||||
image->QueryIntAttribute("width", &tileSetData.width) != tinyxml2::XML_SUCCESS ||
|
tinyxml2::XML_SUCCESS ||
|
||||||
image->QueryIntAttribute("height", &tileSetData.height) != tinyxml2::XML_SUCCESS)
|
image->QueryIntAttribute("width", &tileSetData.width) !=
|
||||||
|
tinyxml2::XML_SUCCESS ||
|
||||||
|
image->QueryIntAttribute("height", &tileSetData.height) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (tinyxml2::XMLElement* tileElement = tileSet->FirstChildElement("tile"); tileElement != NULL; tileElement = tileElement->NextSiblingElement("tile"))
|
for (tinyxml2::XMLElement *tileElement = tileSet->FirstChildElement("tile");
|
||||||
{
|
tileElement != NULL;
|
||||||
|
tileElement = tileElement->NextSiblingElement("tile")) {
|
||||||
TileSetData::TileData tileData;
|
TileSetData::TileData tileData;
|
||||||
if (!loadTile(tileElement, &tileData))
|
if (!loadTile(tileElement, &tileData))
|
||||||
continue;
|
continue;
|
||||||
tileSetData.tiles.push_back(std::make_shared<TileSetData::TileData>(tileData));
|
tileSetData.tiles.push_back(
|
||||||
|
std::make_shared<TileSetData::TileData>(tileData));
|
||||||
}
|
}
|
||||||
tileSetData.name = setName;
|
tileSetData.name = setName;
|
||||||
tileSetData.type = setType;
|
tileSetData.type = setType;
|
||||||
tileSetData.file = file.path().parent_path().string() + "/" + std::string(setFile);
|
tileSetData.file =
|
||||||
std::string key = folder.filename().string() + "/" + file.path().filename().string();
|
file.path().parent_path().string() + "/" + std::string(setFile);
|
||||||
|
std::string key =
|
||||||
|
folder.filename().string() + "/" + file.path().filename().string();
|
||||||
|
|
||||||
tileSets.try_emplace(key, std::make_unique<TileSetData>(tileSetData));
|
tileSets.try_emplace(key, std::make_unique<TileSetData>(tileSetData));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XMLLoader::loadTile(tinyxml2::XMLElement* tileElement, TileSetData::TileData* out)
|
bool XMLLoader::loadTile(tinyxml2::XMLElement *tileElement,
|
||||||
{
|
TileSetData::TileData *out) {
|
||||||
TileSetData::TileData tileData;
|
TileSetData::TileData tileData;
|
||||||
const char* tileType;
|
const char *tileType;
|
||||||
|
|
||||||
if (tileElement == NULL)
|
if (tileElement == NULL)
|
||||||
ERROR_LOG("Failed to find 'tile' tag.", NULL);
|
ERROR_LOG("Failed to find 'tile' tag.", NULL);
|
||||||
if (tileElement->QueryIntAttribute("id", &tileData.id) != tinyxml2::XML_SUCCESS ||
|
if (tileElement->QueryIntAttribute("id", &tileData.id) !=
|
||||||
tileElement->QueryStringAttribute("type", &tileType) != tinyxml2::XML_SUCCESS)
|
tinyxml2::XML_SUCCESS ||
|
||||||
|
tileElement->QueryStringAttribute("type", &tileType) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
ERROR_LOG("Failed to load tile id or type. {}", tileElement->Value());
|
ERROR_LOG("Failed to load tile id or type. {}", tileElement->Value());
|
||||||
|
|
||||||
if (std::string(tileType).compare("object") == 0)
|
if (std::string(tileType).compare("object") == 0) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
Refer to .tsx file of tile set for specific details regarding the layout of the tile element.
|
Refer to .tsx file of tile set for specific details regarding the
|
||||||
You will notice each tile has the potential to be a container for objects, so that is how we are
|
layout of the tile element. You will notice each tile has the potential
|
||||||
handling it here. If the tileType was specified as an object, but it contains no objects, then we don't
|
to be a container for objects, so that is how we are handling it here. If
|
||||||
load the tile. Objects are defined in the Tiled program using the collision editor.
|
the tileType was specified as an object, but it contains no objects, then
|
||||||
|
we don't load the tile. Objects are defined in the Tiled program using
|
||||||
|
the collision editor.
|
||||||
*/
|
*/
|
||||||
tinyxml2::XMLElement* objectGroup = tileElement->FirstChildElement("objectgroup");
|
tinyxml2::XMLElement *objectGroup =
|
||||||
|
tileElement->FirstChildElement("objectgroup");
|
||||||
if (objectGroup == NULL)
|
if (objectGroup == NULL)
|
||||||
ERROR_LOG("Failed to find tag 'objectgroup' in tile id: {}", tileData.id);
|
ERROR_LOG("Failed to find tag 'objectgroup' in tile id: {}", tileData.id);
|
||||||
for (tinyxml2::XMLElement* obj = objectGroup->FirstChildElement("object"); obj != NULL; obj = obj->NextSiblingElement("object"))
|
for (tinyxml2::XMLElement *obj = objectGroup->FirstChildElement("object");
|
||||||
{
|
obj != NULL; obj = obj->NextSiblingElement("object")) {
|
||||||
TileSetData::TileData::ObjectData objData;
|
TileSetData::TileData::ObjectData objData;
|
||||||
if (!loadObject(obj, &objData))
|
if (!loadObject(obj, &objData))
|
||||||
continue;
|
continue;
|
||||||
tileData.objects.push_back(std::make_shared<TileSetData::TileData::ObjectData>(objData));
|
tileData.objects.push_back(
|
||||||
|
std::make_shared<TileSetData::TileData::ObjectData>(objData));
|
||||||
}
|
}
|
||||||
if (tileData.objects.empty())
|
if (tileData.objects.empty())
|
||||||
ERROR_LOG("No objects found", NULL);
|
ERROR_LOG("No objects found", NULL);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
May support multiple properties in the future with a future property struct to hold any value type
|
May support multiple properties in the future with a future property
|
||||||
But this may not be needed, so we'll just capture the walkable property for now.
|
struct to hold any value type But this may not be needed, so we'll just
|
||||||
Assume default of there is no properties tag or walkable property, just use nested if's
|
capture the walkable property for now. Assume default of there is no
|
||||||
|
properties tag or walkable property, just use nested if's
|
||||||
*/
|
*/
|
||||||
tinyxml2::XMLElement* properties = tileElement->FirstChildElement("properties");
|
tinyxml2::XMLElement *properties =
|
||||||
|
tileElement->FirstChildElement("properties");
|
||||||
if (properties == NULL) {
|
if (properties == NULL) {
|
||||||
LOG(WARN, "No properties found on tile id: {} assuming defaults", tileData.id);
|
LOG(WARN, "No properties found on tile id: {} assuming defaults",
|
||||||
|
tileData.id);
|
||||||
} else {
|
} else {
|
||||||
tinyxml2::XMLElement* propWalk = properties->FirstChildElement("property");
|
tinyxml2::XMLElement *propWalk =
|
||||||
|
properties->FirstChildElement("property");
|
||||||
if (propWalk == NULL) {
|
if (propWalk == NULL) {
|
||||||
LOG(WARN, "No walkable propery found on tile id: {} assuming walkable", tileData.id);
|
LOG(WARN, "No walkable propery found on tile id: {} assuming walkable",
|
||||||
|
tileData.id);
|
||||||
} else {
|
} else {
|
||||||
for (auto& prop = propWalk; prop != NULL; prop = prop->NextSiblingElement()) {
|
for (auto &prop = propWalk; prop != NULL;
|
||||||
|
prop = prop->NextSiblingElement()) {
|
||||||
if (prop->Attribute("name", "walkable")) {
|
if (prop->Attribute("name", "walkable")) {
|
||||||
prop->QueryBoolAttribute("value", &tileData.walkable);
|
prop->QueryBoolAttribute("value", &tileData.walkable);
|
||||||
break;
|
break;
|
||||||
|
|
@ -451,32 +598,41 @@ bool XMLLoader::loadTile(tinyxml2::XMLElement* tileElement, TileSetData::TileDat
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XMLLoader::loadObject(tinyxml2::XMLElement* objElement, TileSetData::TileData::ObjectData* out)
|
bool XMLLoader::loadObject(tinyxml2::XMLElement *objElement,
|
||||||
{
|
TileSetData::TileData::ObjectData *out) {
|
||||||
TileSetData::TileData::ObjectData objData;
|
TileSetData::TileData::ObjectData objData;
|
||||||
const char* objName;
|
const char *objName;
|
||||||
|
|
||||||
// avoid null pointer exception
|
// avoid null pointer exception
|
||||||
if (objElement == NULL)
|
if (objElement == NULL)
|
||||||
ERROR_LOG("Failed to find 'object' tag", NULL);
|
ERROR_LOG("Failed to find 'object' tag", NULL);
|
||||||
// load id and name
|
// load id and name
|
||||||
if (objElement->QueryIntAttribute("id", &objData.id) != tinyxml2::XML_SUCCESS ||
|
if (objElement->QueryIntAttribute("id", &objData.id) !=
|
||||||
objElement->QueryStringAttribute("name", &objName) != tinyxml2::XML_SUCCESS)
|
tinyxml2::XML_SUCCESS ||
|
||||||
|
objElement->QueryStringAttribute("name", &objName) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
ERROR_LOG("No id or name found for object. {}", objElement->Value());
|
ERROR_LOG("No id or name found for object. {}", objElement->Value());
|
||||||
// load position into vec2
|
// load position into vec2
|
||||||
if (objElement->QueryFloatAttribute("x", &objData.pos.x) != tinyxml2::XML_SUCCESS ||
|
if (objElement->QueryFloatAttribute("x", &objData.pos.x) !=
|
||||||
objElement->QueryFloatAttribute("y", &objData.pos.y) != tinyxml2::XML_SUCCESS)
|
tinyxml2::XML_SUCCESS ||
|
||||||
ERROR_LOG("Failed to load position coordinates for object: {}", objData.name);
|
objElement->QueryFloatAttribute("y", &objData.pos.y) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
|
ERROR_LOG("Failed to load position coordinates for object: {}",
|
||||||
|
objData.name);
|
||||||
// load size into seperate vec2
|
// load size into seperate vec2
|
||||||
if (objElement->QueryFloatAttribute("width", &objData.size.x) != tinyxml2::XML_SUCCESS ||
|
if (objElement->QueryFloatAttribute("width", &objData.size.x) !=
|
||||||
objElement->QueryFloatAttribute("height", &objData.size.y) != tinyxml2::XML_SUCCESS)
|
tinyxml2::XML_SUCCESS ||
|
||||||
|
objElement->QueryFloatAttribute("height", &objData.size.y) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
ERROR_LOG("Failed to load size of object: {}", objData.name);
|
ERROR_LOG("Failed to load size of object: {}", objData.name);
|
||||||
|
|
||||||
// refer to comment in XMLLoader::loadTile regarding the properties portion as to why we return true here
|
// refer to comment in XMLLoader::loadTile regarding the properties portion as
|
||||||
tinyxml2::XMLElement* properties = objElement->FirstChildElement("properties");
|
// to why we return true here
|
||||||
if (properties != NULL)
|
tinyxml2::XMLElement *properties =
|
||||||
{
|
objElement->FirstChildElement("properties");
|
||||||
tinyxml2::XMLElement* propCollide = properties->FirstChildElement("property");
|
if (properties != NULL) {
|
||||||
|
tinyxml2::XMLElement *propCollide =
|
||||||
|
properties->FirstChildElement("property");
|
||||||
if (propCollide != NULL && propCollide->Attribute("name", "collidable"))
|
if (propCollide != NULL && propCollide->Attribute("name", "collidable"))
|
||||||
propCollide->QueryBoolAttribute("value", &objData.collidable);
|
propCollide->QueryBoolAttribute("value", &objData.collidable);
|
||||||
}
|
}
|
||||||
|
|
@ -488,38 +644,44 @@ bool XMLLoader::loadObject(tinyxml2::XMLElement* objElement, TileSetData::TileDa
|
||||||
}
|
}
|
||||||
/* End of (LoadTileSets) */
|
/* End of (LoadTileSets) */
|
||||||
|
|
||||||
bool XMLLoader::loadMaps(const char* mapFolder)
|
bool XMLLoader::loadMaps(const char *mapFolder) {
|
||||||
{
|
|
||||||
std::filesystem::path folder(mapFolder);
|
std::filesystem::path folder(mapFolder);
|
||||||
if (!std::filesystem::exists(folder) || !std::filesystem::is_directory(folder))
|
if (!std::filesystem::exists(folder) ||
|
||||||
|
!std::filesystem::is_directory(folder))
|
||||||
ERROR_LOG("'{}' folder not found!", mapFolder);
|
ERROR_LOG("'{}' folder not found!", mapFolder);
|
||||||
|
|
||||||
for (auto& file : std::filesystem::directory_iterator(folder))
|
for (auto &file : std::filesystem::directory_iterator(folder)) {
|
||||||
{
|
if (!file.path().has_extension() || !file.path().has_filename() ||
|
||||||
if (!file.path().has_extension() || !file.path().has_filename() || !file.exists() || file.is_directory())
|
!file.exists() || file.is_directory())
|
||||||
continue;
|
continue;
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
if (doc.LoadFile(file.path().generic_string().c_str()) != tinyxml2::XML_SUCCESS)
|
if (doc.LoadFile(file.path().generic_string().c_str()) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tinyxml2::XMLElement* map = doc.FirstChildElement("map");
|
tinyxml2::XMLElement *map = doc.FirstChildElement("map");
|
||||||
if (map == NULL)
|
if (map == NULL)
|
||||||
continue;
|
continue;
|
||||||
MapData mapData;
|
MapData mapData;
|
||||||
|
|
||||||
if (map->QueryIntAttribute("width", &mapData.width) != tinyxml2::XML_SUCCESS ||
|
if (map->QueryIntAttribute("width", &mapData.width) !=
|
||||||
map->QueryIntAttribute("height", &mapData.height) != tinyxml2::XML_SUCCESS ||
|
tinyxml2::XML_SUCCESS ||
|
||||||
map->QueryFloatAttribute("tilewidth", &mapData.tileSize) != tinyxml2::XML_SUCCESS)
|
map->QueryIntAttribute("height", &mapData.height) !=
|
||||||
|
tinyxml2::XML_SUCCESS ||
|
||||||
|
map->QueryFloatAttribute("tilewidth", &mapData.tileSize) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (tinyxml2::XMLElement* tileSet = map->FirstChildElement("tileset"); tileSet != NULL; tileSet = tileSet->NextSiblingElement("tileset"))
|
for (tinyxml2::XMLElement *tileSet = map->FirstChildElement("tileset");
|
||||||
{
|
tileSet != NULL; tileSet = tileSet->NextSiblingElement("tileset")) {
|
||||||
int firstGID = 0;
|
int firstGID = 0;
|
||||||
const char* tileSetPath;
|
const char *tileSetPath;
|
||||||
if (tileSet->QueryStringAttribute("source", &tileSetPath) != tinyxml2::XML_SUCCESS ||
|
if (tileSet->QueryStringAttribute("source", &tileSetPath) !=
|
||||||
tileSet->QueryIntAttribute("firstgid", &firstGID) != tinyxml2::XML_SUCCESS)
|
tinyxml2::XML_SUCCESS ||
|
||||||
|
tileSet->QueryIntAttribute("firstgid", &firstGID) !=
|
||||||
|
tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
mapData.tileSets.push_back({ firstGID, tileSetPath });
|
mapData.tileSets.push_back({firstGID, tileSetPath});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mapData.tileSets.empty())
|
if (mapData.tileSets.empty())
|
||||||
|
|
@ -528,21 +690,19 @@ bool XMLLoader::loadMaps(const char* mapFolder)
|
||||||
mapData.tiles.reserve(10);
|
mapData.tiles.reserve(10);
|
||||||
mapData.tiles.resize(10);
|
mapData.tiles.resize(10);
|
||||||
|
|
||||||
for (int layer = 0; layer < 10; ++layer)
|
for (int layer = 0; layer < 10; ++layer) {
|
||||||
{
|
|
||||||
mapData.tiles[layer].reserve(mapData.height);
|
mapData.tiles[layer].reserve(mapData.height);
|
||||||
mapData.tiles[layer].resize(mapData.height);
|
mapData.tiles[layer].resize(mapData.height);
|
||||||
for (int y = 0; y < mapData.height; ++y)
|
for (int y = 0; y < mapData.height; ++y) {
|
||||||
{
|
|
||||||
mapData.tiles[layer][y].reserve(mapData.width);
|
mapData.tiles[layer][y].reserve(mapData.width);
|
||||||
mapData.tiles[layer][y].resize(mapData.width);
|
mapData.tiles[layer][y].resize(mapData.width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int layerNumber = 0;
|
int layerNumber = 0;
|
||||||
for (tinyxml2::XMLElement* layer = map->FirstChildElement("layer"); layer != NULL; layer = layer->NextSiblingElement("layer"))
|
for (tinyxml2::XMLElement *layer = map->FirstChildElement("layer");
|
||||||
{
|
layer != NULL; layer = layer->NextSiblingElement("layer")) {
|
||||||
tinyxml2::XMLElement* data = layer->FirstChildElement("data");
|
tinyxml2::XMLElement *data = layer->FirstChildElement("data");
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
continue;
|
continue;
|
||||||
if (layerNumber >= 10)
|
if (layerNumber >= 10)
|
||||||
|
|
@ -555,12 +715,10 @@ bool XMLLoader::loadMaps(const char* mapFolder)
|
||||||
std::stringstream ssidSet(idSet);
|
std::stringstream ssidSet(idSet);
|
||||||
int x = 0, y = -1;
|
int x = 0, y = -1;
|
||||||
|
|
||||||
while (std::getline(ssidSet, tileRow) && y < mapData.height)
|
while (std::getline(ssidSet, tileRow) && y < mapData.height) {
|
||||||
{
|
|
||||||
std::stringstream ssid(tileRow);
|
std::stringstream ssid(tileRow);
|
||||||
x = 0;
|
x = 0;
|
||||||
while (std::getline(ssid, tileString, ',') && x < mapData.width)
|
while (std::getline(ssid, tileString, ',') && x < mapData.width) {
|
||||||
{
|
|
||||||
int id = std::stoi(tileString);
|
int id = std::stoi(tileString);
|
||||||
mapData.tiles[layerNumber][y][x] = id;
|
mapData.tiles[layerNumber][y][x] = id;
|
||||||
x++;
|
x++;
|
||||||
|
|
@ -582,22 +740,23 @@ bool XMLLoader::loadMaps(const char* mapFolder)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XMLLoader::loadSoundEffects(const char *soundFolder)
|
bool XMLLoader::loadSoundEffects(const char *soundFolder) {
|
||||||
{
|
|
||||||
std::filesystem::path folder(soundFolder);
|
std::filesystem::path folder(soundFolder);
|
||||||
if (!std::filesystem::exists(folder) || !std::filesystem::is_directory(folder))
|
if (!std::filesystem::exists(folder) ||
|
||||||
|
!std::filesystem::is_directory(folder))
|
||||||
ERROR_LOG("Directory '{}' does not exist!", soundFolder);
|
ERROR_LOG("Directory '{}' does not exist!", soundFolder);
|
||||||
|
|
||||||
for (auto& file : std::filesystem::directory_iterator(folder))
|
for (auto &file : std::filesystem::directory_iterator(folder)) {
|
||||||
{
|
if (!file.path().has_extension() || !file.path().has_filename() ||
|
||||||
if (!file.path().has_extension() || !file.path().has_filename() || !file.exists() || file.is_directory())
|
!file.exists() || file.is_directory())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
if (doc.LoadFile(file.path().string().c_str()) != tinyxml2::XML_SUCCESS)
|
if (doc.LoadFile(file.path().string().c_str()) != tinyxml2::XML_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (tinyxml2::XMLElement *e = doc.FirstChildElement("sound"); e != NULL; e = e->NextSiblingElement("sound")) {
|
for (tinyxml2::XMLElement *e = doc.FirstChildElement("sound"); e != NULL;
|
||||||
|
e = e->NextSiblingElement("sound")) {
|
||||||
SoundData sound;
|
SoundData sound;
|
||||||
const char *id, *path;
|
const char *id, *path;
|
||||||
if (e->QueryStringAttribute("id", &id) != tinyxml2::XML_SUCCESS ||
|
if (e->QueryStringAttribute("id", &id) != tinyxml2::XML_SUCCESS ||
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue