feat: 实现服务定位器模式并重构核心服务架构

重构应用程序架构,引入服务定位器模式解耦模块依赖
新增服务注册表和服务定位器核心组件
实现核心服务接口及实现类(场景、计时器、事件、相机服务)
重构Application类使用服务定位器管理服务
添加服务自动注册宏和类型安全服务获取机制
This commit is contained in:
ChestnutYueyue 2026-02-15 11:40:57 +08:00
parent f8ecf7e03a
commit 453a057c7d
16 changed files with 1634 additions and 98 deletions

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <extra2d/core/types.h> #include <extra2d/core/types.h>
#include <extra2d/core/service_locator.h>
#include <extra2d/config/app_config.h> #include <extra2d/config/app_config.h>
#include <extra2d/config/config_manager.h> #include <extra2d/config/config_manager.h>
#include <extra2d/config/module_config.h> #include <extra2d/config/module_config.h>
@ -10,70 +11,209 @@
namespace extra2d { namespace extra2d {
class IInput; class IInput;
class SceneManager;
class TimerManager;
class EventQueue;
class EventDispatcher;
class Camera;
class ViewportAdapter;
class RenderBackend; class RenderBackend;
/**
* @brief
* 使Mock
*/
class Application { class Application {
public: public:
/**
* @brief
* @return
*/
static Application& get(); static Application& get();
Application(const Application&) = delete; Application(const Application&) = delete;
Application& operator=(const Application&) = delete; Application& operator=(const Application&) = delete;
/**
* @brief 使
* @return true
*/
bool init(); bool init();
/**
* @brief 使
* @param config
* @return true
*/
bool init(const AppConfig& config); bool init(const AppConfig& config);
/**
* @brief 使
* @param configPath
* @return true
*/
bool init(const std::string& configPath); bool init(const std::string& configPath);
/**
* @brief
*/
void shutdown(); void shutdown();
/**
* @brief
*/
void run(); void run();
/**
* @brief 退
*/
void quit(); void quit();
/**
* @brief
*/
void pause(); void pause();
/**
* @brief
*/
void resume(); void resume();
/**
* @brief
* @return true
*/
bool isPaused() const { return paused_; } bool isPaused() const { return paused_; }
/**
* @brief
* @return true
*/
bool isRunning() const { return running_; } bool isRunning() const { return running_; }
/**
* @brief
* @return
*/
IWindow& window() { return *window_; } IWindow& window() { return *window_; }
/**
* @brief
* @return
*/
RenderBackend& renderer(); RenderBackend& renderer();
/**
* @brief
* @return
*/
IInput& input(); IInput& input();
SceneManager& scenes(); /**
TimerManager& timers(); * @brief
EventQueue& eventQueue(); * @return
EventDispatcher& eventDispatcher(); */
Camera& camera(); SharedPtr<class ISceneService> scenes();
ViewportAdapter& viewportAdapter();
/**
* @brief
* @return
*/
SharedPtr<class ITimerService> timers();
/**
* @brief
* @return
*/
SharedPtr<class IEventService> events();
/**
* @brief
* @return
*/
SharedPtr<class ICameraService> camera();
/**
* @brief
* @param scene
*/
void enterScene(Ptr<class Scene> scene); void enterScene(Ptr<class Scene> scene);
/**
* @brief
* @return
*/
float deltaTime() const { return deltaTime_; } float deltaTime() const { return deltaTime_; }
/**
* @brief
* @return
*/
float totalTime() const { return totalTime_; } float totalTime() const { return totalTime_; }
/**
* @brief
* @return
*/
int fps() const { return currentFps_; } int fps() const { return currentFps_; }
/**
* @brief
* @return
*/
ConfigManager& config(); ConfigManager& config();
/**
* @brief
* @return
*/
const AppConfig& getConfig() const; const AppConfig& getConfig() const;
/**
* @brief
* @tparam T
* @param service
*/
template<typename T>
void registerService(SharedPtr<T> service) {
ServiceLocator::instance().registerService(service);
}
/**
* @brief
* @tparam T
* @return
*/
template<typename T>
SharedPtr<T> getService() {
return ServiceLocator::instance().getService<T>();
}
private: private:
Application() = default; Application() = default;
~Application(); ~Application();
/**
* @brief
* @return true
*/
bool initModules(); bool initModules();
/**
* @brief
*/
void registerCoreServices();
/**
* @brief
*/
void mainLoop(); void mainLoop();
/**
* @brief
*/
void update(); void update();
/**
* @brief
*/
void render(); void render();
IWindow* window_ = nullptr; IWindow* window_ = nullptr;
UniquePtr<SceneManager> sceneManager_;
UniquePtr<TimerManager> timerManager_;
UniquePtr<EventQueue> eventQueue_;
UniquePtr<EventDispatcher> eventDispatcher_;
UniquePtr<Camera> camera_;
UniquePtr<ViewportAdapter> viewportAdapter_;
bool initialized_ = false; bool initialized_ = false;
bool running_ = false; bool running_ = false;
@ -88,4 +228,4 @@ private:
int currentFps_ = 0; int currentFps_ = 0;
}; };
} // namespace extra2d }

View File

@ -0,0 +1,144 @@
#pragma once
#include <extra2d/core/types.h>
#include <string>
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<typename T>
ServiceTypeId getServiceTypeId() {
static ServiceTypeId id = nextServiceTypeId();
return id;
}
}
}

