#pragma once #include #include #include #include #include #include #include #include #include namespace boundard::render { class InputMap; } namespace boundard { class Actor : public std::enable_shared_from_this { private: size_t id; std::string nickName_; mutable std::mutex transform_mutex_; std::array position_{0.0F, 0.0F}; std::array facing_{1.0F, 0.0F}; mutable std::mutex tree_mutex_; std::weak_ptr parent_; std::vector> children_; float age_ = 0.0F; bool initialized_ = false; std::function init_handler_; std::function tick_handler_; public: Actor() noexcept = default; virtual ~Actor() = default; Actor(const Actor&) = delete; Actor& operator=(const Actor&) = delete; Actor(Actor&&) noexcept = delete; Actor& operator=(Actor&&) noexcept = delete; Actor(std::string nickName, Game& game) { id = game.new_id(); nickName_ = std::move(nickName); } static Actor& getInstance() { static Actor instance; return instance; } const std::string& name() const { return nickName_; } float age() const { return age_; } void set_init_handler(std::function handler) { init_handler_ = std::move(handler); } void set_tick_handler( std::function handler) { tick_handler_ = std::move(handler); } // 类似 Godot 的 _ready()。 void initialize() { if (initialized_) { return; } initialized_ = true; if (init_handler_) { init_handler_(*this); } for (const std::shared_ptr& child : children()) { child->initialize(); } } // 类似 Godot 的 _process(delta)。 void process(float dt, const render::InputMap& input) { age_ += dt; if (tick_handler_) { tick_handler_(*this, dt, input); } for (const std::shared_ptr& child : children()) { child->process(dt, input); } } std::array position() const { std::lock_guard lock(transform_mutex_); return position_; } void set_position(std::array position) { std::lock_guard lock(transform_mutex_); position_ = position; } std::array global_position() const { const std::array local_position = position(); const std::shared_ptr parent = this->parent(); if (parent == nullptr) return local_position; const std::array parent_position = parent->global_position(); const std::array parent_facing = parent->global_facing(); return {parent_position[0] + parent_facing[0] * local_position[0] - parent_facing[1] * local_position[1], parent_position[1] + parent_facing[1] * local_position[0] + parent_facing[0] * local_position[1]}; } std::array facing() const { std::lock_guard lock(transform_mutex_); return facing_; } void set_facing(std::array facing) { std::lock_guard lock(transform_mutex_); facing_ = facing; } std::array global_facing() const { std::array local_facing = facing(); const std::shared_ptr parent = this->parent(); if (parent == nullptr) return local_facing; const std::array parent_facing = parent->global_facing(); return {parent_facing[0] * local_facing[0] - parent_facing[1] * local_facing[1], parent_facing[1] * local_facing[0] + parent_facing[0] * local_facing[1]}; } virtual const std::shared_ptr& mesh() const { static const std::shared_ptr no_mesh; return no_mesh; } virtual void set_mesh(std::shared_ptr) {} std::shared_ptr parent() const { std::lock_guard lock(tree_mutex_); return parent_.lock(); } std::vector> children() const { std::lock_guard lock(tree_mutex_); return children_; } bool add_child(const std::shared_ptr& child) { if (child == nullptr) return false; const std::shared_ptr self = shared_from_this(); if (child == self) return false; for (std::shared_ptr ancestor = self; ancestor != nullptr; ancestor = ancestor->parent()) { if (ancestor == child) return false; } if (const std::shared_ptr old_parent = child->parent()) { old_parent->remove_child(child); } { std::lock_guard lock(tree_mutex_); children_.push_back(child); } { std::lock_guard lock(child->tree_mutex_); child->parent_ = self; } return true; } bool remove_child(const std::shared_ptr& child) { if (child == nullptr) return false; std::lock_guard lock(tree_mutex_); for (auto it = children_.begin(); it != children_.end(); ++it) { if (*it != child) continue; children_.erase(it); std::lock_guard child_lock(child->tree_mutex_); child->parent_.reset(); return true; } return false; } }; } // namespace boundard