diff --git a/2d-game.vcxproj b/2d-game.vcxproj index 41591cdaed266d052a8b38ed378de06231cae657..d7f0cac57f3be10af1dc3b7217459446d34c803d 100644 --- a/2d-game.vcxproj +++ b/2d-game.vcxproj @@ -151,12 +151,15 @@ <ClCompile Include="LazySprite.cpp" /> <ClCompile Include="LivingEntity.cpp" /> <ClCompile Include="mainGame.cpp" /> + <ClCompile Include="MeleeWeapon.cpp" /> <ClCompile Include="PlayerEntity.cpp" /> <ClCompile Include="ResourceManager.cpp" /> <ClCompile Include="SimpleSprite.cpp" /> <ClCompile Include="TestGenerator.cpp" /> + <ClCompile Include="TypicalMeleeWeapon.cpp" /> <ClCompile Include="WallEntity.cpp" /> <ClCompile Include="WallTexture.cpp" /> + <ClCompile Include="Weapon.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="CharacterTexture.h" /> @@ -165,6 +168,7 @@ <ClInclude Include="GameException.h" /> <ClInclude Include="LivingEntity.h" /> <ClInclude Include="mainGame.h" /> + <ClInclude Include="MeleeWeapon.h" /> <ClInclude Include="olc.h" /> <ClInclude Include="ITexture.h" /> <ClInclude Include="Entity.h" /> @@ -177,8 +181,11 @@ <ClInclude Include="ResourceManager.h" /> <ClInclude Include="SimpleSprite.h" /> <ClInclude Include="TestGenerator.h" /> + <ClInclude Include="TypicalMeleeWeapon.h" /> <ClInclude Include="WallEntity.h" /> <ClInclude Include="WallTexture.h" /> + <ClInclude Include="Weapon.h" /> + <ClInclude Include="WeaponTextures.h" /> </ItemGroup> <ItemGroup> <None Include="ClassDiagram.cd" /> diff --git a/2d-game.vcxproj.filters b/2d-game.vcxproj.filters index cbfe8f806026b8d69ae8842f53cd123c158ccd66..f679b0b73e145faa088657f110ecaddc00d0c24c 100644 --- a/2d-game.vcxproj.filters +++ b/2d-game.vcxproj.filters @@ -74,6 +74,15 @@ <ClCompile Include="PlayerEntity.cpp"> <Filter>Source Files\gameObj\entities</Filter> </ClCompile> + <ClCompile Include="Weapon.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="MeleeWeapon.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="TypicalMeleeWeapon.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="interfaces.h"> @@ -136,6 +145,18 @@ <ClInclude Include="PlayerEntity.h"> <Filter>Header Files\gameObj\entities</Filter> </ClInclude> + <ClInclude Include="Weapon.h"> + <Filter>Header Files\gameObj\entities</Filter> + </ClInclude> + <ClInclude Include="MeleeWeapon.h"> + <Filter>Header Files\gameObj\entities</Filter> + </ClInclude> + <ClInclude Include="WeaponTextures.h"> + <Filter>Header Files\gameObj</Filter> + </ClInclude> + <ClInclude Include="TypicalMeleeWeapon.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="README.md"> diff --git a/Entity.cpp b/Entity.cpp index 8f54a5ca11fd35b386d578a2e32b8f154d023861..e3c5da5473212756690521b84823cd89991a3231 100644 --- a/Entity.cpp +++ b/Entity.cpp @@ -72,6 +72,11 @@ namespace entities { return this->is_alive; } + bool Entity::canBeRemoved() const + { + return this->isAlive(); //most times + } + } TransformedView& operator+=(TransformedView& scene, entities::Entity& entity) { diff --git a/Entity.h b/Entity.h index d35ed8f763ee62ec4734129c2dd10ae2ce015abd..fb76b989cf64e02ae206e39ccc4ab960f5ba4ad6 100644 --- a/Entity.h +++ b/Entity.h @@ -31,6 +31,7 @@ namespace entities { [[nodiscard]] virtual olc::vf2d getPos() const; [[nodiscard]] virtual olc::vf2d getSize() const; [[nodiscard]] virtual bool isAlive() const; + [[nodiscard]] virtual bool canBeRemoved() const; virtual void tick(GameClient& client, float deltaT, std::shared_ptr<Entity>& shared_this){} diff --git a/MeleeWeapon.cpp b/MeleeWeapon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a5dac504b005fafb4014cce840e0592f67058a17 --- /dev/null +++ b/MeleeWeapon.cpp @@ -0,0 +1,35 @@ +#include "MeleeWeapon.h" +#include "mainGame.h" + +namespace weapons { + int MeleeWeapon::getDamage() const + { + return this->baseDamage; + } + bool MeleeWeapon::damageEntity(std::shared_ptr<LivingEntity> user, std::shared_ptr<Entity>& victim) + { + return victim->damage(this->getDamage(), *victim); + } + bool MeleeWeapon::damageIf(std::shared_ptr<LivingEntity>& user, bool(*predicate)(std::shared_ptr<Entity> self, std::shared_ptr<Entity> other)) + { + bool bl = false; + for(auto& entity : GameClient::getInstance().getEntities()){ + if(entity != user && predicate(user, entity)){ + bl = damageEntity(user, entity) || bl; + } + } + return bl; + } + + bool MeleeWeapon::use(std::shared_ptr<LivingEntity> user) + { + if (this->cooldown != 0) return false; + this->cooldown = this->cooldownTime; + + } + bool MeleeWeapon::predicateDistance::operator()(std::shared_ptr<Entity> entity, std::shared_ptr<Entity> other) const + { + float d = (entity->getPos() - other->getPos()).mag(); + return d > minDistance && d <= maxDistance; + } +} \ No newline at end of file diff --git a/MeleeWeapon.h b/MeleeWeapon.h new file mode 100644 index 0000000000000000000000000000000000000000..4e05fe2835f4e43d95cad51ea23989d1321a80d7 --- /dev/null +++ b/MeleeWeapon.h @@ -0,0 +1,31 @@ +#pragma once +#include "Weapon.h" +#include <functional> + +namespace weapons { + class MeleeWeapon : + public Weapon + { + protected: + virtual int getDamage() const; + virtual bool damageEntity(std::shared_ptr<LivingEntity> user, std::shared_ptr<Entity>& victim); + virtual bool damageIf(std::shared_ptr<LivingEntity>& user, bool(*predicate)(std::shared_ptr<Entity> self, std::shared_ptr<Entity> other)); + //virtual bool(*getPredicator())(std::shared_ptr<Entity>, std::shared_ptr<Entity>) = 0; + virtual std::function<bool(std::shared_ptr<Entity>, std::shared_ptr<Entity>)> getPredicator() = 0; + + /** + * Functor to predicate entity distance. + * You can also use lambda, if you want + */ + class predicateDistance + { + public: + float minDistance = 0; + float maxDistance = 5; + bool operator()(std::shared_ptr<Entity> entity, std::shared_ptr<Entity> other) const; + }; + + public: + bool use(std::shared_ptr<LivingEntity> user) override; + }; +} diff --git a/SimpleSprite.h b/SimpleSprite.h index ff6a8163fb0d1b44b8a623bd837936c0ed274db5..4d50d4e5ce949286ce09c4a2cd7192cba35e21de 100644 --- a/SimpleSprite.h +++ b/SimpleSprite.h @@ -13,7 +13,7 @@ namespace render { const olc::vf2d uv, size; public: - SimpleSprite(const std::string& name, const olc::vi2d& pos, const olc::vf2d& size); + SimpleSprite(const std::string& name, const olc::vi2d& pos, const olc::vf2d& size = {16, 16}); void render(olc::TransformedView& scene, entities::Entity& entity) override; }; diff --git a/TypicalMeleeWeapon.cpp b/TypicalMeleeWeapon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a17da5247968f26d4ef8b2c69309ad8feeead481 --- /dev/null +++ b/TypicalMeleeWeapon.cpp @@ -0,0 +1,8 @@ +#include "TypicalMeleeWeapon.h" + +std::function<bool(std::shared_ptr<Entity>, std::shared_ptr<Entity>)> weapons::TypicalMeleeWeapon::getPredicator() +{ + predicateDistance p; + p.maxDistance = this->maxRange; + return p; +} diff --git a/TypicalMeleeWeapon.h b/TypicalMeleeWeapon.h new file mode 100644 index 0000000000000000000000000000000000000000..58fcbca47dedd5fcc0f55beaa682d620c1bf7d4c --- /dev/null +++ b/TypicalMeleeWeapon.h @@ -0,0 +1,14 @@ +#pragma once +#include "MeleeWeapon.h" +namespace weapons { + class TypicalMeleeWeapon : + public MeleeWeapon + { + public: + static TypicalMeleeWeapon sword; + + protected: + float maxRange; + std::function<bool(std::shared_ptr<Entity>, std::shared_ptr<Entity>)> getPredicator() override; + }; +} diff --git a/Weapon.cpp b/Weapon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6bd82de0d2d01334e858724ff1d35862d6992b7c --- /dev/null +++ b/Weapon.cpp @@ -0,0 +1,25 @@ +#include "Weapon.h" + +namespace weapons +{ + render::ITexture& Weapon::getTexture() + { + return this->texture; + } + + Weapon::Weapon(render::ITexture& texture, float cooldownTime, int damage, olc::vf2d pos) + : Entity(pos), texture(texture), cooldown(0), cooldownTime(cooldownTime), baseDamage(damage) {} + + bool Weapon::update(float dTick) + { + this->cooldown = std::max(this->cooldown - dTick, 0.f); + + return this->cooldown == 0.f; + } + + float Weapon::getCooldownBar() + { + return this->cooldown / this->cooldownTime; + } + +} \ No newline at end of file diff --git a/Weapon.h b/Weapon.h new file mode 100644 index 0000000000000000000000000000000000000000..2a6d03bb7b9b3292c3825c7a5fa80dd998be595d --- /dev/null +++ b/Weapon.h @@ -0,0 +1,43 @@ +#pragma once +#include "Entity.h" + +using namespace entities; //yes, I know, I'm using `using namespace` in a header + +namespace weapons { + /** + * You can throw it to the ground, this is why it's an entity. But it will be possible to use it. and shoot enemies. + * or projectiles. + */ + class Weapon : + public Entity + { + private: + render::ITexture& texture; + render::ITexture& getTexture() override; + protected: + float cooldown; + float cooldownTime; + int baseDamage; + public: + + Weapon(render::ITexture& texture, float cooldownTime, int damage = 10, olc::vf2d pos = { 0, 0 }); + + /** + * @return true, if can use + */ + virtual bool use(std::shared_ptr<LivingEntity> user) = 0; + + virtual bool update(float dTick); + + /** + * 0 - 1 cooldown, 1 is ready to use, more than one makes sense, + * like 2 charges + */ + virtual float getCooldownBar(); + + /** + * Secondary charge bar. for some purpose + */ + virtual float getSecondaryBar() { return 0; } + }; +} \ No newline at end of file diff --git a/WeaponTextures.cpp b/WeaponTextures.cpp new file mode 100644 index 0000000000000000000000000000000000000000..97aebaeff2faa986b3607b2eef278f183e6c74a7 --- /dev/null +++ b/WeaponTextures.cpp @@ -0,0 +1 @@ +#include "WeaponTextures.h" \ No newline at end of file diff --git a/WeaponTextures.h b/WeaponTextures.h new file mode 100644 index 0000000000000000000000000000000000000000..cc62346442d93ac0b393aff96254f3df1e5e0735 --- /dev/null +++ b/WeaponTextures.h @@ -0,0 +1,18 @@ +#include "SimpleSprite.h" + +namespace weapons +{ + namespace textures + { + render::SimpleSprite sword1("Items/LongWep.png", { 0, 16 }); + render::SimpleSprite sword2("Items/LongWep.png", { 32, 16 }); + render::SimpleSprite spear("Items/LongWep.png", { 0, 32 }); + render::SimpleSprite scythe("Items/LongWep.png", { 16 * 3, 16 * 4 }); + render::SimpleSprite shovel("Items/LongWep.png", { 16 * 4, 16 * 4 }); //spoon + render::SimpleSprite pickaxe("Items/ShortWep.png", { 16 * 2, 16 * 3 }); + render::SimpleSprite bow("Items/Ammo.png", { 0, 16 }); + render::SimpleSprite crystalBow("Items/Ammo.png", { 48, 16 }); + render::SimpleSprite rifle("Items/Ammo.png", { 16, 64 }); + render::SimpleSprite photoMachine("Items/Light.png", { 16 * 6, 0 });//flash + } +} diff --git a/mainGame.cpp b/mainGame.cpp index 5c3678d42a25e594c835eea35250db503bf02ee3..87c9dcc4d48a0c04e1d5486710aada630cc2a061 100644 --- a/mainGame.cpp +++ b/mainGame.cpp @@ -57,7 +57,6 @@ bool GameClient::OnUserCreate() bool GameClient::OnUserUpdate(float fElapsedTime) { - fElapsedTime = std::min(maxTimeDelta, fElapsedTime); //return false if it want to exit. @@ -75,7 +74,7 @@ bool GameClient::OnUserUpdate(float fElapsedTime) //lambda remove condition. because why not? entities.removeIf([](const shared_ptr<Entity>& entity)->bool { - return !entity->isAlive(); + return !entity->canBeRemoved(); }); this->updateWorldOffset(fElapsedTime);