View File

@ -0,0 +1,252 @@
#pragma once
#include <extra2d/core/service_interface.h>
#include <extra2d/core/types.h>
#include <unordered_map>
#include <vector>
#include <mutex>
#include <functional>
#include <typeindex>
#include <memory>
#include <algorithm>
namespace extra2d {
/**
* @brief
*/
template<typename T>
using ServiceFactory = std::function<SharedPtr<T>()>;
/**
* @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<typename T>
void registerService(SharedPtr<T> service) {
static_assert(std::is_base_of_v<IService, T>,
"T must derive from IService");
std::lock_guard<std::mutex> lock(mutex_);
auto typeId = std::type_index(typeid(T));
services_[typeId] = std::static_pointer_cast<IService>(service);
orderedServices_.push_back(service);
sortServices();
}
/**
* @brief
* @tparam T
* @param factory
*/
template<typename T>
void registerFactory(ServiceFactory<T> factory) {
static_assert(std::is_base_of_v<IService, T>,
"T must derive from IService");
std::lock_guard<std::mutex> lock(mutex_);
auto typeId = std::type_index(typeid(T));
factories_[typeId] = [factory]() -> SharedPtr<IService> {
return std::static_pointer_cast<IService>(factory());
};
}
/**
* @brief
* @tparam T
* @return nullptr
*/
template<typename T>
SharedPtr<T> getService() const {
static_assert(std::is_base_of_v<IService, T>,
"T must derive from IService");
std::lock_guard<std::mutex> lock(mutex_);
auto typeId = std::type_index(typeid(T));
auto it = services_.find(typeId);
if (it != services_.end()) {
return std::static_pointer_cast<T>(it->second);
}
auto factoryIt = factories_.find(typeId);
if (factoryIt != factories_.end()) {
auto service = factoryIt->second();
services_[typeId] = service;
return std::static_pointer_cast<T>(service);
}
return nullptr;
}
/**
* @brief
* @tparam T
* @return nullptr
*/
template<typename T>
SharedPtr<T> tryGetService() const {
static_assert(std::is_base_of_v<IService, T>,
"T must derive from IService");
std::lock_guard<std::mutex> lock(mutex_);
auto typeId = std::type_index(typeid(T));
auto it = services_.find(typeId);
if (it != services_.end()) {
return std::static_pointer_cast<T>(it->second);
}
return nullptr;
}
/**
* @brief
* @tparam T
* @return true
*/
template<typename T>
bool hasService() const {
std::lock_guard<std::mutex> lock(mutex_);
auto typeId = std::type_index(typeid(T));
return services_.find(typeId) != services_.end() ||
factories_.find(typeId) != factories_.end();
}
/**
* @brief
* @tparam T
*/
template<typename T>
void unregisterService() {
std::lock_guard<std::mutex> 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<SharedPtr<IService>> 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<std::type_index, SharedPtr<IService>> services_;
std::unordered_map<std::type_index, std::function<SharedPtr<IService>()>> factories_;
std::vector<SharedPtr<IService>> orderedServices_;
mutable std::mutex mutex_;
};
/**
* @brief
*
*/
template<typename Interface, typename Implementation>
class ServiceRegistrar {
public:
explicit ServiceRegistrar(ServiceFactory<Interface> factory = nullptr) {
if (factory) {
ServiceLocator::instance().registerFactory<Interface>(factory);
} else {
ServiceLocator::instance().registerFactory<Interface>(
[]() -> SharedPtr<Interface> {
return makeShared<Implementation>();
}
);
}
}
};
}
#define E2D_REGISTER_SERVICE(Interface, Implementation) \
namespace { \
static ::extra2d::ServiceRegistrar<Interface, Implementation> \
E2D_CONCAT(service_registrar_, __LINE__); \
}
#define E2D_REGISTER_SERVICE_FACTORY(Interface, Factory) \
namespace { \
static ::extra2d::ServiceRegistrar<Interface, Interface> \
E2D_CONCAT(service_factory_registrar_, __LINE__)(Factory); \
}

