diff options
author | Clyne Sullivan <tullivan99@gmail.com> | 2017-06-13 21:01:08 -0400 |
---|---|---|
committer | Clyne Sullivan <tullivan99@gmail.com> | 2017-06-13 21:01:08 -0400 |
commit | 316df0931c66e43e69f21bda28c77b9bdb1e8bca (patch) | |
tree | d98231e4b41d046a2a60ee9c6f1cc724a9e3837d | |
parent | 11b8e727e04ed6095164bb826541409f88047625 (diff) |
component reorginization; entity flashes
35 files changed, 1370 insertions, 1090 deletions
@@ -18,8 +18,12 @@ CXXWARN = -Wall -Wextra -Werror -pedantic CXXSRCDIR = src CXXOUTDIR = out -CXXSRC = $(wildcard $(CXXSRCDIR)/*.cpp) -CXXOBJ = $(patsubst $(CXXSRCDIR)/%.cpp, $(CXXOUTDIR)/%.o, $(CXXSRC)) +CXXSRC = $(wildcard $(CXXSRCDIR)/*.cpp) \ + $(wildcard $(CXXSRCDIR)/systems/*.cpp) \ + $(wildcard $(CXXSRCDIR)/components/*.cpp) +CXXOBJ = $(patsubst $(CXXSRCDIR)/%.cpp, $(CXXOUTDIR)/%.o, $(CXXSRC)) \ + $(patsubst $(CXXSRCDIR)/systems/%.cpp, $(CXXOUTDIR)/systems/%.o, $(CXXSRC)) \ + $(patsubst $(CXXSRCDIR)/components/%.cpp, $(CXXOUTDIR)/components/%.o, $(CXXSRC)) EXEC = main @@ -28,18 +32,23 @@ all: SPECIAL:=-ggdb game game: $(EXEC) clean: - rm -f $(EXEC) - rm -f out/*.o + @echo " CLEAN" + @rm -f $(EXEC) + @rm -rf out + @mkdir out + @mkdir out/systems + @mkdir out/components $(EXEC): $(CXXOUTDIR)/$(CXXOBJ) main.cpp - g++ -I. -std=c++11 -c entityx/help/Pool.cc -o out/Pool.o - g++ -I. -std=c++11 -c entityx/help/Timer.cc -o out/Timer.o - g++ -I. -std=c++11 -c entityx/Event.cc -o out/Event.o - g++ -I. -std=c++11 -c entityx/Entity.cc -o out/Entity.o - g++ -I. -std=c++11 -c entityx/System.cc -o out/System.o + @echo " CXX entityx" + @g++ -I. -std=c++11 -c entityx/help/Pool.cc -o out/Pool.o + @g++ -I. -std=c++11 -c entityx/help/Timer.cc -o out/Timer.o + @g++ -I. -std=c++11 -c entityx/Event.cc -o out/Event.o + @g++ -I. -std=c++11 -c entityx/Entity.cc -o out/Entity.o + @g++ -I. -std=c++11 -c entityx/System.cc -o out/System.o @echo " CXX/LD main" - @$(CXX) $(SPECIAL) $(CXXFLAGS) $(CXXINC) $(CXXWARN) -o $(EXEC) main.cpp out/*.o $(LIBS) + @$(CXX) $(SPECIAL) $(CXXFLAGS) $(CXXINC) $(CXXWARN) -o $(EXEC) main.cpp out/components/*.o out/systems/*.o out/*.o $(LIBS) @rm -rf xml/*.dat @rm -rf storyXML/*.dat diff --git a/include/components.hpp b/include/components.hpp index fe8e7a6..93d7196 100644 --- a/include/components.hpp +++ b/include/components.hpp @@ -8,669 +8,11 @@ #ifndef COMPONENTS_HPP #define COMPONENTS_HPP -#include <string> -#include <vector> - -#include <error.hpp> -#include <events.hpp> -#include <inventory.hpp> -#include <random.hpp> -#include <texture.hpp> -#include <vector2.hpp> - -#include <entityx/entityx.h> -#include <tinyxml2.h> -using namespace tinyxml2; - -// TODO heyyy guys #include <components/all.hpp> -/** - * @struct Position - * @brief Stores the position of an entity on the xy plane. - */ -struct Position : public Component { - /** - * Constructor that sets the position of the object, if nothing is passed it will default to 0. - * @param x The x position the object will be placed at. - * @param y the y position the object will be placed at. - */ - Position(float x = 0.0f, float y = 0.0f): x(x), y(y) {} - Position(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - float x; /**< The x position in the world */ - float y; /**< The y position in the world */ - - void fromXML(XMLElement* imp, XMLElement* def) final { - vec2 c; - if (imp->Attribute("position") != nullptr) - c = imp->StrAttribute("position"); - else - c = def->StrAttribute("value"); - - x = c.x, y = c.y; - } -}; - -/** - * @struct Direction - * @brief Store an entities velocity. - * This allows the entity to move throughout the world. - */ -struct Direction : public Component { - /** - * Constructor that sets the velocity, if no position is passed, it defaults to (0,0). - * @param x The velocity of the object on the x axis. - * @param y The velocity of the object on the y axis. - */ - Direction(float x = 0.0f, float y = 0.0f): x(x), y(y), grounded(false) {} - Direction(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - float x; /**< Velocity the object is moving in the x direction, this is added to the position */ - float y; /**< Velocity the object is moving in the y direction, this is added to the position */ - bool grounded; - - void fromXML(XMLElement* imp, XMLElement* def) final { - vec2 c; - if (imp->Attribute("direction") != nullptr) { - c = imp->StrAttribute("direction"); - } else if (def->Attribute("value") != nullptr) { - c = def->StrAttribute("value"); - } else { - c = vec2(0, 0); - } - - x = c.x, y = c.y, grounded = false; - } -}; - -/** - * @struct Physics - * @brief Allows and entity to react to gravity and frictions. - * When an entity inherits this component it will react with gravity and move with friction. - */ -struct Physics : public Component { - /** - * Constructor that sets the gravity constant, if not specified it becomes 0. - * @param g The non default gravity constant. - */ - Physics(float g = 0.2f): g(g) {} - Physics(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - float g; /**< The gravity constant, how fast the object falls */ - - void fromXML(XMLElement* imp, XMLElement* def) final { - if (imp->QueryFloatAttribute("gravity", &g) != XML_NO_ERROR) { - if (def->QueryFloatAttribute("value", &g) != XML_NO_ERROR) - g = 0.2f; - } - } -}; - -/** - * @struct Grounded - * @brief Places an entity without physics on the ground. - * This is used so we don't have to update the physics of a non-moving object every loop. - */ -struct Grounded : public Component { - Grounded(bool g = false) - : grounded(g) {} - Grounded(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - bool grounded; - - void fromXML(XMLElement* imp, XMLElement* def) final { - (void)imp; - (void)def; - grounded = false; - } -}; - -/** - * @struct Health - * @brief Gives and entity health and stuff. - */ -struct Health : public Component { - /** - * Constructor that sets the variables, with 1 health as default. - */ - Health(int m = 1, int h = 0) - : health(h != 0 ? h : m), maxHealth(m) {} - Health(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - int health; /**< The current amount of health */ - int maxHealth; /**< The maximum amount of health */ - - void fromXML(XMLElement* imp, XMLElement* def) final { - (void)imp; - (void)def; - // TODO - if (def->QueryIntAttribute("value", &health) != XML_NO_ERROR) - health = 1; - maxHealth = health; - } -}; - -struct Portal : public Component { - Portal(std::string tf = "") - : toFile(tf) {} - Portal(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - std::string toFile; - - void fromXML(XMLElement* imp, XMLElement* def) final { - (void)def; - toFile = imp->StrAttribute("inside"); - } -}; - -struct Name : public Component { - Name(std::string n = "") - : name(n) {} - Name(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - std::string name; - - void fromXML(XMLElement* imp, XMLElement* def) final { - auto n = imp->Attribute("name"); - - // TODO check def's nullness - name = n != nullptr ? n : def->Attribute("value"); - } -}; - -struct Player {}; - -struct ItemDrop { - ItemDrop(InventoryEntry& ie) - : item(ie) {} - - InventoryEntry item; -}; - -/** - * @struct Solid - * @brief Allows an entity to collide with other objects. - * When an entity has this component it can collide with the world and other objects. - */ -struct Solid : public Component { - /** - * Constructor that sets the entities dimensions based on what is passed. - * @param w The desired width of the entity. - * @param h The desired height of the entity. - */ - Solid(float w = 0.0f, float h = 0.0f) - : width(w), height(h), offset(0), passable(true) {} - Solid(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - void Passable(bool v) { passable = v; } - bool Passable(void) { return passable; } - - float width; /**< The width of the entity in units */ - float height; /**< The height of the entity in units */ - vec2 offset; /**< This allows us to make the hitbox in any spot */ - bool passable; /**< This determines whether or not one can pass by the entity */ - - void fromXML(XMLElement* imp, XMLElement* def) final { - (void)imp; - vec2 c; - if (def->Attribute("value") != nullptr) - c = def->StrAttribute("value"); - else - c = vec2(0, 0); - - width = c.x, height = c.y, offset = 0, passable = true; - } -}; - -struct SpriteData { - SpriteData(void) = default; - - SpriteData(std::string path, vec2 off): - offset(off) { - tex = Texture(path); - size = tex.getDim(); - - size_tex = vec2(1.0, 1.0); - - offset_tex.x = offset.x/size.x; - offset_tex.y = offset.y/size.y; - } - - SpriteData(std::string path, vec2 off, vec2 si): - size(si), offset(off) { - tex = Texture(path); - vec2 tmpsize = tex.getDim(); - - size_tex.x = size.x/tmpsize.x; - size_tex.y = size.y/tmpsize.y; - - offset_tex.x = offset.x/tmpsize.x; - offset_tex.y = offset.y/tmpsize.y; - } - - SpriteData(Texture t) - : tex(t) { - size_tex = 1; - offset_tex = 0; - size = tex.getDim(); - offset = 0; - } - - Texture tex; - vec2 size; - vec2 offset; - - vec2 offset_tex; - vec2 size_tex; - - unsigned int limb; -}; - -using Frame = std::vector<std::pair<SpriteData, vec2>>; - -std::vector<Frame> developFrame(XMLElement*); - -/** - * @struct Sprite - * @brief If an entity is visible we want to be able to see it. - * Each entity is given a sprite, a sprite can consist of manu frames or pieces to make one. - */ -struct Sprite : public Component { - Sprite(bool left = false) - : faceLeft(left) {} - Sprite(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - Frame getSprite() { - return sprite; - } - - int clearSprite() { - if (sprite.empty()) - return 0; - - sprite.clear(); - return 1; - } - - int addSpriteSegment(SpriteData data, vec2 loc) { - //TODO if sprite is in this spot, do something - sprite.push_back(std::make_pair(data, loc)); - return 1; - } - - int changeSpriteSegment(SpriteData data, vec2 loc) { - for (auto &s : sprite) { - if (s.second == loc) { - s.first = data; - - return 1; - } - } - addSpriteSegment(data, loc); - return 0; - } - - vec2 getSpriteSize() { - vec2 st; /** the start location of the sprite (bottom left)*/ - vec2 ed; /** the end ofthe location of the sprite (bottom right)*/ - vec2 dim; /** how wide the sprite is */ - - if (sprite.size()) { - st.x = sprite[0].second.x; - st.y = sprite[0].second.y; - - ed.x = sprite[0].second.x + sprite[0].first.size.x; - ed.y = sprite[0].second.y + sprite[0].first.size.y; - } else { - return vec2(0.0f, 0.0f); - } - - for (auto &s : sprite) { - if (s.second.x < st.x) - st.x = s.second.x; - if (s.second.y < st.y) - st.y = s.second.y; - - if (s.second.x + s.first.size.x > ed.x) - ed.x = s.second.x + s.first.size.x; - if (s.second.y + s.first.size.y > ed.y) - ed.y = s.second.y + s.first.size.y; - } - - dim = vec2(ed.x - st.x, ed.y - st.y); - dim.x *= game::HLINE; - dim.y *= game::HLINE; - return dim; - } - - Frame sprite; - bool faceLeft; - - void fromXML(XMLElement* imp, XMLElement* def) final { - (void)imp; - auto frames = developFrame(def); - if (!frames.empty()) - sprite = frames.at(0); - } -}; - -/** - * @struct Limb - * @brief Storage of frames for the limbs of a sprite. - * This will allow us to only update a certain limb. This was we can do mulitple animation types at once. - */ -struct Limb { - Limb() { - } - - // adds frame to the back of the frame stack - void addFrame(Frame fr) { - frame.push_back(fr); - } - - void firstFrame(Frame& duckmyass) { - // loop through the spritedata of the sprite we wanna change - for (auto &d : duckmyass) { - // if the sprite data is the same limb as this limb - if (d.first.limb == limbID) { - // rotate through (for safety) the first frame to set the limb - for (auto &fa : frame.at(0)) { - if (fa.first.limb == limbID) { - d.first = fa.first; - d.second = fa.second; - } - } - } - } - } - - void nextFrame(Frame& duckmyass, float dt) { - updateCurrent -= dt; - if (updateCurrent <= 0) { - updateCurrent = updateRate; - } else { - return; - } - - - if (index < frame.size() - 1) - index++; - else - index = 0; - - for (auto &d : duckmyass) { - if (d.first.limb == limbID) { - for (auto &fa : frame.at(index)) { - if (fa.first.limb == limbID) { - d.first = fa.first; - d.second = fa.second; - } - } - } - } - - } - - float updateRate; /**< How often we will change each frame. */ - float updateCurrent = 0; /**< How much has been updated in the current frame. */ - unsigned int updateType; /**< What the updateRate will base it's updates off of. - ie: Movement, attacking, jumping. */ - unsigned int limbID; /**< The id of the limb we will be updating */ - - unsigned int index = 0; /**< The current sprite being used for the limb. */ - - std::vector<Frame> frame; /**< The multiple frames of each limb. */ -}; - -//TODO kill clyne -struct Animate : public Component { - // COMMENT - std::vector<Limb> limb; - // COMMENT - unsigned int index; - - Animate(){ - index = 0; - } - - Animate(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - // COMMENT - - void firstFrame(unsigned int updateType, Frame &sprite) { - unsigned int upid = updateType; //^see todo - for (auto &l : limb) { - if (l.updateType == upid) { - l.firstFrame(sprite); - } - } - } - //TODO make updateType an enum - void updateAnimation(unsigned int updateType, Frame& sprite, float dt) { - unsigned int upid = updateType; //^see todo - for (auto &l : limb) { - if (l.updateType == upid) { - l.nextFrame(sprite, dt); - } - } - } - - void fromXML(XMLElement* imp, XMLElement* def) final { - (void)imp; - - auto animx = def->FirstChildElement(); - uint limbid = 0; - float limbupdate = 0; - uint limbupdatetype = 0; - - while (animx != nullptr) { - if (std::string(animx->Name()) == "movement") { - limbupdatetype = 1; - - auto limbx = animx->FirstChildElement(); - while (limbx != nullptr) { - if (std::string(limbx->Name()) == "limb") { - auto frames = developFrame(limbx); - limb.push_back(Limb()); - auto& newLimb = limb.back(); - newLimb.updateType = limbupdatetype; - - if (limbx->QueryUnsignedAttribute("id", &limbid) == XML_NO_ERROR) - newLimb.limbID = limbid; - if (limbx->QueryFloatAttribute("update", &limbupdate) == XML_NO_ERROR) - newLimb.updateRate = limbupdate; - - // place our newly developed frames in the entities animation stack - for (auto &f : frames) { - newLimb.addFrame(f); - for (auto &fr : newLimb.frame) { - for (auto &sd : fr) - sd.first.limb = limbid; - } - } - } - - limbx = limbx->NextSiblingElement(); - } - } - - animx = animx->NextSiblingElement(); - } - } -}; - -/** - * @struct Visible - * @brief If an entity is visible we want to be able to draw it. - */ -struct Visible : public Component { - /** - * @brief Decide what layer to draw the entity on. - * When stuff is drawn, it is drawn on a "layer". This layer gives more of a 3D effect to the world. - * @param z The desired "layer" of the entity. - */ - Visible(float z = 0.0f): z(z) {} - Visible(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - float z; /**< The value along the z axis the entity will be drawn on */ - - void fromXML(XMLElement* imp, XMLElement* def) final { - (void)imp; - if (def->QueryFloatAttribute("value", &z) != XML_NO_ERROR) - z = 0; - } -}; - -struct Dialog : public Component { - Dialog(int idx = 0) - : index(idx), rindex((idx == 9999) ? randGet() : idx), talking(false) {} - Dialog(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - int index; - int rindex; - bool talking; - - void fromXML(XMLElement* imp, XMLElement* def) final { - (void)def; - bool hasDialog; - if (imp->QueryBoolAttribute("hasDialog", &hasDialog) != XML_NO_ERROR) - hasDialog = false; - - index = hasDialog ? 0 : 9999; - rindex = (index == 9999) ? randGet() : index; - talking = false; - } -}; - -// movement styles - -/** - * Causes the entity to hop around. - */ -struct Hop { - Hop(float r = 0) - : hopRatio(r) {} - - float hopRatio; -}; - -/** - * Causes the entity to wander about. - */ -struct Wander { - Wander(float ix = 0, float r = 0) - : initialX(ix), range(r), countdown(0) {} - - float initialX; - float range; - int countdown; -}; - -/** - * Causes the entity to get mad at the player, charge and fight. - */ -struct Aggro : public Component { - Aggro(const std::string& a) - : arena(a) {} - Aggro(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - std::string arena; - - void fromXML(XMLElement* imp, XMLElement* def) final { - (void)imp; - // TODO null check..?, imp given - arena = def->StrAttribute("arena"); - } -}; - -struct Hit : public Component { - Hit(int d, bool p = false) - : damage(d), pierce(p) {} - - int damage; - bool pierce; - - void fromXML(XMLElement* imp, XMLElement* def) final { - (void)imp; - (void)def; - } -}; - -struct Trigger : public Component { - Trigger(const std::string& t) - : text(t) {} - Trigger(XMLElement* imp, XMLElement* def) { - fromXML(imp, def); - } - - std::string text; - - void fromXML(XMLElement* imp, XMLElement* def) final { - (void)imp; - (void)def; - text = "You got me!"; - } -}; - -/** - * SYSTEMS - */ - -class MovementSystem : public entityx::System<MovementSystem> { -public: - void update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) override; -}; - -class PhysicsSystem : public entityx::System<PhysicsSystem> { -public: - void update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) override; -}; - -class RenderSystem : public entityx::System<RenderSystem> { -private: - static std::string loadTexString; - static Texture loadTexResult; - -public: - static Texture loadTexture(const std::string& file); - static void render(void); - - void update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) override - { (void)en; (void)ev; (void)dt; } -}; - -class DialogSystem : public entityx::System<DialogSystem>, public entityx::Receiver<DialogSystem> { -public: - void configure(entityx::EventManager&); - void receive(const MouseClickEvent&); - void update(entityx::EntityManager&, entityx::EventManager&, entityx::TimeDelta) override; -}; +#include <systems/dialog.hpp> +#include <systems/movement.hpp> +#include <systems/physics.hpp> +#include <systems/render.hpp> #endif //COMPONENTS_HPP diff --git a/include/components/aggro.hpp b/include/components/aggro.hpp new file mode 100644 index 0000000..17d646c --- /dev/null +++ b/include/components/aggro.hpp @@ -0,0 +1,25 @@ +#ifndef COMPONENTS_AGGRO_HPP_ +#define COMPONENTS_AGGRO_HPP_ + +#include "base.hpp" + +/** + * Causes the entity to get mad at the player, charge and fight. + */ +struct Aggro : public Component { + Aggro(const std::string& a) + : arena(a) {} + Aggro(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + std::string arena; + + void fromXML(XMLElement* imp, XMLElement* def) final { + (void)imp; + // TODO null check..?, imp given + arena = def->StrAttribute("arena"); + } +}; + +#endif // COMPONENTS_AGGRO_HPP_ diff --git a/include/components/all.hpp b/include/components/all.hpp index 2fb3c8d..dda8938 100644 --- a/include/components/all.hpp +++ b/include/components/all.hpp @@ -1,7 +1,26 @@ #ifndef COMPONENTS_ALL_HPP_ #define COMPONENTS_ALL_HPP_ +#include "aggro.hpp" +#include "animate.hpp" #include "damage.hpp" +#include "dialog.hpp" +#include "direction.hpp" #include "drop.hpp" +#include "grounded.hpp" +#include "health.hpp" +#include "hit.hpp" +#include "hop.hpp" +#include "itemdrop.hpp" +#include "name.hpp" +#include "physics.hpp" +#include "player.hpp" +#include "portal.hpp" +#include "position.hpp" +#include "solid.hpp" +#include "sprite.hpp" +#include "trigger.hpp" +#include "visible.hpp" +#include "wander.hpp" #endif // COMPONENTS_ALL_HPP_ diff --git a/include/components/animate.hpp b/include/components/animate.hpp new file mode 100644 index 0000000..116ee3f --- /dev/null +++ b/include/components/animate.hpp @@ -0,0 +1,64 @@ +#ifndef COMPONENTS_ANIMATE_HPP_ +#define COMPONENTS_ANIMATE_HPP_ + +#include "base.hpp" + +#include <components/sprite.hpp> + +#include <vector> + +/** + * @struct Limb + * @brief Storage of frames for the limbs of a sprite. + * This will allow us to only update a certain limb. This was we can do mulitple animation types at once. + */ +struct Limb { + Limb(void) {} // TODO necessary? + + // adds frame to the back of the frame stack + inline void addFrame(Frame fr) { + frame.push_back(fr); + } + + void firstFrame(Frame& duckmyass); + void nextFrame(Frame& duckmyass, float dt); + + /**< How often we will change each frame. */ + float updateRate; + + /**< How much has been updated in the current frame. */ + float updateCurrent = 0; + + /**< What the updateRate will base it's updates off of. ie: Movement, attacking, jumping. */ + unsigned int updateType; + + /**< The id of the limb we will be updating */ + unsigned int limbID; + + /**< The current sprite being used for the limb. */ + unsigned int index = 0; + + /**< The multiple frames of each limb. */ + std::vector<Frame> frame; +}; + +struct Animate : public Component { + // COMMENT + unsigned int index; + // COMMENT + std::vector<Limb> limb; + + Animate(void) + : index(0) {} + Animate(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + // COMMENT + void firstFrame(unsigned int updateType, Frame &sprite); + //TODO make updateType an enum + void updateAnimation(unsigned int updateType, Frame& sprite, float dt); + void fromXML(XMLElement* imp, XMLElement* def) final; +}; + +#endif // COMPONENTS_ANIMATE_HPP_ diff --git a/include/components/dialog.hpp b/include/components/dialog.hpp new file mode 100644 index 0000000..8d26b92 --- /dev/null +++ b/include/components/dialog.hpp @@ -0,0 +1,31 @@ +#ifndef COMPONENTS_DIALOG_HPP_ +#define COMPONENTS_DIALOG_HPP_ + +#include "base.hpp" + +#include <random.hpp> + +struct Dialog : public Component { + Dialog(int idx = 0) + : index(idx), rindex((idx == 9999) ? randGet() : idx), talking(false) {} + Dialog(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + int index; + int rindex; + bool talking; + + void fromXML(XMLElement* imp, XMLElement* def) final { + (void)def; + bool hasDialog; + if (imp->QueryBoolAttribute("hasDialog", &hasDialog) != XML_NO_ERROR) + hasDialog = false; + + index = hasDialog ? 0 : 9999; + rindex = (index == 9999) ? randGet() : index; + talking = false; + } +}; + +#endif // COMPONENTS_DIALOG_HPP_ diff --git a/include/components/direction.hpp b/include/components/direction.hpp new file mode 100644 index 0000000..1229e49 --- /dev/null +++ b/include/components/direction.hpp @@ -0,0 +1,42 @@ +#ifndef COMPONENTS_DIRECTION_HPP_ +#define COMPONENTS_DIRECTION_HPP_ + +#include "base.hpp" + +#include <vector2.hpp> + +/** + * @struct Direction + * @brief Store an entities velocity. + * This allows the entity to move throughout the world. + */ +struct Direction : public Component { + /** + * Constructor that sets the velocity, if no position is passed, it defaults to (0,0). + * @param x The velocity of the object on the x axis. + * @param y The velocity of the object on the y axis. + */ + Direction(float x = 0.0f, float y = 0.0f): x(x), y(y), grounded(false) {} + Direction(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + float x; /**< Velocity the object is moving in the x direction, this is added to the position */ + float y; /**< Velocity the object is moving in the y direction, this is added to the position */ + bool grounded; + + void fromXML(XMLElement* imp, XMLElement* def) final { + vec2 c; + if (imp->Attribute("direction") != nullptr) { + c = imp->StrAttribute("direction"); + } else if (def->Attribute("value") != nullptr) { + c = def->StrAttribute("value"); + } else { + c = vec2(0, 0); + } + + x = c.x, y = c.y, grounded = false; + } +}; + +#endif // COMPONENTS_DIRECTION_HPP_ diff --git a/include/components/flash.hpp b/include/components/flash.hpp new file mode 100644 index 0000000..e53c41c --- /dev/null +++ b/include/components/flash.hpp @@ -0,0 +1,15 @@ +#ifndef COMPONENTS_FLASH_HPP_ +#define COMPONENTS_FLASH_HPP_ + +#include <color.hpp> + +struct Flash +{ + Flash(Color c, int _ms = 500) + : color(c), ms(_ms), totalMs(_ms) {} + + Color color; + int ms, totalMs; +}; + +#endif // COMPONENTS_FLASH_HPP_ diff --git a/include/components/grounded.hpp b/include/components/grounded.hpp new file mode 100644 index 0000000..017c118 --- /dev/null +++ b/include/components/grounded.hpp @@ -0,0 +1,27 @@ +#ifndef COMPONENTS_GROUNDED_HPP_ +#define COMPONENTS_GROUNDED_HPP_ + +#include "base.hpp" + +/** + * @struct Grounded + * @brief Places an entity without physics on the ground. + * This is used so we don't have to update the physics of a non-moving object every loop. + */ +struct Grounded : public Component { + Grounded(bool g = false) + : grounded(g) {} + Grounded(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + bool grounded; + + void fromXML(XMLElement* imp, XMLElement* def) final { + (void)imp; + (void)def; + grounded = false; + } +}; + +#endif // COMPONENTS_GROUNDED_HPP_ diff --git a/include/components/health.hpp b/include/components/health.hpp new file mode 100644 index 0000000..eacaaa5 --- /dev/null +++ b/include/components/health.hpp @@ -0,0 +1,34 @@ +#ifndef COMPONENTS_HEALTH_HPP_ +#define COMPONENTS_HEALTH_HPP_ + +#include "base.hpp" + +/** + * @struct Health + * @brief Gives and entity health and stuff. + */ +struct Health : public Component { + /** + * Constructor that sets the variables, with 1 health as default. + */ + Health(int m = 1, int h = 0) + : health(h != 0 ? h : m), maxHealth(m) {} + Health(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + int health; /**< The current amount of health */ + int maxHealth; /**< The maximum amount of health */ + + void fromXML(XMLElement* imp, XMLElement* def) final { + (void)imp; + (void)def; + // TODO + if (def->QueryIntAttribute("value", &health) != XML_NO_ERROR) + health = 1; + maxHealth = health; + } +}; + + +#endif // COMPONENTS_HEALTH_HPP_ diff --git a/include/components/hit.hpp b/include/components/hit.hpp new file mode 100644 index 0000000..d2e80ca --- /dev/null +++ b/include/components/hit.hpp @@ -0,0 +1,19 @@ +#ifndef COMPONENTS_HIT_HPP_ +#define COMPONENTS_HIT_HPP_ + +#include "base.hpp" + +struct Hit : public Component { + Hit(int d, bool p = false) + : damage(d), pierce(p) {} + + int damage; + bool pierce; + + void fromXML(XMLElement* imp, XMLElement* def) final { + (void)imp; + (void)def; + } +}; + +#endif // COMPONENTS_HIT_HPP_ diff --git a/include/components/hop.hpp b/include/components/hop.hpp new file mode 100644 index 0000000..f114265 --- /dev/null +++ b/include/components/hop.hpp @@ -0,0 +1,14 @@ +#ifndef COMPONENTS_HOP_HPP_ +#define COMPONENTS_HOP_HPP_ + +/** + * Causes the entity to hop around. + */ +struct Hop { + Hop(float r = 0) + : hopRatio(r) {} + + float hopRatio; +}; + +#endif // COMPONENTS_HOP_HPP diff --git a/include/components/itemdrop.hpp b/include/components/itemdrop.hpp new file mode 100644 index 0000000..681c0d6 --- /dev/null +++ b/include/components/itemdrop.hpp @@ -0,0 +1,13 @@ +#ifndef COMPONENTS_ITEMDROP_HPP_ +#define COMPONENTS_ITEMDROP_HPP_ + +#include <inventory.hpp> + +struct ItemDrop { + ItemDrop(InventoryEntry& ie) + : item(ie) {} + + InventoryEntry item; +}; + +#endif // COMPONENTS_ITEMDROP_HPP_ diff --git a/include/components/name.hpp b/include/components/name.hpp new file mode 100644 index 0000000..423a484 --- /dev/null +++ b/include/components/name.hpp @@ -0,0 +1,24 @@ +#ifndef COMPONENTS_NAME_HPP_ +#define COMPONENTS_NAME_HPP_ + +#include "base.hpp" + +#include <string> + +struct Name : public Component { + Name(std::string n = "") + : name(n) {} + Name(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + std::string name; + + void fromXML(XMLElement* imp, XMLElement* def) final { + auto n = imp->Attribute("name"); + + // TODO check def's nullness + name = n != nullptr ? n : def->Attribute("value"); + } +}; +#endif // COMPONENTS_NAME_HPP_ diff --git a/include/components/physics.hpp b/include/components/physics.hpp new file mode 100644 index 0000000..8e462a9 --- /dev/null +++ b/include/components/physics.hpp @@ -0,0 +1,31 @@ +#ifndef COMPONENTS_PHYSICS_HPP_ +#define COMPONENTS_PHYSICS_HPP_ + +#include "base.hpp" + +/** + * @struct Physics + * @brief Allows and entity to react to gravity and frictions. + * When an entity inherits this component it will react with gravity and move with friction. + */ +struct Physics : public Component { + /** + * Constructor that sets the gravity constant, if not specified it becomes 0. + * @param g The non default gravity constant. + */ + Physics(float g = 0.2f): g(g) {} + Physics(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + float g; /**< The gravity constant, how fast the object falls */ + + void fromXML(XMLElement* imp, XMLElement* def) final { + if (imp->QueryFloatAttribute("gravity", &g) != XML_NO_ERROR) { + if (def->QueryFloatAttribute("value", &g) != XML_NO_ERROR) + g = 0.2f; + } + } +}; + +#endif // COMPONENTS_PHYSICS_HPP_ diff --git a/include/components/player.hpp b/include/components/player.hpp new file mode 100644 index 0000000..afcaa90 --- /dev/null +++ b/include/components/player.hpp @@ -0,0 +1,6 @@ +#ifndef COMPONENTS_PLAYER_HPP_ +#define COMPONENTS_PLAYER_HPP_ + +struct Player {}; + +#endif // COMPONENTS_PLAYER_HPP_ diff --git a/include/components/portal.hpp b/include/components/portal.hpp new file mode 100644 index 0000000..ca153e1 --- /dev/null +++ b/include/components/portal.hpp @@ -0,0 +1,23 @@ +#ifndef COMPONENTS_PORTAL_HPP_ +#define COMPONENTS_PORTAL_HPP_ + +#include "base.hpp" + +#include <string> + +struct Portal : public Component { + Portal(std::string tf = "") + : toFile(tf) {} + Portal(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + std::string toFile; + + void fromXML(XMLElement* imp, XMLElement* def) final { + (void)def; + toFile = imp->StrAttribute("inside"); + } +}; + +#endif // COMPONENTS_PORTAL_HPP_ diff --git a/include/components/position.hpp b/include/components/position.hpp new file mode 100644 index 0000000..f040bec --- /dev/null +++ b/include/components/position.hpp @@ -0,0 +1,37 @@ +#ifndef COMPONENTS_POSITION_HPP_ +#define COMPONENTS_POSITION_HPP_ + +#include "base.hpp" + +#include <vector2.hpp> + +/** + * @struct Position + * @brief Stores the position of an entity on the xy plane. + */ +struct Position : public Component { + /** + * Constructor that sets the position of the object, if nothing is passed it will default to 0. + * @param x The x position the object will be placed at. + * @param y the y position the object will be placed at. + */ + Position(float x = 0.0f, float y = 0.0f): x(x), y(y) {} + Position(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + float x; /**< The x position in the world */ + float y; /**< The y position in the world */ + + void fromXML(XMLElement* imp, XMLElement* def) final { + vec2 c; + if (imp->Attribute("position") != nullptr) + c = imp->StrAttribute("position"); + else + c = def->StrAttribute("value"); + + x = c.x, y = c.y; + } +}; + +#endif // COMPONENTS_POSITION_HPP_ diff --git a/include/components/solid.hpp b/include/components/solid.hpp new file mode 100644 index 0000000..35bfcf7 --- /dev/null +++ b/include/components/solid.hpp @@ -0,0 +1,45 @@ +#ifndef COMPONENTS_SOLID_HPP_ +#define COMPONENTS_SOLID_HPP_ + +#include "base.hpp" + +#include <vector2.hpp> + +/** + * @struct Solid + * @brief Allows an entity to collide with other objects. + * When an entity has this component it can collide with the world and other objects. + */ +struct Solid : public Component { + /** + * Constructor that sets the entities dimensions based on what is passed. + * @param w The desired width of the entity. + * @param h The desired height of the entity. + */ + Solid(float w = 0.0f, float h = 0.0f) + : width(w), height(h), offset(0), passable(true) {} + Solid(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + void Passable(bool v) { passable = v; } + bool Passable(void) { return passable; } + + float width; /**< The width of the entity in units */ + float height; /**< The height of the entity in units */ + vec2 offset; /**< This allows us to make the hitbox in any spot */ + bool passable; /**< This determines whether or not one can pass by the entity */ + + void fromXML(XMLElement* imp, XMLElement* def) final { + (void)imp; + vec2 c; + if (def->Attribute("value") != nullptr) + c = def->StrAttribute("value"); + else + c = vec2(0, 0); + + width = c.x, height = c.y, offset = 0, passable = true; + } +}; + +#endif // COMPONENTS_SOLID_HPP_ diff --git a/include/components/sprite.hpp b/include/components/sprite.hpp new file mode 100644 index 0000000..35a13b8 --- /dev/null +++ b/include/components/sprite.hpp @@ -0,0 +1,64 @@ +#ifndef COMPONENTS_SPRITE_HPP_ +#define COMPONENTS_SPRITE_HPP_ + +#include "base.hpp" + +#include <texture.hpp> +#include <vector2.hpp> + +#include <vector> + +struct SpriteData { + SpriteData(void) = default; + SpriteData(Texture t); + SpriteData(std::string path, vec2 off); + SpriteData(std::string path, vec2 off, vec2 si); + + Texture tex; + vec2 size; + vec2 offset; + + vec2 offset_tex; + vec2 size_tex; + + unsigned int limb; +}; + +using Frame = std::vector<std::pair<SpriteData, vec2>>; + +std::vector<Frame> developFrame(XMLElement*); + +/** + * @struct Sprite + * @brief If an entity is visible we want to be able to see it. + * Each entity is given a sprite, a sprite can consist of manu frames or pieces to make one. + */ +struct Sprite : public Component { + Sprite(bool left = false) + : faceLeft(left) {} + Sprite(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + inline Frame getSprite(void) { + return sprite; + } + + int clearSprite(void); + int addSpriteSegment(SpriteData data, vec2 loc); + int changeSpriteSegment(SpriteData data, vec2 loc); + vec2 getSpriteSize(); + + void fromXML(XMLElement* imp, XMLElement* def) final { + (void)imp; + auto frames = developFrame(def); + if (!frames.empty()) + sprite = frames.at(0); + } + + Frame sprite; + bool faceLeft; +}; + + +#endif // COMPONENTS_SPRITE_HPP_ diff --git a/include/components/trigger.hpp b/include/components/trigger.hpp new file mode 100644 index 0000000..c9a53f6 --- /dev/null +++ b/include/components/trigger.hpp @@ -0,0 +1,25 @@ +#ifndef COMPONENTS_TRIGGER_HPP_ +#define COMPONENTS_TRIGGER_HPP_ + +#include "base.hpp" + +#include <string> + +struct Trigger : public Component { + Trigger(const std::string& t) + : text(t) {} + Trigger(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + std::string text; + + void fromXML(XMLElement* imp, XMLElement* def) final { + (void)imp; + (void)def; + text = "You got me!"; + } +}; + + +#endif // COMPONENTS_TRIGGER_HPP_ diff --git a/include/components/visible.hpp b/include/components/visible.hpp new file mode 100644 index 0000000..4785fb0 --- /dev/null +++ b/include/components/visible.hpp @@ -0,0 +1,30 @@ +#ifndef COMPONENTS_VISIBLE_HPP_ +#define COMPONENTS_VISIBLE_HPP_ + +#include "base.hpp" + +/** + * @struct Visible + * @brief If an entity is visible we want to be able to draw it. + */ +struct Visible : public Component { + /** + * @brief Decide what layer to draw the entity on. + * When stuff is drawn, it is drawn on a "layer". This layer gives more of a 3D effect to the world. + * @param z The desired "layer" of the entity. + */ + Visible(float z = 0.0f): z(z) {} + Visible(XMLElement* imp, XMLElement* def) { + fromXML(imp, def); + } + + float z; /**< The value along the z axis the entity will be drawn on */ + + void fromXML(XMLElement* imp, XMLElement* def) final { + (void)imp; + if (def->QueryFloatAttribute("value", &z) != XML_NO_ERROR) + z = 0; + } +}; + +#endif // COMPONENTS_VISIBLE_HPP_ diff --git a/include/components/wander.hpp b/include/components/wander.hpp new file mode 100644 index 0000000..2001e89 --- /dev/null +++ b/include/components/wander.hpp @@ -0,0 +1,16 @@ +#ifndef COMPONENTS_WANDER_HPP_ +#define COMPONENTS_WANDER_HPP_ + +/** + * Causes the entity to wander about. + */ +struct Wander { + Wander(float ix = 0, float r = 0) + : initialX(ix), range(r), countdown(0) {} + + float initialX; + float range; + int countdown; +}; + +#endif // COMPONENTS_WANDER_HPP_ diff --git a/include/systems/dialog.hpp b/include/systems/dialog.hpp new file mode 100644 index 0000000..407f043 --- /dev/null +++ b/include/systems/dialog.hpp @@ -0,0 +1,16 @@ +#ifndef SYSTEM_DIALOG_HPP_ +#define SYSTEM_DIALOG_HPP_ + +#include <entityx/entityx.h> + +#include <events.hpp> + +class DialogSystem : public entityx::System<DialogSystem>, public entityx::Receiver<DialogSystem> { +public: + void configure(entityx::EventManager&); + void receive(const MouseClickEvent&); + void update(entityx::EntityManager&, entityx::EventManager&, entityx::TimeDelta) override; +}; + + +#endif // SYSTEM_DIALOG_HPP_ diff --git a/include/systems/movement.hpp b/include/systems/movement.hpp new file mode 100644 index 0000000..fd37665 --- /dev/null +++ b/include/systems/movement.hpp @@ -0,0 +1,11 @@ +#ifndef SYSTEM_MOVEMENT_HPP_ +#define SYSTEM_MOVEMENT_HPP_ + +#include <entityx/entityx.h> + +class MovementSystem : public entityx::System<MovementSystem> { +public: + void update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) override; +}; + +#endif // SYSTEM_MOVEMENT_HPP_ diff --git a/include/systems/physics.hpp b/include/systems/physics.hpp new file mode 100644 index 0000000..9fd6981 --- /dev/null +++ b/include/systems/physics.hpp @@ -0,0 +1,11 @@ +#ifndef SYSTEM_PHYSICS_HPP_ +#define SYSTEM_PHYSICS_HPP_ + +#include <entityx/entityx.h> + +class PhysicsSystem : public entityx::System<PhysicsSystem> { +public: + void update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) override; +}; + +#endif // SYSTEM_PHYSICS_HPP_ diff --git a/include/systems/render.hpp b/include/systems/render.hpp new file mode 100644 index 0000000..012c6fd --- /dev/null +++ b/include/systems/render.hpp @@ -0,0 +1,23 @@ +#ifndef SYSTEM_RENDER_HPP_ +#define SYSTEM_RENDER_HPP_ + +#include <entityx/entityx.h> + +#include <texture.hpp> + +#include <string> + +class RenderSystem : public entityx::System<RenderSystem> { +private: + static std::string loadTexString; + static Texture loadTexResult; + +public: + static Texture loadTexture(const std::string& file); + static void render(void); + + void update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) override; +}; + + +#endif // SYSTEM_RENDER_HPP_ diff --git a/src/components.cpp b/src/components.cpp deleted file mode 100644 index 056d48b..0000000 --- a/src/components.cpp +++ /dev/null @@ -1,418 +0,0 @@ -#include <components.hpp> - -#include <entityx/entityx.h> -#include <events.hpp> - -#include <attack.hpp> -#include <render.hpp> -#include <ui.hpp> -#include <engine.hpp> -#include <error.hpp> -#include <font.hpp> -#include <world.hpp> -#include <brice.hpp> -#include <quest.hpp> -#include <glm.hpp> -#include <fileio.hpp> -#include <player.hpp> - -#include <atomic> - -using namespace std::literals::chrono_literals; - -std::string RenderSystem::loadTexString; -Texture RenderSystem::loadTexResult; - -static std::vector<std::string> randomDialog (readFileA("assets/dialog_en-us")); - -void MovementSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) -{ - //bool fight = false; - entityx::Entity toFight; - - (void)ev; - en.each<Position, Direction>([&](entityx::Entity entity, Position &position, Direction &direction) { - position.x += HLINES(direction.x) * dt; - position.y += HLINES(direction.y) * dt; - - if (entity.has_component<Animate>() && entity.has_component<Sprite>()) { - auto animate = entity.component<Animate>(); - auto sprite = entity.component<Sprite>(); - - if (direction.x) - animate->updateAnimation(1, sprite->sprite, dt); - else - animate->firstFrame(1, sprite->sprite); - } - if (entity.has_component<Dialog>() && entity.component<Dialog>()->talking) { - direction.x = 0; - } else { - if (entity.has_component<Sprite>()) { - auto& fl = entity.component<Sprite>()->faceLeft; - if (direction.x != 0) - fl = (direction.x < 0); - } - - auto ppos = PlayerSystem::getPosition(); - if (ppos.x > position.x && ppos.x < position.x + entity.component<Solid>()->width) { - if (entity.has_component<Aggro>()) { - auto dim = entity.component<Solid>(); - ev.emit<AttackEvent>(vec2(position.x + dim->width, position.y + dim->height), - AttackType::ShortSlash, false); - /*auto& h = entity.component<Health>()->health; - if (h > 0) { - fight = true; - toFight = entity; - h = 0; - }*/ - } else if (entity.has_component<Trigger>()) { - static bool triggering = false; - if (!triggering) { - triggering = true; - std::thread([&](entityx::Entity e) { - UISystem::fadeToggle(); - UISystem::waitForCover(); - UISystem::dialogImportant(e.component<Trigger>()->text); - UISystem::waitForDialog(); - UISystem::fadeToggle(); - e.destroy(); - triggering = false; - }, entity).detach(); - } - return; - } - } - - // make the entity wander - // TODO initialX and range? - if (entity.has_component<Wander>()) { - auto& countdown = entity.component<Wander>()->countdown; - - if (countdown > 0) { - countdown--; - } else { - countdown = 5000 + randGet() % 10 * 100; - direction.x = (randGet() % 3 - 1) * 0.004f; - } - } - } - }); - -// if (fight) { -// UISystem::fadeToggleFast(); -// UISystem::waitForCover(); - //game::engine.getSystem<WorldSystem>()->fight(toFight); -// UISystem::fadeToggleFast(); -// } -} - -void PhysicsSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) -{ - (void)ev; - en.each<Direction, Physics>([dt](entityx::Entity entity, Direction &direction, Physics &physics) { - (void)entity; - // TODO GET GRAVITY FROM WORLD - direction.y += physics.g * dt; - }); -} - -Texture RenderSystem::loadTexture(const std::string& file) -{ - loadTexString = file; - loadTexResult = Texture(); - while (loadTexResult.isEmpty()) - std::this_thread::sleep_for(1ms); - auto t = loadTexResult; - loadTexResult = Texture(); - return t; -} - -void RenderSystem::render(void) -{ - if (!loadTexString.empty()) { - loadTexResult = Texture(loadTexString, false); - loadTexString.clear(); - } - - if (!loadTexResult.isEmpty()) - return; - - Render::worldShader.use(); - Render::worldShader.enable(); - - game::entities.each<Visible, Sprite, Position>([](entityx::Entity entity, Visible &visible, Sprite &sprite, Position &pos) { - // Verticies and shit - float its = 0; - - float sz; - if (entity.has_component<Solid>()) - sz = entity.component<Solid>()->width; - else - sz = sprite.getSpriteSize().x; - - if (sprite.faceLeft) { - glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(-1.0f,1.0f,1.0f)); - glm::mat4 translate = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f - sz - pos.x * 2.0f, 0.0f, 0.0f)); - - glm::mat4 mov = scale * translate; - glUniformMatrix4fv(Render::worldShader.uniform[WU_transform], 1, GL_FALSE, glm::value_ptr(mov)); - } - - for (auto &S : sprite.sprite) { - auto sp = S.first; - auto size = sp.size * game::HLINE; - vec2 drawOffset (HLINES(S.second.x), HLINES(S.second.y)); - vec2 loc (pos.x + drawOffset.x, pos.y + drawOffset.y); - - GLfloat verts[] = { - loc.x, loc.y, visible.z + its, sp.offset_tex.x, sp.offset_tex.y, - loc.x + size.x, loc.y, visible.z + its, sp.offset_tex.x + sp.size_tex.x, sp.offset_tex.y, - loc.x + size.x, loc.y + size.y, visible.z + its, sp.offset_tex.x + sp.size_tex.x, sp.offset_tex.y + sp.size_tex.y, - loc.x, loc.y, visible.z + its, sp.offset_tex.x, sp.offset_tex.y, - loc.x + size.x, loc.y + size.y, visible.z + its, sp.offset_tex.x + sp.size_tex.x, sp.offset_tex.y + sp.size_tex.y, - loc.x, loc.y + size.y, visible.z + its, sp.offset_tex.x, sp.offset_tex.y + sp.size_tex.y - }; - - // make the entity hit flash red - // TODO - /*if (maxHitDuration-hitDuration) { - float flashAmt = 1-(hitDuration/maxHitDuration); - glUniform4f(Render::worldShader.uniform[WU_tex_color], 1.0, flashAmt, flashAmt, 1.0); - }*/ - - sp.tex.use(); - - glUniform1i(Render::worldShader.uniform[WU_texture], 0); - - glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), verts); - glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), verts + 3); - glDrawArrays(GL_TRIANGLES, 0, 6); - - //glUniform4f(Render::worldShader.uniform[WU_tex_color], 1.0, 1.0, 1.0, 1.0); - - its-=.01; - } - glUniformMatrix4fv(Render::worldShader.uniform[WU_transform], 1, GL_FALSE, glm::value_ptr(glm::mat4(1.0f))); - - if (entity.has_component<Health>()) { - float width = entity.component<Solid>()->width; - auto& health = *entity.component<Health>(); - width *= health.health / static_cast<float>(health.maxHealth); - - GLfloat health_coord[] = { - pos.x, pos.y, -9, 0, 0, - pos.x + width, pos.y, -9, 0, 0, - pos.x + width, pos.y - 5, -9, 0, 0, - pos.x + width, pos.y - 5, -9, 0, 0, - pos.x, pos.y - 5, -9, 0, 0, - pos.x, pos.y, -9, 0, 0, - }; - - Colors::red.use(); - glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), health_coord); - glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), health_coord + 3); - glDrawArrays(GL_TRIANGLES, 0, 6); - } - }); - - Render::worldShader.disable(); - Render::worldShader.unuse(); - - game::entities.each<Visible, Position, Solid, Name>([](entityx::Entity e, Visible &v, Position &pos, Solid& dim, Name &name) { - (void)e; - (void)v; - FontSystem::setFontZ(-5.0f); - UISystem::putStringCentered(vec2(pos.x + dim.width / 2, pos.y - FontSystem::getSize() - HLINES(0.5)), name.name); - }); -} - -void DialogSystem::configure(entityx::EventManager &ev) -{ - ev.subscribe<MouseClickEvent>(*this); -} - -void DialogSystem::receive(const MouseClickEvent &mce) -{ - game::entities.each<Position, Solid, Dialog, Name>( - [&](entityx::Entity e, Position &pos, Solid &dim, Dialog &d, Name &name) { - static std::atomic_bool dialogRun; - (void)e; - (void)d; - - if (((mce.position.x > pos.x) & (mce.position.x < pos.x + dim.width)) && - ((mce.position.y > pos.y) & (mce.position.y < pos.y + dim.height))) { - - if (!dialogRun.load()) { - // copy entity, windows destroys the original after thread detach - std::thread([e, &pos, &dim, &d, &name] { - std::string questAssignedText; - int newIndex; - - auto exml = WorldSystem::getXML()->FirstChildElement("Dialog"); - dialogRun.store(true); - - if (e.has_component<Direction>()) - d.talking = true; - - if (d.index == 9999) { - UISystem::dialogBox(name.name, /*"", false,*/ randomDialog[d.rindex % randomDialog.size()]); - UISystem::waitForDialog(); - } else if (exml != nullptr) { - while (exml->StrAttribute("name") != name.name) - exml = exml->NextSiblingElement(); - - exml = exml->FirstChildElement("text"); - while (exml->IntAttribute("id") != d.index) - exml = exml->NextSiblingElement(); - - auto oxml = exml->FirstChildElement("set"); - if (oxml != nullptr) { - do game::setValue(oxml->StrAttribute("id"), oxml->StrAttribute("value")); - while ((oxml = oxml->NextSiblingElement())); - game::briceUpdate(); - } - - auto ixml = exml->FirstChildElement("give"); - if (ixml != nullptr) { - do { - InventorySystem::add(ixml->StrAttribute("name"), ixml->IntAttribute("count")); - ixml = ixml->NextSiblingElement(); - } while (ixml != nullptr); - } - - auto qxml = exml->FirstChildElement("quest"); - if (qxml != nullptr) { - const char *qname; - - do { - // assign quest - qname = qxml->Attribute("assign"); - if (qname != nullptr) { - questAssignedText = qname; - auto req = qxml->GetText(); - QuestSystem::assign(qname, qxml->StrAttribute("desc"), req ? req : ""); - } - - // check / finish quest - else { - qname = qxml->Attribute("check"); - if (qname != nullptr) { - if (qname != nullptr && QuestSystem::finish(qname) == 0) { - d.index = 9999; - } else { - UISystem::dialogBox(name.name, /*"", false,*/ "Finish my quest u nug"); - UISystem::waitForDialog(); - return; - } - // oldidx = d.index; - // d.index = qxml->UnsignedAttribute("fail"); - // goto COMMONAIFUNC; - } - } - } while((qxml = qxml->NextSiblingElement())); - } - - auto xxml = exml->FirstChildElement("option"); - std::string options; - std::vector<int> optionNexts; - if (xxml != nullptr) { - do { - UISystem::dialogAddOption(xxml->StrAttribute("name")); - - options += '\"' + xxml->StrAttribute("name"); - optionNexts.emplace_back(xxml->IntAttribute("value")); - xxml = xxml->NextSiblingElement(); - } while (xxml != nullptr); - } - - auto cxml = exml->FirstChildElement("content"); - const char *content; - if (cxml == nullptr) { - content = randomDialog[d.rindex % randomDialog.size()].c_str(); - } else { - content = cxml->GetText() - 1; - while (*++content && isspace(*content)); - } - - UISystem::dialogBox(name.name, /*options, false,*/ content); - UISystem::waitForDialog(); - UISystem::waitForDialog(); - - if (!questAssignedText.empty()) - UISystem::dialogImportant("Quest assigned:\n\"" + questAssignedText + "\""); - //passiveImportantText(5000, ("Quest assigned:\n\"" + questAssignedText + "\"").c_str()); - - if (exml->QueryIntAttribute("nextid", &newIndex) == XML_NO_ERROR) - d.index = newIndex; - } - - d.talking = false; - dialogRun.store(false); - }).detach(); - } - } - }); -} - -void DialogSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) -{ - (void)en; - (void)ev; - (void)dt; -} - -std::vector<Frame> developFrame(XMLElement* xml) -{ - Frame tmpf; - std::vector<Frame> tmp; - SpriteData sd; - - unsigned int limb = 0; - - vec2 foffset; - vec2 fsize; - vec2 fdraw; - - tmp.clear(); - - // this is the xml elements first child. It will only be the <frame> tag - auto framexml = xml->FirstChildElement(); - while (framexml) { - // this will always be frame. but if it isn't we don't wanna crash the game - std::string defframe = framexml->Name(); - if (defframe == "frame") { - tmpf.clear(); - // the xml element to parse each src of the frames - auto sxml = framexml->FirstChildElement(); - while (sxml) { - std::string sname = sxml->Name(); - if (sname == "src") { - foffset = (sxml->Attribute("offset") != nullptr) ? - sxml->StrAttribute("offset") : vec2(0,0); - fdraw = (sxml->Attribute("drawOffset") != nullptr) ? - sxml->StrAttribute("drawOffset") : vec2(0,0); - - if (sxml->Attribute("size") != nullptr) { - fsize = sxml->StrAttribute("size"); - sd = SpriteData(sxml->GetText(), foffset, fsize); - } else { - sd = SpriteData(sxml->GetText(), foffset); - } - if (sxml->QueryUnsignedAttribute("limb", &limb) == XML_NO_ERROR) - sd.limb = limb; - tmpf.push_back(std::make_pair(sd, fdraw)); - } - sxml = sxml->NextSiblingElement(); - } - // we don't want segfault - if (tmpf.size()) - tmp.push_back(tmpf); - } - // if it's not a frame we don't care - - // parse next frame - framexml = framexml->NextSiblingElement(); - } - - return tmp; -} diff --git a/src/components/animate.cpp b/src/components/animate.cpp new file mode 100644 index 0000000..2ac1465 --- /dev/null +++ b/src/components/animate.cpp @@ -0,0 +1,106 @@ +#include <components/animate.hpp> + +void Limb::firstFrame(Frame& duckmyass) +{ + // loop through the spritedata of the sprite we wanna change + for (auto &d : duckmyass) { + // if the sprite data is the same limb as this limb + if (d.first.limb == limbID) { + // rotate through (for safety) the first frame to set the limb + for (auto &fa : frame.at(0)) { + if (fa.first.limb == limbID) { + d.first = fa.first; + d.second = fa.second; + } + } + } + } +} + +void Limb::nextFrame(Frame& duckmyass, float dt) { + updateCurrent -= dt; + if (updateCurrent <= 0) { + updateCurrent = updateRate; + } else { + return; + } + + if (index < frame.size() - 1) + index++; + else + index = 0; + + for (auto &d : duckmyass) { + if (d.first.limb == limbID) { + for (auto &fa : frame.at(index)) { + if (fa.first.limb == limbID) { + d.first = fa.first; + d.second = fa.second; + } + } + } + } +} + +void Animate::firstFrame(unsigned int updateType, Frame &sprite) +{ + unsigned int upid = updateType; //^see todo + for (auto &l : limb) { + if (l.updateType == upid) { + l.firstFrame(sprite); + } + } +} + +void Animate::updateAnimation(unsigned int updateType, Frame& sprite, float dt) +{ + unsigned int upid = updateType; //^see todo + for (auto &l : limb) { + if (l.updateType == upid) { + l.nextFrame(sprite, dt); + } + } +} + +void Animate::fromXML(XMLElement* imp, XMLElement* def) +{ + (void)imp; + + auto animx = def->FirstChildElement(); + unsigned int limbid = 0; + float limbupdate = 0; + unsigned int limbupdatetype = 0; + + while (animx != nullptr) { + if (std::string(animx->Name()) == "movement") { + limbupdatetype = 1; + + auto limbx = animx->FirstChildElement(); + while (limbx != nullptr) { + if (std::string(limbx->Name()) == "limb") { + auto frames = developFrame(limbx); + limb.push_back(Limb()); + auto& newLimb = limb.back(); + newLimb.updateType = limbupdatetype; + if (limbx->QueryUnsignedAttribute("id", &limbid) == XML_NO_ERROR) + newLimb.limbID = limbid; + if (limbx->QueryFloatAttribute("update", &limbupdate) == XML_NO_ERROR) + newLimb.updateRate = limbupdate; + + // place our newly developed frames in the entities animation stack + for (auto &f : frames) { + newLimb.addFrame(f); + for (auto &fr : newLimb.frame) { + for (auto &sd : fr) + sd.first.limb = limbid; + } + } + } + limbx = limbx->NextSiblingElement(); + } + } + + animx = animx->NextSiblingElement(); + } +} + diff --git a/src/components/sprite.cpp b/src/components/sprite.cpp new file mode 100644 index 0000000..053d36a --- /dev/null +++ b/src/components/sprite.cpp @@ -0,0 +1,155 @@ +#include <components/sprite.hpp> + +#include <config.hpp> + +SpriteData::SpriteData(std::string path, vec2 off) + : offset(off) +{ + tex = Texture(path); + size = tex.getDim(); + size_tex = vec2(1.0, 1.0); + offset_tex.x = offset.x / size.x; + offset_tex.y = offset.y / size.y; +} + +SpriteData::SpriteData(std::string path, vec2 off, vec2 si) + : size(si), offset(off) +{ + tex = Texture(path); + vec2 tmpsize = tex.getDim(); + + size_tex.x = size.x/tmpsize.x; + size_tex.y = size.y/tmpsize.y; + + offset_tex.x = offset.x/tmpsize.x; + offset_tex.y = offset.y/tmpsize.y; +} + +SpriteData::SpriteData(Texture t) + : tex(t) +{ + size_tex = 1; + offset_tex = 0; + size = tex.getDim(); + offset = 0; +} + +int Sprite::clearSprite(void) +{ + if (sprite.empty()) + return 0; + + sprite.clear(); + return 1; +} + +int Sprite::addSpriteSegment(SpriteData data, vec2 loc) +{ + //TODO if sprite is in this spot, do something + sprite.push_back(std::make_pair(data, loc)); + return 1; +} + +int Sprite::changeSpriteSegment(SpriteData data, vec2 loc) +{ + for (auto &s : sprite) { + if (s.second == loc) { + s.first = data; + + return 1; + } + } + + addSpriteSegment(data, loc); + return 0; +} + +vec2 Sprite::getSpriteSize() +{ + vec2 st; /** the start location of the sprite (bottom left)*/ + vec2 ed; /** the end ofthe location of the sprite (bottom right)*/ + vec2 dim; /** how wide the sprite is */ + + if (sprite.size()) { + st.x = sprite[0].second.x; + st.y = sprite[0].second.y; + + ed.x = sprite[0].second.x + sprite[0].first.size.x; + ed.y = sprite[0].second.y + sprite[0].first.size.y; + } else { + return vec2(0.0f, 0.0f); + } + + for (auto &s : sprite) { + if (s.second.x < st.x) + st.x = s.second.x; + if (s.second.y < st.y) + st.y = s.second.y; + + if (s.second.x + s.first.size.x > ed.x) + ed.x = s.second.x + s.first.size.x; + if (s.second.y + s.first.size.y > ed.y) + ed.y = s.second.y + s.first.size.y; + } + + dim = vec2(ed.x - st.x, ed.y - st.y); + dim.x *= game::HLINE; + dim.y *= game::HLINE; + return dim; +} + +std::vector<Frame> developFrame(XMLElement* xml) +{ + Frame tmpf; + std::vector<Frame> tmp; + SpriteData sd; + + unsigned int limb = 0; + + vec2 foffset; + vec2 fsize; + vec2 fdraw; + + tmp.clear(); + + // this is the xml elements first child. It will only be the <frame> tag + auto framexml = xml->FirstChildElement(); + while (framexml) { + // this will always be frame. but if it isn't we don't wanna crash the game + std::string defframe = framexml->Name(); + if (defframe == "frame") { + tmpf.clear(); + // the xml element to parse each src of the frames + auto sxml = framexml->FirstChildElement(); + while (sxml) { + std::string sname = sxml->Name(); + if (sname == "src") { + foffset = (sxml->Attribute("offset") != nullptr) ? + sxml->StrAttribute("offset") : vec2(0,0); + fdraw = (sxml->Attribute("drawOffset") != nullptr) ? + sxml->StrAttribute("drawOffset") : vec2(0,0); + + if (sxml->Attribute("size") != nullptr) { + fsize = sxml->StrAttribute("size"); + sd = SpriteData(sxml->GetText(), foffset, fsize); + } else { + sd = SpriteData(sxml->GetText(), foffset); + } + if (sxml->QueryUnsignedAttribute("limb", &limb) == XML_NO_ERROR) + sd.limb = limb; + tmpf.push_back(std::make_pair(sd, fdraw)); + } + sxml = sxml->NextSiblingElement(); + } + // we don't want segfault + if (tmpf.size()) + tmp.push_back(tmpf); + } + // if it's not a frame we don't care + + // parse next frame + framexml = framexml->NextSiblingElement(); + } + + return tmp; +} diff --git a/src/engine.cpp b/src/engine.cpp index 07b453c..b596c6e 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -68,6 +68,7 @@ void Engine::update(entityx::TimeDelta dt) systems.update<WeatherSystem>(dt); systems.update<ParticleSystem>(dt); systems.update<AttackSystem>(dt); + systems.update<RenderSystem>(dt); //systems.update<UISystem>(dt); } diff --git a/src/systems/dialog.cpp b/src/systems/dialog.cpp new file mode 100644 index 0000000..0be0acb --- /dev/null +++ b/src/systems/dialog.cpp @@ -0,0 +1,161 @@ +#include <systems/dialog.hpp> + +#include <components/position.hpp> +#include <components/solid.hpp> +#include <components/dialog.hpp> +#include <components/flash.hpp> +#include <components/name.hpp> +#include <components/direction.hpp> + +#include <brice.hpp> +#include <engine.hpp> +#include <fileio.hpp> +#include <quest.hpp> +#include <thread.hpp> +#include <ui.hpp> +#include <world.hpp> + +#include <string> +#include <vector> + +static std::vector<std::string> randomDialog (readFileA("assets/dialog_en-us")); + +void DialogSystem::configure(entityx::EventManager &ev) +{ + ev.subscribe<MouseClickEvent>(*this); +} + +void DialogSystem::receive(const MouseClickEvent &mce) +{ + game::entities.each<Position, Solid, Dialog, Name>( + [&](entityx::Entity e, Position &pos, Solid &dim, Dialog &d, Name &name) { + static std::atomic_bool dialogRun; + (void)e; + (void)d; + + if (((mce.position.x > pos.x) & (mce.position.x < pos.x + dim.width)) && + ((mce.position.y > pos.y) & (mce.position.y < pos.y + dim.height))) { + + if (e.has_component<Flash>()) + e.remove<Flash>(); + e.assign<Flash>(Color(0, 255, 255)); + + if (!dialogRun.load()) { + // copy entity, windows destroys the original after thread detach + std::thread([e, &pos, &dim, &d, &name] { + std::string questAssignedText; + int newIndex; + + auto exml = WorldSystem::getXML()->FirstChildElement("Dialog"); + dialogRun.store(true); + + if (e.has_component<Direction>()) + d.talking = true; + + if (d.index == 9999) { + UISystem::dialogBox(name.name, /*"", false,*/ randomDialog[d.rindex % randomDialog.size()]); + UISystem::waitForDialog(); + } else if (exml != nullptr) { + while (exml->StrAttribute("name") != name.name) + exml = exml->NextSiblingElement(); + + exml = exml->FirstChildElement("text"); + while (exml->IntAttribute("id") != d.index) + exml = exml->NextSiblingElement(); + + auto oxml = exml->FirstChildElement("set"); + if (oxml != nullptr) { + do game::setValue(oxml->StrAttribute("id"), oxml->StrAttribute("value")); + while ((oxml = oxml->NextSiblingElement())); + game::briceUpdate(); + } + + auto ixml = exml->FirstChildElement("give"); + if (ixml != nullptr) { + do { + InventorySystem::add(ixml->StrAttribute("name"), ixml->IntAttribute("count")); + ixml = ixml->NextSiblingElement(); + } while (ixml != nullptr); + } + + auto qxml = exml->FirstChildElement("quest"); + if (qxml != nullptr) { + const char *qname; + + do { + // assign quest + qname = qxml->Attribute("assign"); + if (qname != nullptr) { + questAssignedText = qname; + auto req = qxml->GetText(); + QuestSystem::assign(qname, qxml->StrAttribute("desc"), req ? req : ""); + } + + // check / finish quest + else { + qname = qxml->Attribute("check"); + if (qname != nullptr) { + if (qname != nullptr && QuestSystem::finish(qname) == 0) { + d.index = 9999; + } else { + UISystem::dialogBox(name.name, /*"", false,*/ "Finish my quest u nug"); + UISystem::waitForDialog(); + return; + } + // oldidx = d.index; + // d.index = qxml->UnsignedAttribute("fail"); + // goto COMMONAIFUNC; + } + } + } while((qxml = qxml->NextSiblingElement())); + } + + auto xxml = exml->FirstChildElement("option"); + std::string options; + std::vector<int> optionNexts; + if (xxml != nullptr) { + do { + UISystem::dialogAddOption(xxml->StrAttribute("name")); + + options += '\"' + xxml->StrAttribute("name"); + optionNexts.emplace_back(xxml->IntAttribute("value")); + xxml = xxml->NextSiblingElement(); + } while (xxml != nullptr); + } + + auto cxml = exml->FirstChildElement("content"); + const char *content; + if (cxml == nullptr) { + content = randomDialog[d.rindex % randomDialog.size()].c_str(); + } else { + content = cxml->GetText() - 1; + while (*++content && isspace(*content)); + } + + UISystem::dialogBox(name.name, /*options, false,*/ content); + UISystem::waitForDialog(); + UISystem::waitForDialog(); + + if (!questAssignedText.empty()) + UISystem::dialogImportant("Quest assigned:\n\"" + questAssignedText + "\""); + //passiveImportantText(5000, ("Quest assigned:\n\"" + questAssignedText + "\"").c_str()); + + if (exml->QueryIntAttribute("nextid", &newIndex) == XML_NO_ERROR) + d.index = newIndex; + } + + d.talking = false; + dialogRun.store(false); + }).detach(); + } + } + }); +} + +void DialogSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) +{ + (void)en; + (void)ev; + (void)dt; +} + diff --git a/src/systems/movement.cpp b/src/systems/movement.cpp new file mode 100644 index 0000000..00baa40 --- /dev/null +++ b/src/systems/movement.cpp @@ -0,0 +1,98 @@ +#include <systems/movement.hpp> + +#include <components/position.hpp> +#include <components/direction.hpp> +#include <components/solid.hpp> +#include <components/animate.hpp> +#include <components/sprite.hpp> +#include <components/aggro.hpp> +#include <components/dialog.hpp> + +#include <thread> + +#include <attack.hpp> +#include <events.hpp> +#include <player.hpp> +#include <ui.hpp> + +void MovementSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) +{ + //bool fight = false; + entityx::Entity toFight; + + (void)ev; + en.each<Position, Direction>([&](entityx::Entity entity, Position &position, Direction &direction) { + position.x += HLINES(direction.x) * dt; + position.y += HLINES(direction.y) * dt; + + if (entity.has_component<Animate>() && entity.has_component<Sprite>()) { + auto animate = entity.component<Animate>(); + auto sprite = entity.component<Sprite>(); + + if (direction.x) + animate->updateAnimation(1, sprite->sprite, dt); + else + animate->firstFrame(1, sprite->sprite); + } + if (entity.has_component<Dialog>() && entity.component<Dialog>()->talking) { + direction.x = 0; + } else { + if (entity.has_component<Sprite>()) { + auto& fl = entity.component<Sprite>()->faceLeft; + if (direction.x != 0) + fl = (direction.x < 0); + } + + auto ppos = PlayerSystem::getPosition(); + if (ppos.x > position.x && ppos.x < position.x + entity.component<Solid>()->width) { + if (entity.has_component<Aggro>()) { + auto dim = entity.component<Solid>(); + ev.emit<AttackEvent>(vec2(position.x + dim->width, position.y + dim->height), + AttackType::ShortSlash, false); + /*auto& h = entity.component<Health>()->health; + if (h > 0) { + fight = true; + toFight = entity; + h = 0; + }*/ + } else if (entity.has_component<Trigger>()) { + static bool triggering = false; + if (!triggering) { + triggering = true; + std::thread([&](entityx::Entity e) { + UISystem::fadeToggle(); + UISystem::waitForCover(); + UISystem::dialogImportant(e.component<Trigger>()->text); + UISystem::waitForDialog(); + UISystem::fadeToggle(); + e.destroy(); + triggering = false; + }, entity).detach(); + } + return; + } + } + + // make the entity wander + // TODO initialX and range? + if (entity.has_component<Wander>()) { + auto& countdown = entity.component<Wander>()->countdown; + + if (countdown > 0) { + countdown--; + } else { + countdown = 5000 + randGet() % 10 * 100; + direction.x = (randGet() % 3 - 1) * 0.004f; + } + } + } + }); + +// if (fight) { +// UISystem::fadeToggleFast(); +// UISystem::waitForCover(); + //game::engine.getSystem<WorldSystem>()->fight(toFight); +// UISystem::fadeToggleFast(); +// } +} + diff --git a/src/systems/physics.cpp b/src/systems/physics.cpp new file mode 100644 index 0000000..4cee110 --- /dev/null +++ b/src/systems/physics.cpp @@ -0,0 +1,15 @@ +#include <systems/physics.hpp> + +#include <components/direction.hpp> +#include <components/physics.hpp> + +void PhysicsSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) +{ + (void)ev; + en.each<Direction, Physics>([dt](entityx::Entity entity, Direction &direction, Physics &physics) { + (void)entity; + // TODO GET GRAVITY FROM WORLD + direction.y += physics.g * dt; + }); +} + diff --git a/src/systems/render.cpp b/src/systems/render.cpp new file mode 100644 index 0000000..ce79522 --- /dev/null +++ b/src/systems/render.cpp @@ -0,0 +1,146 @@ +#include <systems/render.hpp> + +#include <components/visible.hpp> +#include <components/sprite.hpp> +#include <components/position.hpp> +#include <components/solid.hpp> +#include <components/flash.hpp> + +#include <thread> +#include <chrono> +using namespace std::literals::chrono_literals; + +#include <glm.hpp> +#include <render.hpp> +#include <engine.hpp> +#include <font.hpp> +#include <ui.hpp> + +std::string RenderSystem::loadTexString; +Texture RenderSystem::loadTexResult; + +Texture RenderSystem::loadTexture(const std::string& file) +{ + loadTexString = file; + loadTexResult = Texture(); + while (loadTexResult.isEmpty()) + std::this_thread::sleep_for(1ms); + auto t = loadTexResult; + loadTexResult = Texture(); + return t; +} + +void RenderSystem::render(void) +{ + if (!loadTexString.empty()) { + loadTexResult = Texture(loadTexString, false); + loadTexString.clear(); + } + + if (!loadTexResult.isEmpty()) + return; + + Render::worldShader.use(); + Render::worldShader.enable(); + + game::entities.each<Visible, Sprite, Position>([](entityx::Entity entity, Visible &visible, Sprite &sprite, Position &pos) { + // Verticies and shit + float its = 0; + + float sz; + if (entity.has_component<Solid>()) + sz = entity.component<Solid>()->width; + else + sz = sprite.getSpriteSize().x; + + if (sprite.faceLeft) { + glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(-1.0f,1.0f,1.0f)); + glm::mat4 translate = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f - sz - pos.x * 2.0f, 0.0f, 0.0f)); + + glm::mat4 mov = scale * translate; + glUniformMatrix4fv(Render::worldShader.uniform[WU_transform], 1, GL_FALSE, glm::value_ptr(mov)); + } + + for (auto &S : sprite.sprite) { + auto sp = S.first; + auto size = sp.size * game::HLINE; + vec2 drawOffset (HLINES(S.second.x), HLINES(S.second.y)); + vec2 loc (pos.x + drawOffset.x, pos.y + drawOffset.y); + + GLfloat verts[] = { + loc.x, loc.y, visible.z + its, sp.offset_tex.x, sp.offset_tex.y, + loc.x + size.x, loc.y, visible.z + its, sp.offset_tex.x + sp.size_tex.x, sp.offset_tex.y, + loc.x + size.x, loc.y + size.y, visible.z + its, sp.offset_tex.x + sp.size_tex.x, sp.offset_tex.y + sp.size_tex.y, + loc.x, loc.y, visible.z + its, sp.offset_tex.x, sp.offset_tex.y, + loc.x + size.x, loc.y + size.y, visible.z + its, sp.offset_tex.x + sp.size_tex.x, sp.offset_tex.y + sp.size_tex.y, + loc.x, loc.y + size.y, visible.z + its, sp.offset_tex.x, sp.offset_tex.y + sp.size_tex.y + }; + + sp.tex.use(); + + glUniform1i(Render::worldShader.uniform[WU_texture], 0); + + glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), verts); + glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), verts + 3); + glDrawArrays(GL_TRIANGLES, 0, 6); + + if (entity.has_component<Flash>()) { + auto& f = *entity.component<Flash>(); + if (f.ms > 0) { + verts[2] = verts[7] = verts[12] = verts[17] = verts[22] = verts[27] = visible.z + its - 0.001f; + float alpha = static_cast<float>(f.ms) / static_cast<float>(f.totalMs); + glUniform4f(Render::worldShader.uniform[WU_tex_color], f.color.red, f.color.green, f.color.blue, alpha); + glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), verts); + glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), verts + 3); + glDrawArrays(GL_TRIANGLES, 0, 6); + glUniform4f(Render::worldShader.uniform[WU_tex_color], 1.0, 1.0, 1.0, 1.0); + } + } + + its-=.01; + } + glUniformMatrix4fv(Render::worldShader.uniform[WU_transform], 1, GL_FALSE, glm::value_ptr(glm::mat4(1.0f))); + + if (entity.has_component<Health>()) { + float width = entity.component<Solid>()->width; + auto& health = *entity.component<Health>(); + width *= health.health / static_cast<float>(health.maxHealth); + + GLfloat health_coord[] = { + pos.x, pos.y, -9, 0, 0, + pos.x + width, pos.y, -9, 0, 0, + pos.x + width, pos.y - 5, -9, 0, 0, + pos.x + width, pos.y - 5, -9, 0, 0, + pos.x, pos.y - 5, -9, 0, 0, + pos.x, pos.y, -9, 0, 0, + }; + + Colors::red.use(); + glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), health_coord); + glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), health_coord + 3); + glDrawArrays(GL_TRIANGLES, 0, 6); + } + }); + + Render::worldShader.disable(); + Render::worldShader.unuse(); + + game::entities.each<Visible, Position, Solid, Name>([](entityx::Entity e, Visible &v, Position &pos, Solid& dim, Name &name) { + (void)e; + (void)v; + FontSystem::setFontZ(-5.0f); + UISystem::putStringCentered(vec2(pos.x + dim.width / 2, pos.y - FontSystem::getSize() - HLINES(0.5)), name.name); + }); +} + +void RenderSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) +{ + (void)ev; + (void)dt; + + en.each<Flash>([](entityx::Entity e, Flash& flash) { + if (--flash.ms <= 0) // TODO delta time? + e.remove<Flash>(); + }); +} + |