a9f639893301db31ac547eceaa486f2238b158df — Leinnan 7 months ago 1bc64f5
Switch between isometric and third person camera
M src/components/CameraTarget.hpp => src/components/CameraTarget.hpp +5 -2
@@ 4,13 4,16 @@
 
 namespace Components {
 struct CameraTarget final {
-    Vector3 offset;
+    Vector3 orthographicOffset;
+    Vector3 perspectiveOffset;
+    float targetYOffset = 0.0f;
     float fov = 20.0f;
     float multiplier = 1.0f;
     float minMultiplier = 0.7f;
     float maxMultiplier = 3.0f;
+    bool isPerspective = false;
 };
 } // namespace Components
   // Components
 
-#endif>
\ No newline at end of file
+#endif

M src/components/Collisions.hpp => src/components/Collisions.hpp +1 -1
@@ 10,7 10,7 @@ struct Collision final {
     Vector3 size;
 
     Collision(Vector3 offset, Vector3 size) : offset(offset), size(size) {}
-    Collision(){}
+    Collision() {}
 };
 
 struct Collisions final {

M src/components/Destroyable.hpp => src/components/Destroyable.hpp +3 -3
@@ 9,9 9,9 @@ struct Destroyable final {
     std::string destroyedModel;
     std::string destroyedModelDiffuse;
 
-    Destroyable(){}
-    Destroyable(int life, std::string destroyedModel, std::string diffuse) :
-    destroyedModel( destroyedModel), destroyedModelDiffuse(diffuse), maxLife(life),currentLife(life){}
+    Destroyable() {}
+    Destroyable(int life, std::string destroyedModel, std::string diffuse)
+        : destroyedModel(destroyedModel), destroyedModelDiffuse(diffuse), maxLife(life), currentLife(life) {}
 };
 
 } // namespace Components

