diff --git a/CMakeLists.txt b/CMakeLists.txt index 01e9510..df78572 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) include(cmake/vcpkg.cmake) endif() -project(RType VERSION 1.0.0 LANGUAGES CXX) +project(RTypeEngine VERSION 2.0.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -24,58 +24,106 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +# Copy assets to build directory add_custom_target(copy_assets ALL COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets ${CMAKE_BINARY_DIR}/assets ) +# ============================================================================= +# Dependencies +# ============================================================================= find_package(asio CONFIG REQUIRED) find_package(nlohmann_json CONFIG REQUIRED) find_package(Threads REQUIRED) -add_subdirectory(libs/engine) +# ============================================================================= +# Engine Libraries (generic, reusable by any game) +# ============================================================================= +add_subdirectory(engine) + +# ============================================================================= +# Games (R-Type game library must be built before network due to dependencies) +# ============================================================================= + +# R-Type Game (systems library - used by network library) +add_subdirectory(games/rtype) + +# ============================================================================= +# Network Libraries (depends on rtype_game for GameServer/GameClient) +# ============================================================================= add_subdirectory(libs/network) -add_executable(r-type_server server/main.cpp) +# R-Type Server +add_executable(r-type_server games/rtype/server/main.cpp) target_link_libraries(r-type_server PRIVATE rtype_network rtype_asio_network) add_executable(r-type_client - client/main.cpp - client/src/MenuState.cpp - client/src/SettingsState.cpp - client/src/room/RoomListState.cpp - client/src/LobbyState.cpp - client/src/GameState.cpp - client/src/ResultsState.cpp - client/src/EditorState.cpp - client/src/editor/EditorCanvasManager.cpp - client/src/editor/EditorAssetLibrary.cpp - client/src/editor/EditorUIManager.cpp - client/src/editor/EditorEntityManager.cpp - client/src/editor/EditorFileManager.cpp - client/src/editor/EditorInputHandler.cpp - client/src/editor/EditorDrawing.cpp - client/src/editor/EditorPropertyManager.cpp - client/src/editor/EditorColliderManager.cpp + games/rtype/client/main.cpp + games/rtype/client/src/MenuState.cpp + games/rtype/client/src/SettingsState.cpp + games/rtype/client/src/room/RoomListState.cpp + games/rtype/client/src/LobbyState.cpp + games/rtype/client/src/GameState.cpp + games/rtype/client/src/ResultsState.cpp + games/rtype/client/src/EditorState.cpp + games/rtype/client/src/editor/EditorCanvasManager.cpp + games/rtype/client/src/editor/EditorAssetLibrary.cpp + games/rtype/client/src/editor/EditorUIManager.cpp + games/rtype/client/src/editor/EditorEntityManager.cpp + games/rtype/client/src/editor/EditorFileManager.cpp + games/rtype/client/src/editor/EditorInputHandler.cpp + games/rtype/client/src/editor/EditorDrawing.cpp + games/rtype/client/src/editor/EditorPropertyManager.cpp + games/rtype/client/src/editor/EditorColliderManager.cpp ) target_include_directories(r-type_client PRIVATE - ${CMAKE_SOURCE_DIR}/client/include + ${CMAKE_SOURCE_DIR}/games/rtype/client/include + ${CMAKE_SOURCE_DIR}/games/rtype/include ) target_link_libraries(r-type_client PRIVATE rtype_network rtype_asio_network - rtype_ecs + rtype_game + rtype_ecs_core rtype_core rtype_sfml_renderer rtype_sfml_audio ) +# Breakout Game (demo of engine reusability) +if(TARGET rtype_sfml_renderer) + add_executable(breakout + games/breakout/src/main.cpp + games/breakout/src/BreakoutPhysicsSystem.cpp + games/breakout/src/BreakoutRenderSystem.cpp + games/breakout/src/BallAccelerationSystem.cpp + ) + target_include_directories(breakout PRIVATE + ${CMAKE_SOURCE_DIR}/games/breakout/include + ) + target_link_libraries(breakout PRIVATE + rtype_core + rtype_ecs_core + rtype_sfml_renderer + ) + message(STATUS "breakout will be built (engine reusability demo)") +endif() + +# Metroidvania Game (NEW - to be developed) +# add_subdirectory(games/metroidvania) + +# ============================================================================= +# Tests +# ============================================================================= +enable_testing() + add_executable(test_lobby tests/test_lobby.cpp) target_link_libraries(test_lobby PRIVATE rtype_network rtype_asio_network) add_executable(test_sparse_array tests/test_sparse_array.cpp) -target_link_libraries(test_sparse_array PRIVATE rtype_ecs) +target_link_libraries(test_sparse_array PRIVATE rtype_ecs_core) add_executable(test_udp_protocol tests/test_udp_protocol.cpp) target_link_libraries(test_udp_protocol PRIVATE rtype_network rtype_asio_network) @@ -84,49 +132,48 @@ message(STATUS "test_udp_protocol will be built (UDP game protocol test)") add_executable(test_tcp_framing tests/test_tcp_framing.cpp) target_link_libraries(test_tcp_framing PRIVATE rtype_asio_network) +add_executable(test_event_bus tests/test_event_bus.cpp) +target_link_libraries(test_event_bus PRIVATE rtype_core) + +add_executable(test_scene_manager tests/test_scene_manager.cpp) +target_link_libraries(test_scene_manager PRIVATE rtype_core rtype_ecs_core) + +add_executable(test_camera_system tests/test_camera_system.cpp) +target_link_libraries(test_camera_system PRIVATE rtype_core rtype_ecs_core) + if(TARGET rtype_sfml_renderer) add_executable(test_renderer tests/test_renderer.cpp) target_link_libraries(test_renderer PRIVATE rtype_core - rtype_ecs + rtype_ecs_core ) message(STATUS "test_renderer will be built (loads renderer plugin dynamically)") add_executable(test_player_system tests/test_player_system.cpp) + target_include_directories(test_player_system PRIVATE + ${CMAKE_SOURCE_DIR}/games/rtype/include + ) target_link_libraries(test_player_system PRIVATE rtype_core - rtype_ecs + rtype_game ) message(STATUS "test_player_system will be built (loads renderer plugin dynamically)") add_executable(test_health_system tests/test_health_system.cpp) + target_include_directories(test_health_system PRIVATE + ${CMAKE_SOURCE_DIR}/games/rtype/include + ) target_link_libraries(test_health_system PRIVATE rtype_core - rtype_ecs + rtype_game ) message(STATUS "test_health_system will be built (loads renderer plugin dynamically)") add_executable(test_background tests/test_background.cpp) target_link_libraries(test_background PRIVATE rtype_core - rtype_ecs + rtype_ecs_core rtype_sfml_renderer ) message(STATUS "test_background will be built") - - add_executable(breakout - breakout/src/main.cpp - breakout/src/BreakoutPhysicsSystem.cpp - breakout/src/BreakoutRenderSystem.cpp - breakout/src/BallAccelerationSystem.cpp - ) - target_include_directories(breakout PRIVATE - ${CMAKE_SOURCE_DIR}/breakout/include - ) - target_link_libraries(breakout PRIVATE - rtype_core - rtype_ecs - rtype_sfml_renderer - ) - message(STATUS "breakout will be built (second game demo)") endif() diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt new file mode 100644 index 0000000..23bfad3 --- /dev/null +++ b/engine/CMakeLists.txt @@ -0,0 +1,19 @@ +# Engine CMakeLists.txt - Generic Game Engine +# +# This builds the generic engine libraries that can be used by any game. +# Game-specific code belongs in games// + +# Core subsystem (Logger, Engine, Module system) +add_subdirectory(src/Core) + +# ECS subsystem (split into generic and rtype-specific) +add_subdirectory(src/ECS) + +# Renderer plugin (SFML implementation) +add_subdirectory(src/Renderer) + +# Audio plugin (SFML implementation) +add_subdirectory(src/Audio) + +# Animation system +add_subdirectory(src/Animation) diff --git a/libs/engine/README.md b/engine/README.md similarity index 100% rename from libs/engine/README.md rename to engine/README.md diff --git a/libs/engine/include/Animation/AnimationModule.hpp b/engine/include/Animation/AnimationModule.hpp similarity index 100% rename from libs/engine/include/Animation/AnimationModule.hpp rename to engine/include/Animation/AnimationModule.hpp diff --git a/libs/engine/include/Animation/AnimationTypes.hpp b/engine/include/Animation/AnimationTypes.hpp similarity index 100% rename from libs/engine/include/Animation/AnimationTypes.hpp rename to engine/include/Animation/AnimationTypes.hpp diff --git a/libs/engine/include/Animation/IAnimation.hpp b/engine/include/Animation/IAnimation.hpp similarity index 100% rename from libs/engine/include/Animation/IAnimation.hpp rename to engine/include/Animation/IAnimation.hpp diff --git a/libs/engine/include/Audio/IAudio.hpp b/engine/include/Audio/IAudio.hpp similarity index 100% rename from libs/engine/include/Audio/IAudio.hpp rename to engine/include/Audio/IAudio.hpp diff --git a/libs/engine/include/Audio/SFMLAudio.hpp b/engine/include/Audio/SFMLAudio.hpp similarity index 100% rename from libs/engine/include/Audio/SFMLAudio.hpp rename to engine/include/Audio/SFMLAudio.hpp diff --git a/libs/engine/include/Core/ColorFilter.hpp b/engine/include/Core/ColorFilter.hpp similarity index 100% rename from libs/engine/include/Core/ColorFilter.hpp rename to engine/include/Core/ColorFilter.hpp diff --git a/libs/engine/include/Core/Engine.hpp b/engine/include/Core/Engine.hpp similarity index 86% rename from libs/engine/include/Core/Engine.hpp rename to engine/include/Core/Engine.hpp index e01682f..b3e87be 100644 --- a/libs/engine/include/Core/Engine.hpp +++ b/engine/include/Core/Engine.hpp @@ -3,6 +3,10 @@ #include "Module.hpp" #include "ModuleLoader.hpp" #include "Logger.hpp" +#include "SceneManager.hpp" +#include "ResourceManager.hpp" +#include "InputManager.hpp" +#include "EventBus.hpp" #include "../ECS/Registry.hpp" #include "../ECS/ISystem.hpp" #include @@ -48,6 +52,11 @@ namespace RType { template void RegisterSystem(std::unique_ptr system); void UpdateSystems(float deltaTime); + SceneManager& GetSceneManager() { return m_sceneManager; } + ResourceManager& GetResourceManager() { return m_resourceManager; } + InputManager& GetInputManager() { return m_inputManager; } + EventBus& GetEventBus() { return m_eventBus; } + private: void SortModulesByPriority(); bool InitializeModules(); @@ -61,6 +70,12 @@ namespace RType { std::vector m_sortedModules; ECS::Registry m_registry; std::vector> m_systems; + + SceneManager m_sceneManager; + ResourceManager m_resourceManager; + InputManager m_inputManager; + EventBus m_eventBus; + bool m_initialized{false}; }; diff --git a/engine/include/Core/EventBus.hpp b/engine/include/Core/EventBus.hpp new file mode 100644 index 0000000..6e7a13a --- /dev/null +++ b/engine/include/Core/EventBus.hpp @@ -0,0 +1,152 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type Engine +** File description: +** EventBus - Simple publish-subscribe event system for decoupled communication +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace RType { + + namespace Core { + + + class EventBus { + public: + EventBus() = default; + ~EventBus() = default; + + // Non-copyable but movable + EventBus(const EventBus&) = delete; + EventBus& operator=(const EventBus&) = delete; + EventBus(EventBus&&) = default; + EventBus& operator=(EventBus&&) = default; + + + template + size_t Subscribe(std::function handler) { + std::type_index typeId = std::type_index(typeid(EventT)); + + auto wrapper = [handler](const std::any& event) { + handler(std::any_cast(event)); + }; + + size_t id = m_nextId++; + m_handlers[typeId].push_back({id, std::move(wrapper)}); + return id; + } + + + template + void Unsubscribe(size_t subscriptionId) { + std::type_index typeId = std::type_index(typeid(EventT)); + + auto it = m_handlers.find(typeId); + if (it != m_handlers.end()) { + auto& handlers = it->second; + handlers.erase( + std::remove_if(handlers.begin(), handlers.end(), + [subscriptionId](const HandlerEntry& entry) { + return entry.id == subscriptionId; + }), + handlers.end() + ); + } + } + + + template + void Publish(const EventT& event) { + std::type_index typeId = std::type_index(typeid(EventT)); + + auto it = m_handlers.find(typeId); + if (it != m_handlers.end()) { + for (const auto& entry : it->second) { + entry.handler(event); + } + } + } + + + template + void ClearSubscribers() { + std::type_index typeId = std::type_index(typeid(EventT)); + m_handlers.erase(typeId); + } + + + void Clear() { + m_handlers.clear(); + } + + + template + size_t GetSubscriberCount() const { + std::type_index typeId = std::type_index(typeid(EventT)); + + auto it = m_handlers.find(typeId); + if (it != m_handlers.end()) { + return it->second.size(); + } + return 0; + } + + private: + struct HandlerEntry { + size_t id; + std::function handler; + }; + + std::unordered_map> m_handlers; + size_t m_nextId = 0; + }; + + + + namespace Events { + + /// Fired when an entity is created + struct EntityCreated { + uint32_t entity; + }; + + /// Fired when an entity is destroyed + struct EntityDestroyed { + uint32_t entity; + }; + + /// Fired when a collision occurs between two entities + struct Collision { + uint32_t entityA; + uint32_t entityB; + }; + + /// Fired when a scene is loaded + struct SceneLoaded { + std::string sceneName; + }; + + /// Fired when a scene is unloaded + struct SceneUnloaded { + std::string sceneName; + }; + + /// Fired when input action is triggered + struct ActionTriggered { + std::string action; + bool pressed; // true = pressed, false = released + }; + + } + + } + +} diff --git a/engine/include/Core/InputManager.hpp b/engine/include/Core/InputManager.hpp new file mode 100644 index 0000000..ab4adbf --- /dev/null +++ b/engine/include/Core/InputManager.hpp @@ -0,0 +1,65 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type Engine +** File description: +** InputManager - Action and axis-based input abstraction +*/ + +#pragma once + +#include "../Renderer/IRenderer.hpp" +#include +#include +#include + +namespace RType { + + namespace Core { + + class InputManager { + public: + InputManager() = default; + ~InputManager() = default; + + // Non-copyable + InputManager(const InputManager&) = delete; + InputManager& operator=(const InputManager&) = delete; + + void bindAction(const std::string& action, Renderer::Key key); + void bindActionMouse(const std::string& action, Renderer::MouseButton button); + void unbindAction(const std::string& action); + bool isActionPressed(const std::string& action) const; + bool isActionJustPressed(const std::string& action) const; + bool isActionJustReleased(const std::string& action) const; + void bindAxis(const std::string& axis, Renderer::Key negative, Renderer::Key positive); + void unbindAxis(const std::string& axis); + float getAxisValue(const std::string& axis) const; + + void update(Renderer::IRenderer* renderer); + + void clearBindings(); + + void loadDefaults(); + + private: + struct ActionBinding { + Renderer::Key key = Renderer::Key::Unknown; + Renderer::MouseButton mouseButton = Renderer::MouseButton::Left; + bool isMouseBinding = false; + bool currentlyPressed = false; + bool wasPressed = false; + }; + + struct AxisBinding { + Renderer::Key negative = Renderer::Key::Unknown; + Renderer::Key positive = Renderer::Key::Unknown; + }; + + std::unordered_map m_actions; + std::unordered_map m_axes; + Renderer::IRenderer* m_renderer = nullptr; + }; + + } + +} diff --git a/libs/engine/include/Core/InputMapping.hpp b/engine/include/Core/InputMapping.hpp similarity index 100% rename from libs/engine/include/Core/InputMapping.hpp rename to engine/include/Core/InputMapping.hpp diff --git a/libs/engine/include/Core/Logger.hpp b/engine/include/Core/Logger.hpp similarity index 100% rename from libs/engine/include/Core/Logger.hpp rename to engine/include/Core/Logger.hpp diff --git a/libs/engine/include/Core/Module.hpp b/engine/include/Core/Module.hpp similarity index 100% rename from libs/engine/include/Core/Module.hpp rename to engine/include/Core/Module.hpp diff --git a/libs/engine/include/Core/ModuleLoader.hpp b/engine/include/Core/ModuleLoader.hpp similarity index 100% rename from libs/engine/include/Core/ModuleLoader.hpp rename to engine/include/Core/ModuleLoader.hpp diff --git a/libs/engine/include/Core/Platform.hpp b/engine/include/Core/Platform.hpp similarity index 100% rename from libs/engine/include/Core/Platform.hpp rename to engine/include/Core/Platform.hpp diff --git a/engine/include/Core/ResourceManager.hpp b/engine/include/Core/ResourceManager.hpp new file mode 100644 index 0000000..02d8c28 --- /dev/null +++ b/engine/include/Core/ResourceManager.hpp @@ -0,0 +1,133 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type Engine +** File description: +** ResourceManager - Centralized asset loading with caching +*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace RType { + + namespace Core { + + + class ResourceManager { + public: + ResourceManager() = default; + ~ResourceManager() = default; + + // Non-copyable + ResourceManager(const ResourceManager&) = delete; + ResourceManager& operator=(const ResourceManager&) = delete; + + + template + void RegisterLoader(std::function(const std::string&)> loader) { + std::type_index typeId = std::type_index(typeid(T)); + m_loaders[typeId] = [loader](const std::string& path) -> std::shared_ptr { + return loader(path); + }; + } + + + template + std::shared_ptr Load(const std::string& path) { + std::string cacheKey = GetCacheKey(path); + + // Check cache first + auto it = m_cache.find(cacheKey); + if (it != m_cache.end()) { + auto locked = it->second.lock(); + if (locked) { + return std::static_pointer_cast(locked); + } + // Expired, remove from cache + m_cache.erase(it); + } + + // Load using registered loader + std::type_index typeId = std::type_index(typeid(T)); + auto loaderIt = m_loaders.find(typeId); + if (loaderIt == m_loaders.end()) { + return nullptr; // No loader registered + } + + auto resource = loaderIt->second(path); + if (resource) { + m_cache[cacheKey] = resource; + return std::static_pointer_cast(resource); + } + return nullptr; + } + + + template + void Preload(const std::vector& paths) { + for (const auto& path : paths) { + Load(path); + } + } + + + template + bool IsCached(const std::string& path) const { + std::string cacheKey = GetCacheKey(path); + auto it = m_cache.find(cacheKey); + if (it != m_cache.end()) { + return !it->second.expired(); + } + return false; + } + + + void CleanupExpired() { + for (auto it = m_cache.begin(); it != m_cache.end(); ) { + if (it->second.expired()) { + it = m_cache.erase(it); + } else { + ++it; + } + } + } + + + void Clear() { + m_cache.clear(); + } + + + size_t GetCacheSize() const { + return m_cache.size(); + } + + + size_t GetActiveCacheCount() const { + size_t count = 0; + for (const auto& [key, weakPtr] : m_cache) { + if (!weakPtr.expired()) { + count++; + } + } + return count; + } + + private: + template + std::string GetCacheKey(const std::string& path) const { + return std::string(typeid(T).name()) + ":" + path; + } + + std::unordered_map> m_cache; + std::unordered_map(const std::string&)>> m_loaders; + }; + + } + +} diff --git a/engine/include/Core/SceneManager.hpp b/engine/include/Core/SceneManager.hpp new file mode 100644 index 0000000..ff8b8db --- /dev/null +++ b/engine/include/Core/SceneManager.hpp @@ -0,0 +1,81 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type Engine +** File description: +** SceneManager - Basic scene lifecycle management +*/ + +#pragma once + +#include "../ECS/Registry.hpp" +#include +#include +#include + +namespace RType { + + namespace Core { + + + class SceneManager { + public: + using SceneSetupFn = std::function; + using SceneTeardownFn = std::function; + + explicit SceneManager(ECS::Registry* registry = nullptr); + ~SceneManager() = default; + + // Non-copyable + SceneManager(const SceneManager&) = delete; + SceneManager& operator=(const SceneManager&) = delete; + + + void SetRegistry(ECS::Registry* registry) { m_registry = registry; } + + + void RegisterScene(const std::string& sceneName, + SceneSetupFn setup, + SceneTeardownFn teardown = nullptr); + + + bool LoadScene(const std::string& sceneName); + + + bool LoadScene(const std::string& sceneName, SceneSetupFn setup); + + + void UnloadCurrentScene(); + + + bool TransitionTo(const std::string& sceneName); + + + const std::string& GetCurrentSceneName() const { return m_currentScene; } + + + bool HasActiveScene() const { return !m_currentScene.empty(); } + + + bool IsSceneRegistered(const std::string& sceneName) const; + + + void UnregisterScene(const std::string& sceneName); + + + void ClearScenes(); + + private: + struct SceneData { + SceneSetupFn setup; + SceneTeardownFn teardown; + }; + + ECS::Registry* m_registry = nullptr; + std::string m_currentScene; + SceneTeardownFn m_currentTeardown; + std::unordered_map m_scenes; + }; + + } + +} diff --git a/libs/engine/include/ECS/AnimationSystem.hpp b/engine/include/ECS/AnimationSystem.hpp similarity index 100% rename from libs/engine/include/ECS/AnimationSystem.hpp rename to engine/include/ECS/AnimationSystem.hpp diff --git a/libs/engine/include/ECS/AudioSystem.hpp b/engine/include/ECS/AudioSystem.hpp similarity index 100% rename from libs/engine/include/ECS/AudioSystem.hpp rename to engine/include/ECS/AudioSystem.hpp diff --git a/engine/include/ECS/Camera2DSystem.hpp b/engine/include/ECS/Camera2DSystem.hpp new file mode 100644 index 0000000..fec902e --- /dev/null +++ b/engine/include/ECS/Camera2DSystem.hpp @@ -0,0 +1,82 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type Engine +** File description: +** Camera2DSystem - Updates camera position based on target following +*/ + +#pragma once + +#include "ISystem.hpp" +#include "../Renderer/IRenderer.hpp" +#include "../Math/Types.hpp" + +namespace RType { + + namespace ECS { + + /** + * @brief System that updates Camera2D components + * + * This system handles: + * - Smooth target following with configurable speed + * - World bounds clamping + * - Screen shake effects + * - Viewport updates on renderer + * + * The system should be registered early to ensure camera position + * is updated before rendering systems use it. + */ + class Camera2DSystem : public ISystem { + public: + explicit Camera2DSystem(Renderer::IRenderer* renderer = nullptr); + ~Camera2DSystem() override = default; + + void Update(Registry& registry, float deltaTime) override; + const char* GetName() const override { return "Camera2DSystem"; } + + /** + * @brief Set the renderer for viewport updates + * @param renderer The renderer to update + */ + void SetRenderer(Renderer::IRenderer* renderer) { m_renderer = renderer; } + + /** + * @brief Get the current active camera position + * @return Camera position in world coordinates + */ + Math::Vector2 GetCameraPosition() const { return m_cameraPosition; } + + /** + * @brief Convert screen coordinates to world coordinates + * @param screenPos Position in screen space + * @return Position in world space + */ + Math::Vector2 ScreenToWorld(const Math::Vector2& screenPos) const; + + /** + * @brief Convert world coordinates to screen coordinates + * @param worldPos Position in world space + * @return Position in screen space + */ + Math::Vector2 WorldToScreen(const Math::Vector2& worldPos) const; + + /** + * @brief Get the current camera zoom + */ + float GetZoom() const { return m_zoom; } + + private: + Renderer::IRenderer* m_renderer = nullptr; + Math::Vector2 m_cameraPosition{0.0f, 0.0f}; + Math::Vector2 m_screenSize{1920.0f, 1080.0f}; + float m_zoom = 1.0f; + + Math::Vector2 Lerp(const Math::Vector2& a, const Math::Vector2& b, float t) const; + Math::Vector2 Clamp(const Math::Vector2& value, const Math::Vector2& min, const Math::Vector2& max) const; + Math::Vector2 GetShakeOffset(float intensity) const; + }; + + } + +} diff --git a/libs/engine/include/ECS/CollisionDetectionSystem.hpp b/engine/include/ECS/CollisionDetectionSystem.hpp similarity index 100% rename from libs/engine/include/ECS/CollisionDetectionSystem.hpp rename to engine/include/ECS/CollisionDetectionSystem.hpp diff --git a/engine/include/ECS/Component.hpp b/engine/include/ECS/Component.hpp new file mode 100644 index 0000000..9032814 --- /dev/null +++ b/engine/include/ECS/Component.hpp @@ -0,0 +1,298 @@ +#pragma once +/** + * @file Component.hpp + * @brief Master include file for all ECS components. + * + * This file includes all generic engine components from modular files, + * and contains R-Type specific components inline for backwards compatibility. + * + * For new games, use only the generic component headers from ECS/Components/. + * R-Type specific components will be moved to games/rtype/components/ in a future phase. + */ + +// ============================================================================= +// Generic Engine Components (game-agnostic) +// ============================================================================= +#include "ECS/Components/IComponent.hpp" // Base component interface +#include "ECS/Components/Transform.hpp" // Position, Velocity, Transform2D, Controllable, Scrollable, NetworkId +#include "ECS/Components/Rendering.hpp" // Drawable, DamageFlash, FloatingText +#include "ECS/Components/Physics.hpp" // BoxCollider, CircleCollider, CollisionLayer, Obstacle, Invincibility, Rigidbody2D, PhysicsMaterial +#include "ECS/Components/Audio.hpp" // SoundEffect, MusicEffect +#include "ECS/Components/Animation.hpp" // SpriteAnimation, AnimationStateMachine, VisualEffect, AnimationEvents, AnimationLayer +#include "ECS/Components/Gameplay.hpp" // Health, Damage, ScoreValue, ScoreTimer, Bullet, Shooter, ShootCommand, ProximityDamage, Lifetime, Tag + +// Standard library includes for R-Type components +#include +#include +#include +#include +#include +#include "Renderer/IRenderer.hpp" +#include "Math/Types.hpp" +#include "Entity.hpp" +#include "Animation/AnimationTypes.hpp" + +namespace RType { +namespace ECS { + +// ============================================================================= +// R-Type Specific Components (will be moved to games/rtype/components/ later) +// ============================================================================= + + struct NetworkPlayer : public IComponent { + uint8_t playerNumber = 0; + uint64_t playerHash = 0; + char name[32] = {}; + bool ready = false; + + NetworkPlayer() = default; + NetworkPlayer(uint8_t num, uint64_t hash, const char* playerName, bool isReady = false) + : playerNumber(num), playerHash(hash), ready(isReady) { + if (playerName) { + std::strncpy(name, playerName, 31); + name[31] = '\0'; + } + } + }; + + struct Player : public IComponent { + uint8_t playerNumber = 0; + uint64_t playerHash = 0; + bool isLocalPlayer = false; + uint8_t lives = 3; + + Player() = default; + Player(uint8_t number, uint64_t hash, bool local = false, uint8_t startLives = 3) + : playerNumber(number), playerHash(hash), isLocalPlayer(local), lives(startLives) {} + }; + + enum class EnemyType : uint8_t { + BASIC = 0, + FAST = 1, + TANK = 2, + BOSS = 3, + FORMATION = 4 + }; + + struct Enemy : public IComponent { + EnemyType type = EnemyType::BASIC; + uint32_t id = 0; + + Enemy() = default; + Enemy(EnemyType enemyType, uint32_t enemyId = 0) + : type(enemyType), id(enemyId) {} + }; + + struct Boss : public IComponent { + uint8_t bossId = 1; + + Boss() = default; + Boss(uint8_t id) : bossId(id) {} + }; + + struct BossKilled : public IComponent { + Entity bossEntity; + int levelNumber; + float timeSinceDeath = 0.0f; + + BossKilled() = default; + BossKilled(Entity boss, int level) + : bossEntity(boss), levelNumber(level) {} + }; + + enum class BossAttackPattern { + IDLE = 0, + // Boss 1 + FAN_SPRAY = 1, + DIRECT_SHOT = 2, + CIRCLE = 3, + BLACK_ORB = 4, + THIRD_BULLET = 5, + // Boss 2 + SPIRAL_WAVE = 6, + ANIMATED_ORB = 7, + LASER_BEAM = 8 + }; + + struct BossAttack : public IComponent { + float attackCooldown = 3.0f; + float timeSinceLastAttack = 0.0f; + BossAttackPattern currentPattern = BossAttackPattern::FAN_SPRAY; + + BossAttack() = default; + BossAttack(float cooldown) : attackCooldown(cooldown) {} + }; + + struct BossBullet : public IComponent { + BossBullet() = default; + }; + + struct WaveAttack : public IComponent { + WaveAttack() = default; + }; + + struct SecondAttack : public IComponent { + SecondAttack() = default; + }; + + struct FireBullet : public IComponent { + FireBullet() = default; + }; + + struct Mine : public IComponent { + float proximityRadius = 80.0f; + float explosionRadius = 100.0f; + float lifeTime = 10.0f; + float timer = 0.0f; + bool isExploding = false; + float explosionTimer = 0.0f; + + Mine() = default; + Mine(float proximity, float explosion, float life) + : proximityRadius(proximity), explosionRadius(explosion), lifeTime(life) {} + }; + + struct BossMovementPattern : public IComponent { + float timer = 0.0f; + float amplitudeY = 200.0f; + float amplitudeX = 80.0f; + float frequencyY = 0.5f; + float frequencyX = 0.3f; + float centerY = 0.0f; + float centerX = 0.0f; + + BossMovementPattern() = default; + BossMovementPattern(float ampY, float ampX, float freqY, float freqX, float centerYPos, float centerXPos) + : amplitudeY(ampY), amplitudeX(ampX), frequencyY(freqY), frequencyX(freqX), centerY(centerYPos), centerX(centerXPos) {} + }; + + struct BlackOrb : public IComponent { + float attractionRadius = 200.0f; + float absorptionRadius = 30.0f; + float attractionForce = 500.0f; + bool isActive = true; + + BlackOrb() = default; + BlackOrb(float attraction, float absorption, float force) + : attractionRadius(attraction), absorptionRadius(absorption), attractionForce(force) {} + }; + + struct ThirdBullet : public IComponent { + float spawnInterval = 0.3f; + float timeSinceSpawn = 0.0f; + int damage = 50; + bool isActive = true; + + ThirdBullet() = default; + ThirdBullet(float interval, int dmg) + : spawnInterval(interval), damage(dmg) {} + }; + + struct EnemyKilled : public IComponent { + uint32_t enemyId = 0; + Entity killedBy = NULL_ENTITY; + + EnemyKilled() = default; + EnemyKilled(uint32_t id, Entity killer = NULL_ENTITY) + : enemyId(id), killedBy(killer) {} + }; + + struct ObstacleVisual : public IComponent { + }; + + struct ObstacleMetadata : public IComponent { + uint32_t uniqueId = 0; + Entity visualEntity = NULL_ENTITY; + float offsetX = 0.0f; + float offsetY = 0.0f; + + ObstacleMetadata() = default; + ObstacleMetadata(uint32_t id, + Entity visual = NULL_ENTITY, + float offsetX = 0.0f, + float offsetY = 0.0f) + : uniqueId(id), + visualEntity(visual), + offsetX(offsetX), + offsetY(offsetY) {} + }; + + // Powerup system components + enum class PowerUpType : uint8_t { + FIRE_RATE_BOOST = 0, + SPREAD_SHOT = 1, + LASER_BEAM = 2, + FORCE_POD = 3, + SPEED_BOOST = 4, + SHIELD = 5 + }; + + struct PowerUp : public IComponent { + PowerUpType type = PowerUpType::FIRE_RATE_BOOST; + uint32_t id = 0; + + PowerUp() = default; + PowerUp(PowerUpType powerupType, uint32_t powerupId = 0) + : type(powerupType), id(powerupId) {} + }; + + struct ActivePowerUps : public IComponent { + bool hasFireRateBoost = false; + bool hasSpreadShot = false; + bool hasLaserBeam = false; + bool hasShield = false; + float speedMultiplier = 1.0f; + + ActivePowerUps() = default; + }; + + enum class WeaponType : uint8_t { + STANDARD = 0, + SPREAD = 1, + LASER = 2 + }; + + struct WeaponSlot : public IComponent { + WeaponType type = WeaponType::STANDARD; + float fireRate = 0.2f; + float cooldown = 0.0f; + int damage = 25; + bool enabled = true; + + WeaponSlot() = default; + WeaponSlot(WeaponType weaponType, float rate, int dmg) + : type(weaponType), fireRate(rate), damage(dmg) {} + }; + + struct ForcePod : public IComponent { + Entity owner = NULL_ENTITY; + float offsetX = -60.0f; + float offsetY = 0.0f; + bool isAttached = true; + + ForcePod() = default; + ForcePod(Entity ownerEntity, float oX = -60.0f, float oY = 0.0f) + : owner(ownerEntity), offsetX(oX), offsetY(oY) {} + }; + + struct Shield : public IComponent { + float duration = 0.0f; // 0 = permanent (until death) + float timeRemaining = 0.0f; + + Shield() = default; + Shield(float dur = 0.0f) : duration(dur), timeRemaining(dur) {} + }; + + struct PowerUpGlow : public IComponent { + float time = 0.0f; + float pulseSpeed = 2.0f; + float minAlpha = 0.7f; + float maxAlpha = 1.0f; + float baseScale = 2.5f; + float scalePulse = 0.08f; + + PowerUpGlow() = default; + }; + +} // namespace ECS +} // namespace RType diff --git a/engine/include/ECS/Components/Animation.hpp b/engine/include/ECS/Components/Animation.hpp new file mode 100644 index 0000000..239c590 --- /dev/null +++ b/engine/include/ECS/Components/Animation.hpp @@ -0,0 +1,156 @@ +#pragma once +/** + * @file Animation.hpp + * @brief Generic animation components for any game engine. + */ + +#include +#include +#include "Animation/AnimationTypes.hpp" +#include "Math/Types.hpp" +#include "ECS/Entity.hpp" +#include "ECS/Components/IComponent.hpp" + +namespace RType { +namespace ECS { + + /** + * @brief Sprite animation playback component. + */ + struct SpriteAnimation : public IComponent { + Animation::AnimationClipId clipId = Animation::INVALID_CLIP_ID; + float currentTime = 0.0f; + float playbackSpeed = 1.0f; + bool playing = true; + bool looping = false; + bool destroyOnComplete = false; + + std::size_t currentFrameIndex = 0; + Math::Rectangle currentRegion{}; + + SpriteAnimation() = default; + SpriteAnimation(Animation::AnimationClipId clip, bool loop = false, float speed = 1.0f) + : clipId(clip), playbackSpeed(speed), looping(loop) {} + }; + + /** + * @brief Animation state machine for complex animations. + */ + struct AnimationStateMachine : public IComponent { + Animation::AnimationGraphId graphId = Animation::INVALID_GRAPH_ID; + Animation::AnimationStateId currentState = Animation::INVALID_STATE_ID; + Animation::AnimationStateId previousState = Animation::INVALID_STATE_ID; + float stateTime = 0.0f; + float blendFactor = 0.0f; + float blendDuration = 0.0f; + bool isTransitioning = false; + + static constexpr std::size_t MAX_PARAMS = 8; + std::array parameters{}; + std::array, MAX_PARAMS> parameterNames{}; + std::size_t parameterCount = 0; + + AnimationStateMachine() = default; + explicit AnimationStateMachine(Animation::AnimationGraphId graph) + : graphId(graph) {} + + void SetParameter(const char* name, float value) { + for (std::size_t i = 0; i < parameterCount; ++i) { + if (std::strncmp(parameterNames[i].data(), name, 31) == 0) { + parameters[i] = value; + return; + } + } + if (parameterCount < MAX_PARAMS) { + std::strncpy(parameterNames[parameterCount].data(), name, 31); + parameterNames[parameterCount][31] = '\0'; + parameters[parameterCount] = value; + parameterCount++; + } + } + + float GetParameter(const char* name) const { + for (std::size_t i = 0; i < parameterCount; ++i) { + if (std::strncmp(parameterNames[i].data(), name, 31) == 0) { + return parameters[i]; + } + } + return 0.0f; + } + }; + + /** + * @brief Marker for animated sprites that need frame updates. + */ + struct AnimatedSprite : public IComponent { + bool needsUpdate = true; + + AnimatedSprite() = default; + }; + + /** + * @brief Visual effect component (explosions, particles, etc). + */ + struct VisualEffect : public IComponent { + Animation::EffectType type = Animation::EffectType::EXPLOSION_SMALL; + float lifetime = 0.0f; + float maxLifetime = 1.0f; + Entity owner = NULL_ENTITY; + float offsetX = 0.0f; + float offsetY = 0.0f; + + VisualEffect() = default; + VisualEffect(Animation::EffectType t, float duration) + : type(t), maxLifetime(duration) {} + VisualEffect(Animation::EffectType t, float duration, Entity ownerEntity, float offX, float offY) + : type(t), maxLifetime(duration), owner(ownerEntity), offsetX(offX), offsetY(offY) {} + }; + + /** + * @brief Animation events for triggering actions at specific frames. + */ + struct AnimationEvents : public IComponent { + static constexpr std::size_t MAX_EVENTS = 4; + std::array, MAX_EVENTS> eventNames{}; + std::size_t eventCount = 0; + + AnimationEvents() = default; + + void PushEvent(const char* name) { + if (eventCount < MAX_EVENTS && name) { + std::strncpy(eventNames[eventCount].data(), name, 31); + eventNames[eventCount][31] = '\0'; + eventCount++; + } + } + + void Clear() { eventCount = 0; } + + bool HasEvent(const char* name) const { + for (std::size_t i = 0; i < eventCount; ++i) { + if (std::strncmp(eventNames[i].data(), name, 31) == 0) { + return true; + } + } + return false; + } + }; + + /** + * @brief Animation layer for blending multiple animations. + */ + struct AnimationLayer : public IComponent { + Animation::AnimationClipId clipId = Animation::INVALID_CLIP_ID; + float currentTime = 0.0f; + float weight = 1.0f; + float playbackSpeed = 1.0f; + bool additive = false; + int layerIndex = 0; + + AnimationLayer() = default; + AnimationLayer(Animation::AnimationClipId clip, int layer, float w = 1.0f) + : clipId(clip), weight(w), layerIndex(layer) {} + }; + +} // namespace ECS +} // namespace RType diff --git a/engine/include/ECS/Components/Audio.hpp b/engine/include/ECS/Components/Audio.hpp new file mode 100644 index 0000000..b51ec0c --- /dev/null +++ b/engine/include/ECS/Components/Audio.hpp @@ -0,0 +1,46 @@ +#pragma once +/** + * @file Audio.hpp + * @brief Generic audio components for any game engine. + */ + +#include "Audio/IAudio.hpp" +#include "ECS/Components/IComponent.hpp" + +namespace RType { +namespace ECS { + + /** + * @brief Sound effect component for one-shot or looping sounds. + */ + struct SoundEffect : public IComponent { + Audio::SoundId soundId = Audio::INVALID_SOUND_ID; + float volume = 1.0f; + float pitch = 1.0f; + float pan = 0.0f; + bool loop = false; + bool positional = false; + + SoundEffect() = default; + SoundEffect(Audio::SoundId id, float vol = 1.0f) + : soundId(id), volume(vol) {} + }; + + /** + * @brief Music/stream component for background music. + */ + struct MusicEffect : public IComponent { + Audio::MusicId musicId = Audio::INVALID_MUSIC_ID; + bool play = true; + bool stop = false; + float volume = 1.0f; + float pitch = 1.0f; + bool loop = true; + + MusicEffect() = default; + explicit MusicEffect(Audio::MusicId id) + : musicId(id) {} + }; + +} // namespace ECS +} // namespace RType diff --git a/engine/include/ECS/Components/Camera2D.hpp b/engine/include/ECS/Components/Camera2D.hpp new file mode 100644 index 0000000..867cc60 --- /dev/null +++ b/engine/include/ECS/Components/Camera2D.hpp @@ -0,0 +1,64 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type Engine +** File description: +** Camera2D - 2D camera component for target following +*/ + +#pragma once + +#include "IComponent.hpp" +#include "../Entity.hpp" +#include "../../Math/Types.hpp" + +namespace RType { + + namespace ECS { + + + struct Camera2D : public IComponent { + /// Entity to follow (NULL_ENTITY for static camera) + Entity target = NULL_ENTITY; + + /// Offset from target position + Math::Vector2 offset{0.0f, 0.0f}; + + /// Current camera position (updated by Camera2DSystem) + Math::Vector2 position{0.0f, 0.0f}; + + /// World bounds for camera clamping (0 = no bounds) + Math::Vector2 boundsMin{0.0f, 0.0f}; + Math::Vector2 boundsMax{0.0f, 0.0f}; + + /// Smooth interpolation speed (higher = snappier, 0 = instant) + float smoothSpeed = 5.0f; + + /// Camera zoom level (1.0 = default, 2.0 = 2x zoom in) + float zoom = 1.0f; + + /// Whether this camera is active + bool active = true; + + /// Screen shake intensity (0 = no shake) + float shakeIntensity = 0.0f; + + /// Screen shake duration remaining + float shakeDuration = 0.0f; + + Camera2D() = default; + + + void Shake(float intensity, float duration) { + shakeIntensity = intensity; + shakeDuration = duration; + } + + + bool HasBounds() const { + return boundsMax.x > boundsMin.x || boundsMax.y > boundsMin.y; + } + }; + + } + +} diff --git a/libs/engine/include/ECS/Components/Clickable.hpp b/engine/include/ECS/Components/Clickable.hpp similarity index 100% rename from libs/engine/include/ECS/Components/Clickable.hpp rename to engine/include/ECS/Components/Clickable.hpp diff --git a/engine/include/ECS/Components/Gameplay.hpp b/engine/include/ECS/Components/Gameplay.hpp new file mode 100644 index 0000000..96b7257 --- /dev/null +++ b/engine/include/ECS/Components/Gameplay.hpp @@ -0,0 +1,142 @@ +#pragma once +/** + * @file Gameplay.hpp + * @brief Generic gameplay components for any game engine. + * + * These include health, damage, scoring, and combat-related components. + */ + +#include +#include +#include "ECS/Entity.hpp" +#include "ECS/Components/IComponent.hpp" + +namespace RType { +namespace ECS { + + /** + * @brief Health component for damageable entities. + */ + struct Health : public IComponent { + int current = 100; + int max = 100; + + Health() = default; + Health(int maxHealth) + : current(maxHealth), max(maxHealth) {} + Health(int currentHealth, int maxHealth) + : current(currentHealth), max(maxHealth) {} + + bool IsDead() const { return current <= 0; } + float GetPercentage() const { return max > 0 ? static_cast(current) / max : 0.0f; } + }; + + /** + * @brief Damage component for entities that deal damage. + */ + struct Damage : public IComponent { + int amount = 10; + + Damage() = default; + Damage(int damageAmount) + : amount(damageAmount) {} + }; + + /** + * @brief Score value for collectibles/enemies. + */ + struct ScoreValue : public IComponent { + uint32_t points = 100; + + ScoreValue() = default; + ScoreValue(uint32_t scorePoints) + : points(scorePoints) {} + }; + + /** + * @brief Score timer for time-based scoring. + */ + struct ScoreTimer : public IComponent { + float elapsed = 0.0f; + + ScoreTimer() = default; + ScoreTimer(float startElapsed) + : elapsed(startElapsed) {} + }; + + /** + * @brief Bullet/projectile component. + */ + struct Bullet : public IComponent { + Entity owner = NULL_ENTITY; + + Bullet() = default; + Bullet(Entity shooter) + : owner(shooter) {} + }; + + /** + * @brief Component for entities that can shoot. + */ + struct Shooter : public IComponent { + float fireRate = 0.2f; + float cooldown = 0.0f; + float offsetX = 50.0f; + float offsetY = 20.0f; + + Shooter() = default; + Shooter(float rate, float oX = 50.0f, float oY = 20.0f) + : fireRate(rate), offsetX(oX), offsetY(oY) {} + }; + + /** + * @brief Shoot command input state. + */ + struct ShootCommand : public IComponent { + bool wantsToShoot = false; + + ShootCommand() = default; + ShootCommand(bool shoot) : wantsToShoot(shoot) {} + }; + + /** + * @brief Proximity damage for AOE effects. + */ + struct ProximityDamage : public IComponent { + float damageRadius = 120.0f; + float damageAmount = 1.0f; + float tickRate = 0.5f; + float timeSinceDamage = 0.0f; + + ProximityDamage() = default; + ProximityDamage(float radius, float damage, float rate) + : damageRadius(radius), damageAmount(damage), tickRate(rate) {} + }; + + /** + * @brief Lifetime component for auto-destruction. + */ + struct Lifetime : public IComponent { + float remaining = 1.0f; + + Lifetime() = default; + Lifetime(float duration) : remaining(duration) {} + }; + + /** + * @brief Tag component for entity categorization. + */ + struct Tag : public IComponent { + char name[32] = {}; + + Tag() = default; + Tag(const char* tagName) { + if (tagName) { + std::strncpy(name, tagName, 31); + name[31] = '\0'; + } + } + }; + +} // namespace ECS +} // namespace RType diff --git a/engine/include/ECS/Components/IComponent.hpp b/engine/include/ECS/Components/IComponent.hpp new file mode 100644 index 0000000..6697e1f --- /dev/null +++ b/engine/include/ECS/Components/IComponent.hpp @@ -0,0 +1,23 @@ +#pragma once +/** + * @file IComponent.hpp + * @brief Base interface for all ECS components. + */ + +#include + +namespace RType { +namespace ECS { + + using ComponentID = std::type_index; + + /** + * @brief Base interface for all components. + * All components should inherit from this. + */ + struct IComponent { + virtual ~IComponent() = default; + }; + +} // namespace ECS +} // namespace RType diff --git a/engine/include/ECS/Components/Physics.hpp b/engine/include/ECS/Components/Physics.hpp new file mode 100644 index 0000000..a97c743 --- /dev/null +++ b/engine/include/ECS/Components/Physics.hpp @@ -0,0 +1,121 @@ +#pragma once +/** + * @file Physics.hpp + * @brief Generic physics and collision components for any 2D game engine. + */ + +#include +#include "ECS/Entity.hpp" +#include "ECS/Components/IComponent.hpp" + +namespace RType { +namespace ECS { + + /** + * @brief Axis-aligned box collider. + */ + struct BoxCollider : public IComponent { + float width = 0.0f; + float height = 0.0f; + + BoxCollider() = default; + BoxCollider(float width, float height) + : width(width), height(height) {} + }; + + /** + * @brief Circle collider. + */ + struct CircleCollider : public IComponent { + float radius = 0.0f; + + CircleCollider() = default; + CircleCollider(float r) : radius(r) {} + }; + + /** + * @brief Collision layer for filtering collisions. + */ + struct CollisionLayer : public IComponent { + uint16_t layer = 0; // What layer this entity is on + uint16_t mask = 0xFFFF; // Which layers this entity collides with + + CollisionLayer() = default; + CollisionLayer(uint16_t l, uint16_t m) : layer(l), mask(m) {} + }; + + /** + * @brief Standard collision layer masks. + */ + namespace CollisionLayers { + constexpr uint16_t NONE = 0; + constexpr uint16_t PLAYER = 1 << 0; // 0x0001 + constexpr uint16_t ENEMY = 1 << 1; // 0x0002 + constexpr uint16_t PLAYER_BULLET = 1 << 2; // 0x0004 + constexpr uint16_t ENEMY_BULLET = 1 << 3; // 0x0008 + constexpr uint16_t OBSTACLE = 1 << 4; // 0x0010 + constexpr uint16_t POWERUP = 1 << 5; // 0x0020 + constexpr uint16_t GROUND = 1 << 6; // 0x0040 (for platformers) + constexpr uint16_t TRIGGER = 1 << 7; // 0x0080 (for trigger zones) + constexpr uint16_t ALL = 0xFFFF; + } + + /** + * @brief Collision event marker component. + */ + struct CollisionEvent : public IComponent { + Entity other = NULL_ENTITY; + + CollisionEvent() = default; + CollisionEvent(Entity e) : other(e) {} + }; + + /** + * @brief Static obstacle that blocks movement. + */ + struct Obstacle : public IComponent { + bool blocking = true; + + Obstacle() = default; + Obstacle(bool isBlocking) : blocking(isBlocking) {} + }; + + /** + * @brief Invincibility frames/state. + */ + struct Invincibility : public IComponent { + float remainingTime = 0.0f; + + Invincibility() = default; + Invincibility(float duration) : remainingTime(duration) {} + }; + + /** + * @brief 2D Rigidbody with physics properties (NEW for metroidvania). + */ + struct Rigidbody2D : public IComponent { + float mass = 1.0f; + float gravityScale = 1.0f; + float drag = 0.0f; + bool isKinematic = false; + bool isGrounded = false; + bool useGravity = true; + + Rigidbody2D() = default; + Rigidbody2D(float m, float gravity = 1.0f) + : mass(m), gravityScale(gravity) {} + }; + + /** + * @brief Physics material for collision response. + */ + struct PhysicsMaterial : public IComponent { + float friction = 0.5f; + float bounciness = 0.0f; + + PhysicsMaterial() = default; + PhysicsMaterial(float f, float b) : friction(f), bounciness(b) {} + }; + +} // namespace ECS +} // namespace RType diff --git a/engine/include/ECS/Components/Rendering.hpp b/engine/include/ECS/Components/Rendering.hpp new file mode 100644 index 0000000..bbd0fc1 --- /dev/null +++ b/engine/include/ECS/Components/Rendering.hpp @@ -0,0 +1,70 @@ +#pragma once +/** + * @file Rendering.hpp + * @brief Generic rendering components for any 2D game engine. + */ + +#include +#include "Renderer/IRenderer.hpp" +#include "Math/Types.hpp" +#include "ECS/Components/IComponent.hpp" + +namespace RType { +namespace ECS { + + /** + * @brief Sprite rendering component. + */ + struct Drawable : public IComponent { + Renderer::SpriteId spriteId = Renderer::INVALID_SPRITE_ID; + Math::Vector2 scale{1.0f, 1.0f}; + float rotation = 0.0f; + Math::Vector2 origin{0.0f, 0.0f}; + Math::Color tint{1.0f, 1.0f, 1.0f, 1.0f}; + int layer = 0; + + Drawable() = default; + Drawable(Renderer::SpriteId sprite, int renderLayer = 0) + : spriteId(sprite), layer(renderLayer) {} + }; + + /** + * @brief Visual damage flash effect. + */ + struct DamageFlash : public IComponent { + float duration = 0.1f; + float timeRemaining = 0.0f; + bool isActive = false; + + DamageFlash() = default; + DamageFlash(float flashDuration) : duration(flashDuration) {} + + void Trigger() { + isActive = true; + timeRemaining = duration; + } + }; + + /** + * @brief Floating text that animates upward and fades. + */ + struct FloatingText : public IComponent { + char text[32] = {}; + float lifetime = 0.0f; + float maxLifetime = 1.5f; + float velocityY = -50.0f; + float fadeStartTime = 0.5f; + Math::Color color{1.0f, 1.0f, 1.0f, 1.0f}; + + FloatingText() = default; + FloatingText(const char* txt, float duration, const Math::Color& col) + : maxLifetime(duration), color(col) { + if (txt) { + std::strncpy(text, txt, 31); + text[31] = '\0'; + } + } + }; + +} // namespace ECS +} // namespace RType diff --git a/libs/engine/include/ECS/Components/TextLabel.hpp b/engine/include/ECS/Components/TextLabel.hpp similarity index 100% rename from libs/engine/include/ECS/Components/TextLabel.hpp rename to engine/include/ECS/Components/TextLabel.hpp diff --git a/engine/include/ECS/Components/Transform.hpp b/engine/include/ECS/Components/Transform.hpp new file mode 100644 index 0000000..0d198c0 --- /dev/null +++ b/engine/include/ECS/Components/Transform.hpp @@ -0,0 +1,89 @@ +#pragma once +/** + * @file Transform.hpp + * @brief Generic transform-related components for any 2D/3D game engine. + * + * These components are game-agnostic and can be used by any project. + */ + +#include +#include "Math/Types.hpp" +#include "ECS/Entity.hpp" +#include "ECS/Components/IComponent.hpp" + +namespace RType { +namespace ECS { + + /** + * @brief 2D position component. + */ + struct Position : public IComponent { + float x = 0.0f; + float y = 0.0f; + + Position() = default; + Position(float x, float y) : x(x), y(y) {} + }; + + /** + * @brief 2D velocity component. + */ + struct Velocity : public IComponent { + float dx = 0.0f; + float dy = 0.0f; + + Velocity() = default; + Velocity(float dx, float dy) : dx(dx), dy(dy) {} + }; + + /** + * @brief Full 2D transform (position + rotation + scale). + * Use this when you need full transform capabilities. + */ + struct Transform2D : public IComponent { + Math::Vector2 position{0.0f, 0.0f}; + float rotation = 0.0f; + Math::Vector2 scale{1.0f, 1.0f}; + + Transform2D() = default; + Transform2D(float x, float y, float rot = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f) + : position{x, y}, rotation(rot), scale{scaleX, scaleY} {} + }; + + /** + * @brief Component for entities that can be controlled by input. + */ + struct Controllable : public IComponent { + float speed = 200.0f; + + Controllable() = default; + Controllable(float moveSpeed) : speed(moveSpeed) {} + }; + + /** + * @brief Indicates scrolling behavior for backgrounds/parallax. + */ + struct Scrollable : public IComponent { + float speed = -100.0f; + + Scrollable() = default; + Scrollable(float scrollSpeed) : speed(scrollSpeed) {} + }; + + /** + * @brief Stable network identifier for server->client entity mirroring. + * + * IMPORTANT: This must live on the entity as a component, because raw ECS + * entity IDs are recycled. If we map "ECS entity id -> network id" in a + * hash map, then destroying and reusing an ECS id in the same tick can + * cause a new entity to inherit the old network id (type confusion). + */ + struct NetworkId : public IComponent { + uint32_t id = 0; + + NetworkId() = default; + explicit NetworkId(uint32_t networkId) : id(networkId) {} + }; + +} // namespace ECS +} // namespace RType diff --git a/libs/engine/include/ECS/Entity.hpp b/engine/include/ECS/Entity.hpp similarity index 100% rename from libs/engine/include/ECS/Entity.hpp rename to engine/include/ECS/Entity.hpp diff --git a/libs/engine/include/ECS/HealthSystem.hpp b/engine/include/ECS/HealthSystem.hpp similarity index 100% rename from libs/engine/include/ECS/HealthSystem.hpp rename to engine/include/ECS/HealthSystem.hpp diff --git a/libs/engine/include/ECS/ISystem.hpp b/engine/include/ECS/ISystem.hpp similarity index 100% rename from libs/engine/include/ECS/ISystem.hpp rename to engine/include/ECS/ISystem.hpp diff --git a/libs/engine/include/ECS/InputSystem.hpp b/engine/include/ECS/InputSystem.hpp similarity index 100% rename from libs/engine/include/ECS/InputSystem.hpp rename to engine/include/ECS/InputSystem.hpp diff --git a/libs/engine/include/ECS/MenuSystem.hpp b/engine/include/ECS/MenuSystem.hpp similarity index 100% rename from libs/engine/include/ECS/MenuSystem.hpp rename to engine/include/ECS/MenuSystem.hpp diff --git a/libs/engine/include/ECS/MovementSystem.hpp b/engine/include/ECS/MovementSystem.hpp similarity index 100% rename from libs/engine/include/ECS/MovementSystem.hpp rename to engine/include/ECS/MovementSystem.hpp diff --git a/libs/engine/include/ECS/Registry.hpp b/engine/include/ECS/Registry.hpp similarity index 97% rename from libs/engine/include/ECS/Registry.hpp rename to engine/include/ECS/Registry.hpp index 3f0e4e6..e4451df 100644 --- a/libs/engine/include/ECS/Registry.hpp +++ b/engine/include/ECS/Registry.hpp @@ -22,6 +22,7 @@ namespace RType { virtual ~IComponentPool() = default; virtual bool Has(Entity entity) const = 0; virtual void Remove(Entity entity) = 0; + virtual void Clear() = 0; }; template @@ -32,6 +33,7 @@ namespace RType { const T& Get(Entity entity) const; bool Has(Entity entity) const override; void Remove(Entity entity) override; + void Clear() override; std::vector GetEntities() const; private: SparseArray m_components; @@ -64,6 +66,7 @@ namespace RType { template std::vector GetEntitiesWithComponent() const; size_t GetEntityCount() const { return m_entityCount; } + void Clear(); private: template ComponentPool* GetOrCreatePool(); @@ -119,6 +122,11 @@ namespace RType { m_components.erase(entity); } + template + void ComponentPool::Clear() { + m_components.clear(); + } + template std::vector ComponentPool::GetEntities() const { std::vector entities; diff --git a/libs/engine/include/ECS/RenderingSystem.hpp b/engine/include/ECS/RenderingSystem.hpp similarity index 100% rename from libs/engine/include/ECS/RenderingSystem.hpp rename to engine/include/ECS/RenderingSystem.hpp diff --git a/libs/engine/include/ECS/ScoreSystem.hpp b/engine/include/ECS/ScoreSystem.hpp similarity index 100% rename from libs/engine/include/ECS/ScoreSystem.hpp rename to engine/include/ECS/ScoreSystem.hpp diff --git a/libs/engine/include/ECS/ScrollingSystem.hpp b/engine/include/ECS/ScrollingSystem.hpp similarity index 100% rename from libs/engine/include/ECS/ScrollingSystem.hpp rename to engine/include/ECS/ScrollingSystem.hpp diff --git a/libs/engine/include/ECS/SparseArray.hpp b/engine/include/ECS/SparseArray.hpp similarity index 100% rename from libs/engine/include/ECS/SparseArray.hpp rename to engine/include/ECS/SparseArray.hpp diff --git a/libs/engine/include/ECS/TextRenderingSystem.hpp b/engine/include/ECS/TextRenderingSystem.hpp similarity index 100% rename from libs/engine/include/ECS/TextRenderingSystem.hpp rename to engine/include/ECS/TextRenderingSystem.hpp diff --git a/libs/engine/include/Math/Types.hpp b/engine/include/Math/Types.hpp similarity index 100% rename from libs/engine/include/Math/Types.hpp rename to engine/include/Math/Types.hpp diff --git a/libs/engine/include/Physics/IPhysics.hpp b/engine/include/Physics/IPhysics.hpp similarity index 100% rename from libs/engine/include/Physics/IPhysics.hpp rename to engine/include/Physics/IPhysics.hpp diff --git a/libs/engine/include/Renderer/IRenderer.hpp b/engine/include/Renderer/IRenderer.hpp similarity index 97% rename from libs/engine/include/Renderer/IRenderer.hpp rename to engine/include/Renderer/IRenderer.hpp index 6012dfb..e30759e 100644 --- a/libs/engine/include/Renderer/IRenderer.hpp +++ b/engine/include/Renderer/IRenderer.hpp @@ -118,6 +118,12 @@ namespace Renderer { RAlt }; + enum class MouseButton { + Left, + Right, + Middle + }; + class IRenderer : public RType::Core::IModule { public: ~IRenderer() override = default; @@ -131,6 +137,7 @@ namespace Renderer { virtual bool CreateWindow(const WindowConfig& config) = 0; virtual void Destroy() = 0; virtual bool IsWindowOpen() const = 0; + virtual Vector2 GetWindowSize() const = 0; virtual void Resize(std::uint32_t width, std::uint32_t height) = 0; virtual void SetWindowTitle(const std::string& title) = 0; @@ -166,11 +173,6 @@ namespace Renderer { virtual bool IsKeyPressed(Key key) const = 0; - enum class MouseButton { - Left, - Right, - Middle - }; virtual bool IsMouseButtonPressed(MouseButton button) const = 0; virtual Vector2 GetMousePosition() const = 0; }; diff --git a/libs/engine/include/Renderer/SFMLRenderer.hpp b/engine/include/Renderer/SFMLRenderer.hpp similarity index 98% rename from libs/engine/include/Renderer/SFMLRenderer.hpp rename to engine/include/Renderer/SFMLRenderer.hpp index 3d8edd1..f95e1f0 100644 --- a/libs/engine/include/Renderer/SFMLRenderer.hpp +++ b/engine/include/Renderer/SFMLRenderer.hpp @@ -22,6 +22,7 @@ namespace Renderer { bool CreateWindow(const WindowConfig& config) override; void Destroy() override; bool IsWindowOpen() const override; + Vector2 GetWindowSize() const override; void Resize(std::uint32_t width, std::uint32_t height) override; void SetWindowTitle(const std::string& title) override; diff --git a/libs/engine/src/Animation/AnimationModule.cpp b/engine/src/Animation/AnimationModule.cpp similarity index 100% rename from libs/engine/src/Animation/AnimationModule.cpp rename to engine/src/Animation/AnimationModule.cpp diff --git a/libs/engine/src/Animation/CMakeLists.txt b/engine/src/Animation/CMakeLists.txt similarity index 100% rename from libs/engine/src/Animation/CMakeLists.txt rename to engine/src/Animation/CMakeLists.txt diff --git a/libs/engine/src/Audio/CMakeLists.txt b/engine/src/Audio/CMakeLists.txt similarity index 100% rename from libs/engine/src/Audio/CMakeLists.txt rename to engine/src/Audio/CMakeLists.txt diff --git a/libs/engine/src/Audio/SFMLAudio.cpp b/engine/src/Audio/SFMLAudio.cpp similarity index 100% rename from libs/engine/src/Audio/SFMLAudio.cpp rename to engine/src/Audio/SFMLAudio.cpp diff --git a/libs/engine/src/Core/CMakeLists.txt b/engine/src/Core/CMakeLists.txt similarity index 96% rename from libs/engine/src/Core/CMakeLists.txt rename to engine/src/Core/CMakeLists.txt index da61b84..ac0db2b 100644 --- a/libs/engine/src/Core/CMakeLists.txt +++ b/engine/src/Core/CMakeLists.txt @@ -3,6 +3,8 @@ set(CORE_SOURCES ModuleLoader.cpp ColorFilter.cpp InputMapping.cpp + InputManager.cpp + SceneManager.cpp ) set(CORE_HEADERS diff --git a/libs/engine/src/Core/ColorFilter.cpp b/engine/src/Core/ColorFilter.cpp similarity index 100% rename from libs/engine/src/Core/ColorFilter.cpp rename to engine/src/Core/ColorFilter.cpp diff --git a/libs/engine/src/Core/Engine.cpp b/engine/src/Core/Engine.cpp similarity index 93% rename from libs/engine/src/Core/Engine.cpp rename to engine/src/Core/Engine.cpp index 9c91b1d..6c5c0ea 100644 --- a/libs/engine/src/Core/Engine.cpp +++ b/engine/src/Core/Engine.cpp @@ -1,4 +1,5 @@ #include "../../include/Core/Engine.hpp" +#include "../../include/Renderer/IRenderer.hpp" #include namespace RType { @@ -6,8 +7,9 @@ namespace RType { namespace Core { Engine::Engine(const EngineConfig& config) - : m_config(config) { + : m_config(config), m_sceneManager(&m_registry) { Logger::Info("Creating R-Type Engine"); + m_inputManager.loadDefaults(); } Engine::~Engine() { @@ -140,6 +142,12 @@ namespace RType { } void Engine::UpdateSystems(float deltaTime) { + // Update input manager first + auto renderer = GetModule(); + if (renderer) { + m_inputManager.update(renderer); + } + for (auto& system : m_systems) { system->Update(m_registry, deltaTime); } diff --git a/engine/src/Core/InputManager.cpp b/engine/src/Core/InputManager.cpp new file mode 100644 index 0000000..1e3ffe8 --- /dev/null +++ b/engine/src/Core/InputManager.cpp @@ -0,0 +1,124 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type Engine +** File description: +** InputManager implementation +*/ + +#include "Core/InputManager.hpp" + +namespace RType { + + namespace Core { + + void InputManager::bindAction(const std::string& action, Renderer::Key key) { + ActionBinding binding; + binding.key = key; + binding.isMouseBinding = false; + m_actions[action] = binding; + } + + void InputManager::bindActionMouse(const std::string& action, Renderer::MouseButton button) { + ActionBinding binding; + binding.mouseButton = button; + binding.isMouseBinding = true; + m_actions[action] = binding; + } + + void InputManager::unbindAction(const std::string& action) { + m_actions.erase(action); + } + + bool InputManager::isActionPressed(const std::string& action) const { + auto it = m_actions.find(action); + if (it == m_actions.end()) { + return false; + } + return it->second.currentlyPressed; + } + + bool InputManager::isActionJustPressed(const std::string& action) const { + auto it = m_actions.find(action); + if (it == m_actions.end()) { + return false; + } + return it->second.currentlyPressed && !it->second.wasPressed; + } + + bool InputManager::isActionJustReleased(const std::string& action) const { + auto it = m_actions.find(action); + if (it == m_actions.end()) { + return false; + } + return !it->second.currentlyPressed && it->second.wasPressed; + } + + void InputManager::bindAxis(const std::string& axis, Renderer::Key negative, Renderer::Key positive) { + AxisBinding binding; + binding.negative = negative; + binding.positive = positive; + m_axes[axis] = binding; + } + + void InputManager::unbindAxis(const std::string& axis) { + m_axes.erase(axis); + } + + float InputManager::getAxisValue(const std::string& axis) const { + auto it = m_axes.find(axis); + if (it == m_axes.end() || m_renderer == nullptr) { + return 0.0F; + } + + float value = 0.0F; + if (m_renderer->IsKeyPressed(it->second.negative)) { + value -= 1.0F; + } + if (m_renderer->IsKeyPressed(it->second.positive)) { + value += 1.0F; + } + return value; + } + + void InputManager::update(Renderer::IRenderer* renderer) { + m_renderer = renderer; + if (m_renderer == nullptr) { + return; + } + + for (auto& [name, binding] : m_actions) { + binding.wasPressed = binding.currentlyPressed; + + if (binding.isMouseBinding) { + binding.currentlyPressed = m_renderer->IsMouseButtonPressed(binding.mouseButton); + } else { + binding.currentlyPressed = m_renderer->IsKeyPressed(binding.key); + } + } + } + + void InputManager::clearBindings() { + m_actions.clear(); + m_axes.clear(); + } + + void InputManager::loadDefaults() { + // Movement + bindAction("MoveLeft", Renderer::Key::A); + bindAction("MoveRight", Renderer::Key::D); + bindAction("MoveUp", Renderer::Key::W); + bindAction("MoveDown", Renderer::Key::S); + + // Movement axes + bindAxis("MoveX", Renderer::Key::A, Renderer::Key::D); + bindAxis("MoveY", Renderer::Key::S, Renderer::Key::W); // S=up (positive Y), W=down + + // Actions + bindAction("Jump", Renderer::Key::Space); + bindActionMouse("Shoot", Renderer::MouseButton::Left); + bindAction("Pause", Renderer::Key::Escape); + } + + } + +} diff --git a/libs/engine/src/Core/InputMapping.cpp b/engine/src/Core/InputMapping.cpp similarity index 100% rename from libs/engine/src/Core/InputMapping.cpp rename to engine/src/Core/InputMapping.cpp diff --git a/libs/engine/src/Core/ModuleLoader.cpp b/engine/src/Core/ModuleLoader.cpp similarity index 100% rename from libs/engine/src/Core/ModuleLoader.cpp rename to engine/src/Core/ModuleLoader.cpp diff --git a/engine/src/Core/SceneManager.cpp b/engine/src/Core/SceneManager.cpp new file mode 100644 index 0000000..3dc4e00 --- /dev/null +++ b/engine/src/Core/SceneManager.cpp @@ -0,0 +1,109 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type Engine +** File description: +** SceneManager implementation +*/ + +#include "Core/SceneManager.hpp" +#include "Core/Logger.hpp" + +namespace RType { + + namespace Core { + + SceneManager::SceneManager(ECS::Registry* registry) + : m_registry(registry) {} + + void SceneManager::RegisterScene(const std::string& sceneName, + SceneSetupFn setup, + SceneTeardownFn teardown) { + if (!setup) { + Logger::Warning("SceneManager: Cannot register scene '{}' with null setup function", sceneName); + return; + } + + m_scenes[sceneName] = SceneData{std::move(setup), std::move(teardown)}; + Logger::Info("SceneManager: Registered scene '{}'", sceneName); + } + + bool SceneManager::LoadScene(const std::string& sceneName) { + auto it = m_scenes.find(sceneName); + if (it == m_scenes.end()) { + Logger::Error("SceneManager: Scene '{}' not registered", sceneName); + return false; + } + + return LoadScene(sceneName, it->second.setup); + } + + bool SceneManager::LoadScene(const std::string& sceneName, SceneSetupFn setup) { + if (!m_registry) { + Logger::Error("SceneManager: No registry set"); + return false; + } + + if (!setup) { + Logger::Error("SceneManager: Setup function is null"); + return false; + } + + // Unload current scene first + UnloadCurrentScene(); + + // Store teardown for later if scene is registered + auto it = m_scenes.find(sceneName); + if (it != m_scenes.end()) { + m_currentTeardown = it->second.teardown; + } else { + m_currentTeardown = nullptr; + } + + // Set current scene + m_currentScene = sceneName; + + // Call setup function + Logger::Info("SceneManager: Loading scene '{}'", sceneName); + setup(*m_registry); + + return true; + } + + void SceneManager::UnloadCurrentScene() { + if (m_currentScene.empty() || !m_registry) { + return; + } + + Logger::Info("SceneManager: Unloading scene '{}'", m_currentScene); + + // Call teardown if registered + if (m_currentTeardown) { + m_currentTeardown(*m_registry); + } + + // Clear the registry (destroy all entities) + m_registry->Clear(); + + m_currentScene.clear(); + m_currentTeardown = nullptr; + } + + bool SceneManager::TransitionTo(const std::string& sceneName) { + return LoadScene(sceneName); + } + + bool SceneManager::IsSceneRegistered(const std::string& sceneName) const { + return m_scenes.find(sceneName) != m_scenes.end(); + } + + void SceneManager::UnregisterScene(const std::string& sceneName) { + m_scenes.erase(sceneName); + } + + void SceneManager::ClearScenes() { + m_scenes.clear(); + } + + } + +} diff --git a/libs/engine/src/ECS/AnimationSystem.cpp b/engine/src/ECS/AnimationSystem.cpp similarity index 100% rename from libs/engine/src/ECS/AnimationSystem.cpp rename to engine/src/ECS/AnimationSystem.cpp diff --git a/libs/engine/src/ECS/AudioSystem.cpp b/engine/src/ECS/AudioSystem.cpp similarity index 100% rename from libs/engine/src/ECS/AudioSystem.cpp rename to engine/src/ECS/AudioSystem.cpp diff --git a/engine/src/ECS/CMakeLists.txt b/engine/src/ECS/CMakeLists.txt new file mode 100644 index 0000000..1d63e97 --- /dev/null +++ b/engine/src/ECS/CMakeLists.txt @@ -0,0 +1,75 @@ +# ECS CMakeLists.txt +# +# This builds the core ECS library (game-agnostic). +# R-Type specific systems have been moved to games/rtype/ + +# ============================================================================= +# Generic ECS Core Library (game-agnostic) +# ============================================================================= +set(ECS_CORE_SOURCES + Registry.cpp + MovementSystem.cpp + RenderingSystem.cpp + TextRenderingSystem.cpp + CollisionDetectionSystem.cpp + ScrollingSystem.cpp + AnimationSystem.cpp + AudioSystem.cpp + InputSystem.cpp + MenuSystem.cpp + HealthSystem.cpp + ScoreSystem.cpp + Camera2DSystem.cpp +) + +set(ECS_CORE_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Entity.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Registry.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/ISystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/SparseArray.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Component.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Components/IComponent.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Components/Transform.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Components/Rendering.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Components/Physics.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Components/Audio.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Components/Animation.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Components/Gameplay.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Components/TextLabel.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Components/Clickable.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/MovementSystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/RenderingSystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/TextRenderingSystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/CollisionDetectionSystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/ScrollingSystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/AnimationSystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/AudioSystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/InputSystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/MenuSystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/HealthSystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/ScoreSystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Camera2DSystem.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Components/Camera2D.hpp +) + +add_library(rtype_ecs_core STATIC + ${ECS_CORE_SOURCES} + ${ECS_CORE_HEADERS} +) + +target_include_directories(rtype_ecs_core PUBLIC + $ + $ +) + +target_link_libraries(rtype_ecs_core PUBLIC nlohmann_json::nlohmann_json rtype_animation) + +set_target_properties(rtype_ecs_core PROPERTIES + POSITION_INDEPENDENT_CODE ON +) + +# ============================================================================= +# Legacy rtype_ecs library (alias to rtype_ecs_core for backwards compatibility) +# ============================================================================= +# Note: R-Type specific systems are now in games/rtype/systems/ and built as rtype_game +add_library(rtype_ecs ALIAS rtype_ecs_core) diff --git a/engine/src/ECS/Camera2DSystem.cpp b/engine/src/ECS/Camera2DSystem.cpp new file mode 100644 index 0000000..30fc6b3 --- /dev/null +++ b/engine/src/ECS/Camera2DSystem.cpp @@ -0,0 +1,135 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type Engine +** File description: +** Camera2DSystem implementation +*/ + +#include "ECS/Camera2DSystem.hpp" +#include "ECS/Registry.hpp" +#include "ECS/Components/Camera2D.hpp" +#include "ECS/Components/Transform.hpp" +#include "Math/Types.hpp" +#include +#include +#include + +namespace RType { + + namespace ECS { + + Camera2DSystem::Camera2DSystem(Renderer::IRenderer* renderer) + : m_renderer(renderer) { + if (m_renderer) { + Math::Vector2 size = m_renderer->GetWindowSize(); + m_screenSize = size; + } + } + + void Camera2DSystem::Update(Registry& registry, float deltaTime) { + auto cameras = registry.GetEntitiesWithComponent(); + + for (Entity cameraEntity : cameras) { + auto& camera = registry.GetComponent(cameraEntity); + + if (!camera.active) { + continue; + } + + // Calculate target position + Math::Vector2 targetPos = camera.position; + + if (camera.target != NULL_ENTITY && registry.HasComponent(camera.target)) { + auto& targetTransform = registry.GetComponent(camera.target); + targetPos.x = targetTransform.x + camera.offset.x; + targetPos.y = targetTransform.y + camera.offset.y; + } + + // Smooth interpolation + if (camera.smoothSpeed > 0.0f) { + float t = 1.0f - std::exp(-camera.smoothSpeed * deltaTime); + camera.position = Lerp(camera.position, targetPos, t); + } else { + camera.position = targetPos; + } + + // Apply bounds clamping + if (camera.HasBounds()) { + camera.position = Clamp(camera.position, camera.boundsMin, camera.boundsMax); + } + + // Update screen shake + Math::Vector2 shakeOffset{0.0f, 0.0f}; + if (camera.shakeDuration > 0.0f) { + shakeOffset = GetShakeOffset(camera.shakeIntensity); + camera.shakeDuration -= deltaTime; + if (camera.shakeDuration <= 0.0f) { + camera.shakeIntensity = 0.0f; + } + } + + // Store final camera position (with shake) + m_cameraPosition = camera.position; + m_cameraPosition.x += shakeOffset.x; + m_cameraPosition.y += shakeOffset.y; + m_zoom = camera.zoom; + + // Update renderer viewport if available + if (m_renderer) { + m_screenSize = m_renderer->GetWindowSize(); + + Renderer::Camera2D renderCam; + renderCam.center = m_cameraPosition; + renderCam.size.x = m_screenSize.x / m_zoom; + renderCam.size.y = m_screenSize.y / m_zoom; + + m_renderer->SetCamera(renderCam); + } + + // Only process first active camera + break; + } + } + + Math::Vector2 Camera2DSystem::ScreenToWorld(const Math::Vector2& screenPos) const { + Math::Vector2 worldPos; + worldPos.x = (screenPos.x / m_zoom) + m_cameraPosition.x - (m_screenSize.x / (2.0f * m_zoom)); + worldPos.y = (screenPos.y / m_zoom) + m_cameraPosition.y - (m_screenSize.y / (2.0f * m_zoom)); + return worldPos; + } + + Math::Vector2 Camera2DSystem::WorldToScreen(const Math::Vector2& worldPos) const { + Math::Vector2 screenPos; + screenPos.x = (worldPos.x - m_cameraPosition.x + (m_screenSize.x / (2.0f * m_zoom))) * m_zoom; + screenPos.y = (worldPos.y - m_cameraPosition.y + (m_screenSize.y / (2.0f * m_zoom))) * m_zoom; + return screenPos; + } + + Math::Vector2 Camera2DSystem::Lerp(const Math::Vector2& a, const Math::Vector2& b, float t) const { + return Math::Vector2{ + a.x + (b.x - a.x) * t, + a.y + (b.y - a.y) * t + }; + } + + Math::Vector2 Camera2DSystem::Clamp(const Math::Vector2& value, const Math::Vector2& min, const Math::Vector2& max) const { + return Math::Vector2{ + std::clamp(value.x, min.x, max.x), + std::clamp(value.y, min.y, max.y) + }; + } + + Math::Vector2 Camera2DSystem::GetShakeOffset(float intensity) const { + static std::random_device rd; + static std::mt19937 gen(rd()); + std::uniform_real_distribution dist(-1.0f, 1.0f); + + return Math::Vector2{ + dist(gen) * intensity, + dist(gen) * intensity + }; + } + + } + +} diff --git a/libs/engine/src/ECS/CollisionDetectionSystem.cpp b/engine/src/ECS/CollisionDetectionSystem.cpp similarity index 100% rename from libs/engine/src/ECS/CollisionDetectionSystem.cpp rename to engine/src/ECS/CollisionDetectionSystem.cpp diff --git a/libs/engine/src/ECS/HealthSystem.cpp b/engine/src/ECS/HealthSystem.cpp similarity index 100% rename from libs/engine/src/ECS/HealthSystem.cpp rename to engine/src/ECS/HealthSystem.cpp diff --git a/libs/engine/src/ECS/InputSystem.cpp b/engine/src/ECS/InputSystem.cpp similarity index 100% rename from libs/engine/src/ECS/InputSystem.cpp rename to engine/src/ECS/InputSystem.cpp diff --git a/libs/engine/src/ECS/MenuSystem.cpp b/engine/src/ECS/MenuSystem.cpp similarity index 98% rename from libs/engine/src/ECS/MenuSystem.cpp rename to engine/src/ECS/MenuSystem.cpp index 9b3d9d1..6bade0a 100644 --- a/libs/engine/src/ECS/MenuSystem.cpp +++ b/engine/src/ECS/MenuSystem.cpp @@ -14,7 +14,7 @@ namespace RType { return; Renderer::Vector2 mousePos = m_renderer->GetMousePosition(); - bool isMouseDown = m_renderer->IsMouseButtonPressed(Renderer::IRenderer::MouseButton::Left); + bool isMouseDown = m_renderer->IsMouseButtonPressed(Renderer::MouseButton::Left); auto entities = registry.GetEntitiesWithComponent(); diff --git a/libs/engine/src/ECS/MovementSystem.cpp b/engine/src/ECS/MovementSystem.cpp similarity index 100% rename from libs/engine/src/ECS/MovementSystem.cpp rename to engine/src/ECS/MovementSystem.cpp diff --git a/libs/engine/src/ECS/Registry.cpp b/engine/src/ECS/Registry.cpp similarity index 90% rename from libs/engine/src/ECS/Registry.cpp rename to engine/src/ECS/Registry.cpp index 96525e9..063b111 100644 --- a/libs/engine/src/ECS/Registry.cpp +++ b/engine/src/ECS/Registry.cpp @@ -75,6 +75,16 @@ namespace RType { return m_aliveEntities.find(entity) != m_aliveEntities.end(); } + void Registry::Clear() { + for (auto& [id, pool] : m_componentPools) { + pool->Clear(); + } + m_aliveEntities.clear(); + m_freeEntityIds.clear(); + m_nextEntityID = 1; + m_entityCount = 0; + } + } } diff --git a/libs/engine/src/ECS/RenderingSystem.cpp b/engine/src/ECS/RenderingSystem.cpp similarity index 100% rename from libs/engine/src/ECS/RenderingSystem.cpp rename to engine/src/ECS/RenderingSystem.cpp diff --git a/libs/engine/src/ECS/ScoreSystem.cpp b/engine/src/ECS/ScoreSystem.cpp similarity index 100% rename from libs/engine/src/ECS/ScoreSystem.cpp rename to engine/src/ECS/ScoreSystem.cpp diff --git a/libs/engine/src/ECS/ScrollingSystem.cpp b/engine/src/ECS/ScrollingSystem.cpp similarity index 100% rename from libs/engine/src/ECS/ScrollingSystem.cpp rename to engine/src/ECS/ScrollingSystem.cpp diff --git a/libs/engine/src/ECS/TextRenderingSystem.cpp b/engine/src/ECS/TextRenderingSystem.cpp similarity index 100% rename from libs/engine/src/ECS/TextRenderingSystem.cpp rename to engine/src/ECS/TextRenderingSystem.cpp diff --git a/libs/engine/src/Renderer/CMakeLists.txt b/engine/src/Renderer/CMakeLists.txt similarity index 100% rename from libs/engine/src/Renderer/CMakeLists.txt rename to engine/src/Renderer/CMakeLists.txt diff --git a/libs/engine/src/Renderer/SFMLRenderer.cpp b/engine/src/Renderer/SFMLRenderer.cpp similarity index 98% rename from libs/engine/src/Renderer/SFMLRenderer.cpp rename to engine/src/Renderer/SFMLRenderer.cpp index c7b7fe9..0c53199 100644 --- a/libs/engine/src/Renderer/SFMLRenderer.cpp +++ b/engine/src/Renderer/SFMLRenderer.cpp @@ -103,6 +103,14 @@ namespace Renderer { return m_window && m_window->isOpen(); } + Vector2 SFMLRenderer::GetWindowSize() const { + if (!m_window) { + return {0.0f, 0.0f}; + } + sf::Vector2u size = m_window->getSize(); + return {static_cast(size.x), static_cast(size.y)}; + } + void SFMLRenderer::Resize(std::uint32_t width, std::uint32_t height) { if (!m_window) { RType::Core::Logger::Warning("Cannot resize: window not created"); diff --git a/libs/engine/src/main.cpp b/engine/src/main.cpp similarity index 100% rename from libs/engine/src/main.cpp rename to engine/src/main.cpp diff --git a/breakout/README.md b/games/breakout/README.md similarity index 100% rename from breakout/README.md rename to games/breakout/README.md diff --git a/breakout/include/BallAccelerationSystem.hpp b/games/breakout/include/BallAccelerationSystem.hpp similarity index 100% rename from breakout/include/BallAccelerationSystem.hpp rename to games/breakout/include/BallAccelerationSystem.hpp diff --git a/breakout/include/BreakoutPhysicsSystem.hpp b/games/breakout/include/BreakoutPhysicsSystem.hpp similarity index 100% rename from breakout/include/BreakoutPhysicsSystem.hpp rename to games/breakout/include/BreakoutPhysicsSystem.hpp diff --git a/breakout/include/BreakoutRenderSystem.hpp b/games/breakout/include/BreakoutRenderSystem.hpp similarity index 100% rename from breakout/include/BreakoutRenderSystem.hpp rename to games/breakout/include/BreakoutRenderSystem.hpp diff --git a/breakout/src/BallAccelerationSystem.cpp b/games/breakout/src/BallAccelerationSystem.cpp similarity index 100% rename from breakout/src/BallAccelerationSystem.cpp rename to games/breakout/src/BallAccelerationSystem.cpp diff --git a/breakout/src/BreakoutPhysicsSystem.cpp b/games/breakout/src/BreakoutPhysicsSystem.cpp similarity index 100% rename from breakout/src/BreakoutPhysicsSystem.cpp rename to games/breakout/src/BreakoutPhysicsSystem.cpp diff --git a/breakout/src/BreakoutRenderSystem.cpp b/games/breakout/src/BreakoutRenderSystem.cpp similarity index 100% rename from breakout/src/BreakoutRenderSystem.cpp rename to games/breakout/src/BreakoutRenderSystem.cpp diff --git a/breakout/src/main.cpp b/games/breakout/src/main.cpp similarity index 100% rename from breakout/src/main.cpp rename to games/breakout/src/main.cpp diff --git a/games/rtype/CMakeLists.txt b/games/rtype/CMakeLists.txt new file mode 100644 index 0000000..b49b644 --- /dev/null +++ b/games/rtype/CMakeLists.txt @@ -0,0 +1,65 @@ +# R-Type Game - Systems and Factories +# +# This builds R-Type specific systems as a library that extends rtype_ecs_core. + +set(RTYPE_SYSTEMS_SOURCES + systems/PlayerSystem.cpp + systems/PlayerFactory.cpp + systems/BulletCollisionResponseSystem.cpp + systems/PlayerCollisionResponseSystem.cpp + systems/ObstacleCollisionResponseSystem.cpp + systems/EnemySystem.cpp + systems/EnemyFactory.cpp + systems/ShootingSystem.cpp + systems/LevelLoader.cpp + systems/PowerUpFactory.cpp + systems/PowerUpSpawnSystem.cpp + systems/PowerUpCollisionSystem.cpp + systems/ForcePodSystem.cpp + systems/ShieldSystem.cpp + systems/BossSystem.cpp + systems/BossAttackSystem.cpp + systems/MineSystem.cpp + systems/BlackOrbSystem.cpp + systems/ThirdBulletSystem.cpp + systems/EffectFactory.cpp +) + +set(RTYPE_SYSTEMS_HEADERS + include/PlayerSystem.hpp + include/PlayerFactory.hpp + include/BulletCollisionResponseSystem.hpp + include/PlayerCollisionResponseSystem.hpp + include/ObstacleCollisionResponseSystem.hpp + include/EnemySystem.hpp + include/EnemyFactory.hpp + include/ShootingSystem.hpp + include/LevelLoader.hpp + include/PowerUpFactory.hpp + include/PowerUpSpawnSystem.hpp + include/PowerUpCollisionSystem.hpp + include/ForcePodSystem.hpp + include/ShieldSystem.hpp + include/BossSystem.hpp + include/BossAttackSystem.hpp + include/MineSystem.hpp + include/BlackOrbSystem.hpp + include/ThirdBulletSystem.hpp + include/EffectFactory.hpp +) + +add_library(rtype_game STATIC + ${RTYPE_SYSTEMS_SOURCES} + ${RTYPE_SYSTEMS_HEADERS} +) + +target_include_directories(rtype_game PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/../../engine/include +) + +target_link_libraries(rtype_game PUBLIC rtype_ecs_core rtype_animation) + +set_target_properties(rtype_game PROPERTIES + POSITION_INDEPENDENT_CODE ON +) diff --git a/client/include/EditorState.hpp b/games/rtype/client/include/EditorState.hpp similarity index 100% rename from client/include/EditorState.hpp rename to games/rtype/client/include/EditorState.hpp diff --git a/client/include/GameState.hpp b/games/rtype/client/include/GameState.hpp similarity index 97% rename from client/include/GameState.hpp rename to games/rtype/client/include/GameState.hpp index b9575cf..72d8dbb 100644 --- a/client/include/GameState.hpp +++ b/games/rtype/client/include/GameState.hpp @@ -12,25 +12,25 @@ #include "ECS/RenderingSystem.hpp" #include "ECS/TextRenderingSystem.hpp" #include "ECS/ScrollingSystem.hpp" -#include "ECS/ShootingSystem.hpp" +#include "ShootingSystem.hpp" #include "ECS/MovementSystem.hpp" #include "ECS/InputSystem.hpp" #include "ECS/CollisionDetectionSystem.hpp" -#include "ECS/BulletCollisionResponseSystem.hpp" -#include "ECS/PlayerCollisionResponseSystem.hpp" -#include "ECS/ObstacleCollisionResponseSystem.hpp" +#include "BulletCollisionResponseSystem.hpp" +#include "PlayerCollisionResponseSystem.hpp" +#include "ObstacleCollisionResponseSystem.hpp" #include "ECS/HealthSystem.hpp" #include "ECS/ScoreSystem.hpp" -#include "ECS/ShieldSystem.hpp" -#include "ECS/ForcePodSystem.hpp" -#include "ECS/PowerUpSpawnSystem.hpp" -#include "ECS/PowerUpCollisionSystem.hpp" +#include "ShieldSystem.hpp" +#include "ForcePodSystem.hpp" +#include "PowerUpSpawnSystem.hpp" +#include "PowerUpCollisionSystem.hpp" #include "ECS/AudioSystem.hpp" #include "ECS/AnimationSystem.hpp" -#include "ECS/EffectFactory.hpp" +#include "EffectFactory.hpp" #include "ECS/Component.hpp" -#include "ECS/PowerUpFactory.hpp" -#include "ECS/LevelLoader.hpp" +#include "PowerUpFactory.hpp" +#include "LevelLoader.hpp" #include "Animation/AnimationModule.hpp" #include "Renderer/IRenderer.hpp" diff --git a/client/include/GameStateMachine.hpp b/games/rtype/client/include/GameStateMachine.hpp similarity index 100% rename from client/include/GameStateMachine.hpp rename to games/rtype/client/include/GameStateMachine.hpp diff --git a/client/include/LobbyState.hpp b/games/rtype/client/include/LobbyState.hpp similarity index 100% rename from client/include/LobbyState.hpp rename to games/rtype/client/include/LobbyState.hpp diff --git a/client/include/MenuState.hpp b/games/rtype/client/include/MenuState.hpp similarity index 100% rename from client/include/MenuState.hpp rename to games/rtype/client/include/MenuState.hpp diff --git a/client/include/ResultsState.hpp b/games/rtype/client/include/ResultsState.hpp similarity index 100% rename from client/include/ResultsState.hpp rename to games/rtype/client/include/ResultsState.hpp diff --git a/client/include/RoomListState.hpp b/games/rtype/client/include/RoomListState.hpp similarity index 100% rename from client/include/RoomListState.hpp rename to games/rtype/client/include/RoomListState.hpp diff --git a/client/include/SettingsState.hpp b/games/rtype/client/include/SettingsState.hpp similarity index 100% rename from client/include/SettingsState.hpp rename to games/rtype/client/include/SettingsState.hpp diff --git a/client/include/editor/EditorAssetLibrary.hpp b/games/rtype/client/include/editor/EditorAssetLibrary.hpp similarity index 100% rename from client/include/editor/EditorAssetLibrary.hpp rename to games/rtype/client/include/editor/EditorAssetLibrary.hpp diff --git a/client/include/editor/EditorCanvasManager.hpp b/games/rtype/client/include/editor/EditorCanvasManager.hpp similarity index 100% rename from client/include/editor/EditorCanvasManager.hpp rename to games/rtype/client/include/editor/EditorCanvasManager.hpp diff --git a/client/include/editor/EditorColliderManager.hpp b/games/rtype/client/include/editor/EditorColliderManager.hpp similarity index 98% rename from client/include/editor/EditorColliderManager.hpp rename to games/rtype/client/include/editor/EditorColliderManager.hpp index 11fb700..01aa777 100644 --- a/client/include/editor/EditorColliderManager.hpp +++ b/games/rtype/client/include/editor/EditorColliderManager.hpp @@ -8,7 +8,7 @@ #pragma once #include "editor/EditorTypes.hpp" -#include "ECS/LevelLoader.hpp" +#include "LevelLoader.hpp" #include "Renderer/IRenderer.hpp" #include "Math/Types.hpp" #include diff --git a/client/include/editor/EditorConstants.hpp b/games/rtype/client/include/editor/EditorConstants.hpp similarity index 100% rename from client/include/editor/EditorConstants.hpp rename to games/rtype/client/include/editor/EditorConstants.hpp diff --git a/client/include/editor/EditorDrawing.hpp b/games/rtype/client/include/editor/EditorDrawing.hpp similarity index 96% rename from client/include/editor/EditorDrawing.hpp rename to games/rtype/client/include/editor/EditorDrawing.hpp index 4645baa..7497e1d 100644 --- a/client/include/editor/EditorDrawing.hpp +++ b/games/rtype/client/include/editor/EditorDrawing.hpp @@ -9,7 +9,7 @@ #include "Math/Types.hpp" #include "Renderer/IRenderer.hpp" -#include "ECS/LevelLoader.hpp" +#include "LevelLoader.hpp" namespace RType { namespace Client { diff --git a/client/include/editor/EditorEntityManager.hpp b/games/rtype/client/include/editor/EditorEntityManager.hpp similarity index 100% rename from client/include/editor/EditorEntityManager.hpp rename to games/rtype/client/include/editor/EditorEntityManager.hpp diff --git a/client/include/editor/EditorFileManager.hpp b/games/rtype/client/include/editor/EditorFileManager.hpp similarity index 98% rename from client/include/editor/EditorFileManager.hpp rename to games/rtype/client/include/editor/EditorFileManager.hpp index e0140fa..dc45077 100644 --- a/client/include/editor/EditorFileManager.hpp +++ b/games/rtype/client/include/editor/EditorFileManager.hpp @@ -9,7 +9,7 @@ #include "editor/EditorTypes.hpp" #include "editor/EditorAssetLibrary.hpp" -#include "ECS/LevelLoader.hpp" +#include "LevelLoader.hpp" #include "ECS/Registry.hpp" #include "Renderer/IRenderer.hpp" #include diff --git a/client/include/editor/EditorGeometry.hpp b/games/rtype/client/include/editor/EditorGeometry.hpp similarity index 100% rename from client/include/editor/EditorGeometry.hpp rename to games/rtype/client/include/editor/EditorGeometry.hpp diff --git a/client/include/editor/EditorInputHandler.hpp b/games/rtype/client/include/editor/EditorInputHandler.hpp similarity index 100% rename from client/include/editor/EditorInputHandler.hpp rename to games/rtype/client/include/editor/EditorInputHandler.hpp diff --git a/client/include/editor/EditorPropertyManager.hpp b/games/rtype/client/include/editor/EditorPropertyManager.hpp similarity index 100% rename from client/include/editor/EditorPropertyManager.hpp rename to games/rtype/client/include/editor/EditorPropertyManager.hpp diff --git a/client/include/editor/EditorTypes.hpp b/games/rtype/client/include/editor/EditorTypes.hpp similarity index 98% rename from client/include/editor/EditorTypes.hpp rename to games/rtype/client/include/editor/EditorTypes.hpp index 8b18fd4..66c81cc 100644 --- a/client/include/editor/EditorTypes.hpp +++ b/games/rtype/client/include/editor/EditorTypes.hpp @@ -8,7 +8,7 @@ #pragma once #include "ECS/Entity.hpp" -#include "ECS/LevelLoader.hpp" +#include "LevelLoader.hpp" #include "Math/Types.hpp" #include #include diff --git a/client/include/editor/EditorUIManager.hpp b/games/rtype/client/include/editor/EditorUIManager.hpp similarity index 100% rename from client/include/editor/EditorUIManager.hpp rename to games/rtype/client/include/editor/EditorUIManager.hpp diff --git a/client/main.cpp b/games/rtype/client/main.cpp similarity index 100% rename from client/main.cpp rename to games/rtype/client/main.cpp diff --git a/client/src/EditorState.cpp b/games/rtype/client/src/EditorState.cpp similarity index 99% rename from client/src/EditorState.cpp rename to games/rtype/client/src/EditorState.cpp index 8eb5475..39c33c1 100644 --- a/client/src/EditorState.cpp +++ b/games/rtype/client/src/EditorState.cpp @@ -173,7 +173,7 @@ namespace RType { m_canvasManager->HandleCameraInput(); } - bool isLeftPressed = m_renderer->IsMouseButtonPressed(Renderer::IRenderer::MouseButton::Left); + bool isLeftPressed = m_renderer->IsMouseButtonPressed(Renderer::MouseButton::Left); if (isLeftPressed && !m_leftMousePressed) { bool consumedByUI = false; diff --git a/client/src/GameState.cpp b/games/rtype/client/src/GameState.cpp similarity index 100% rename from client/src/GameState.cpp rename to games/rtype/client/src/GameState.cpp diff --git a/client/src/LobbyState.cpp b/games/rtype/client/src/LobbyState.cpp similarity index 100% rename from client/src/LobbyState.cpp rename to games/rtype/client/src/LobbyState.cpp diff --git a/client/src/MenuState.cpp b/games/rtype/client/src/MenuState.cpp similarity index 100% rename from client/src/MenuState.cpp rename to games/rtype/client/src/MenuState.cpp diff --git a/client/src/ResultsState.cpp b/games/rtype/client/src/ResultsState.cpp similarity index 100% rename from client/src/ResultsState.cpp rename to games/rtype/client/src/ResultsState.cpp diff --git a/client/src/SettingsState.cpp b/games/rtype/client/src/SettingsState.cpp similarity index 100% rename from client/src/SettingsState.cpp rename to games/rtype/client/src/SettingsState.cpp diff --git a/client/src/editor/EditorAssetLibrary.cpp b/games/rtype/client/src/editor/EditorAssetLibrary.cpp similarity index 100% rename from client/src/editor/EditorAssetLibrary.cpp rename to games/rtype/client/src/editor/EditorAssetLibrary.cpp diff --git a/client/src/editor/EditorCanvasManager.cpp b/games/rtype/client/src/editor/EditorCanvasManager.cpp similarity index 100% rename from client/src/editor/EditorCanvasManager.cpp rename to games/rtype/client/src/editor/EditorCanvasManager.cpp diff --git a/client/src/editor/EditorColliderManager.cpp b/games/rtype/client/src/editor/EditorColliderManager.cpp similarity index 100% rename from client/src/editor/EditorColliderManager.cpp rename to games/rtype/client/src/editor/EditorColliderManager.cpp diff --git a/client/src/editor/EditorDrawing.cpp b/games/rtype/client/src/editor/EditorDrawing.cpp similarity index 100% rename from client/src/editor/EditorDrawing.cpp rename to games/rtype/client/src/editor/EditorDrawing.cpp diff --git a/client/src/editor/EditorEntityManager.cpp b/games/rtype/client/src/editor/EditorEntityManager.cpp similarity index 100% rename from client/src/editor/EditorEntityManager.cpp rename to games/rtype/client/src/editor/EditorEntityManager.cpp diff --git a/client/src/editor/EditorFileManager.cpp b/games/rtype/client/src/editor/EditorFileManager.cpp similarity index 100% rename from client/src/editor/EditorFileManager.cpp rename to games/rtype/client/src/editor/EditorFileManager.cpp diff --git a/client/src/editor/EditorInputHandler.cpp b/games/rtype/client/src/editor/EditorInputHandler.cpp similarity index 100% rename from client/src/editor/EditorInputHandler.cpp rename to games/rtype/client/src/editor/EditorInputHandler.cpp diff --git a/client/src/editor/EditorPropertyManager.cpp b/games/rtype/client/src/editor/EditorPropertyManager.cpp similarity index 100% rename from client/src/editor/EditorPropertyManager.cpp rename to games/rtype/client/src/editor/EditorPropertyManager.cpp diff --git a/client/src/editor/EditorUIManager.cpp b/games/rtype/client/src/editor/EditorUIManager.cpp similarity index 100% rename from client/src/editor/EditorUIManager.cpp rename to games/rtype/client/src/editor/EditorUIManager.cpp diff --git a/client/src/game/GameStateHelpers.cpp b/games/rtype/client/src/game/GameStateHelpers.cpp similarity index 100% rename from client/src/game/GameStateHelpers.cpp rename to games/rtype/client/src/game/GameStateHelpers.cpp diff --git a/client/src/game/GameStateInit.cpp b/games/rtype/client/src/game/GameStateInit.cpp similarity index 99% rename from client/src/game/GameStateInit.cpp rename to games/rtype/client/src/game/GameStateInit.cpp index 8f5cbb9..0efacea 100644 --- a/client/src/game/GameStateInit.cpp +++ b/games/rtype/client/src/game/GameStateInit.cpp @@ -10,7 +10,7 @@ #include "ECS/Components/TextLabel.hpp" #include "ECS/Component.hpp" #include "Core/Logger.hpp" -#include "ECS/PlayerFactory.hpp" +#include "PlayerFactory.hpp" #include "Animation/AnimationTypes.hpp" using namespace RType::ECS; diff --git a/client/src/game/GameStateNetwork.cpp b/games/rtype/client/src/game/GameStateNetwork.cpp similarity index 99% rename from client/src/game/GameStateNetwork.cpp rename to games/rtype/client/src/game/GameStateNetwork.cpp index d443c3e..83ce971 100644 --- a/client/src/game/GameStateNetwork.cpp +++ b/games/rtype/client/src/game/GameStateNetwork.cpp @@ -10,7 +10,7 @@ #include "ECS/Components/TextLabel.hpp" #include "ECS/Component.hpp" #include "Core/Logger.hpp" -#include "ECS/PowerUpFactory.hpp" +#include "PowerUpFactory.hpp" #include "Animation/AnimationModule.hpp" #include diff --git a/client/src/game/GameStateTransition.cpp b/games/rtype/client/src/game/GameStateTransition.cpp similarity index 100% rename from client/src/game/GameStateTransition.cpp rename to games/rtype/client/src/game/GameStateTransition.cpp diff --git a/client/src/game/GameStateUI.cpp b/games/rtype/client/src/game/GameStateUI.cpp similarity index 100% rename from client/src/game/GameStateUI.cpp rename to games/rtype/client/src/game/GameStateUI.cpp diff --git a/client/src/game/GameStateUpdate.cpp b/games/rtype/client/src/game/GameStateUpdate.cpp similarity index 100% rename from client/src/game/GameStateUpdate.cpp rename to games/rtype/client/src/game/GameStateUpdate.cpp diff --git a/client/src/lobby/LobbyStateInit.cpp b/games/rtype/client/src/lobby/LobbyStateInit.cpp similarity index 100% rename from client/src/lobby/LobbyStateInit.cpp rename to games/rtype/client/src/lobby/LobbyStateInit.cpp diff --git a/client/src/lobby/LobbyStateUpdate.cpp b/games/rtype/client/src/lobby/LobbyStateUpdate.cpp similarity index 100% rename from client/src/lobby/LobbyStateUpdate.cpp rename to games/rtype/client/src/lobby/LobbyStateUpdate.cpp diff --git a/client/src/room/RoomListState.cpp b/games/rtype/client/src/room/RoomListState.cpp similarity index 100% rename from client/src/room/RoomListState.cpp rename to games/rtype/client/src/room/RoomListState.cpp diff --git a/libs/engine/include/ECS/BlackOrbSystem.hpp b/games/rtype/include/BlackOrbSystem.hpp similarity index 90% rename from libs/engine/include/ECS/BlackOrbSystem.hpp rename to games/rtype/include/BlackOrbSystem.hpp index c9f71c1..fd65a65 100644 --- a/libs/engine/include/ECS/BlackOrbSystem.hpp +++ b/games/rtype/include/BlackOrbSystem.hpp @@ -7,8 +7,8 @@ #pragma once -#include "ISystem.hpp" -#include "Registry.hpp" +#include "ECS/ISystem.hpp" +#include "ECS/Registry.hpp" #include namespace RType { diff --git a/libs/engine/include/ECS/BossAttackSystem.hpp b/games/rtype/include/BossAttackSystem.hpp similarity index 96% rename from libs/engine/include/ECS/BossAttackSystem.hpp rename to games/rtype/include/BossAttackSystem.hpp index 8cef9ee..1feecb7 100644 --- a/libs/engine/include/ECS/BossAttackSystem.hpp +++ b/games/rtype/include/BossAttackSystem.hpp @@ -7,8 +7,8 @@ #pragma once -#include "ISystem.hpp" -#include "Registry.hpp" +#include "ECS/ISystem.hpp" +#include "ECS/Registry.hpp" #include namespace RType { diff --git a/libs/engine/include/ECS/BossSystem.hpp b/games/rtype/include/BossSystem.hpp similarity index 89% rename from libs/engine/include/ECS/BossSystem.hpp rename to games/rtype/include/BossSystem.hpp index ba492a7..d850165 100644 --- a/libs/engine/include/ECS/BossSystem.hpp +++ b/games/rtype/include/BossSystem.hpp @@ -7,8 +7,8 @@ #pragma once -#include "ISystem.hpp" -#include "Registry.hpp" +#include "ECS/ISystem.hpp" +#include "ECS/Registry.hpp" namespace RType { namespace ECS { diff --git a/libs/engine/include/ECS/BulletCollisionResponseSystem.hpp b/games/rtype/include/BulletCollisionResponseSystem.hpp similarity index 91% rename from libs/engine/include/ECS/BulletCollisionResponseSystem.hpp rename to games/rtype/include/BulletCollisionResponseSystem.hpp index 0a09137..ee8b219 100644 --- a/libs/engine/include/ECS/BulletCollisionResponseSystem.hpp +++ b/games/rtype/include/BulletCollisionResponseSystem.hpp @@ -7,9 +7,9 @@ #pragma once -#include "ISystem.hpp" -#include "Registry.hpp" -#include "Component.hpp" +#include "ECS/ISystem.hpp" +#include "ECS/Registry.hpp" +#include "ECS/Component.hpp" namespace RType { namespace ECS { diff --git a/libs/engine/include/ECS/EffectFactory.hpp b/games/rtype/include/EffectFactory.hpp similarity index 99% rename from libs/engine/include/ECS/EffectFactory.hpp rename to games/rtype/include/EffectFactory.hpp index e4a3b7d..a4ee50a 100644 --- a/libs/engine/include/ECS/EffectFactory.hpp +++ b/games/rtype/include/EffectFactory.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Entity.hpp" +#include "ECS/Entity.hpp" #include "Animation/AnimationTypes.hpp" #include "Renderer/IRenderer.hpp" #include "Math/Types.hpp" diff --git a/libs/engine/include/ECS/EnemyFactory.hpp b/games/rtype/include/EnemyFactory.hpp similarity index 91% rename from libs/engine/include/ECS/EnemyFactory.hpp rename to games/rtype/include/EnemyFactory.hpp index 8410294..c561a83 100644 --- a/libs/engine/include/ECS/EnemyFactory.hpp +++ b/games/rtype/include/EnemyFactory.hpp @@ -1,7 +1,7 @@ #pragma once -#include "Registry.hpp" -#include "Component.hpp" +#include "ECS/Registry.hpp" +#include "ECS/Component.hpp" #include "Renderer/IRenderer.hpp" #include "Math/Types.hpp" #include diff --git a/libs/engine/include/ECS/EnemySystem.hpp b/games/rtype/include/EnemySystem.hpp similarity index 97% rename from libs/engine/include/ECS/EnemySystem.hpp rename to games/rtype/include/EnemySystem.hpp index f392589..3ad6f07 100644 --- a/libs/engine/include/ECS/EnemySystem.hpp +++ b/games/rtype/include/EnemySystem.hpp @@ -1,6 +1,6 @@ #pragma once -#include "ISystem.hpp" +#include "ECS/ISystem.hpp" #include "Renderer/IRenderer.hpp" #include diff --git a/libs/engine/include/ECS/ForcePodSystem.hpp b/games/rtype/include/ForcePodSystem.hpp similarity index 94% rename from libs/engine/include/ECS/ForcePodSystem.hpp rename to games/rtype/include/ForcePodSystem.hpp index c827392..5fbfdec 100644 --- a/libs/engine/include/ECS/ForcePodSystem.hpp +++ b/games/rtype/include/ForcePodSystem.hpp @@ -7,7 +7,7 @@ #pragma once -#include "ISystem.hpp" +#include "ECS/ISystem.hpp" namespace RType { namespace ECS { diff --git a/libs/engine/include/ECS/LevelLoader.hpp b/games/rtype/include/LevelLoader.hpp similarity index 98% rename from libs/engine/include/ECS/LevelLoader.hpp rename to games/rtype/include/LevelLoader.hpp index cb4c96d..6de695b 100644 --- a/libs/engine/include/ECS/LevelLoader.hpp +++ b/games/rtype/include/LevelLoader.hpp @@ -7,8 +7,8 @@ #pragma once -#include "Registry.hpp" -#include "Component.hpp" +#include "ECS/Registry.hpp" +#include "ECS/Component.hpp" #include "Renderer/IRenderer.hpp" #include #include diff --git a/libs/engine/include/ECS/MineSystem.hpp b/games/rtype/include/MineSystem.hpp similarity index 91% rename from libs/engine/include/ECS/MineSystem.hpp rename to games/rtype/include/MineSystem.hpp index 5873b85..f12920e 100644 --- a/libs/engine/include/ECS/MineSystem.hpp +++ b/games/rtype/include/MineSystem.hpp @@ -7,8 +7,8 @@ #pragma once -#include "ISystem.hpp" -#include "Registry.hpp" +#include "ECS/ISystem.hpp" +#include "ECS/Registry.hpp" #include namespace RType { diff --git a/libs/engine/include/ECS/ObstacleCollisionResponseSystem.hpp b/games/rtype/include/ObstacleCollisionResponseSystem.hpp similarity index 87% rename from libs/engine/include/ECS/ObstacleCollisionResponseSystem.hpp rename to games/rtype/include/ObstacleCollisionResponseSystem.hpp index 080f588..93224ad 100644 --- a/libs/engine/include/ECS/ObstacleCollisionResponseSystem.hpp +++ b/games/rtype/include/ObstacleCollisionResponseSystem.hpp @@ -7,9 +7,9 @@ #pragma once -#include "ISystem.hpp" -#include "Registry.hpp" -#include "Component.hpp" +#include "ECS/ISystem.hpp" +#include "ECS/Registry.hpp" +#include "ECS/Component.hpp" namespace RType { namespace ECS { diff --git a/libs/engine/include/ECS/PlayerCollisionResponseSystem.hpp b/games/rtype/include/PlayerCollisionResponseSystem.hpp similarity index 92% rename from libs/engine/include/ECS/PlayerCollisionResponseSystem.hpp rename to games/rtype/include/PlayerCollisionResponseSystem.hpp index 0acf686..31e08f6 100644 --- a/libs/engine/include/ECS/PlayerCollisionResponseSystem.hpp +++ b/games/rtype/include/PlayerCollisionResponseSystem.hpp @@ -7,9 +7,9 @@ #pragma once -#include "ISystem.hpp" -#include "Registry.hpp" -#include "Component.hpp" +#include "ECS/ISystem.hpp" +#include "ECS/Registry.hpp" +#include "ECS/Component.hpp" namespace RType { namespace ECS { diff --git a/libs/engine/include/ECS/PlayerFactory.hpp b/games/rtype/include/PlayerFactory.hpp similarity index 90% rename from libs/engine/include/ECS/PlayerFactory.hpp rename to games/rtype/include/PlayerFactory.hpp index 6ada9f0..401891b 100644 --- a/libs/engine/include/ECS/PlayerFactory.hpp +++ b/games/rtype/include/PlayerFactory.hpp @@ -1,7 +1,7 @@ #pragma once -#include "Registry.hpp" -#include "Component.hpp" +#include "ECS/Registry.hpp" +#include "ECS/Component.hpp" #include "Renderer/IRenderer.hpp" #include "Math/Types.hpp" #include diff --git a/libs/engine/include/ECS/PlayerSystem.hpp b/games/rtype/include/PlayerSystem.hpp similarity index 97% rename from libs/engine/include/ECS/PlayerSystem.hpp rename to games/rtype/include/PlayerSystem.hpp index d7e3d36..9602e44 100644 --- a/libs/engine/include/ECS/PlayerSystem.hpp +++ b/games/rtype/include/PlayerSystem.hpp @@ -1,6 +1,6 @@ #pragma once -#include "ISystem.hpp" +#include "ECS/ISystem.hpp" #include "Renderer/IRenderer.hpp" namespace RType { diff --git a/libs/engine/include/ECS/PowerUpCollisionSystem.hpp b/games/rtype/include/PowerUpCollisionSystem.hpp similarity index 88% rename from libs/engine/include/ECS/PowerUpCollisionSystem.hpp rename to games/rtype/include/PowerUpCollisionSystem.hpp index f6dbc1e..efc3345 100644 --- a/libs/engine/include/ECS/PowerUpCollisionSystem.hpp +++ b/games/rtype/include/PowerUpCollisionSystem.hpp @@ -7,10 +7,10 @@ #pragma once -#include "ISystem.hpp" -#include "CollisionDetectionSystem.hpp" +#include "ECS/ISystem.hpp" +#include "ECS/CollisionDetectionSystem.hpp" #include "Renderer/IRenderer.hpp" -#include "../Audio/IAudio.hpp" +#include "Audio/IAudio.hpp" namespace RType { namespace ECS { diff --git a/libs/engine/include/ECS/PowerUpFactory.hpp b/games/rtype/include/PowerUpFactory.hpp similarity index 96% rename from libs/engine/include/ECS/PowerUpFactory.hpp rename to games/rtype/include/PowerUpFactory.hpp index 4bced5f..38c5ca3 100644 --- a/libs/engine/include/ECS/PowerUpFactory.hpp +++ b/games/rtype/include/PowerUpFactory.hpp @@ -7,8 +7,8 @@ #pragma once -#include "Registry.hpp" -#include "Component.hpp" +#include "ECS/Registry.hpp" +#include "ECS/Component.hpp" #include "Renderer/IRenderer.hpp" #include "Math/Types.hpp" #include diff --git a/libs/engine/include/ECS/PowerUpSpawnSystem.hpp b/games/rtype/include/PowerUpSpawnSystem.hpp similarity index 98% rename from libs/engine/include/ECS/PowerUpSpawnSystem.hpp rename to games/rtype/include/PowerUpSpawnSystem.hpp index 2abeb35..b3094d8 100644 --- a/libs/engine/include/ECS/PowerUpSpawnSystem.hpp +++ b/games/rtype/include/PowerUpSpawnSystem.hpp @@ -7,7 +7,7 @@ #pragma once -#include "ISystem.hpp" +#include "ECS/ISystem.hpp" #include "Renderer/IRenderer.hpp" #include diff --git a/libs/engine/include/ECS/ShieldSystem.hpp b/games/rtype/include/ShieldSystem.hpp similarity index 94% rename from libs/engine/include/ECS/ShieldSystem.hpp rename to games/rtype/include/ShieldSystem.hpp index f4a77d8..a5811cc 100644 --- a/libs/engine/include/ECS/ShieldSystem.hpp +++ b/games/rtype/include/ShieldSystem.hpp @@ -7,7 +7,7 @@ #pragma once -#include "ISystem.hpp" +#include "ECS/ISystem.hpp" namespace RType { namespace ECS { diff --git a/libs/engine/include/ECS/ShootingSystem.hpp b/games/rtype/include/ShootingSystem.hpp similarity index 91% rename from libs/engine/include/ECS/ShootingSystem.hpp rename to games/rtype/include/ShootingSystem.hpp index fa309b1..a06121f 100644 --- a/libs/engine/include/ECS/ShootingSystem.hpp +++ b/games/rtype/include/ShootingSystem.hpp @@ -1,8 +1,8 @@ #pragma once -#include "ISystem.hpp" -#include "../Renderer/IRenderer.hpp" -#include "../Audio/IAudio.hpp" +#include "ECS/ISystem.hpp" +#include "Renderer/IRenderer.hpp" +#include "Audio/IAudio.hpp" namespace RType { namespace ECS { diff --git a/libs/engine/include/ECS/ThirdBulletSystem.hpp b/games/rtype/include/ThirdBulletSystem.hpp similarity index 91% rename from libs/engine/include/ECS/ThirdBulletSystem.hpp rename to games/rtype/include/ThirdBulletSystem.hpp index 10d8f6a..ac03b4a 100644 --- a/libs/engine/include/ECS/ThirdBulletSystem.hpp +++ b/games/rtype/include/ThirdBulletSystem.hpp @@ -1,7 +1,7 @@ #pragma once -#include "ISystem.hpp" -#include "Registry.hpp" +#include "ECS/ISystem.hpp" +#include "ECS/Registry.hpp" namespace RType { namespace ECS { diff --git a/games/rtype/server/main.cpp b/games/rtype/server/main.cpp new file mode 100644 index 0000000..b8d1418 --- /dev/null +++ b/games/rtype/server/main.cpp @@ -0,0 +1,81 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type +** File description: +** Server main entry point +*/ + +#include "RoomManager.hpp" +#include "GameServer.hpp" +#include "AsioNetworkModule.hpp" +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) { + uint16_t port = 4242; + size_t minPlayers = 2; + std::string levelPath = "assets/levels/level1.json"; + + if (argc > 1) + port = std::stoi(argv[1]); + if (argc > 2) + minPlayers = std::stoi(argv[2]); + if (argc > 3) + levelPath = argv[3]; + + std::cout << "\n=== Starting R-Type server with room support on port " << port << " ===" << std::endl; + + auto networkModule = std::make_shared(); + networkModule->Initialize(nullptr); + + network::RoomManager roomManager(networkModule.get(), port, MAX_ROOMS, minPlayers); + + std::atomic gameStarted{false}; + std::optional startedRoomId; + std::vector gamePlayers; + + roomManager.onGameStart([&](uint32_t roomId, const network::RoomManager::Room& room) { + gamePlayers.clear(); + for (const auto& maybePlayer : room.players) { + if (maybePlayer) { + gamePlayers.push_back(*maybePlayer); + } + } + startedRoomId = roomId; + gameStarted = true; + }); + + while (true) { + roomManager.update(); + + if (gameStarted) { + std::cout << "Game started in room " << *startedRoomId << " with " << gamePlayers.size() << " players!" << std::endl; + + std::cout << "Waiting 2 seconds for clients to transition..." << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(2)); + + std::cout << "Starting UDP GameServer on port " << port << " with " << gamePlayers.size() << " players..." << std::endl; + std::cout << "Level: " << levelPath << std::endl; + + network::GameServer gameServer(networkModule.get(), port, gamePlayers, levelPath); + gameServer.Run(); + + std::cout << "\n=== Game ended in room " << *startedRoomId << ". Room available again. ===" << std::endl; + + gameStarted = false; + startedRoomId.reset(); + gamePlayers.clear(); + + std::this_thread::sleep_for(std::chrono::seconds(2)); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(16)); + } + + return 0; +} diff --git a/libs/engine/src/ECS/BlackOrbSystem.cpp b/games/rtype/systems/BlackOrbSystem.cpp similarity index 99% rename from libs/engine/src/ECS/BlackOrbSystem.cpp rename to games/rtype/systems/BlackOrbSystem.cpp index 3bff0a2..f6d9e2c 100644 --- a/libs/engine/src/ECS/BlackOrbSystem.cpp +++ b/games/rtype/systems/BlackOrbSystem.cpp @@ -5,7 +5,7 @@ ** BlackOrbSystem implementation */ -#include "ECS/BlackOrbSystem.hpp" +#include "BlackOrbSystem.hpp" #include "ECS/Component.hpp" #include "Core/Logger.hpp" #include diff --git a/libs/engine/src/ECS/BossAttackSystem.cpp b/games/rtype/systems/BossAttackSystem.cpp similarity index 99% rename from libs/engine/src/ECS/BossAttackSystem.cpp rename to games/rtype/systems/BossAttackSystem.cpp index 7615dc3..46b4a14 100644 --- a/libs/engine/src/ECS/BossAttackSystem.cpp +++ b/games/rtype/systems/BossAttackSystem.cpp @@ -5,7 +5,7 @@ ** BossAttackSystem - Handles boss attack patterns */ -#include "ECS/BossAttackSystem.hpp" +#include "BossAttackSystem.hpp" #include "ECS/Component.hpp" #include "Core/Logger.hpp" #include diff --git a/libs/engine/src/ECS/BossSystem.cpp b/games/rtype/systems/BossSystem.cpp similarity index 99% rename from libs/engine/src/ECS/BossSystem.cpp rename to games/rtype/systems/BossSystem.cpp index 16e0826..675d440 100644 --- a/libs/engine/src/ECS/BossSystem.cpp +++ b/games/rtype/systems/BossSystem.cpp @@ -5,7 +5,7 @@ ** BossSystem - Handles boss behavior */ -#include "ECS/BossSystem.hpp" +#include "BossSystem.hpp" #include "ECS/Component.hpp" #include "Core/Logger.hpp" #include diff --git a/libs/engine/src/ECS/BulletCollisionResponseSystem.cpp b/games/rtype/systems/BulletCollisionResponseSystem.cpp similarity index 98% rename from libs/engine/src/ECS/BulletCollisionResponseSystem.cpp rename to games/rtype/systems/BulletCollisionResponseSystem.cpp index f56c3e1..877ba7d 100644 --- a/libs/engine/src/ECS/BulletCollisionResponseSystem.cpp +++ b/games/rtype/systems/BulletCollisionResponseSystem.cpp @@ -5,8 +5,8 @@ ** BulletCollisionResponseSystem implementation */ -#include "ECS/BulletCollisionResponseSystem.hpp" -#include "ECS/EffectFactory.hpp" +#include "BulletCollisionResponseSystem.hpp" +#include "EffectFactory.hpp" #include "Core/Logger.hpp" #include #include diff --git a/libs/engine/src/ECS/EffectFactory.cpp b/games/rtype/systems/EffectFactory.cpp similarity index 99% rename from libs/engine/src/ECS/EffectFactory.cpp rename to games/rtype/systems/EffectFactory.cpp index 159af8f..b0f9e9d 100644 --- a/libs/engine/src/ECS/EffectFactory.cpp +++ b/games/rtype/systems/EffectFactory.cpp @@ -1,4 +1,4 @@ -#include "ECS/EffectFactory.hpp" +#include "EffectFactory.hpp" #include "ECS/Component.hpp" #include "ECS/Components/TextLabel.hpp" #include "ECS/Registry.hpp" diff --git a/libs/engine/src/ECS/EnemyFactory.cpp b/games/rtype/systems/EnemyFactory.cpp similarity index 99% rename from libs/engine/src/ECS/EnemyFactory.cpp rename to games/rtype/systems/EnemyFactory.cpp index 05acd74..c8d33af 100644 --- a/libs/engine/src/ECS/EnemyFactory.cpp +++ b/games/rtype/systems/EnemyFactory.cpp @@ -1,4 +1,4 @@ -#include "ECS/EnemyFactory.hpp" +#include "EnemyFactory.hpp" #include "Core/Logger.hpp" #include #include diff --git a/libs/engine/src/ECS/EnemySystem.cpp b/games/rtype/systems/EnemySystem.cpp similarity index 98% rename from libs/engine/src/ECS/EnemySystem.cpp rename to games/rtype/systems/EnemySystem.cpp index 5eed3cc..112b909 100644 --- a/libs/engine/src/ECS/EnemySystem.cpp +++ b/games/rtype/systems/EnemySystem.cpp @@ -1,5 +1,5 @@ -#include "ECS/EnemySystem.hpp" -#include "ECS/EnemyFactory.hpp" +#include "EnemySystem.hpp" +#include "EnemyFactory.hpp" #include "ECS/Component.hpp" #include "Core/Logger.hpp" #include diff --git a/libs/engine/src/ECS/ForcePodSystem.cpp b/games/rtype/systems/ForcePodSystem.cpp similarity index 98% rename from libs/engine/src/ECS/ForcePodSystem.cpp rename to games/rtype/systems/ForcePodSystem.cpp index e730551..a894603 100644 --- a/libs/engine/src/ECS/ForcePodSystem.cpp +++ b/games/rtype/systems/ForcePodSystem.cpp @@ -5,7 +5,7 @@ ** ForcePodSystem */ -#include "ECS/ForcePodSystem.hpp" +#include "ForcePodSystem.hpp" #include "ECS/Component.hpp" namespace RType { diff --git a/libs/engine/src/ECS/LevelLoader.cpp b/games/rtype/systems/LevelLoader.cpp similarity index 99% rename from libs/engine/src/ECS/LevelLoader.cpp rename to games/rtype/systems/LevelLoader.cpp index e8fbc57..157487a 100644 --- a/libs/engine/src/ECS/LevelLoader.cpp +++ b/games/rtype/systems/LevelLoader.cpp @@ -5,8 +5,8 @@ ** LevelLoader - JSON-based level loading implementation */ -#include "ECS/LevelLoader.hpp" -#include "ECS/EnemyFactory.hpp" +#include "LevelLoader.hpp" +#include "EnemyFactory.hpp" #include "Core/Logger.hpp" #include #include diff --git a/libs/engine/src/ECS/MineSystem.cpp b/games/rtype/systems/MineSystem.cpp similarity index 99% rename from libs/engine/src/ECS/MineSystem.cpp rename to games/rtype/systems/MineSystem.cpp index ec0cd4c..257dece 100644 --- a/libs/engine/src/ECS/MineSystem.cpp +++ b/games/rtype/systems/MineSystem.cpp @@ -5,7 +5,7 @@ ** MineSystem - Handles mine proximity detection and explosions */ -#include "ECS/MineSystem.hpp" +#include "MineSystem.hpp" #include "ECS/Component.hpp" #include "Core/Logger.hpp" #include diff --git a/libs/engine/src/ECS/ObstacleCollisionResponseSystem.cpp b/games/rtype/systems/ObstacleCollisionResponseSystem.cpp similarity index 99% rename from libs/engine/src/ECS/ObstacleCollisionResponseSystem.cpp rename to games/rtype/systems/ObstacleCollisionResponseSystem.cpp index be288e0..64b8568 100644 --- a/libs/engine/src/ECS/ObstacleCollisionResponseSystem.cpp +++ b/games/rtype/systems/ObstacleCollisionResponseSystem.cpp @@ -5,7 +5,7 @@ ** ObstacleCollisionResponseSystem implementation */ -#include "ECS/ObstacleCollisionResponseSystem.hpp" +#include "ObstacleCollisionResponseSystem.hpp" #include #include diff --git a/libs/engine/src/ECS/PlayerCollisionResponseSystem.cpp b/games/rtype/systems/PlayerCollisionResponseSystem.cpp similarity index 99% rename from libs/engine/src/ECS/PlayerCollisionResponseSystem.cpp rename to games/rtype/systems/PlayerCollisionResponseSystem.cpp index 2e75ab2..5530308 100644 --- a/libs/engine/src/ECS/PlayerCollisionResponseSystem.cpp +++ b/games/rtype/systems/PlayerCollisionResponseSystem.cpp @@ -5,7 +5,7 @@ ** PlayerCollisionResponseSystem implementation */ -#include "ECS/PlayerCollisionResponseSystem.hpp" +#include "PlayerCollisionResponseSystem.hpp" #include #include #include diff --git a/libs/engine/src/ECS/PlayerFactory.cpp b/games/rtype/systems/PlayerFactory.cpp similarity index 99% rename from libs/engine/src/ECS/PlayerFactory.cpp rename to games/rtype/systems/PlayerFactory.cpp index 113a091..259ecaa 100644 --- a/libs/engine/src/ECS/PlayerFactory.cpp +++ b/games/rtype/systems/PlayerFactory.cpp @@ -1,4 +1,4 @@ -#include "ECS/PlayerFactory.hpp" +#include "PlayerFactory.hpp" #include "Core/Logger.hpp" #include #include diff --git a/libs/engine/src/ECS/PlayerSystem.cpp b/games/rtype/systems/PlayerSystem.cpp similarity index 96% rename from libs/engine/src/ECS/PlayerSystem.cpp rename to games/rtype/systems/PlayerSystem.cpp index 2e078b2..967fed8 100644 --- a/libs/engine/src/ECS/PlayerSystem.cpp +++ b/games/rtype/systems/PlayerSystem.cpp @@ -1,6 +1,6 @@ -#include "ECS/PlayerSystem.hpp" +#include "PlayerSystem.hpp" #include "ECS/Component.hpp" -#include "ECS/PlayerFactory.hpp" +#include "PlayerFactory.hpp" #include namespace RType { diff --git a/libs/engine/src/ECS/PowerUpCollisionSystem.cpp b/games/rtype/systems/PowerUpCollisionSystem.cpp similarity index 96% rename from libs/engine/src/ECS/PowerUpCollisionSystem.cpp rename to games/rtype/systems/PowerUpCollisionSystem.cpp index 1dcdbad..9fdc989 100644 --- a/libs/engine/src/ECS/PowerUpCollisionSystem.cpp +++ b/games/rtype/systems/PowerUpCollisionSystem.cpp @@ -5,8 +5,8 @@ ** PowerUpCollisionSystem */ -#include "ECS/PowerUpCollisionSystem.hpp" -#include "ECS/PowerUpFactory.hpp" +#include "PowerUpCollisionSystem.hpp" +#include "PowerUpFactory.hpp" #include "ECS/CollisionDetectionSystem.hpp" #include "ECS/Component.hpp" #include "Core/Logger.hpp" diff --git a/libs/engine/src/ECS/PowerUpFactory.cpp b/games/rtype/systems/PowerUpFactory.cpp similarity index 99% rename from libs/engine/src/ECS/PowerUpFactory.cpp rename to games/rtype/systems/PowerUpFactory.cpp index bf97a9c..b51841a 100644 --- a/libs/engine/src/ECS/PowerUpFactory.cpp +++ b/games/rtype/systems/PowerUpFactory.cpp @@ -5,8 +5,8 @@ ** PowerUpFactory */ -#include "ECS/PowerUpFactory.hpp" -#include "ECS/EffectFactory.hpp" +#include "PowerUpFactory.hpp" +#include "EffectFactory.hpp" #include "Animation/AnimationTypes.hpp" #include "Core/Logger.hpp" #include diff --git a/libs/engine/src/ECS/PowerUpSpawnSystem.cpp b/games/rtype/systems/PowerUpSpawnSystem.cpp similarity index 95% rename from libs/engine/src/ECS/PowerUpSpawnSystem.cpp rename to games/rtype/systems/PowerUpSpawnSystem.cpp index a4016d7..1d9892b 100644 --- a/libs/engine/src/ECS/PowerUpSpawnSystem.cpp +++ b/games/rtype/systems/PowerUpSpawnSystem.cpp @@ -5,9 +5,9 @@ ** PowerUpSpawnSystem */ -#include "ECS/PowerUpSpawnSystem.hpp" -#include "ECS/PowerUpFactory.hpp" -#include "ECS/EffectFactory.hpp" +#include "PowerUpSpawnSystem.hpp" +#include "PowerUpFactory.hpp" +#include "EffectFactory.hpp" #include "ECS/Component.hpp" #include "Core/Logger.hpp" #include diff --git a/libs/engine/src/ECS/ShieldSystem.cpp b/games/rtype/systems/ShieldSystem.cpp similarity index 98% rename from libs/engine/src/ECS/ShieldSystem.cpp rename to games/rtype/systems/ShieldSystem.cpp index 1ba20f4..538132a 100644 --- a/libs/engine/src/ECS/ShieldSystem.cpp +++ b/games/rtype/systems/ShieldSystem.cpp @@ -5,7 +5,7 @@ ** ShieldSystem */ -#include "ECS/ShieldSystem.hpp" +#include "ShieldSystem.hpp" #include "ECS/Component.hpp" namespace RType { diff --git a/libs/engine/src/ECS/ShootingSystem.cpp b/games/rtype/systems/ShootingSystem.cpp similarity index 98% rename from libs/engine/src/ECS/ShootingSystem.cpp rename to games/rtype/systems/ShootingSystem.cpp index f33f12c..0643a4d 100644 --- a/libs/engine/src/ECS/ShootingSystem.cpp +++ b/games/rtype/systems/ShootingSystem.cpp @@ -1,8 +1,8 @@ -#include "../../include/ECS/ScoreSystem.hpp" -#include "../../include/ECS/Component.hpp" -#include "../../include/ECS/ShootingSystem.hpp" -#include "../../include/ECS/RenderingSystem.hpp" -#include "../../include/ECS/EffectFactory.hpp" +#include "ECS/ScoreSystem.hpp" +#include "ECS/Component.hpp" +#include "ShootingSystem.hpp" +#include "ECS/RenderingSystem.hpp" +#include "EffectFactory.hpp" #include #include diff --git a/libs/engine/src/ECS/ThirdBulletSystem.cpp b/games/rtype/systems/ThirdBulletSystem.cpp similarity index 98% rename from libs/engine/src/ECS/ThirdBulletSystem.cpp rename to games/rtype/systems/ThirdBulletSystem.cpp index 7ea3e87..405bd6c 100644 --- a/libs/engine/src/ECS/ThirdBulletSystem.cpp +++ b/games/rtype/systems/ThirdBulletSystem.cpp @@ -1,4 +1,4 @@ -#include "ECS/ThirdBulletSystem.hpp" +#include "ThirdBulletSystem.hpp" #include "ECS/Component.hpp" #include "Core/Logger.hpp" #include diff --git a/libs/engine/CMakeLists.txt b/libs/engine/CMakeLists.txt deleted file mode 100644 index 05ba46a..0000000 --- a/libs/engine/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_subdirectory(src/ECS) -add_subdirectory(src/Core) -add_subdirectory(src/Renderer) -add_subdirectory(src/Audio) -add_subdirectory(src/Animation) diff --git a/libs/engine/include/ECS/Component.hpp b/libs/engine/include/ECS/Component.hpp deleted file mode 100644 index 7920583..0000000 --- a/libs/engine/include/ECS/Component.hpp +++ /dev/null @@ -1,644 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include "Renderer/IRenderer.hpp" -#include "Math/Types.hpp" -#include "Entity.hpp" -#include "Audio/IAudio.hpp" -#include "Animation/AnimationTypes.hpp" - -namespace RType { - - namespace ECS { - using ComponentID = std::type_index; - - struct IComponent { - virtual ~IComponent() = default; - }; - - struct Position : public IComponent { - float x = 0.0f; - float y = 0.0f; - - Position() = default; - Position(float x, float y) - : x(x), y(y) {} - }; - - struct Velocity : public IComponent { - float dx = 0.0f; - float dy = 0.0f; - - Velocity() = default; - Velocity(float dx, float dy) - : dx(dx), dy(dy) {} - }; - - struct Drawable : public IComponent { - Renderer::SpriteId spriteId = Renderer::INVALID_SPRITE_ID; - Math::Vector2 scale{1.0f, 1.0f}; - float rotation = 0.0f; - Math::Vector2 origin{0.0f, 0.0f}; - Math::Color tint{1.0f, 1.0f, 1.0f, 1.0f}; - int layer = 0; - - Drawable() = default; - Drawable(Renderer::SpriteId sprite, int renderLayer = 0) - : spriteId(sprite), layer(renderLayer) {} - }; - - struct NetworkPlayer : public IComponent { - uint8_t playerNumber = 0; - uint64_t playerHash = 0; - char name[32] = {}; - bool ready = false; - - NetworkPlayer() = default; - NetworkPlayer(uint8_t num, uint64_t hash, const char* playerName, bool isReady = false) - : playerNumber(num), playerHash(hash), ready(isReady) { - if (playerName) { - std::strncpy(name, playerName, 31); - name[31] = '\0'; - } - } - }; - - struct BoxCollider : public IComponent { - float width = 0.0f; - float height = 0.0f; - - BoxCollider() = default; - BoxCollider(float width, float height) - : width(width), height(height) {} - }; - - struct Controllable : public IComponent { - float speed = 200.0f; - - Controllable() = default; - Controllable(float moveSpeed) - : speed(moveSpeed) {} - }; - - struct Player : public IComponent { - uint8_t playerNumber = 0; - uint64_t playerHash = 0; - bool isLocalPlayer = false; - uint8_t lives = 3; - - Player() = default; - Player(uint8_t number, uint64_t hash, bool local = false, uint8_t startLives = 3) - : playerNumber(number), playerHash(hash), isLocalPlayer(local), lives(startLives) {} - }; - - enum class EnemyType : uint8_t { - BASIC = 0, - FAST = 1, - TANK = 2, - BOSS = 3, - FORMATION = 4 - }; - - struct Enemy : public IComponent { - EnemyType type = EnemyType::BASIC; - uint32_t id = 0; - - Enemy() = default; - Enemy(EnemyType enemyType, uint32_t enemyId = 0) - : type(enemyType), id(enemyId) {} - }; - - struct Boss : public IComponent { - uint8_t bossId = 1; - - Boss() = default; - Boss(uint8_t id) : bossId(id) {} - }; - - struct BossKilled : public IComponent { - Entity bossEntity; - int levelNumber; - float timeSinceDeath = 0.0f; - - BossKilled() = default; - BossKilled(Entity boss, int level) - : bossEntity(boss), levelNumber(level) {} - }; - - enum class BossAttackPattern { - IDLE = 0, - // Boss 1 - FAN_SPRAY = 1, - DIRECT_SHOT = 2, - CIRCLE = 3, - BLACK_ORB = 4, - THIRD_BULLET = 5, - // Boss 2 - SPIRAL_WAVE = 6, - ANIMATED_ORB = 7, - LASER_BEAM = 8 - }; - - struct BossAttack : public IComponent { - float attackCooldown = 3.0f; - float timeSinceLastAttack = 0.0f; - BossAttackPattern currentPattern = BossAttackPattern::FAN_SPRAY; - - BossAttack() = default; - BossAttack(float cooldown) : attackCooldown(cooldown) {} - }; - - struct BossBullet : public IComponent { - BossBullet() = default; - }; - - struct WaveAttack : public IComponent { - WaveAttack() = default; - }; - - struct SecondAttack : public IComponent { - SecondAttack() = default; - }; - - struct FireBullet : public IComponent { - FireBullet() = default; - }; - - struct Mine : public IComponent { - float proximityRadius = 80.0f; - float explosionRadius = 100.0f; - float lifeTime = 10.0f; - float timer = 0.0f; - bool isExploding = false; - float explosionTimer = 0.0f; - - Mine() = default; - Mine(float proximity, float explosion, float life) - : proximityRadius(proximity), explosionRadius(explosion), lifeTime(life) {} - }; - - struct BossMovementPattern : public IComponent { - float timer = 0.0f; - float amplitudeY = 200.0f; - float amplitudeX = 80.0f; - float frequencyY = 0.5f; - float frequencyX = 0.3f; - float centerY = 0.0f; - float centerX = 0.0f; - - BossMovementPattern() = default; - BossMovementPattern(float ampY, float ampX, float freqY, float freqX, float centerYPos, float centerXPos) - : amplitudeY(ampY), amplitudeX(ampX), frequencyY(freqY), frequencyX(freqX), centerY(centerYPos), centerX(centerXPos) {} - }; - - struct BlackOrb : public IComponent { - float attractionRadius = 200.0f; - float absorptionRadius = 30.0f; - float attractionForce = 500.0f; - bool isActive = true; - - BlackOrb() = default; - BlackOrb(float attraction, float absorption, float force) - : attractionRadius(attraction), absorptionRadius(absorption), attractionForce(force) {} - }; - - struct ProximityDamage : public IComponent { - float damageRadius = 120.0f; - float damageAmount = 1.0f; - float tickRate = 0.5f; - float timeSinceDamage = 0.0f; - - ProximityDamage() = default; - ProximityDamage(float radius, float damage, float rate) - : damageRadius(radius), damageAmount(damage), tickRate(rate) {} - }; - - struct DamageFlash : public IComponent { - float duration = 0.1f; - float timeRemaining = 0.0f; - bool isActive = false; - - DamageFlash() = default; - DamageFlash(float flashDuration) : duration(flashDuration) {} - - void Trigger() { - isActive = true; - timeRemaining = duration; - } - }; - - struct ThirdBullet : public IComponent { - float spawnInterval = 0.3f; - float timeSinceSpawn = 0.0f; - int damage = 50; - bool isActive = true; - - ThirdBullet() = default; - ThirdBullet(float interval, int dmg) - : spawnInterval(interval), damage(dmg) {} - }; - - struct Health : public IComponent { - int current = 100; - int max = 100; - - Health() = default; - Health(int maxHealth) - : current(maxHealth), max(maxHealth) {} - Health(int currentHealth, int maxHealth) - : current(currentHealth), max(maxHealth) {} - }; - - struct ScoreValue : public IComponent { - uint32_t points = 100; - - ScoreValue() = default; - ScoreValue(uint32_t scorePoints) - : points(scorePoints) {} - }; - - struct ScoreTimer : public IComponent { - float elapsed = 0.0f; - - ScoreTimer() = default; - ScoreTimer(float startElapsed) - : elapsed(startElapsed) {} - }; - - struct Damage : public IComponent { - int amount = 10; - - Damage() = default; - Damage(int damageAmount) - : amount(damageAmount) {} - }; - - struct EnemyKilled : public IComponent { - uint32_t enemyId = 0; - Entity killedBy = NULL_ENTITY; - - EnemyKilled() = default; - EnemyKilled(uint32_t id, Entity killer = NULL_ENTITY) - : enemyId(id), killedBy(killer) {} - }; - - struct Bullet : public IComponent { - Entity owner = NULL_ENTITY; - - Bullet() = default; - Bullet(Entity shooter) - : owner(shooter) {} - }; - - struct Shooter : public IComponent { - float fireRate = 0.2f; - float cooldown = 0.0f; - float offsetX = 50.0f; - float offsetY = 20.0f; - - Shooter() = default; - Shooter(float rate, float oX = 50.0f, float oY = 20.0f) : fireRate(rate), offsetX(oX), offsetY(oY) {} - }; - - struct ShootCommand : public IComponent { - bool wantsToShoot = false; - - ShootCommand() = default; - ShootCommand(bool shoot) : wantsToShoot(shoot) {} - }; - - struct Scrollable : public IComponent { - float speed = -100.0f; - - Scrollable() = default; - Scrollable(float scrollSpeed) : speed(scrollSpeed) {} - }; - - struct Obstacle : public IComponent { - bool blocking = true; - - Obstacle() = default; - Obstacle(bool isBlocking) : blocking(isBlocking) {} - }; - - struct ObstacleVisual : public IComponent { - }; - - // Stable network identifier for server->client entity mirroring. - // IMPORTANT: This must live on the entity as a component, because raw ECS entity IDs are recycled. - // If we instead map "ECS entity id -> network id" in a hash map, then destroying and reusing an - // ECS id in the same tick can cause a new entity to inherit the old network id (type confusion). - struct NetworkId : public IComponent { - uint32_t id = 0; - - NetworkId() = default; - explicit NetworkId(uint32_t networkId) : id(networkId) {} - }; - - struct ObstacleMetadata : public IComponent { - uint32_t uniqueId = 0; - Entity visualEntity = NULL_ENTITY; - float offsetX = 0.0f; - float offsetY = 0.0f; - - ObstacleMetadata() = default; - ObstacleMetadata(uint32_t id, - Entity visual = NULL_ENTITY, - float offsetX = 0.0f, - float offsetY = 0.0f) - : uniqueId(id), - visualEntity(visual), - offsetX(offsetX), - offsetY(offsetY) {} - }; - - struct Invincibility : public IComponent { - float remainingTime = 0.0f; - - Invincibility() = default; - Invincibility(float duration) : remainingTime(duration) {} - }; - - struct CollisionLayer : public IComponent { - uint16_t layer = 0; // What layer this entity is on - uint16_t mask = 0xFFFF; // Which layers this entity collides with - - CollisionLayer() = default; - CollisionLayer(uint16_t l, uint16_t m) : layer(l), mask(m) {} - }; - - // masks for collision layers - namespace CollisionLayers { - constexpr uint16_t NONE = 0; - constexpr uint16_t PLAYER = 1 << 0; // 0x0001 - constexpr uint16_t ENEMY = 1 << 1; // 0x0002 - constexpr uint16_t PLAYER_BULLET = 1 << 2; // 0x0004 - constexpr uint16_t ENEMY_BULLET = 1 << 3; // 0x0008 - constexpr uint16_t OBSTACLE = 1 << 4; // 0x0010 - constexpr uint16_t POWERUP = 1 << 5; // 0x0020 - constexpr uint16_t ALL = 0xFFFF; - } - - struct CircleCollider : public IComponent { - float radius = 0.0f; - - CircleCollider() = default; - CircleCollider(float r) : radius(r) {} - }; - - struct CollisionEvent : public IComponent { - Entity other = NULL_ENTITY; - - CollisionEvent() = default; - CollisionEvent(Entity e) : other(e) {} - }; - - // Powerup system components - enum class PowerUpType : uint8_t { - FIRE_RATE_BOOST = 0, - SPREAD_SHOT = 1, - LASER_BEAM = 2, - FORCE_POD = 3, - SPEED_BOOST = 4, - SHIELD = 5 - }; - - struct PowerUp : public IComponent { - PowerUpType type = PowerUpType::FIRE_RATE_BOOST; - uint32_t id = 0; - - PowerUp() = default; - PowerUp(PowerUpType powerupType, uint32_t powerupId = 0) - : type(powerupType), id(powerupId) {} - }; - - struct ActivePowerUps : public IComponent { - bool hasFireRateBoost = false; - bool hasSpreadShot = false; - bool hasLaserBeam = false; - bool hasShield = false; - float speedMultiplier = 1.0f; - - ActivePowerUps() = default; - }; - - enum class WeaponType : uint8_t { - STANDARD = 0, - SPREAD = 1, - LASER = 2 - }; - - struct WeaponSlot : public IComponent { - WeaponType type = WeaponType::STANDARD; - float fireRate = 0.2f; - float cooldown = 0.0f; - int damage = 25; - bool enabled = true; - - WeaponSlot() = default; - WeaponSlot(WeaponType weaponType, float rate, int dmg) - : type(weaponType), fireRate(rate), damage(dmg) {} - }; - - struct ForcePod : public IComponent { - Entity owner = NULL_ENTITY; - float offsetX = -60.0f; - float offsetY = 0.0f; - bool isAttached = true; - - ForcePod() = default; - ForcePod(Entity ownerEntity, float oX = -60.0f, float oY = 0.0f) - : owner(ownerEntity), offsetX(oX), offsetY(oY) {} - }; - - struct Shield : public IComponent { - float duration = 0.0f; // 0 = permanent (until death) - float timeRemaining = 0.0f; - - Shield() = default; - Shield(float dur = 0.0f) : duration(dur), timeRemaining(dur) {} - }; - - struct SoundEffect : public IComponent { - Audio::SoundId soundId = Audio::INVALID_SOUND_ID; - float volume = 1.0f; - float pitch = 1.0f; - float pan = 0.0f; - bool loop = false; - bool positional = false; - - SoundEffect() = default; - SoundEffect(Audio::SoundId id, float vol = 1.0f) - : soundId(id), volume(vol) {} - }; - - struct MusicEffect : public IComponent { - Audio::MusicId musicId = Audio::INVALID_MUSIC_ID; - bool play = true; - bool stop = false; - float volume = 1.0f; - float pitch = 1.0f; - bool loop = true; - - MusicEffect() = default; - explicit MusicEffect(Audio::MusicId id) - : musicId(id) {} - }; - - struct SpriteAnimation : public IComponent { - Animation::AnimationClipId clipId = Animation::INVALID_CLIP_ID; - float currentTime = 0.0f; - float playbackSpeed = 1.0f; - bool playing = true; - bool looping = false; - bool destroyOnComplete = false; - - std::size_t currentFrameIndex = 0; - Math::Rectangle currentRegion{}; - - SpriteAnimation() = default; - SpriteAnimation(Animation::AnimationClipId clip, bool loop = false, float speed = 1.0f) - : clipId(clip), playbackSpeed(speed), looping(loop) {} - }; - - struct AnimationStateMachine : public IComponent { - Animation::AnimationGraphId graphId = Animation::INVALID_GRAPH_ID; - Animation::AnimationStateId currentState = Animation::INVALID_STATE_ID; - Animation::AnimationStateId previousState = Animation::INVALID_STATE_ID; - float stateTime = 0.0f; - float blendFactor = 0.0f; - float blendDuration = 0.0f; - bool isTransitioning = false; - - static constexpr std::size_t MAX_PARAMS = 8; - std::array parameters{}; - std::array, MAX_PARAMS> parameterNames{}; - std::size_t parameterCount = 0; - - AnimationStateMachine() = default; - explicit AnimationStateMachine(Animation::AnimationGraphId graph) - : graphId(graph) {} - - void SetParameter(const char* name, float value) { - for (std::size_t i = 0; i < parameterCount; ++i) { - if (std::strncmp(parameterNames[i].data(), name, 31) == 0) { - parameters[i] = value; - return; - } - } - if (parameterCount < MAX_PARAMS) { - std::strncpy(parameterNames[parameterCount].data(), name, 31); - parameterNames[parameterCount][31] = '\0'; - parameters[parameterCount] = value; - parameterCount++; - } - } - - float GetParameter(const char* name) const { - for (std::size_t i = 0; i < parameterCount; ++i) { - if (std::strncmp(parameterNames[i].data(), name, 31) == 0) { - return parameters[i]; - } - } - return 0.0f; - } - }; - - struct AnimatedSprite : public IComponent { - bool needsUpdate = true; - - AnimatedSprite() = default; - }; - - struct VisualEffect : public IComponent { - Animation::EffectType type = Animation::EffectType::EXPLOSION_SMALL; - float lifetime = 0.0f; - float maxLifetime = 1.0f; - Entity owner = NULL_ENTITY; - float offsetX = 0.0f; - float offsetY = 0.0f; - - VisualEffect() = default; - VisualEffect(Animation::EffectType t, float duration) - : type(t), maxLifetime(duration) {} - VisualEffect(Animation::EffectType t, float duration, Entity ownerEntity, float offX, float offY) - : type(t), maxLifetime(duration), owner(ownerEntity), offsetX(offX), offsetY(offY) {} - }; - - struct FloatingText : public IComponent { - char text[32] = {}; - float lifetime = 0.0f; - float maxLifetime = 1.5f; - float velocityY = -50.0f; - float fadeStartTime = 0.5f; - Math::Color color{1.0f, 1.0f, 1.0f, 1.0f}; - - FloatingText() = default; - FloatingText(const char* txt, float duration, const Math::Color& col) - : maxLifetime(duration), color(col) { - if (txt) { - std::strncpy(text, txt, 31); - text[31] = '\0'; - } - } - }; - - struct AnimationEvents : public IComponent { - static constexpr std::size_t MAX_EVENTS = 4; - std::array, MAX_EVENTS> eventNames{}; - std::size_t eventCount = 0; - - AnimationEvents() = default; - - void PushEvent(const char* name) { - if (eventCount < MAX_EVENTS && name) { - std::strncpy(eventNames[eventCount].data(), name, 31); - eventNames[eventCount][31] = '\0'; - eventCount++; - } - } - - void Clear() { eventCount = 0; } - - bool HasEvent(const char* name) const { - for (std::size_t i = 0; i < eventCount; ++i) { - if (std::strncmp(eventNames[i].data(), name, 31) == 0) { - return true; - } - } - return false; - } - }; - - struct AnimationLayer : public IComponent { - Animation::AnimationClipId clipId = Animation::INVALID_CLIP_ID; - float currentTime = 0.0f; - float weight = 1.0f; - float playbackSpeed = 1.0f; - bool additive = false; - int layerIndex = 0; - - AnimationLayer() = default; - AnimationLayer(Animation::AnimationClipId clip, int layer, float w = 1.0f) - : clipId(clip), weight(w), layerIndex(layer) {} - }; - - struct PowerUpGlow : public IComponent { - float time = 0.0f; - float pulseSpeed = 2.0f; - float minAlpha = 0.7f; - float maxAlpha = 1.0f; - float baseScale = 2.5f; - float scalePulse = 0.08f; - - PowerUpGlow() = default; - }; - } - -} diff --git a/libs/engine/src/ECS/CMakeLists.txt b/libs/engine/src/ECS/CMakeLists.txt deleted file mode 100644 index 72a199e..0000000 --- a/libs/engine/src/ECS/CMakeLists.txt +++ /dev/null @@ -1,91 +0,0 @@ -set(ECS_SOURCES - Registry.cpp - AudioSystem.cpp - MovementSystem.cpp - InputSystem.cpp - RenderingSystem.cpp - TextRenderingSystem.cpp - MenuSystem.cpp - PlayerSystem.cpp - PlayerFactory.cpp - CollisionDetectionSystem.cpp - BulletCollisionResponseSystem.cpp - PlayerCollisionResponseSystem.cpp - ObstacleCollisionResponseSystem.cpp - EnemySystem.cpp - EnemyFactory.cpp - HealthSystem.cpp - ScoreSystem.cpp - ShootingSystem.cpp - ScrollingSystem.cpp - LevelLoader.cpp - PowerUpFactory.cpp - PowerUpSpawnSystem.cpp - PowerUpCollisionSystem.cpp - ForcePodSystem.cpp - ShieldSystem.cpp - BossSystem.cpp - BossAttackSystem.cpp - MineSystem.cpp - BlackOrbSystem.cpp - ThirdBulletSystem.cpp - AnimationSystem.cpp - EffectFactory.cpp -) - -set(ECS_HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Component.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/AudioSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Components/TextLabel.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Components/Clickable.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Entity.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/Registry.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/ISystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/SparseArray.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/MovementSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/InputSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/RenderingSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/TextRenderingSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/MenuSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/PlayerSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/PlayerFactory.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/CollisionDetectionSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/BulletCollisionResponseSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/PlayerCollisionResponseSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/ObstacleCollisionResponseSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/EnemySystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/EnemyFactory.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/HealthSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/ScoreSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/ShootingSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/ScrollingSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/LevelLoader.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/PowerUpFactory.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/PowerUpSpawnSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/PowerUpCollisionSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/ForcePodSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/ShieldSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/BossSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/BossAttackSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/MineSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/BlackOrbSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/ThirdBulletSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/AnimationSystem.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../include/ECS/EffectFactory.hpp -) - -add_library(rtype_ecs STATIC - ${ECS_SOURCES} - ${ECS_HEADERS} -) - -target_include_directories(rtype_ecs PUBLIC - $ - $ -) - -target_link_libraries(rtype_ecs PUBLIC nlohmann_json::nlohmann_json rtype_animation) - -set_target_properties(rtype_ecs PROPERTIES - POSITION_INDEPENDENT_CODE ON -) diff --git a/libs/network/CMakeLists.txt b/libs/network/CMakeLists.txt index fae57fc..488f8b7 100644 --- a/libs/network/CMakeLists.txt +++ b/libs/network/CMakeLists.txt @@ -39,7 +39,8 @@ add_library(rtype_network target_include_directories(rtype_network PUBLIC $ - $ + $ + $ ) find_package(lz4 CONFIG REQUIRED) @@ -48,7 +49,7 @@ target_link_libraries(rtype_network PUBLIC asio Threads::Threads nlohmann_json::nlohmann_json - rtype_ecs + rtype_game lz4::lz4 ) diff --git a/libs/network/include/GameServer.hpp b/libs/network/include/GameServer.hpp index fee7267..d98c429 100644 --- a/libs/network/include/GameServer.hpp +++ b/libs/network/include/GameServer.hpp @@ -12,27 +12,27 @@ #include "ECS/Registry.hpp" #include "ECS/Component.hpp" #include "ECS/MovementSystem.hpp" -#include "ECS/EnemySystem.hpp" +#include "EnemySystem.hpp" #include "ECS/CollisionDetectionSystem.hpp" -#include "ECS/BulletCollisionResponseSystem.hpp" -#include "ECS/PlayerCollisionResponseSystem.hpp" -#include "ECS/ObstacleCollisionResponseSystem.hpp" +#include "BulletCollisionResponseSystem.hpp" +#include "PlayerCollisionResponseSystem.hpp" +#include "ObstacleCollisionResponseSystem.hpp" #include "ECS/ScrollingSystem.hpp" -#include "ECS/BossSystem.hpp" -#include "ECS/BossAttackSystem.hpp" -#include "ECS/MineSystem.hpp" -#include "ECS/BlackOrbSystem.hpp" -#include "ECS/ThirdBulletSystem.hpp" -#include "ECS/LevelLoader.hpp" +#include "BossSystem.hpp" +#include "BossAttackSystem.hpp" +#include "MineSystem.hpp" +#include "BlackOrbSystem.hpp" +#include "ThirdBulletSystem.hpp" +#include "LevelLoader.hpp" #include "ECS/HealthSystem.hpp" #include "ECS/ScoreSystem.hpp" -#include "ECS/PlayerFactory.hpp" -#include "ECS/EnemyFactory.hpp" -#include "ECS/PowerUpSpawnSystem.hpp" -#include "ECS/PowerUpCollisionSystem.hpp" -#include "ECS/ShootingSystem.hpp" -#include "ECS/ForcePodSystem.hpp" -#include "ECS/ShieldSystem.hpp" +#include "PlayerFactory.hpp" +#include "EnemyFactory.hpp" +#include "PowerUpSpawnSystem.hpp" +#include "PowerUpCollisionSystem.hpp" +#include "ShootingSystem.hpp" +#include "ForcePodSystem.hpp" +#include "ShieldSystem.hpp" #include #include #include diff --git a/libs/network/src/GameServer.cpp b/libs/network/src/GameServer.cpp index 766250e..7fad140 100644 --- a/libs/network/src/GameServer.cpp +++ b/libs/network/src/GameServer.cpp @@ -7,8 +7,8 @@ #include "GameServer.hpp" #include "Compression.hpp" -#include "ECS/BossSystem.hpp" -#include "ECS/MineSystem.hpp" +#include "BossSystem.hpp" +#include "MineSystem.hpp" #include #include #include diff --git a/tests/test_camera_system.cpp b/tests/test_camera_system.cpp new file mode 100644 index 0000000..b02d73c --- /dev/null +++ b/tests/test_camera_system.cpp @@ -0,0 +1,108 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type +** File description: +** Test Camera2DSystem +*/ + +#include "ECS/Components/Camera2D.hpp" +#include "ECS/Camera2DSystem.hpp" +#include "Renderer/IRenderer.hpp" +#include "ECS/Registry.hpp" +#include "ECS/Component.hpp" +#include +#include + +class MockRenderer : public Renderer::IRenderer { +public: + Renderer::Vector2 GetWindowSize() const override { + return {1280.0f, 720.0f}; + } + + // Minimal override stubs for abstract class (returning default values) + const char* GetName() const override { return "Mock"; } + RType::Core::ModulePriority GetPriority() const override { return RType::Core::ModulePriority::Normal; } + bool Initialize(RType::Core::Engine*) override { return true; } + void Shutdown() override {} + void Update(float) override {} + bool ShouldUpdateInRenderThread() const override { return false; } + bool CreateWindow(const Renderer::WindowConfig&) override { return true; } + void Destroy() override {} + bool IsWindowOpen() const override { return true; } + void Resize(std::uint32_t, std::uint32_t) override {} + void SetWindowTitle(const std::string&) override {} + void BeginFrame() override {} + void EndFrame() override {} + void Clear(const Renderer::Color&) override {} + Renderer::TextureId LoadTexture(const std::string&, const Renderer::TextureConfig&) override { return 0; } + void UnloadTexture(Renderer::TextureId) override {} + Renderer::Vector2 GetTextureSize(Renderer::TextureId) const override { return {0,0}; } + Renderer::SpriteId CreateSprite(Renderer::TextureId, const Renderer::Rectangle&) override { return 0; } + void DestroySprite(Renderer::SpriteId) override {} + void SetSpriteRegion(Renderer::SpriteId, const Renderer::Rectangle&) override {} + void DrawSprite(Renderer::SpriteId, const Renderer::Transform2D&, const Renderer::Color&) override {} + void DrawRectangle(const Renderer::Rectangle&, const Renderer::Color&) override {} + Renderer::FontId LoadFont(const std::string&, std::uint32_t) override { return 0; } + void UnloadFont(Renderer::FontId) override {} + void DrawText(Renderer::FontId, const std::string&, const Renderer::TextParams&) override {} + + void SetCamera(const Renderer::Camera2D& cam) override { + lastCamera = cam; + cameraSet = true; + } + void ResetCamera() override { + cameraSet = false; + } + Renderer::RenderStats GetRenderStats() const override { return {}; } + float GetDeltaTime() override { return 0.016f; } + bool IsKeyPressed(Renderer::Key) const override { return false; } + bool IsMouseButtonPressed(Renderer::MouseButton) const override { return false; } + Renderer::Vector2 GetMousePosition() const override { return {0,0}; } + + Renderer::Camera2D lastCamera; + bool cameraSet = false; +}; + +int main() { + MockRenderer renderer; + RType::ECS::Camera2DSystem cameraSystem(&renderer); + RType::ECS::Registry registry; + + // Create camera entity + auto camEntity = registry.CreateEntity(); + auto& cam = registry.AddComponent(camEntity); + cam.active = true; + cam.zoom = 1.0f; + cam.smoothSpeed = 100.0f; // High speed for instant snap test or multiple updates + + // Create target entity + auto targetEntity = registry.CreateEntity(); + registry.AddComponent(targetEntity, RType::ECS::Position{100.0f, 200.0f}); + + // Set target + cam.target = targetEntity; + + // Initial update + cameraSystem.Update(registry, 1.0f); + + // Implementation detail: Camera2DSystem centers camera + // Window size (1280, 720) -> Center is offset (640, 360) + // If target is at (100, 200), Camera should center on it. + // SFML View center should be (100, 200). + // Let's verify what SetCamera received. + + assert(renderer.cameraSet && "SetCamera should be called"); + // Depending on implementation, Camera2DSystem logic might vary. + // Typically: view.setCenter(targetPos + offset) + assert(renderer.lastCamera.center.x == 100.0f); + assert(renderer.lastCamera.center.y == 200.0f); + + // Test screen to world + Math::Vector2 screenPos{640.0f, 360.0f}; // Center of screen + Math::Vector2 worldPos = cameraSystem.ScreenToWorld(screenPos); + // Should be approx 100, 200 + std::cout << "Screen(640,360) -> World(" << worldPos.x << "," << worldPos.y << ")" << std::endl; + + std::cout << "Camera2DSystem tests passed!" << std::endl; + return 0; +} diff --git a/tests/test_event_bus.cpp b/tests/test_event_bus.cpp new file mode 100644 index 0000000..69da887 --- /dev/null +++ b/tests/test_event_bus.cpp @@ -0,0 +1,69 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type +** File description: +** Test EventBus +*/ + +#include "Core/EventBus.hpp" +#include +#include + +struct TestEvent { + int value; +}; + +struct AnotherEvent { + std::string message; +}; + +int main() { + RType::Core::EventBus eventBus; + bool handlerCalled = false; + int receivedValue = 0; + + // Test Subscription + eventBus.Subscribe([&](const TestEvent& event) { + handlerCalled = true; + receivedValue = event.value; + }); + + // Test Publish + TestEvent event{42}; + eventBus.Publish(event); + + assert(handlerCalled && "Handler should be called"); + assert(receivedValue == 42 && "Value should be 42"); + + // Test multiple handlers + bool handler2Called = false; + eventBus.Subscribe([&](const TestEvent&) { + handler2Called = true; + }); + + handlerCalled = false; + handler2Called = false; + eventBus.Publish(TestEvent{100}); + + assert(handlerCalled && "Handler 1 should be called"); + assert(handler2Called && "Handler 2 should be called"); + + // Test different event type + bool stringHandlerCalled = false; + eventBus.Subscribe([&](const AnotherEvent& event) { + stringHandlerCalled = true; + assert(event.message == "Hello"); + }); + + eventBus.Publish(AnotherEvent{"Hello"}); + assert(stringHandlerCalled && "String handler should be called"); + + // Test Clear + eventBus.Clear(); + handlerCalled = false; + eventBus.Publish(TestEvent{1}); + assert(!handlerCalled && "Handler should NOT be called after Clear()"); + + std::cout << "EventBus tests passed!" << std::endl; + return 0; +} diff --git a/tests/test_health_system.cpp b/tests/test_health_system.cpp index eeda349..693fbbf 100644 --- a/tests/test_health_system.cpp +++ b/tests/test_health_system.cpp @@ -11,10 +11,10 @@ #include "Renderer/IRenderer.hpp" #include "ECS/Component.hpp" #include "ECS/InputSystem.hpp" -#include "ECS/PlayerSystem.hpp" -#include "ECS/PlayerFactory.hpp" -#include "ECS/EnemySystem.hpp" -#include "ECS/EnemyFactory.hpp" +#include "PlayerSystem.hpp" +#include "PlayerFactory.hpp" +#include "EnemySystem.hpp" +#include "EnemyFactory.hpp" #include "ECS/MovementSystem.hpp" #include "ECS/CollisionDetectionSystem.hpp" #include "ECS/HealthSystem.hpp" diff --git a/tests/test_player_system.cpp b/tests/test_player_system.cpp index 238a2b1..7ee47ca 100644 --- a/tests/test_player_system.cpp +++ b/tests/test_player_system.cpp @@ -11,8 +11,8 @@ #include "Renderer/IRenderer.hpp" #include "ECS/Component.hpp" #include "ECS/InputSystem.hpp" -#include "ECS/PlayerSystem.hpp" -#include "ECS/PlayerFactory.hpp" +#include "PlayerSystem.hpp" +#include "PlayerFactory.hpp" #include "ECS/MovementSystem.hpp" #include "ECS/RenderingSystem.hpp" #include diff --git a/tests/test_scene_manager.cpp b/tests/test_scene_manager.cpp new file mode 100644 index 0000000..28c4b9b --- /dev/null +++ b/tests/test_scene_manager.cpp @@ -0,0 +1,47 @@ +/* +** EPITECH PROJECT, 2025 +** R-Type +** File description: +** Test SceneManager +*/ + +#include "Core/SceneManager.hpp" +#include "ECS/Registry.hpp" +#include +#include + +int main() { + RType::ECS::Registry registry; + RType::Core::SceneManager sceneManager(®istry); + + bool scene1Loaded = false; + bool scene2Loaded = false; + + // Test LoadScene + sceneManager.LoadScene("Scene1", [&](RType::ECS::Registry& r) { + scene1Loaded = true; + auto e = r.CreateEntity(); // Create one entity + }); + + assert(scene1Loaded && "Scene1 setup should be called"); + assert(sceneManager.GetCurrentSceneName() == "Scene1"); + assert(registry.GetEntityCount() == 1 && "Registry should have 1 entity"); + + // Test Transition (should clear previous scene) + sceneManager.RegisterScene("Scene2", [&](RType::ECS::Registry& r) { + scene2Loaded = true; + // Verify registry was cleared (Entity count reset? ID reset?) + // Note: Registry::Clear resets ID to 1. + auto e = r.CreateEntity(); + }); + sceneManager.TransitionTo("Scene2"); + + assert(scene2Loaded && "Scene2 setup should be called"); + assert(sceneManager.GetCurrentSceneName() == "Scene2"); + // Implementation detail: SceneManager::TransitionTo calls UnloadCurrentScene (which clears registry) then LoadScene. + // So entity count should be 1 (from Scene2), not 2. + assert(registry.GetEntityCount() == 1 && "Registry should be cleared and have 1 entity from Scene2"); + + std::cout << "SceneManager tests passed!" << std::endl; + return 0; +}