~leinnan/raylibGame unlisted

a9f639893301db31ac547eceaa486f2238b158df — Leinnan 1 year, 3 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>