diff --git a/Extra2D/include/extra2d/app/application.h b/Extra2D/include/extra2d/app/application.h index f498ce2..df343e9 100644 --- a/Extra2D/include/extra2d/app/application.h +++ b/Extra2D/include/extra2d/app/application.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -10,70 +11,209 @@ namespace extra2d { class IInput; -class SceneManager; -class TimerManager; -class EventQueue; -class EventDispatcher; -class Camera; -class ViewportAdapter; class RenderBackend; +/** + * @brief 应用程序类 + * 使用服务定位器模式管理模块依赖,支持依赖注入和测试Mock + */ class Application { public: + /** + * @brief 获取单例实例 + * @return 应用程序实例引用 + */ static Application& get(); Application(const Application&) = delete; Application& operator=(const Application&) = delete; + /** + * @brief 使用默认配置初始化 + * @return 初始化成功返回 true + */ bool init(); + + /** + * @brief 使用指定配置初始化 + * @param config 应用配置 + * @return 初始化成功返回 true + */ bool init(const AppConfig& config); + + /** + * @brief 使用配置文件初始化 + * @param configPath 配置文件路径 + * @return 初始化成功返回 true + */ bool init(const std::string& configPath); + /** + * @brief 关闭应用程序 + */ void shutdown(); + + /** + * @brief 运行主循环 + */ void run(); + + /** + * @brief 请求退出 + */ void quit(); + + /** + * @brief 暂停应用程序 + */ void pause(); + + /** + * @brief 恢复应用程序 + */ void resume(); + /** + * @brief 检查是否暂停 + * @return 暂停状态返回 true + */ bool isPaused() const { return paused_; } + + /** + * @brief 检查是否运行中 + * @return 运行中返回 true + */ bool isRunning() const { return running_; } + /** + * @brief 获取窗口 + * @return 窗口引用 + */ IWindow& window() { return *window_; } + + /** + * @brief 获取渲染器 + * @return 渲染器引用 + */ RenderBackend& renderer(); + + /** + * @brief 获取输入接口 + * @return 输入接口引用 + */ IInput& input(); - SceneManager& scenes(); - TimerManager& timers(); - EventQueue& eventQueue(); - EventDispatcher& eventDispatcher(); - Camera& camera(); - ViewportAdapter& viewportAdapter(); + /** + * @brief 获取场景服务 + * @return 场景服务共享指针 + */ + SharedPtr scenes(); + /** + * @brief 获取计时器服务 + * @return 计时器服务共享指针 + */ + SharedPtr timers(); + + /** + * @brief 获取事件服务 + * @return 事件服务共享指针 + */ + SharedPtr events(); + + /** + * @brief 获取相机服务 + * @return 相机服务共享指针 + */ + SharedPtr camera(); + + /** + * @brief 进入场景 + * @param scene 场景指针 + */ void enterScene(Ptr scene); + /** + * @brief 获取帧间隔时间 + * @return 帧间隔时间(秒) + */ float deltaTime() const { return deltaTime_; } + + /** + * @brief 获取总运行时间 + * @return 总运行时间(秒) + */ float totalTime() const { return totalTime_; } + + /** + * @brief 获取当前帧率 + * @return 帧率 + */ int fps() const { return currentFps_; } + /** + * @brief 获取配置管理器 + * @return 配置管理器引用 + */ ConfigManager& config(); + + /** + * @brief 获取应用配置 + * @return 应用配置常量引用 + */ const AppConfig& getConfig() const; + /** + * @brief 注册自定义服务 + * @tparam T 服务接口类型 + * @param service 服务实例 + */ + template + void registerService(SharedPtr service) { + ServiceLocator::instance().registerService(service); + } + + /** + * @brief 获取服务 + * @tparam T 服务接口类型 + * @return 服务共享指针 + */ + template + SharedPtr getService() { + return ServiceLocator::instance().getService(); + } + private: Application() = default; ~Application(); + /** + * @brief 初始化模块 + * @return 初始化成功返回 true + */ bool initModules(); + + /** + * @brief 注册核心服务 + */ + void registerCoreServices(); + + /** + * @brief 主循环 + */ void mainLoop(); + + /** + * @brief 更新 + */ void update(); + + /** + * @brief 渲染 + */ void render(); IWindow* window_ = nullptr; - UniquePtr sceneManager_; - UniquePtr timerManager_; - UniquePtr eventQueue_; - UniquePtr eventDispatcher_; - UniquePtr camera_; - UniquePtr viewportAdapter_; bool initialized_ = false; bool running_ = false; @@ -88,4 +228,4 @@ private: int currentFps_ = 0; }; -} // namespace extra2d +} diff --git a/Extra2D/include/extra2d/core/service_interface.h b/Extra2D/include/extra2d/core/service_interface.h new file mode 100644 index 0000000..0b77e69 --- /dev/null +++ b/Extra2D/include/extra2d/core/service_interface.h @@ -0,0 +1,144 @@ +#pragma once + +#include +#include + +namespace extra2d { + +/** + * @brief 服务优先级枚举 + * 定义服务的初始化顺序,数值越小越先初始化 + */ +enum class ServicePriority : int { + Core = 0, + Event = 100, + Timer = 200, + Scene = 300, + Camera = 400, + Resource = 500, + Audio = 600, + User = 1000 +}; + +/** + * @brief 服务状态枚举 + */ +enum class ServiceState { + Uninitialized, + Initializing, + Running, + Paused, + Stopping, + Stopped +}; + +/** + * @brief 服务信息结构体 + */ +struct ServiceInfo { + std::string name; + ServicePriority priority = ServicePriority::User; + ServiceState state = ServiceState::Uninitialized; + bool enabled = true; +}; + +/** + * @brief 服务接口基类 + * 所有服务必须实现此接口,支持依赖注入和生命周期管理 + */ +class IService { + friend class ServiceLocator; + +public: + virtual ~IService() = default; + + /** + * @brief 获取服务信息 + * @return 服务信息结构体 + */ + virtual ServiceInfo getServiceInfo() const = 0; + + /** + * @brief 初始化服务 + * @return 初始化成功返回 true + */ + virtual bool initialize() = 0; + + /** + * @brief 关闭服务 + */ + virtual void shutdown() = 0; + + /** + * @brief 暂停服务 + */ + virtual void pause() { + info_.state = ServiceState::Paused; + } + + /** + * @brief 恢复服务 + */ + virtual void resume() { + if (info_.state == ServiceState::Paused) { + info_.state = ServiceState::Running; + } + } + + /** + * @brief 更新服务 + * @param deltaTime 帧间隔时间 + */ + virtual void update(float deltaTime) { } + + /** + * @brief 检查服务是否已初始化 + * @return 已初始化返回 true + */ + virtual bool isInitialized() const { + return info_.state == ServiceState::Running || + info_.state == ServiceState::Paused; + } + + /** + * @brief 获取服务状态 + * @return 当前服务状态 + */ + ServiceState getState() const { return info_.state; } + + /** + * @brief 获取服务名称 + * @return 服务名称 + */ + const std::string& getName() const { return info_.name; } + +protected: + ServiceInfo info_; + + /** + * @brief 设置服务状态 + * @param state 新状态 + */ + void setState(ServiceState state) { info_.state = state; } +}; + +/** + * @brief 类型ID生成器 + * 用于为每种服务类型生成唯一ID + */ +using ServiceTypeId = size_t; + +namespace detail { + inline ServiceTypeId nextServiceTypeId() { + static ServiceTypeId id = 0; + return ++id; + } + + template + ServiceTypeId getServiceTypeId() { + static ServiceTypeId id = nextServiceTypeId(); + return id; + } +} + +} diff --git a/Extra2D/include/extra2d/core/service_locator.h b/Extra2D/include/extra2d/core/service_locator.h new file mode 100644 index 0000000..e2735fd --- /dev/null +++ b/Extra2D/include/extra2d/core/service_locator.h @@ -0,0 +1,252 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace extra2d { + +/** + * @brief 服务工厂函数类型 + */ +template +using ServiceFactory = std::function()>; + +/** + * @brief 服务定位器 + * 实现依赖注入和服务发现模式,解耦模块间依赖 + * + * 特性: + * - 类型安全的服务注册和获取 + * - 支持服务工厂延迟创建 + * - 支持服务依赖声明 + * - 线程安全 + * - 支持 Mock 测试 + */ +class ServiceLocator { +public: + /** + * @brief 获取单例实例 + * @return 服务定位器实例引用 + */ + static ServiceLocator& instance(); + + ServiceLocator(const ServiceLocator&) = delete; + ServiceLocator& operator=(const ServiceLocator&) = delete; + + /** + * @brief 注册服务实例 + * @tparam T 服务接口类型 + * @param service 服务实例 + */ + template + void registerService(SharedPtr service) { + static_assert(std::is_base_of_v, + "T must derive from IService"); + + std::lock_guard lock(mutex_); + auto typeId = std::type_index(typeid(T)); + services_[typeId] = std::static_pointer_cast(service); + orderedServices_.push_back(service); + sortServices(); + } + + /** + * @brief 注册服务工厂 + * @tparam T 服务接口类型 + * @param factory 服务工厂函数 + */ + template + void registerFactory(ServiceFactory factory) { + static_assert(std::is_base_of_v, + "T must derive from IService"); + + std::lock_guard lock(mutex_); + auto typeId = std::type_index(typeid(T)); + factories_[typeId] = [factory]() -> SharedPtr { + return std::static_pointer_cast(factory()); + }; + } + + /** + * @brief 获取服务实例 + * @tparam T 服务接口类型 + * @return 服务实例,不存在返回 nullptr + */ + template + SharedPtr getService() const { + static_assert(std::is_base_of_v, + "T must derive from IService"); + + std::lock_guard lock(mutex_); + auto typeId = std::type_index(typeid(T)); + + auto it = services_.find(typeId); + if (it != services_.end()) { + return std::static_pointer_cast(it->second); + } + + auto factoryIt = factories_.find(typeId); + if (factoryIt != factories_.end()) { + auto service = factoryIt->second(); + services_[typeId] = service; + return std::static_pointer_cast(service); + } + + return nullptr; + } + + /** + * @brief 尝试获取服务实例(不创建) + * @tparam T 服务接口类型 + * @return 服务实例,不存在返回 nullptr + */ + template + SharedPtr tryGetService() const { + static_assert(std::is_base_of_v, + "T must derive from IService"); + + std::lock_guard lock(mutex_); + auto typeId = std::type_index(typeid(T)); + auto it = services_.find(typeId); + if (it != services_.end()) { + return std::static_pointer_cast(it->second); + } + return nullptr; + } + + /** + * @brief 检查服务是否已注册 + * @tparam T 服务接口类型 + * @return 已注册返回 true + */ + template + bool hasService() const { + std::lock_guard lock(mutex_); + auto typeId = std::type_index(typeid(T)); + return services_.find(typeId) != services_.end() || + factories_.find(typeId) != factories_.end(); + } + + /** + * @brief 注销服务 + * @tparam T 服务接口类型 + */ + template + void unregisterService() { + std::lock_guard lock(mutex_); + auto typeId = std::type_index(typeid(T)); + + auto it = services_.find(typeId); + if (it != services_.end()) { + auto service = it->second; + services_.erase(it); + + auto orderIt = std::find(orderedServices_.begin(), + orderedServices_.end(), service); + if (orderIt != orderedServices_.end()) { + orderedServices_.erase(orderIt); + } + } + + factories_.erase(typeId); + } + + /** + * @brief 初始化所有已注册的服务 + * @return 所有服务初始化成功返回 true + */ + bool initializeAll(); + + /** + * @brief 关闭所有服务 + */ + void shutdownAll(); + + /** + * @brief 更新所有服务 + * @param deltaTime 帧间隔时间 + */ + void updateAll(float deltaTime); + + /** + * @brief 暂停所有服务 + */ + void pauseAll(); + + /** + * @brief 恢复所有服务 + */ + void resumeAll(); + + /** + * @brief 获取所有服务(按优先级排序) + * @return 服务列表 + */ + std::vector> getAllServices() const; + + /** + * @brief 清空所有服务和工厂 + */ + void clear(); + + /** + * @brief 获取已注册服务数量 + * @return 服务数量 + */ + size_t size() const { return services_.size(); } + +private: + ServiceLocator() = default; + ~ServiceLocator() = default; + + /** + * @brief 按优先级排序服务 + */ + void sortServices(); + + mutable std::unordered_map> services_; + std::unordered_map()>> factories_; + std::vector> orderedServices_; + mutable std::mutex mutex_; +}; + +/** + * @brief 服务注册器 + * 用于静态注册服务 + */ +template +class ServiceRegistrar { +public: + explicit ServiceRegistrar(ServiceFactory factory = nullptr) { + if (factory) { + ServiceLocator::instance().registerFactory(factory); + } else { + ServiceLocator::instance().registerFactory( + []() -> SharedPtr { + return makeShared(); + } + ); + } + } +}; + +} + +#define E2D_REGISTER_SERVICE(Interface, Implementation) \ + namespace { \ + static ::extra2d::ServiceRegistrar \ + E2D_CONCAT(service_registrar_, __LINE__); \ + } + +#define E2D_REGISTER_SERVICE_FACTORY(Interface, Factory) \ + namespace { \ + static ::extra2d::ServiceRegistrar \ + E2D_CONCAT(service_factory_registrar_, __LINE__)(Factory); \ + } diff --git a/Extra2D/include/extra2d/core/service_registry.h b/Extra2D/include/extra2d/core/service_registry.h new file mode 100644 index 0000000..7ce4964 --- /dev/null +++ b/Extra2D/include/extra2d/core/service_registry.h @@ -0,0 +1,137 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace extra2d { + +/** + * @brief 服务注册信息 + */ +struct ServiceRegistration { + std::string name; + ServicePriority priority; + std::function()> factory; + bool enabled = true; +}; + +/** + * @brief 服务注册表 + * 管理服务的注册信息,支持延迟创建和配置 + */ +class ServiceRegistry { +public: + /** + * @brief 获取单例实例 + * @return 服务注册表实例引用 + */ + static ServiceRegistry& instance(); + + ServiceRegistry(const ServiceRegistry&) = delete; + ServiceRegistry& operator=(const ServiceRegistry&) = delete; + + /** + * @brief 注册服务 + * @tparam T 服务接口类型 + * @tparam Impl 服务实现类型 + * @param name 服务名称 + * @param priority 服务优先级 + */ + template + void registerService(const std::string& name, ServicePriority priority) { + static_assert(std::is_base_of_v, + "T must derive from IService"); + static_assert(std::is_base_of_v, + "Impl must derive from T"); + + ServiceRegistration reg; + reg.name = name; + reg.priority = priority; + reg.factory = []() -> SharedPtr { + return std::static_pointer_cast(makeShared()); + }; + registrations_.push_back(reg); + } + + /** + * @brief 注册服务(带工厂函数) + * @tparam T 服务接口类型 + * @param name 服务名称 + * @param priority 服务优先级 + * @param factory 工厂函数 + */ + template + void registerServiceWithFactory( + const std::string& name, + ServicePriority priority, + std::function()> factory) { + static_assert(std::is_base_of_v, + "T must derive from IService"); + + ServiceRegistration reg; + reg.name = name; + reg.priority = priority; + reg.factory = [factory]() -> SharedPtr { + return std::static_pointer_cast(factory()); + }; + registrations_.push_back(reg); + } + + /** + * @brief 启用/禁用服务 + * @param name 服务名称 + * @param enabled 是否启用 + */ + void setServiceEnabled(const std::string& name, bool enabled); + + /** + * @brief 创建所有已注册的服务 + * 并注册到 ServiceLocator + */ + void createAllServices(); + + /** + * @brief 获取所有注册信息 + * @return 注册信息列表 + */ + const std::vector& getRegistrations() const { + return registrations_; + } + + /** + * @brief 清空所有注册 + */ + void clear() { + registrations_.clear(); + } + +private: + ServiceRegistry() = default; + ~ServiceRegistry() = default; + + std::vector registrations_; +}; + +/** + * @brief 自动服务注册器 + * 在全局作用域使用,自动注册服务 + */ +template +class AutoServiceRegistrar { +public: + AutoServiceRegistrar(const std::string& name, ServicePriority priority) { + ServiceRegistry::instance().registerService( + name, priority); + } +}; + +} + +#define E2D_REGISTER_SERVICE_AUTO(Interface, Implementation, Name, Priority) \ + namespace { \ + static ::extra2d::AutoServiceRegistrar \ + E2D_CONCAT(auto_service_registrar_, __LINE__)(Name, Priority); \ + } diff --git a/Extra2D/include/extra2d/core/types.h b/Extra2D/include/extra2d/core/types.h index fb75de7..b3720eb 100644 --- a/Extra2D/include/extra2d/core/types.h +++ b/Extra2D/include/extra2d/core/types.h @@ -7,10 +7,17 @@ namespace extra2d { +// --------------------------------------------------------------------------- +// 宏定义 +// --------------------------------------------------------------------------- +#define E2D_CONCAT_IMPL(a, b) a##b +#define E2D_CONCAT(a, b) E2D_CONCAT_IMPL(a, b) + // --------------------------------------------------------------------------- // 智能指针别名 // --------------------------------------------------------------------------- template using Ptr = std::shared_ptr; +template using SharedPtr = std::shared_ptr; template using UniquePtr = std::unique_ptr; @@ -21,6 +28,10 @@ template inline Ptr makePtr(Args &&...args) { return std::make_shared(std::forward(args)...); } +template inline SharedPtr makeShared(Args &&...args) { + return std::make_shared(std::forward(args)...); +} + /// 创建 unique_ptr 的便捷函数 template inline UniquePtr makeUnique(Args &&...args) { diff --git a/Extra2D/include/extra2d/services/camera_service.h b/Extra2D/include/extra2d/services/camera_service.h new file mode 100644 index 0000000..5143377 --- /dev/null +++ b/Extra2D/include/extra2d/services/camera_service.h @@ -0,0 +1,111 @@ +#pragma once + +#include +#include +#include + +namespace extra2d { + +/** + * @brief 相机服务接口 + */ +class ICameraService : public IService { +public: + virtual ~ICameraService() = default; + + virtual void setPosition(const Vec2& position) = 0; + virtual void setPosition(float x, float y) = 0; + virtual Vec2 getPosition() const = 0; + + virtual void setRotation(float degrees) = 0; + virtual float getRotation() const = 0; + + virtual void setZoom(float zoom) = 0; + virtual float getZoom() const = 0; + + virtual void setViewport(float left, float right, float bottom, float top) = 0; + virtual Rect getViewport() const = 0; + + virtual glm::mat4 getViewMatrix() const = 0; + virtual glm::mat4 getProjectionMatrix() const = 0; + virtual glm::mat4 getViewProjectionMatrix() const = 0; + + virtual Vec2 screenToWorld(const Vec2& screenPos) const = 0; + virtual Vec2 worldToScreen(const Vec2& worldPos) const = 0; + + virtual void move(const Vec2& offset) = 0; + virtual void move(float x, float y) = 0; + + virtual void setBounds(const Rect& bounds) = 0; + virtual void clearBounds() = 0; + + virtual void lookAt(const Vec2& target) = 0; + + virtual void setViewportConfig(const ViewportConfig& config) = 0; + virtual const ViewportConfig& getViewportConfig() const = 0; + virtual void updateViewport(int screenWidth, int screenHeight) = 0; + virtual const ViewportResult& getViewportResult() const = 0; + + virtual void applyViewportAdapter() = 0; +}; + +/** + * @brief 相机服务实现 + */ +class CameraService : public ICameraService { +public: + CameraService(); + explicit CameraService(float left, float right, float bottom, float top); + ~CameraService() override = default; + + ServiceInfo getServiceInfo() const override; + + bool initialize() override; + void shutdown() override; + + void setPosition(const Vec2& position) override; + void setPosition(float x, float y) override; + Vec2 getPosition() const override; + + void setRotation(float degrees) override; + float getRotation() const override; + + void setZoom(float zoom) override; + float getZoom() const override; + + void setViewport(float left, float right, float bottom, float top) override; + Rect getViewport() const override; + + glm::mat4 getViewMatrix() const override; + glm::mat4 getProjectionMatrix() const override; + glm::mat4 getViewProjectionMatrix() const override; + + Vec2 screenToWorld(const Vec2& screenPos) const override; + Vec2 worldToScreen(const Vec2& worldPos) const override; + + void move(const Vec2& offset) override; + void move(float x, float y) override; + + void setBounds(const Rect& bounds) override; + void clearBounds() override; + + void lookAt(const Vec2& target) override; + + void setViewportConfig(const ViewportConfig& config) override; + const ViewportConfig& getViewportConfig() const override; + void updateViewport(int screenWidth, int screenHeight) override; + const ViewportResult& getViewportResult() const override; + + void applyViewportAdapter() override; + + Camera& getCamera() { return camera_; } + const Camera& getCamera() const { return camera_; } + ViewportAdapter& getViewportAdapter() { return viewportAdapter_; } + const ViewportAdapter& getViewportAdapter() const { return viewportAdapter_; } + +private: + Camera camera_; + ViewportAdapter viewportAdapter_; +}; + +} diff --git a/Extra2D/include/extra2d/services/event_service.h b/Extra2D/include/extra2d/services/event_service.h new file mode 100644 index 0000000..7b91819 --- /dev/null +++ b/Extra2D/include/extra2d/services/event_service.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include + +namespace extra2d { + +/** + * @brief 事件服务接口 + */ +class IEventService : public IService { +public: + virtual ~IEventService() = default; + + virtual void pushEvent(const Event& event) = 0; + virtual void pushEvent(Event&& event) = 0; + virtual bool pollEvent(Event& event) = 0; + + virtual ListenerId addListener(EventType type, EventDispatcher::EventCallback callback) = 0; + virtual void removeListener(ListenerId id) = 0; + virtual void removeAllListeners(EventType type) = 0; + virtual void removeAllListeners() = 0; + + virtual void dispatch(Event& event) = 0; + virtual void processQueue() = 0; + + virtual size_t getListenerCount(EventType type) const = 0; + virtual size_t getTotalListenerCount() const = 0; + virtual size_t getQueueSize() const = 0; +}; + +/** + * @brief 事件服务实现 + */ +class EventService : public IEventService { +public: + EventService(); + ~EventService() override = default; + + ServiceInfo getServiceInfo() const override; + + bool initialize() override; + void shutdown() override; + void update(float deltaTime) override; + + void pushEvent(const Event& event) override; + void pushEvent(Event&& event) override; + bool pollEvent(Event& event) override; + + ListenerId addListener(EventType type, EventDispatcher::EventCallback callback) override; + void removeListener(ListenerId id) override; + void removeAllListeners(EventType type) override; + void removeAllListeners() override; + + void dispatch(Event& event) override; + void processQueue() override; + + size_t getListenerCount(EventType type) const override; + size_t getTotalListenerCount() const override; + size_t getQueueSize() const override; + + EventQueue& getQueue() { return queue_; } + const EventQueue& getQueue() const { return queue_; } + EventDispatcher& getDispatcher() { return dispatcher_; } + const EventDispatcher& getDispatcher() const { return dispatcher_; } + +private: + EventQueue queue_; + EventDispatcher dispatcher_; +}; + +} diff --git a/Extra2D/include/extra2d/services/scene_service.h b/Extra2D/include/extra2d/services/scene_service.h new file mode 100644 index 0000000..742893a --- /dev/null +++ b/Extra2D/include/extra2d/services/scene_service.h @@ -0,0 +1,91 @@ +#pragma once + +#include +#include + +namespace extra2d { + +/** + * @brief 场景服务接口 + * 定义场景管理的抽象接口,便于测试和Mock + */ +class ISceneService : public IService { +public: + virtual ~ISceneService() = default; + + virtual void runWithScene(Ptr scene) = 0; + virtual void replaceScene(Ptr scene) = 0; + virtual void pushScene(Ptr scene) = 0; + virtual void popScene() = 0; + virtual void popToRootScene() = 0; + virtual void popToScene(const std::string& name) = 0; + + virtual Ptr getCurrentScene() const = 0; + virtual Ptr getPreviousScene() const = 0; + virtual Ptr getRootScene() const = 0; + virtual Ptr getSceneByName(const std::string& name) const = 0; + + virtual size_t getSceneCount() const = 0; + virtual bool isEmpty() const = 0; + virtual bool hasScene(const std::string& name) const = 0; + + virtual void render(RenderBackend& renderer) = 0; + virtual void collectRenderCommands(std::vector& commands) = 0; + + virtual bool isTransitioning() const = 0; + virtual void setTransitionCallback(SceneManager::TransitionCallback callback) = 0; + + virtual void end() = 0; + virtual void purgeCachedScenes() = 0; + virtual void enterScene(Ptr scene) = 0; +}; + +/** + * @brief 场景服务实现 + * 包装 SceneManager,实现 IService 接口 + */ +class SceneService : public ISceneService { +public: + SceneService(); + ~SceneService() override = default; + + ServiceInfo getServiceInfo() const override; + + bool initialize() override; + void shutdown() override; + void update(float deltaTime) override; + + void runWithScene(Ptr scene) override; + void replaceScene(Ptr scene) override; + void pushScene(Ptr scene) override; + void popScene() override; + void popToRootScene() override; + void popToScene(const std::string& name) override; + + Ptr getCurrentScene() const override; + Ptr getPreviousScene() const override; + Ptr getRootScene() const override; + Ptr getSceneByName(const std::string& name) const override; + + size_t getSceneCount() const override; + bool isEmpty() const override; + bool hasScene(const std::string& name) const override; + + void render(RenderBackend& renderer) override; + void collectRenderCommands(std::vector& commands) override; + + bool isTransitioning() const override; + void setTransitionCallback(SceneManager::TransitionCallback callback) override; + + void end() override; + void purgeCachedScenes() override; + void enterScene(Ptr scene) override; + + SceneManager& getManager() { return manager_; } + const SceneManager& getManager() const { return manager_; } + +private: + SceneManager manager_; +}; + +} diff --git a/Extra2D/include/extra2d/services/timer_service.h b/Extra2D/include/extra2d/services/timer_service.h new file mode 100644 index 0000000..65a9762 --- /dev/null +++ b/Extra2D/include/extra2d/services/timer_service.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +namespace extra2d { + +/** + * @brief 计时器服务接口 + */ +class ITimerService : public IService { +public: + virtual ~ITimerService() = default; + + virtual uint32 addTimer(float delay, Timer::Callback callback) = 0; + virtual uint32 addRepeatingTimer(float interval, Timer::Callback callback) = 0; + virtual void cancelTimer(uint32 timerId) = 0; + virtual void pauseTimer(uint32 timerId) = 0; + virtual void resumeTimer(uint32 timerId) = 0; + virtual void clear() = 0; + virtual size_t getTimerCount() const = 0; +}; + +/** + * @brief 计时器服务实现 + */ +class TimerService : public ITimerService { +public: + TimerService(); + ~TimerService() override = default; + + ServiceInfo getServiceInfo() const override; + + bool initialize() override; + void shutdown() override; + void update(float deltaTime) override; + + uint32 addTimer(float delay, Timer::Callback callback) override; + uint32 addRepeatingTimer(float interval, Timer::Callback callback) override; + void cancelTimer(uint32 timerId) override; + void pauseTimer(uint32 timerId) override; + void resumeTimer(uint32 timerId) override; + void clear() override; + size_t getTimerCount() const override; + + TimerManager& getManager() { return manager_; } + const TimerManager& getManager() const { return manager_; } + +private: + TimerManager manager_; +}; + +} diff --git a/Extra2D/src/app/application.cpp b/Extra2D/src/app/application.cpp index 1db115c..8a3105c 100644 --- a/Extra2D/src/app/application.cpp +++ b/Extra2D/src/app/application.cpp @@ -1,17 +1,15 @@ #include #include #include -#include -#include -#include #include -#include #include #include #include #include -#include -#include +#include +#include +#include +#include #include #include @@ -88,6 +86,37 @@ bool Application::init(const std::string& configPath) { return initModules(); } +void Application::registerCoreServices() { + auto& locator = ServiceLocator::instance(); + + if (!locator.hasService()) { + locator.registerService(makeShared()); + } + + if (!locator.hasService()) { + locator.registerService(makeShared()); + } + + if (!locator.hasService()) { + locator.registerService(makeShared()); + } + + if (!locator.hasService()) { + auto cameraService = makeShared(); + if (window_) { + cameraService->setViewport(0, static_cast(window_->width()), + static_cast(window_->height()), 0); + ViewportConfig vpConfig; + vpConfig.logicWidth = static_cast(window_->width()); + vpConfig.logicHeight = static_cast(window_->height()); + vpConfig.mode = ViewportMode::AspectRatio; + cameraService->setViewportConfig(vpConfig); + cameraService->updateViewport(window_->width(), window_->height()); + } + locator.registerService(cameraService); + } +} + bool Application::initModules() { auto initOrder = ModuleRegistry::instance().getInitializationOrder(); @@ -144,40 +173,28 @@ bool Application::initModules() { } } - sceneManager_ = makeUnique(); - timerManager_ = makeUnique(); - eventQueue_ = makeUnique(); - eventDispatcher_ = makeUnique(); - camera_ = makeUnique(0, static_cast(window_->width()), - static_cast(window_->height()), 0); + registerCoreServices(); - viewportAdapter_ = makeUnique(); - ViewportConfig vpConfig; - vpConfig.logicWidth = static_cast(window_->width()); - vpConfig.logicHeight = static_cast(window_->height()); - vpConfig.mode = ViewportMode::AspectRatio; - viewportAdapter_->setConfig(vpConfig); + if (!ServiceLocator::instance().initializeAll()) { + return false; + } - camera_->setViewportAdapter(viewportAdapter_.get()); - viewportAdapter_->update(window_->width(), window_->height()); + auto cameraService = ServiceLocator::instance().getService(); + if (cameraService && window_) { + window_->onResize([this, cameraService](int width, int height) { + cameraService->updateViewport(width, height); + cameraService->applyViewportAdapter(); - window_->onResize([this](int width, int height) { - if (viewportAdapter_) { - viewportAdapter_->update(width, height); - } - - if (camera_) { - camera_->applyViewportAdapter(); - } - - if (sceneManager_) { - auto currentScene = sceneManager_->getCurrentScene(); - if (currentScene) { - currentScene->setViewportSize(static_cast(width), - static_cast(height)); + auto sceneService = ServiceLocator::instance().getService(); + if (sceneService) { + auto currentScene = sceneService->getCurrentScene(); + if (currentScene) { + currentScene->setViewportSize(static_cast(width), + static_cast(height)); + } } - } - }); + }); + } initialized_ = true; running_ = true; @@ -191,17 +208,7 @@ void Application::shutdown() { VRAMMgr::get().printStats(); - if (sceneManager_) { - sceneManager_->end(); - } - - sceneManager_.reset(); - viewportAdapter_.reset(); - camera_.reset(); - - timerManager_.reset(); - eventQueue_.reset(); - eventDispatcher_.reset(); + ServiceLocator::instance().clear(); window_ = nullptr; @@ -239,12 +246,14 @@ void Application::quit() { void Application::pause() { if (!paused_) { paused_ = true; + ServiceLocator::instance().pauseAll(); } } void Application::resume() { if (paused_) { paused_ = false; + ServiceLocator::instance().resumeAll(); lastFrameTime_ = getTimeSeconds(); } } @@ -266,8 +275,9 @@ void Application::mainLoop() { window_->poll(); - if (eventDispatcher_ && eventQueue_) { - eventDispatcher_->processQueue(*eventQueue_); + auto eventService = ServiceLocator::instance().getService(); + if (eventService) { + eventService->processQueue(); } if (!paused_) { @@ -291,13 +301,7 @@ void Application::mainLoop() { } void Application::update() { - if (timerManager_) { - timerManager_->update(deltaTime_); - } - - if (sceneManager_) { - sceneManager_->update(deltaTime_); - } + ServiceLocator::instance().updateAll(deltaTime_); } void Application::render() { @@ -314,8 +318,9 @@ void Application::render() { return; } - if (viewportAdapter_) { - const auto& vp = viewportAdapter_->getViewport(); + auto cameraService = ServiceLocator::instance().getService(); + if (cameraService) { + const auto& vp = cameraService->getViewportResult().viewport; renderer->setViewport( static_cast(vp.origin.x), static_cast(vp.origin.y), static_cast(vp.size.width), static_cast(vp.size.height)); @@ -323,8 +328,9 @@ void Application::render() { renderer->setViewport(0, 0, window_->width(), window_->height()); } - if (sceneManager_) { - sceneManager_->render(*renderer); + auto sceneService = ServiceLocator::instance().getService(); + if (sceneService) { + sceneService->render(*renderer); } window_->swap(); @@ -349,35 +355,28 @@ RenderBackend& Application::renderer() { return *dummy; } -SceneManager& Application::scenes() { - return *sceneManager_; +SharedPtr Application::scenes() { + return ServiceLocator::instance().getService(); } -TimerManager& Application::timers() { - return *timerManager_; +SharedPtr Application::timers() { + return ServiceLocator::instance().getService(); } -EventQueue& Application::eventQueue() { - return *eventQueue_; +SharedPtr Application::events() { + return ServiceLocator::instance().getService(); } -EventDispatcher& Application::eventDispatcher() { - return *eventDispatcher_; -} - -Camera& Application::camera() { - return *camera_; -} - -ViewportAdapter& Application::viewportAdapter() { - return *viewportAdapter_; +SharedPtr Application::camera() { + return ServiceLocator::instance().getService(); } void Application::enterScene(Ptr scene) { - if (sceneManager_ && scene) { + auto sceneService = ServiceLocator::instance().getService(); + if (sceneService && scene) { scene->setViewportSize(static_cast(window_->width()), static_cast(window_->height())); - sceneManager_->enterScene(scene); + sceneService->enterScene(scene); } } @@ -389,4 +388,4 @@ const AppConfig& Application::getConfig() const { return ConfigManager::instance().appConfig(); } -} // namespace extra2d +} diff --git a/Extra2D/src/core/service_locator.cpp b/Extra2D/src/core/service_locator.cpp new file mode 100644 index 0000000..de00dfa --- /dev/null +++ b/Extra2D/src/core/service_locator.cpp @@ -0,0 +1,110 @@ +#include +#include + +namespace extra2d { + +ServiceLocator& ServiceLocator::instance() { + static ServiceLocator instance; + return instance; +} + +bool ServiceLocator::initializeAll() { + std::lock_guard lock(mutex_); + + for (auto& service : orderedServices_) { + if (!service) continue; + + auto info = service->getServiceInfo(); + if (!info.enabled) continue; + + if (!service->isInitialized()) { + service->setState(ServiceState::Initializing); + if (!service->initialize()) { + service->setState(ServiceState::Stopped); + return false; + } + service->setState(ServiceState::Running); + } + } + + return true; +} + +void ServiceLocator::shutdownAll() { + std::lock_guard lock(mutex_); + + for (auto it = orderedServices_.rbegin(); + it != orderedServices_.rend(); ++it) { + if (*it && (*it)->isInitialized()) { + (*it)->setState(ServiceState::Stopping); + (*it)->shutdown(); + (*it)->setState(ServiceState::Stopped); + } + } +} + +void ServiceLocator::updateAll(float deltaTime) { + std::lock_guard lock(mutex_); + + for (auto& service : orderedServices_) { + if (service && service->isInitialized()) { + auto state = service->getState(); + if (state == ServiceState::Running) { + service->update(deltaTime); + } + } + } +} + +void ServiceLocator::pauseAll() { + std::lock_guard lock(mutex_); + + for (auto& service : orderedServices_) { + if (service && service->isInitialized()) { + service->pause(); + } + } +} + +void ServiceLocator::resumeAll() { + std::lock_guard lock(mutex_); + + for (auto& service : orderedServices_) { + if (service && service->isInitialized()) { + service->resume(); + } + } +} + +std::vector> ServiceLocator::getAllServices() const { + std::lock_guard lock(mutex_); + return orderedServices_; +} + +void ServiceLocator::clear() { + std::lock_guard lock(mutex_); + + for (auto it = orderedServices_.rbegin(); + it != orderedServices_.rend(); ++it) { + if (*it && (*it)->isInitialized()) { + (*it)->setState(ServiceState::Stopping); + (*it)->shutdown(); + (*it)->setState(ServiceState::Stopped); + } + } + + services_.clear(); + factories_.clear(); + orderedServices_.clear(); +} + +void ServiceLocator::sortServices() { + std::stable_sort(orderedServices_.begin(), orderedServices_.end(), + [](const SharedPtr& a, const SharedPtr& b) { + if (!a || !b) return false; + return static_cast(a->getServiceInfo().priority) < + static_cast(b->getServiceInfo().priority); + }); +} + +} diff --git a/Extra2D/src/core/service_registry.cpp b/Extra2D/src/core/service_registry.cpp new file mode 100644 index 0000000..752de31 --- /dev/null +++ b/Extra2D/src/core/service_registry.cpp @@ -0,0 +1,37 @@ +#include + +namespace extra2d { + +ServiceRegistry& ServiceRegistry::instance() { + static ServiceRegistry instance; + return instance; +} + +void ServiceRegistry::setServiceEnabled(const std::string& name, bool enabled) { + for (auto& reg : registrations_) { + if (reg.name == name) { + reg.enabled = enabled; + break; + } + } +} + +void ServiceRegistry::createAllServices() { + std::sort(registrations_.begin(), registrations_.end(), + [](const ServiceRegistration& a, const ServiceRegistration& b) { + return static_cast(a.priority) < static_cast(b.priority); + }); + + for (const auto& reg : registrations_) { + if (!reg.enabled) { + continue; + } + + auto service = reg.factory(); + if (service) { + ServiceLocator::instance().registerService(service); + } + } +} + +} diff --git a/Extra2D/src/services/camera_service.cpp b/Extra2D/src/services/camera_service.cpp new file mode 100644 index 0000000..0748f03 --- /dev/null +++ b/Extra2D/src/services/camera_service.cpp @@ -0,0 +1,128 @@ +#include + +namespace extra2d { + +CameraService::CameraService() { + info_.name = "CameraService"; + info_.priority = ServicePriority::Camera; + info_.enabled = true; +} + +CameraService::CameraService(float left, float right, float bottom, float top) + : camera_(left, right, bottom, top) { + info_.name = "CameraService"; + info_.priority = ServicePriority::Camera; + info_.enabled = true; +} + +ServiceInfo CameraService::getServiceInfo() const { + return info_; +} + +bool CameraService::initialize() { + camera_.setViewportAdapter(&viewportAdapter_); + setState(ServiceState::Running); + return true; +} + +void CameraService::shutdown() { + setState(ServiceState::Stopped); +} + +void CameraService::setPosition(const Vec2& position) { + camera_.setPos(position); +} + +void CameraService::setPosition(float x, float y) { + camera_.setPos(x, y); +} + +Vec2 CameraService::getPosition() const { + return camera_.getPosition(); +} + +void CameraService::setRotation(float degrees) { + camera_.setRotation(degrees); +} + +float CameraService::getRotation() const { + return camera_.getRotation(); +} + +void CameraService::setZoom(float zoom) { + camera_.setZoom(zoom); +} + +float CameraService::getZoom() const { + return camera_.getZoom(); +} + +void CameraService::setViewport(float left, float right, float bottom, float top) { + camera_.setViewport(left, right, bottom, top); +} + +Rect CameraService::getViewport() const { + return camera_.getViewport(); +} + +glm::mat4 CameraService::getViewMatrix() const { + return camera_.getViewMatrix(); +} + +glm::mat4 CameraService::getProjectionMatrix() const { + return camera_.getProjectionMatrix(); +} + +glm::mat4 CameraService::getViewProjectionMatrix() const { + return camera_.getViewProjectionMatrix(); +} + +Vec2 CameraService::screenToWorld(const Vec2& screenPos) const { + return camera_.screenToWorld(screenPos); +} + +Vec2 CameraService::worldToScreen(const Vec2& worldPos) const { + return camera_.worldToScreen(worldPos); +} + +void CameraService::move(const Vec2& offset) { + camera_.move(offset); +} + +void CameraService::move(float x, float y) { + camera_.move(x, y); +} + +void CameraService::setBounds(const Rect& bounds) { + camera_.setBounds(bounds); +} + +void CameraService::clearBounds() { + camera_.clearBounds(); +} + +void CameraService::lookAt(const Vec2& target) { + camera_.lookAt(target); +} + +void CameraService::setViewportConfig(const ViewportConfig& config) { + viewportAdapter_.setConfig(config); +} + +const ViewportConfig& CameraService::getViewportConfig() const { + return viewportAdapter_.getConfig(); +} + +void CameraService::updateViewport(int screenWidth, int screenHeight) { + viewportAdapter_.update(screenWidth, screenHeight); +} + +const ViewportResult& CameraService::getViewportResult() const { + return viewportAdapter_.getResult(); +} + +void CameraService::applyViewportAdapter() { + camera_.applyViewportAdapter(); +} + +} diff --git a/Extra2D/src/services/event_service.cpp b/Extra2D/src/services/event_service.cpp new file mode 100644 index 0000000..9551b75 --- /dev/null +++ b/Extra2D/src/services/event_service.cpp @@ -0,0 +1,80 @@ +#include + +namespace extra2d { + +EventService::EventService() { + info_.name = "EventService"; + info_.priority = ServicePriority::Event; + info_.enabled = true; +} + +ServiceInfo EventService::getServiceInfo() const { + return info_; +} + +bool EventService::initialize() { + setState(ServiceState::Running); + return true; +} + +void EventService::shutdown() { + queue_.clear(); + dispatcher_.removeAllListeners(); + setState(ServiceState::Stopped); +} + +void EventService::update(float deltaTime) { + if (getState() == ServiceState::Running) { + processQueue(); + } +} + +void EventService::pushEvent(const Event& event) { + queue_.push(event); +} + +void EventService::pushEvent(Event&& event) { + queue_.push(std::move(event)); +} + +bool EventService::pollEvent(Event& event) { + return queue_.poll(event); +} + +ListenerId EventService::addListener(EventType type, EventDispatcher::EventCallback callback) { + return dispatcher_.addListener(type, callback); +} + +void EventService::removeListener(ListenerId id) { + dispatcher_.removeListener(id); +} + +void EventService::removeAllListeners(EventType type) { + dispatcher_.removeAllListeners(type); +} + +void EventService::removeAllListeners() { + dispatcher_.removeAllListeners(); +} + +void EventService::dispatch(Event& event) { + dispatcher_.dispatch(event); +} + +void EventService::processQueue() { + dispatcher_.processQueue(queue_); +} + +size_t EventService::getListenerCount(EventType type) const { + return dispatcher_.getListenerCount(type); +} + +size_t EventService::getTotalListenerCount() const { + return dispatcher_.getTotalListenerCount(); +} + +size_t EventService::getQueueSize() const { + return queue_.size(); +} + +} diff --git a/Extra2D/src/services/scene_service.cpp b/Extra2D/src/services/scene_service.cpp new file mode 100644 index 0000000..2ef197a --- /dev/null +++ b/Extra2D/src/services/scene_service.cpp @@ -0,0 +1,111 @@ +#include + +namespace extra2d { + +SceneService::SceneService() { + info_.name = "SceneService"; + info_.priority = ServicePriority::Scene; + info_.enabled = true; +} + +ServiceInfo SceneService::getServiceInfo() const { + return info_; +} + +bool SceneService::initialize() { + setState(ServiceState::Running); + return true; +} + +void SceneService::shutdown() { + manager_.end(); + setState(ServiceState::Stopped); +} + +void SceneService::update(float deltaTime) { + if (getState() == ServiceState::Running) { + manager_.update(deltaTime); + } +} + +void SceneService::runWithScene(Ptr scene) { + manager_.runWithScene(scene); +} + +void SceneService::replaceScene(Ptr scene) { + manager_.replaceScene(scene); +} + +void SceneService::pushScene(Ptr scene) { + manager_.pushScene(scene); +} + +void SceneService::popScene() { + manager_.popScene(); +} + +void SceneService::popToRootScene() { + manager_.popToRootScene(); +} + +void SceneService::popToScene(const std::string& name) { + manager_.popToScene(name); +} + +Ptr SceneService::getCurrentScene() const { + return manager_.getCurrentScene(); +} + +Ptr SceneService::getPreviousScene() const { + return manager_.getPreviousScene(); +} + +Ptr SceneService::getRootScene() const { + return manager_.getRootScene(); +} + +Ptr SceneService::getSceneByName(const std::string& name) const { + return manager_.getSceneByName(name); +} + +size_t SceneService::getSceneCount() const { + return manager_.getSceneCount(); +} + +bool SceneService::isEmpty() const { + return manager_.isEmpty(); +} + +bool SceneService::hasScene(const std::string& name) const { + return manager_.hasScene(name); +} + +void SceneService::render(RenderBackend& renderer) { + manager_.render(renderer); +} + +void SceneService::collectRenderCommands(std::vector& commands) { + manager_.collectRenderCommands(commands); +} + +bool SceneService::isTransitioning() const { + return manager_.isTransitioning(); +} + +void SceneService::setTransitionCallback(SceneManager::TransitionCallback callback) { + manager_.setTransitionCallback(callback); +} + +void SceneService::end() { + manager_.end(); +} + +void SceneService::purgeCachedScenes() { + manager_.purgeCachedScenes(); +} + +void SceneService::enterScene(Ptr scene) { + manager_.enterScene(scene); +} + +} diff --git a/Extra2D/src/services/timer_service.cpp b/Extra2D/src/services/timer_service.cpp new file mode 100644 index 0000000..8674c3f --- /dev/null +++ b/Extra2D/src/services/timer_service.cpp @@ -0,0 +1,59 @@ +#include + +namespace extra2d { + +TimerService::TimerService() { + info_.name = "TimerService"; + info_.priority = ServicePriority::Timer; + info_.enabled = true; +} + +ServiceInfo TimerService::getServiceInfo() const { + return info_; +} + +bool TimerService::initialize() { + setState(ServiceState::Running); + return true; +} + +void TimerService::shutdown() { + manager_.clear(); + setState(ServiceState::Stopped); +} + +void TimerService::update(float deltaTime) { + if (getState() == ServiceState::Running) { + manager_.update(deltaTime); + } +} + +uint32 TimerService::addTimer(float delay, Timer::Callback callback) { + return manager_.addTimer(delay, callback); +} + +uint32 TimerService::addRepeatingTimer(float interval, Timer::Callback callback) { + return manager_.addRepeatingTimer(interval, callback); +} + +void TimerService::cancelTimer(uint32 timerId) { + manager_.cancelTimer(timerId); +} + +void TimerService::pauseTimer(uint32 timerId) { + manager_.pauseTimer(timerId); +} + +void TimerService::resumeTimer(uint32 timerId) { + manager_.resumeTimer(timerId); +} + +void TimerService::clear() { + manager_.clear(); +} + +size_t TimerService::getTimerCount() const { + return manager_.getTimerCount(); +} + +}