M src/components/Fighter.hpp => src/components/Fighter.hpp +2 -6
@@ 10,8 10,7 @@ struct Fighter final {
     float currentAttackDuration = 0.0f;
     bool isAttacking = false;
 
-    Activity getCurrentActivity() const
-    {
+    Activity getCurrentActivity() const {
         if(!isAttacking)
             return Activity::Idle;
 


@@ 23,10 22,7 @@ struct Fighter final {
             return Activity::AttackAnticipation;
     }
 
-    float getTotalDuration() const
-    {
-        return anticipationDuration + contactDuration + recoveryDuration;
-    }
+    float getTotalDuration() const { return anticipationDuration + contactDuration + recoveryDuration; }
 };
 } // namespace Components
   // Components

M src/factories/UnitFactory.hpp => src/factories/UnitFactory.hpp +31 -32
@@ 1,101 1,100 @@
 #ifndef UNIT_FACTORY_HPP
 #define UNIT_FACTORY_HPP
 #include "components/Actor.hpp"
-#include "components/Transform.hpp"
 #include "components/CameraTarget.hpp"
-#include "components/MeshRenderer.hpp"
 #include "components/Fighter.hpp"
+#include "components/MeshRenderer.hpp"
 #include "components/Patrol.hpp"
 #include "components/PlayerInput.hpp"
-#include "components/WorldScreenText.hpp"
+#include "components/Transform.hpp"
 #include "components/Velocity.hpp"
-#include "presets/Unit.hpp"
+#include "components/WorldScreenText.hpp"
 #include "controllers/Controller.hpp"
+#include "presets/Unit.hpp"
 
 #include <entt/entt.hpp>
-#include <json.hpp>
-#include <memory>
 #include <fstream>
 #include <iostream>
+#include <json.hpp>
+#include <memory>
 #include <sstream>
 #include <string>
 
 namespace Factories {
-struct UnitLoader final: entt::resource_loader<UnitLoader, Presets::Unit> {
-    std::shared_ptr<Presets::Unit> load(nlohmann::json j) const
-    {
+struct UnitLoader final : entt::resource_loader<UnitLoader, Presets::Unit> {
+    std::shared_ptr<Presets::Unit> load(nlohmann::json j) const {
         std::shared_ptr<Presets::Unit> unit = std::make_shared<Presets::Unit>();
         unit->scale = j.at("scale").get<float>();
         unit->speed = j.at("speed").get<float>();
-        unit->name= j.at("name").get<std::string>();
-        unit->modelPath= j.at("modelPath").get<std::string>();
-        unit->diffusePath= j.at("diffusePath").get<std::string>();
+        unit->name = j.at("name").get<std::string>();
+        unit->modelPath = j.at("modelPath").get<std::string>();
+        unit->diffusePath = j.at("diffusePath").get<std::string>();
         unit->isPlayer = (j.at("isPlayer").get<int>() == 1);
 
         return unit;
     }
 };
 
-class UnitFactory final: public Controllers::Controller<UnitFactory> {
+class UnitFactory final : public Controllers::Controller<UnitFactory> {
   public:
-    void loadFromFile(std::string path)
-    {
+    void loadFromFile(std::string path) {
         nlohmann::json jsonReader;
         std::ifstream file(path.c_str());
         file >> jsonReader;
 
-        for(nlohmann::json &object : jsonReader)
-        {
+        for(nlohmann::json &object : jsonReader) {
             std::cout << object << '\n';
             const auto hashedPath = entt::hashed_string(object.at("id").get<std::string>().c_str());
-            unitCache.load<UnitLoader>(hashedPath,object);
+            unitCache.load<UnitLoader>(hashedPath, object);
         }
         const auto size = unitCache.size();
         std::cout << "Size of unitCache: " << size << '\n';
     }
 
-    uint32_t spawnUnit(entt::registry<> &registry,entt::hashed_string id)
-    {
+    uint32_t spawnUnit(entt::registry<> &registry, entt::hashed_string id) {
         if(!unitCache.contains(id))
             return -1;
 
         auto entity = registry.create();
-        const auto& unitPreset = unitCache.handle(id);
+        const auto &unitPreset = unitCache.handle(id);
 
         Components::Transform transformComponent;
-        transformComponent.pos = {0,0,0};
+        transformComponent.pos = {0, 0, 0};
         transformComponent.angle = 0.0f;
-        registry.assign<Components::Transform>(entity,transformComponent);
-        registry.assign<Components::MeshRenderer>(entity,unitPreset->modelPath.c_str(),unitPreset->diffusePath.c_str(),unitPreset->scale);
+        registry.assign<Components::Transform>(entity, transformComponent);
+        registry.assign<Components::MeshRenderer>(entity, unitPreset->modelPath.c_str(),
+                                                  unitPreset->diffusePath.c_str(), unitPreset->scale);
 
         Components::Actor actorComponent;
         actorComponent.name = unitPreset->name;
         actorComponent.speed = unitPreset->speed;
-        registry.assign<Components::Actor>(entity,actorComponent);
+        registry.assign<Components::Actor>(entity, actorComponent);
 
         Components::WorldScreenText worldScreenTextComponent;
         worldScreenTextComponent.fontSize = 10.0f;
         worldScreenTextComponent.text = unitPreset->name;
-        worldScreenTextComponent.offset = {0.0f,4.0f,0.0f};
-        registry.assign<Components::WorldScreenText>(entity,worldScreenTextComponent);
+        worldScreenTextComponent.offset = {0.0f, 4.0f, 0.0f};
+        registry.assign<Components::WorldScreenText>(entity, worldScreenTextComponent);
         registry.assign<Components::Velocity>(entity);
 
-        if(unitPreset->isPlayer)
-        {
+        if(unitPreset->isPlayer) {
             registry.assign<Components::PlayerInput>(entity);
             registry.assign<Components::Fighter>(entity);
 
             Components::CameraTarget cameraTarget;
-            cameraTarget.offset = {8.0f,12.0f,8.0f};
-            registry.assign<Components::CameraTarget>(entity,cameraTarget);
+            cameraTarget.orthographicOffset = {8.0f, 12.0f, 8.0f};
+            cameraTarget.perspectiveOffset = {-7.0f, 6.0f, -7.0f};
+            cameraTarget.targetYOffset = 1.4f;
+            registry.assign<Components::CameraTarget>(entity, cameraTarget);
         }
         registry.assign<Components::Patrol>(entity);
 
         return entity;
     }
+
   private:
     entt::resource_cache<Presets::Unit> unitCache;
 };
-};
+}; // namespace Factories
 
 #endif

M src/main.cpp => src/main.cpp +14 -13
@@ 1,5 1,7 @@
 #include "raylib.h"
 
+#include "INIReader.hpp"
+#include "factories/UnitFactory.hpp"
 #include "systems/AiSystem.hpp"
 #include "systems/CollisionSystem.hpp"
 #include "systems/DamageSystem.hpp"


@@ 10,18 12,16 @@
 #include "systems/RenderSystem.hpp"
 #include "systems/SpawnSystem.hpp"
 #include "utils/JsonParser.hpp"
-#include <iostream>
-#include "INIReader.hpp"
 #include <entt/entt.hpp>
+#include <iostream>
 #include <string>
-#include "factories/UnitFactory.hpp"
 #if defined(PLATFORM_WEB)
 #include <emscripten/emscripten.h>
 #endif
 
 const int SCREEN_WIDTH = 600;
 const int SCREEN_HEIGHT = 480;
-const char* CONFIG_PATH = "data/mod.ini";
+const char *CONFIG_PATH = "data/mod.ini";
 
 void UpdateDrawFrame(void);
 


@@ 40,29 40,30 @@ Camera camera;
 int main(int argc, char **argv) {
     INIReader reader(argc == 2 ? argv[1] : CONFIG_PATH);
 
-    if (reader.ParseError() != 0) {
-        std::cout << "Can't load "<< (argc == 2 ? argv[1] : CONFIG_PATH) <<"\n";
+    if(reader.ParseError() != 0) {
+        std::cout << "Can't load " << (argc == 2 ? argv[1] : CONFIG_PATH) << "\n";
         return 1;
     }
     const auto windowName = reader.Get("game", "name", "Raylib");
-    const auto jsonFile = reader.Get("game","firstJson","data.json");
+    const auto jsonFile = reader.Get("game", "firstJson", "data.json");
 
     int flags = FLAG_WINDOW_RESIZABLE;
-    if(reader.GetBoolean("gfx","fullscreen",false))
+    if(reader.GetBoolean("gfx", "fullscreen", false))
         flags |= FLAG_FULLSCREEN_MODE;
-    if(reader.GetBoolean("gfx","showLogo",false))
+    if(reader.GetBoolean("gfx", "showLogo", false))
         flags |= FLAG_SHOW_LOGO;
-    if(reader.GetBoolean("gfx","msaa",false))
+    if(reader.GetBoolean("gfx", "msaa", false))
         flags |= FLAG_MSAA_4X_HINT;
 
     SetConfigFlags(flags);
-    InitWindow(reader.GetInteger("gfx","width",SCREEN_WIDTH), reader.GetInteger("gfx","height",SCREEN_HEIGHT), windowName.c_str());
+    InitWindow(reader.GetInteger("gfx", "width", SCREEN_WIDTH), reader.GetInteger("gfx", "height", SCREEN_HEIGHT),
+               windowName.c_str());
     renderSystem.Init(registry);
     collisionSystem.Init(registry);
     aiSystem.Init(registry);
     damageSystem.Init();
 
-    Factories::UnitFactory::getInstance().loadFromFile(reader.Get("game","units","units.json"));
+    Factories::UnitFactory::getInstance().loadFromFile(reader.Get("game", "units", "units.json"));
     Components::readFromFile(registry, jsonFile.c_str());
 
     camera = {0};


@@ 93,7 94,7 @@ int main(int argc, char **argv) {
 void UpdateDrawFrame(void) {
     spawnSystem.Update(registry);
     destroySystem.Update(registry);
-    damageSystem.Update(registry,GetFrameTime());
+    damageSystem.Update(registry, GetFrameTime());
     playerInputSystem.Update(registry, camera);
     missileSystem.Update(registry);
     aiSystem.Update(registry, GetFrameTime());

M src/presets/Unit.hpp => src/presets/Unit.hpp +2 -2
@@ 3,7 3,7 @@
 #include <string>
 
 namespace Presets {
-struct Unit final{
+struct Unit final {
     std::string type = "Unit";
 
     float speed;


@@ 13,6 13,6 @@ struct Unit final{
     std::string modelPath;
     std::string diffusePath;
 };
-}
+} // namespace Presets
 
 #endif

M src/systems/AiSystem.cpp => src/systems/AiSystem.cpp +2 -3
@@ 72,8 72,7 @@ void AiSystem::Update(entt::registry<> &registry, const float &delta) {
             }
         });
 
-        registry.view<Components::Actor>().each(
-                [&](const auto entity, const auto &actor) {
+    registry.view<Components::Actor>().each([&](const auto entity, const auto &actor) {
         if(registry.has<Components::WorldScreenText>(entity)) {
             auto &screenText = registry.get<Components::WorldScreenText>(entity);
             screenText.text = actor.name;


@@ 95,7 94,7 @@ void AiSystem::Update(entt::registry<> &registry, const float &delta) {
                 break;
             }
         }
-        });
+    });
 }
 
 void AiSystem::PreparePatrolEntity(entt::registry<> &registry, std::uint32_t entity) {

M src/systems/CollisionSystem.cpp => src/systems/CollisionSystem.cpp +3 -5
@@ 48,18 48,16 @@ void CollisionSystem::Update(entt::registry<> &registry) {
 void CollisionSystem::PrepareCollisions(entt::registry<> &registry, std::uint32_t entity) {
     if(registry.has<Components::Transform>(entity)) {
         auto &transform = registry.get<Components::Transform>(entity);
-        if(registry.has<Components::Collisions>(entity))
-        {
+        if(registry.has<Components::Collisions>(entity)) {
             auto &collider = registry.get<Components::Collisions>(entity);
 
             collider.boxes.clear();
             for(const auto &col : collider.collisions)
                 collider.boxes.push_back(BoundingBoxFromCollision(transform.pos, col));
         }
-        if(registry.has<Components::DamageBox>(entity))
-        {
+        if(registry.has<Components::DamageBox>(entity)) {
             auto &damageBox = registry.get<Components::DamageBox>(entity);
-            damageBox.box = BoundingBoxFromCollision(transform.pos,damageBox.collision);
+            damageBox.box = BoundingBoxFromCollision(transform.pos, damageBox.collision);
         }
     }
 }

M src/systems/DamageSystem.cpp => src/systems/DamageSystem.cpp +33 -46
@@ 13,45 13,36 @@
 
 namespace Systems {
 void DamageSystem::Update(entt::registry<> &registry, const float delta) {
-        registry.view<Components::Actor,Components::Fighter>().each(
-                [&](const auto entity, auto &actor, auto& fighter) {
-                if(fighter.isAttacking)
-                {
-                    if(fighter.currentAttackDuration > fighter.getTotalDuration())
-                    {
-                        fighter.isAttacking = false;
-                    }
-                    else
-                    {
-                        fighter.currentAttackDuration += delta;
-                    }
-                    const auto previousAction = actor.curAction;
-                    actor.curAction = fighter.getCurrentActivity();
+    registry.view<Components::Actor, Components::Fighter>().each([&](const auto entity, auto &actor, auto &fighter) {
+        if(fighter.isAttacking) {
+            if(fighter.currentAttackDuration > fighter.getTotalDuration()) {
+                fighter.isAttacking = false;
+            } else {
+                fighter.currentAttackDuration += delta;
+            }
+            const auto previousAction = actor.curAction;
+            actor.curAction = fighter.getCurrentActivity();
 
-                    if(previousAction != actor.curAction)
-                    {
-                        if(actor.curAction == Components::Activity::AttackRecovery && registry.has<Components::DamageBox>(entity))
-                        {
-                            registry.remove<Components::DamageBox>(entity);
-                        }
-                        else if(actor.curAction == Components::Activity::AttackContact)
-                        {
-                            Components::DamageBox damageBox;
-                            damageBox.collision.offset = (Vector3){0.0,0.0,0.0f};
-                            damageBox.collision.size = (Vector3){3.0,3.0,3.0f};
-                            damageBox.damage = 3;
+            if(previousAction != actor.curAction) {
+                if(actor.curAction == Components::Activity::AttackRecovery &&
+                   registry.has<Components::DamageBox>(entity)) {
+                    registry.remove<Components::DamageBox>(entity);
+                } else if(actor.curAction == Components::Activity::AttackContact) {
+                    Components::DamageBox damageBox;
+                    damageBox.collision.offset = (Vector3){0.0, 0.0, 0.0f};
+                    damageBox.collision.size = (Vector3){3.0, 3.0, 3.0f};
+                    damageBox.damage = 3;
 
-                            registry.assign_or_replace<Components::DamageBox>(entity,damageBox);
-                        }
-                    }
+                    registry.assign_or_replace<Components::DamageBox>(entity, damageBox);
                 }
-        });
-
-        auto damageBoxes = registry.view<Components::Transform, Components::DamageBox>();
+            }
+        }
+    });
 
-        registry.view<Components::Transform, Components::Destroyable, Components::Collisions>().each(
-        [&](const auto entity, const auto &transform, auto &destroyable, const auto& collider){
+    auto damageBoxes = registry.view<Components::Transform, Components::DamageBox>();
 
+    registry.view<Components::Transform, Components::Destroyable, Components::Collisions>().each(
+        [&](const auto entity, const auto &transform, auto &destroyable, const auto &collider) {
             const auto boxes = collider.boxes;
             bool isColliding = false;
             int damageTaken = 0;


@@ 62,17 53,14 @@ void DamageSystem::Update(entt::registry<> &registry, const float delta) {
 
                 auto &damage = registry.get<Components::DamageBox>(damageBox).box;
 
-                for(const auto& box : boxes)
-                {
-                    if(CheckCollisionBoxes(damage, box))
-                    {
+                for(const auto &box : boxes) {
+                    if(CheckCollisionBoxes(damage, box)) {
                         isColliding = true;
                         break;
                     }
                 }
 
-                if(isColliding)
-                {
+                if(isColliding) {
                     damageTaken += registry.get<Components::DamageBox>(damageBox).damage;
                     registry.remove<Components::DamageBox>(damageBox);
                 }


@@ 80,18 68,17 @@ void DamageSystem::Update(entt::registry<> &registry, const float delta) {
 
             destroyable.currentLife -= damageTaken;
             if(damageTaken > 0)
-                std::cout << "Damage points! Even " << damageTaken << " of them, there is only " << destroyable.currentLife << " left!\n";
-            if(destroyable.currentLife <= 0)
-            {
-                if(registry.has<Components::MeshRenderer>(entity))
-                {
+                std::cout << "Damage points! Even " << damageTaken << " of them, there is only "
+                          << destroyable.currentLife << " left!\n";
+            if(destroyable.currentLife <= 0) {
+                if(registry.has<Components::MeshRenderer>(entity)) {
                     auto renderer = registry.get<Components::MeshRenderer>(entity);
 
                     registry.remove<Components::MeshRenderer>(entity);
 
                     renderer.diffusePath = destroyable.destroyedModelDiffuse;
                     renderer.modelPath = destroyable.destroyedModel;
-                    registry.assign<Components::MeshRenderer>(entity,renderer);
+                    registry.assign<Components::MeshRenderer>(entity, renderer);
                 }
                 registry.remove<Components::Destroyable>(entity);
             }

M src/systems/PlayerInputSystem.cpp => src/systems/PlayerInputSystem.cpp +29 -21
@@ 25,33 25,41 @@ void PlayerInputSystem::Update(entt::registry<> &registry, const Camera &camera)
         }
     });
 
-    registry.view<Components::Patrol, Components::PlayerInput>().each([&](const auto entity, auto &patrol,
-                                                                          const auto &playerInput) {
-        const bool isFighter = registry.has<Components::Fighter>(entity);
-        const bool isAttacking = isFighter ? registry.get<Components::Fighter>(entity).isAttacking : false;
-        if(isLeftMouseBtnDown && !isAttacking) {
-            RayHitInfo groundHitInfo = GetCollisionRayGround(ray, 0.0f);
-
-            if(groundHitInfo.hit) {
-                if(patrol.points.size() != 1)
-                    patrol.points.resize(1);
-
-                patrol.points.at(0) = groundHitInfo.position;
+    registry.view<Components::Patrol, Components::PlayerInput>().each(
+        [&](const auto entity, auto &patrol, const auto &playerInput) {
+            const bool isFighter = registry.has<Components::Fighter>(entity);
+            const bool isAttacking = isFighter ? registry.get<Components::Fighter>(entity).isAttacking : false;
+            if(isLeftMouseBtnDown && !isAttacking) {
+                RayHitInfo groundHitInfo = GetCollisionRayGround(ray, 0.0f);
+
+                if(groundHitInfo.hit) {
+                    if(patrol.points.size() != 1)
+                        patrol.points.resize(1);
+
+                    patrol.points.at(0) = groundHitInfo.position;
+                }
             }
-        }
-    });
+        });
 
-    registry.view<Components::Fighter, Components::PlayerInput>().each([&](const auto entity, auto &fighter, const auto &playerInput) {
-        if(IsKeyDown(KEY_SPACE) && !fighter.isAttacking)
-        {
-            fighter.isAttacking = true;
-            fighter.currentAttackDuration = 0.0f;
-        }
-    });
+    registry.view<Components::Fighter, Components::PlayerInput>().each(
+        [&](const auto entity, auto &fighter, const auto &playerInput) {
+            if(IsKeyDown(KEY_SPACE) && !fighter.isAttacking) {
+                fighter.isAttacking = true;
+                fighter.currentAttackDuration = 0.0f;
+            }
+        });
+
+    if(IsKeyPressed(KEY_F))
+        switchCameraMode(registry);
 }
 
 Vector3 PlayerInputSystem::getHorizontalMovement(const float &length, const float &angle) {
     return {std::cos(PI * angle / 180.f) * length, 0.f, std::sin(PI * angle / 180.f) * length};
 }
+
+void PlayerInputSystem::switchCameraMode(entt::registry<> &registry) {
+    registry.view<Components::CameraTarget>().each(
+        [&](const auto, auto &target) { target.isPerspective = !target.isPerspective; });
+}
 } // namespace Systems
   // Systems

M src/systems/PlayerInputSystem.hpp => src/systems/PlayerInputSystem.hpp +3 -0
@@ 12,6 12,9 @@ class PlayerInputSystem {
     void Update(entt::registry<> &registry, const Camera &camera);
     void Shutdown(){};
     Vector3 getHorizontalMovement(const float &length, const float &angle);
+
+  private:
+    void switchCameraMode(entt::registry<> &registry);
 };
 } // namespace Systems
   // Systems

M src/systems/RenderSystem.cpp => src/systems/RenderSystem.cpp +27 -16
@@ 21,16 21,6 @@ void RenderSystem::Init(entt::registry<> &registry) {
 }
 
 void RenderSystem::Update(entt::registry<> &registry, Camera &camera) {
-    registry.view<Components::Transform, Components::CameraTarget>().each(
-        [&](const auto, const auto transform, const auto &target) {
-            camera.position.x = transform.pos.x + (target.offset.x * target.multiplier);
-            camera.position.y = transform.pos.y + (target.offset.y * target.multiplier);
-            camera.position.z = transform.pos.z + (target.offset.z * target.multiplier);
-            camera.fovy = target.fov * target.multiplier;
-            // getCameraPos(transform.pos, transform.angle, target.offset);
-            camera.target = transform.pos;
-        });
-
     BeginDrawing();
     ClearBackground({180, 180, 180, 255});
     BeginMode3D(camera);


@@ 55,9 45,7 @@ void RenderSystem::Update(entt::registry<> &registry, Camera &camera) {
                 DrawBoundingBox(box, RED);
         });
     registry.view<Components::DamageBox, Components::Transform>().each(
-        [&](const auto, const auto &damageBox, const auto &transform) {
-            DrawBoundingBox(damageBox.box, ORANGE);
-        });
+        [&](const auto, const auto &damageBox, const auto &transform) { DrawBoundingBox(damageBox.box, ORANGE); });
 
     EndMode3D();
     registry.view<Components::WorldScreenText, Components::Transform>().each(


@@ 90,9 78,11 @@ void RenderSystem::LoadEntityTexture(entt::registry<> &registry, std::uint32_t e
         Components::MeshRenderer &mesh = registry.get<Components::MeshRenderer>(entity);
 
         mesh.model = LoadModel(mesh.modelPath.c_str());
-        mesh.diffuse = LoadTexture(mesh.diffusePath.c_str());
-        if(mesh.model.materialCount > 0)
-            mesh.model.materials[0].maps[MAP_DIFFUSE].texture = mesh.diffuse;
+        if(!mesh.diffusePath.empty()) {
+            mesh.diffuse = LoadTexture(mesh.diffusePath.c_str());
+            if(mesh.model.materialCount > 0)
+                mesh.model.materials[0].maps[MAP_DIFFUSE].texture = mesh.diffuse;
+        }
     }
 }
 


@@ 108,5 98,26 @@ void RenderSystem::UnloadEntityTexture(entt::registry<> &registry, std::uint32_t
         UnloadTexture(mesh.diffuse);
     }
 }
+
+void RenderSystem::UpdateCamera(entt::registry<> &registry) {
+    registry.view<Components::Transform, Components::CameraTarget>().each(
+        [&](const auto, const auto transform, const auto &target) {
+            const Vector3 usedOffset = target.isPerspective ? target.perspectiveOffset : target.orthographicOffset;
+            const Vector3 calculatedOffset{usedOffset.x * target.multiplier, usedOffset.y * target.multiplier,
+                                           usedOffset.z * target.multiplier};
+            camera.target = transform.pos;
+            camera.type = target.isPerspective ? CAMERA_PERSPECTIVE : CAMERA_ORTHOGRAPHIC;
+            if(target.isPerspective) {
+                camera.position = getCameraPos(transform.pos, transform.angle, calculatedOffset);
+                camera.fovy = 80.0f;
+                camera.target.y += target.targetYOffset;
+            } else {
+                camera.position.x = transform.pos.x + (calculatedOffset.x);
+                camera.position.y = transform.pos.y + (calculatedOffset.y);
+                camera.position.z = transform.pos.z + (calculatedOffset.z);
+                camera.fovy = target.fov * target.multiplier;
+            }
+        });
+}
 } // namespace Systems
   // Systems

M src/systems/RenderSystem.hpp => src/systems/RenderSystem.hpp +2 -0
@@ 15,6 15,8 @@ class RenderSystem {
     void UnloadEntityTexture(entt::registry<> &registry, std::uint32_t entity);
 
   private:
+    void UpdateCamera(entt::registry<> &registry);
+
     Camera3D camera;
 };
 } // namespace Systems

M src/systems/SpawnSystem.cpp => src/systems/SpawnSystem.cpp +3 -2
@@ 9,8 9,9 @@ void SpawnSystem::Update(entt::registry<> &registry) {
         [&](const auto, auto &spawnPoint, const auto &transform) {
             if(spawnPoint.spawned)
                 return;
-            uint32_t spawnedEntity = Factories::UnitFactory::getInstance().spawnUnit(registry,entt::hashed_string(spawnPoint.idToSpawn.c_str()));
-            registry.assign_or_replace<Components::Transform>(spawnedEntity,transform);
+            uint32_t spawnedEntity = Factories::UnitFactory::getInstance().spawnUnit(
+                registry, entt::hashed_string(spawnPoint.idToSpawn.c_str()));
+            registry.assign_or_replace<Components::Transform>(spawnedEntity, transform);
             spawnPoint.spawned = true;
         });
 }

M src/utils/JsonParser.cpp => src/utils/JsonParser.cpp +59 -52
@@ 29,11 29,20 @@ void Components::from_json(const json &j, Components::Transform &t) {
 }
 
 void Components::to_json(json &j, const Components::CameraTarget &t) {
-    j = json{{"type", "CameraTarget"}, {"offsetX", t.offset.x}, {"offsetY", t.offset.y}, {"offsetZ", t.offset.z}};
+    j = json{{"type", "CameraTarget"},
+             {"orthographicOffsetX", t.orthographicOffset.x},
+             {"orthographicOffsetY", t.orthographicOffset.y},
+             {"orthographicOffsetZ", t.orthographicOffset.z},
+             {"perspectiveOffsetX", t.perspectiveOffset.x},
+             {"perspectiveOffsetY", t.perspectiveOffset.y},
+             {"perspectiveOffsetZ", t.perspectiveOffset.z}};
 }
 
 void Components::from_json(const json &j, Components::CameraTarget &t) {
-    t.offset = {j.at("offsetX").get<float>(), j.at("offsetY").get<float>(), j.at("offsetZ").get<float>()};
+    t.perspectiveOffset = {j.at("perspectiveOffsetX").get<float>(), j.at("perspectiveOffsetY").get<float>(),
+                           j.at("perspectiveOffsetZ").get<float>()};
+    t.orthographicOffset = {j.at("orthographicOffsetX").get<float>(), j.at("orthographicOffsetY").get<float>(),
+                            j.at("orthographicOffsetZ").get<float>()};
 }
 
 void Components::to_json(json &j, const Components::PlayerInput &t) { j = json{{"type", "PlayerInput"}}; }


@@ 50,9 59,9 @@ void Components::from_json(const json &j, Components::Fighter &t) {}
 
 void Components::to_json(json &j, const Components::Destroyable &t) {
     j = json{{"type", "Destroyable"},
-        {"destroyedModelDiffuse",t.destroyedModelDiffuse},
-        {"destroyedModel",t.destroyedModel}};
-    }
+             {"destroyedModelDiffuse", t.destroyedModelDiffuse},
+             {"destroyedModel", t.destroyedModel}};
+}
 
 void Components::from_json(const json &j, Components::Destroyable &t) {
     t.destroyedModel = j.at("destroyedModel").get<std::string>();


@@ 256,55 265,53 @@ void Components::readFromFile(entt::registry<> &registry, const char *filename) 
     file >> jsonReader;
 
     for(nlohmann::json &object : jsonReader)
-        createEntityFromJson(registry,object);
+        createEntityFromJson(registry, object);
 }
 
-    uint32_t Components::createEntityFromJson(entt::registry<> &registry, json &object)
-    {
-        if(!object.is_array())
-            return 0;
-
-        auto entity = registry.create();
-
-        for(const nlohmann::json &component : object) {
-            const std::string type = component.at("type").get<std::string>();
-
-            if(type.compare("MeshRenderer") == 0) {
-                registry.assign<Components::MeshRenderer>(entity, component.get<Components::MeshRenderer>());
-            } else if(type.compare("Transform") == 0) {
-                registry.assign<Components::Transform>(entity, component.get<Components::Transform>());
-            } else if(type.compare("CameraTarget") == 0) {
-                registry.assign<Components::CameraTarget>(entity, component.get<Components::CameraTarget>());
-            } else if(type.compare("PlayerInput") == 0) {
-                registry.assign<Components::PlayerInput>(entity, component.get<Components::PlayerInput>());
-            } else if(type.compare("Velocity") == 0) {
-                registry.assign<Components::Velocity>(entity, component.get<Components::Velocity>());
-            } else if(type.compare("Actor") == 0) {
-                registry.assign<Components::Actor>(entity, component.get<Components::Actor>());
-            } else if(type.compare("RotatingObject") == 0) {
-                registry.assign<Components::RotatingObject>(entity, component.get<Components::RotatingObject>());
-            } else if(type.compare("Missile") == 0) {
-                registry.assign<Components::Missile>(entity, component.get<Components::Missile>());
-            } else if(type.compare("DestroyAfterTime") == 0) {
-                registry.assign<Components::DestroyAfterTime>(entity, component.get<Components::DestroyAfterTime>());
-            } else if(type.compare("Patrol") == 0) {
-                registry.assign<Components::Patrol>(entity, component.get<Components::Patrol>());
-            } else if(type.compare("Collisions") == 0) {
-                registry.assign<Components::Collisions>(entity, component.get<Components::Collisions>());
-            } else if(type.compare("WorldScreenText") == 0) {
-                registry.assign<Components::WorldScreenText>(entity, component.get<Components::WorldScreenText>());
-            } else if(type.compare("Fighter") == 0) {
-                registry.assign<Components::Fighter>(entity, component.get<Components::Fighter>());
-            } else if(type.compare("Destroyable") == 0) {
-                registry.assign<Components::Destroyable>(entity, component.get<Components::Destroyable>());
-            } else if(type.compare("SpawnPoint") == 0) {
-                registry.assign<Components::SpawnPoint>(entity, component.get<Components::SpawnPoint>());
-            }
+uint32_t Components::createEntityFromJson(entt::registry<> &registry, json &object) {
+    if(!object.is_array())
+        return 0;
+
+    auto entity = registry.create();
+
+    for(const nlohmann::json &component : object) {
+        const std::string type = component.at("type").get<std::string>();
+
+        if(type.compare("MeshRenderer") == 0) {
+            registry.assign<Components::MeshRenderer>(entity, component.get<Components::MeshRenderer>());
+        } else if(type.compare("Transform") == 0) {
+            registry.assign<Components::Transform>(entity, component.get<Components::Transform>());
+        } else if(type.compare("CameraTarget") == 0) {
+            registry.assign<Components::CameraTarget>(entity, component.get<Components::CameraTarget>());
+        } else if(type.compare("PlayerInput") == 0) {
+            registry.assign<Components::PlayerInput>(entity, component.get<Components::PlayerInput>());
+        } else if(type.compare("Velocity") == 0) {
+            registry.assign<Components::Velocity>(entity, component.get<Components::Velocity>());
+        } else if(type.compare("Actor") == 0) {
+            registry.assign<Components::Actor>(entity, component.get<Components::Actor>());
+        } else if(type.compare("RotatingObject") == 0) {
+            registry.assign<Components::RotatingObject>(entity, component.get<Components::RotatingObject>());
+        } else if(type.compare("Missile") == 0) {
+            registry.assign<Components::Missile>(entity, component.get<Components::Missile>());
+        } else if(type.compare("DestroyAfterTime") == 0) {
+            registry.assign<Components::DestroyAfterTime>(entity, component.get<Components::DestroyAfterTime>());
+        } else if(type.compare("Patrol") == 0) {
+            registry.assign<Components::Patrol>(entity, component.get<Components::Patrol>());
+        } else if(type.compare("Collisions") == 0) {
+            registry.assign<Components::Collisions>(entity, component.get<Components::Collisions>());
+        } else if(type.compare("WorldScreenText") == 0) {
+            registry.assign<Components::WorldScreenText>(entity, component.get<Components::WorldScreenText>());
+        } else if(type.compare("Fighter") == 0) {
+            registry.assign<Components::Fighter>(entity, component.get<Components::Fighter>());
+        } else if(type.compare("Destroyable") == 0) {
+            registry.assign<Components::Destroyable>(entity, component.get<Components::Destroyable>());
+        } else if(type.compare("SpawnPoint") == 0) {
+            registry.assign<Components::SpawnPoint>(entity, component.get<Components::SpawnPoint>());
         }
-        return entity;
     }
+    return entity;
+}
 
-    uint32_t Components::createEntityFromJson(entt::registry<> &registry, const std::string &s)
-    {
-        return createEntityFromJson(registry,json::parse(s));
-    }
+uint32_t Components::createEntityFromJson(entt::registry<> &registry, const std::string &s) {
+    return createEntityFromJson(registry, json::parse(s));
+}

M src/utils/JsonParser.hpp => src/utils/JsonParser.hpp +1 -1
@@ 13,10 13,10 @@
 #include "components/Patrol.hpp"
 #include "components/PlayerInput.hpp"
 #include "components/RotatingObject.hpp"
+#include "components/SpawnPoint.hpp"
 #include "components/Transform.hpp"
 #include "components/Velocity.hpp"
 #include "components/WorldScreenText.hpp"
-#include "components/SpawnPoint.hpp"
 
 #include <entt/entt.hpp>
 #include <json.hpp>