View File

@ -0,0 +1,137 @@
#pragma once
#include <extra2d/core/service_interface.h>
#include <extra2d/core/service_locator.h>
#include <functional>
#include <vector>
#include <string>
namespace extra2d {
/**
* @brief
*/
struct ServiceRegistration {
std::string name;
ServicePriority priority;
std::function<SharedPtr<IService>()> 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<typename T, typename Impl>
void registerService(const std::string& name, ServicePriority priority) {
static_assert(std::is_base_of_v<IService, T>,
"T must derive from IService");
static_assert(std::is_base_of_v<T, Impl>,
"Impl must derive from T");
ServiceRegistration reg;
reg.name = name;
reg.priority = priority;
reg.factory = []() -> SharedPtr<IService> {
return std::static_pointer_cast<IService>(makeShared<Impl>());
};
registrations_.push_back(reg);
}
/**
* @brief
* @tparam T
* @param name
* @param priority
* @param factory
*/
template<typename T>
void registerServiceWithFactory(
const std::string& name,
ServicePriority priority,
std::function<SharedPtr<T>()> factory) {
static_assert(std::is_base_of_v<IService, T>,
"T must derive from IService");
ServiceRegistration reg;
reg.name = name;
reg.priority = priority;
reg.factory = [factory]() -> SharedPtr<IService> {
return std::static_pointer_cast<IService>(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<ServiceRegistration>& getRegistrations() const {
return registrations_;
}
/**
* @brief
*/
void clear() {
registrations_.clear();
}
private:
ServiceRegistry() = default;
~ServiceRegistry() = default;
std::vector<ServiceRegistration> registrations_;
};
/**
* @brief
* 使
*/
template<typename Interface, typename Implementation>
class AutoServiceRegistrar {
public:
AutoServiceRegistrar(const std::string& name, ServicePriority priority) {
ServiceRegistry::instance().registerService<Interface, Implementation>(
name, priority);
}
};
}
#define E2D_REGISTER_SERVICE_AUTO(Interface, Implementation, Name, Priority) \
namespace { \
static ::extra2d::AutoServiceRegistrar<Interface, Implementation> \
E2D_CONCAT(auto_service_registrar_, __LINE__)(Name, Priority); \
}

View File

@ -7,10 +7,17 @@
namespace extra2d { namespace extra2d {
// ---------------------------------------------------------------------------
// 宏定义
// ---------------------------------------------------------------------------
#define E2D_CONCAT_IMPL(a, b) a##b
#define E2D_CONCAT(a, b) E2D_CONCAT_IMPL(a, b)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// 智能指针别名 // 智能指针别名
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
template <typename T> using Ptr = std::shared_ptr<T>; template <typename T> using Ptr = std::shared_ptr<T>;
template <typename T> using SharedPtr = std::shared_ptr<T>;
template <typename T> using UniquePtr = std::unique_ptr<T>; template <typename T> using UniquePtr = std::unique_ptr<T>;
@ -21,6 +28,10 @@ template <typename T, typename... Args> inline Ptr<T> makePtr(Args &&...args) {
return std::make_shared<T>(std::forward<Args>(args)...); return std::make_shared<T>(std::forward<Args>(args)...);
} }
template <typename T, typename... Args> inline SharedPtr<T> makeShared(Args &&...args) {
return std::make_shared<T>(std::forward<Args>(args)...);
}
/// 创建 unique_ptr 的便捷函数 /// 创建 unique_ptr 的便捷函数
template <typename T, typename... Args> template <typename T, typename... Args>
inline UniquePtr<T> makeUnique(Args &&...args) { inline UniquePtr<T> makeUnique(Args &&...args) {

View File

@ -0,0 +1,111 @@
#pragma once
#include <extra2d/core/service_interface.h>
#include <extra2d/graphics/camera.h>
#include <extra2d/graphics/viewport_adapter.h>
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_;
};
}

View File

@ -0,0 +1,73 @@
#pragma once
#include <extra2d/core/service_interface.h>
#include <extra2d/event/event_dispatcher.h>
#include <extra2d/event/event_queue.h>
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_;
};
}

View File

@ -0,0 +1,91 @@
#pragma once
#include <extra2d/core/service_interface.h>
#include <extra2d/scene/scene_manager.h>
namespace extra2d {
/**
* @brief
* 便Mock
*/
class ISceneService : public IService {
public:
virtual ~ISceneService() = default;
virtual void runWithScene(Ptr<Scene> scene) = 0;
virtual void replaceScene(Ptr<Scene> scene) = 0;
virtual void pushScene(Ptr<Scene> scene) = 0;
virtual void popScene() = 0;
virtual void popToRootScene() = 0;
virtual void popToScene(const std::string& name) = 0;
virtual Ptr<Scene> getCurrentScene() const = 0;
virtual Ptr<Scene> getPreviousScene() const = 0;
virtual Ptr<Scene> getRootScene() const = 0;
virtual Ptr<Scene> 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<RenderCommand>& 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> 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> scene) override;
void replaceScene(Ptr<Scene> scene) override;
void pushScene(Ptr<Scene> scene) override;
void popScene() override;
void popToRootScene() override;
void popToScene(const std::string& name) override;
Ptr<Scene> getCurrentScene() const override;
Ptr<Scene> getPreviousScene() const override;
Ptr<Scene> getRootScene() const override;
Ptr<Scene> 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<RenderCommand>& commands) override;
bool isTransitioning() const override;
void setTransitionCallback(SceneManager::TransitionCallback callback) override;
void end() override;
void purgeCachedScenes() override;
void enterScene(Ptr<Scene> scene) override;
SceneManager& getManager() { return manager_; }
const SceneManager& getManager() const { return manager_; }
private:
SceneManager manager_;
};
}

View File

@ -0,0 +1,53 @@
#pragma once
#include <extra2d/core/service_interface.h>
#include <extra2d/utils/timer.h>
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_;
};
}

View File

@ -1,17 +1,15 @@
#include <extra2d/app/application.h> #include <extra2d/app/application.h>
#include <extra2d/config/config_module.h> #include <extra2d/config/config_module.h>
#include <extra2d/config/module_registry.h> #include <extra2d/config/module_registry.h>
#include <extra2d/event/event_dispatcher.h>
#include <extra2d/event/event_queue.h>
#include <extra2d/graphics/camera.h>
#include <extra2d/graphics/render_module.h> #include <extra2d/graphics/render_module.h>
#include <extra2d/graphics/viewport_adapter.h>
#include <extra2d/graphics/vram_manager.h> #include <extra2d/graphics/vram_manager.h>
#include <extra2d/platform/iinput.h> #include <extra2d/platform/iinput.h>
#include <extra2d/platform/platform_init_module.h> #include <extra2d/platform/platform_init_module.h>
#include <extra2d/platform/window_module.h> #include <extra2d/platform/window_module.h>
#include <extra2d/scene/scene_manager.h> #include <extra2d/services/scene_service.h>
#include <extra2d/utils/timer.h> #include <extra2d/services/timer_service.h>
#include <extra2d/services/event_service.h>
#include <extra2d/services/camera_service.h>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
@ -88,6 +86,37 @@ bool Application::init(const std::string& configPath) {
return initModules(); return initModules();
} }
void Application::registerCoreServices() {
auto& locator = ServiceLocator::instance();
if (!locator.hasService<IEventService>()) {
locator.registerService<ISceneService>(makeShared<SceneService>());
}
if (!locator.hasService<ITimerService>()) {
locator.registerService<ITimerService>(makeShared<TimerService>());
}
if (!locator.hasService<IEventService>()) {
locator.registerService<IEventService>(makeShared<EventService>());
}
if (!locator.hasService<ICameraService>()) {
auto cameraService = makeShared<CameraService>();
if (window_) {
cameraService->setViewport(0, static_cast<float>(window_->width()),
static_cast<float>(window_->height()), 0);
ViewportConfig vpConfig;
vpConfig.logicWidth = static_cast<float>(window_->width());
vpConfig.logicHeight = static_cast<float>(window_->height());
vpConfig.mode = ViewportMode::AspectRatio;
cameraService->setViewportConfig(vpConfig);
cameraService->updateViewport(window_->width(), window_->height());
}
locator.registerService<ICameraService>(cameraService);
}
}
bool Application::initModules() { bool Application::initModules() {
auto initOrder = ModuleRegistry::instance().getInitializationOrder(); auto initOrder = ModuleRegistry::instance().getInitializationOrder();
@ -144,40 +173,28 @@ bool Application::initModules() {
} }
} }
sceneManager_ = makeUnique<SceneManager>(); registerCoreServices();
timerManager_ = makeUnique<TimerManager>();
eventQueue_ = makeUnique<EventQueue>();
eventDispatcher_ = makeUnique<EventDispatcher>();
camera_ = makeUnique<Camera>(0, static_cast<float>(window_->width()),
static_cast<float>(window_->height()), 0);
viewportAdapter_ = makeUnique<ViewportAdapter>(); if (!ServiceLocator::instance().initializeAll()) {
ViewportConfig vpConfig; return false;
vpConfig.logicWidth = static_cast<float>(window_->width()); }
vpConfig.logicHeight = static_cast<float>(window_->height());
vpConfig.mode = ViewportMode::AspectRatio;
viewportAdapter_->setConfig(vpConfig);
camera_->setViewportAdapter(viewportAdapter_.get()); auto cameraService = ServiceLocator::instance().getService<ICameraService>();
viewportAdapter_->update(window_->width(), window_->height()); if (cameraService && window_) {
window_->onResize([this, cameraService](int width, int height) {
cameraService->updateViewport(width, height);
cameraService->applyViewportAdapter();
window_->onResize([this](int width, int height) { auto sceneService = ServiceLocator::instance().getService<ISceneService>();
if (viewportAdapter_) { if (sceneService) {
viewportAdapter_->update(width, height); auto currentScene = sceneService->getCurrentScene();
} if (currentScene) {
currentScene->setViewportSize(static_cast<float>(width),
if (camera_) { static_cast<float>(height));
camera_->applyViewportAdapter(); }
}
if (sceneManager_) {
auto currentScene = sceneManager_->getCurrentScene();
if (currentScene) {
currentScene->setViewportSize(static_cast<float>(width),
static_cast<float>(height));
} }
} });
}); }
initialized_ = true; initialized_ = true;
running_ = true; running_ = true;
@ -191,17 +208,7 @@ void Application::shutdown() {
VRAMMgr::get().printStats(); VRAMMgr::get().printStats();
if (sceneManager_) { ServiceLocator::instance().clear();
sceneManager_->end();
}
sceneManager_.reset();
viewportAdapter_.reset();
camera_.reset();
timerManager_.reset();
eventQueue_.reset();
eventDispatcher_.reset();
window_ = nullptr; window_ = nullptr;
@ -239,12 +246,14 @@ void Application::quit() {
void Application::pause() { void Application::pause() {
if (!paused_) { if (!paused_) {
paused_ = true; paused_ = true;
ServiceLocator::instance().pauseAll();
} }
} }
void Application::resume() { void Application::resume() {
if (paused_) { if (paused_) {
paused_ = false; paused_ = false;
ServiceLocator::instance().resumeAll();
lastFrameTime_ = getTimeSeconds(); lastFrameTime_ = getTimeSeconds();
} }
} }
@ -266,8 +275,9 @@ void Application::mainLoop() {
window_->poll(); window_->poll();
if (eventDispatcher_ && eventQueue_) { auto eventService = ServiceLocator::instance().getService<IEventService>();
eventDispatcher_->processQueue(*eventQueue_); if (eventService) {
eventService->processQueue();
} }
if (!paused_) { if (!paused_) {
@ -291,13 +301,7 @@ void Application::mainLoop() {
} }
void Application::update() { void Application::update() {
if (timerManager_) { ServiceLocator::instance().updateAll(deltaTime_);
timerManager_->update(deltaTime_);
}
if (sceneManager_) {
sceneManager_->update(deltaTime_);
}
} }
void Application::render() { void Application::render() {
@ -314,8 +318,9 @@ void Application::render() {
return; return;
} }
if (viewportAdapter_) { auto cameraService = ServiceLocator::instance().getService<ICameraService>();
const auto& vp = viewportAdapter_->getViewport(); if (cameraService) {
const auto& vp = cameraService->getViewportResult().viewport;
renderer->setViewport( renderer->setViewport(
static_cast<int>(vp.origin.x), static_cast<int>(vp.origin.y), static_cast<int>(vp.origin.x), static_cast<int>(vp.origin.y),
static_cast<int>(vp.size.width), static_cast<int>(vp.size.height)); static_cast<int>(vp.size.width), static_cast<int>(vp.size.height));
@ -323,8 +328,9 @@ void Application::render() {
renderer->setViewport(0, 0, window_->width(), window_->height()); renderer->setViewport(0, 0, window_->width(), window_->height());
} }
if (sceneManager_) { auto sceneService = ServiceLocator::instance().getService<ISceneService>();
sceneManager_->render(*renderer); if (sceneService) {
sceneService->render(*renderer);
} }
window_->swap(); window_->swap();
@ -349,35 +355,28 @@ RenderBackend& Application::renderer() {
return *dummy; return *dummy;
} }
SceneManager& Application::scenes() { SharedPtr<ISceneService> Application::scenes() {
return *sceneManager_; return ServiceLocator::instance().getService<ISceneService>();
} }
TimerManager& Application::timers() { SharedPtr<ITimerService> Application::timers() {
return *timerManager_; return ServiceLocator::instance().getService<ITimerService>();
} }
EventQueue& Application::eventQueue() { SharedPtr<IEventService> Application::events() {
return *eventQueue_; return ServiceLocator::instance().getService<IEventService>();
} }
EventDispatcher& Application::eventDispatcher() { SharedPtr<ICameraService> Application::camera() {
return *eventDispatcher_; return ServiceLocator::instance().getService<ICameraService>();
}
Camera& Application::camera() {
return *camera_;
}
ViewportAdapter& Application::viewportAdapter() {
return *viewportAdapter_;
} }
void Application::enterScene(Ptr<Scene> scene) { void Application::enterScene(Ptr<Scene> scene) {
if (sceneManager_ && scene) { auto sceneService = ServiceLocator::instance().getService<ISceneService>();
if (sceneService && scene) {
scene->setViewportSize(static_cast<float>(window_->width()), scene->setViewportSize(static_cast<float>(window_->width()),
static_cast<float>(window_->height())); static_cast<float>(window_->height()));
sceneManager_->enterScene(scene); sceneService->enterScene(scene);
} }
} }
@ -389,4 +388,4 @@ const AppConfig& Application::getConfig() const {
return ConfigManager::instance().appConfig(); return ConfigManager::instance().appConfig();
} }
} // namespace extra2d }

View File

@ -0,0 +1,110 @@
#include <extra2d/core/service_locator.h>
#include <algorithm>
namespace extra2d {
ServiceLocator& ServiceLocator::instance() {
static ServiceLocator instance;
return instance;
}
bool ServiceLocator::initializeAll() {
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(mutex_);
for (auto& service : orderedServices_) {
if (service && service->isInitialized()) {
service->pause();
}
}
}
void ServiceLocator::resumeAll() {
std::lock_guard<std::mutex> lock(mutex_);
for (auto& service : orderedServices_) {
if (service && service->isInitialized()) {
service->resume();
}
}
}
std::vector<SharedPtr<IService>> ServiceLocator::getAllServices() const {
std::lock_guard<std::mutex> lock(mutex_);
return orderedServices_;
}
void ServiceLocator::clear() {
std::lock_guard<std::mutex> 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<IService>& a, const SharedPtr<IService>& b) {
if (!a || !b) return false;
return static_cast<int>(a->getServiceInfo().priority) <
static_cast<int>(b->getServiceInfo().priority);
});
}
}

View File

@ -0,0 +1,37 @@
#include <extra2d/core/service_registry.h>
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<int>(a.priority) < static_cast<int>(b.priority);
});
for (const auto& reg : registrations_) {
if (!reg.enabled) {
continue;
}
auto service = reg.factory();
if (service) {
ServiceLocator::instance().registerService<IService>(service);
}
}
}
}

View File

@ -0,0 +1,128 @@
#include <extra2d/services/camera_service.h>
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();
}
}

View File

@ -0,0 +1,80 @@
#include <extra2d/services/event_service.h>
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();
}
}

View File

@ -0,0 +1,111 @@
#include <extra2d/services/scene_service.h>
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> scene) {
manager_.runWithScene(scene);
}
void SceneService::replaceScene(Ptr<Scene> scene) {
manager_.replaceScene(scene);
}
void SceneService::pushScene(Ptr<Scene> 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<Scene> SceneService::getCurrentScene() const {
return manager_.getCurrentScene();
}
Ptr<Scene> SceneService::getPreviousScene() const {
return manager_.getPreviousScene();
}
Ptr<Scene> SceneService::getRootScene() const {
return manager_.getRootScene();
}
Ptr<Scene> 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<RenderCommand>& 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> scene) {
manager_.enterScene(scene);
}
}

View File

@ -0,0 +1,59 @@
#include <extra2d/services/timer_service.h>
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();
}
}