#pragma once #include "BoneAnimatedModel.h" #include "render/Renderer.h" #include "render/TextureManager.h" #include "items/Item.h" #include #include #include #include #include #include namespace ZL { enum class AnimationState { STAND = 0, WALK = 1, STAND_TO_ACTION = 2, ACTION_ATTACK = 3, ACTION_IDLE = 4, ACTION_TO_STAND = 5 }; class Character { public: using PathPlanner = std::function( const Eigen::Vector3f& start, const Eigen::Vector3f& end)>; void loadAnimation(AnimationState state, const std::string& filename, const std::string& zipFile = ""); // void setTexture(std::shared_ptr texture); void setTexture(std::shared_ptr texture) { this->texture = texture; } void update(int64_t deltaMs); // onArrived is called once when the character reaches this target. // From Python you can chain further commands (walk, wait, trigger others). void setTarget(const Eigen::Vector3f& target, std::function onArrived = nullptr); void setPathPlanner(PathPlanner planner); void draw(Renderer& renderer); // Public: read by Game for camera tracking and ray-cast origin Eigen::Vector3f position = Eigen::Vector3f(0.f, 0.f, 0.f); float facingAngle = 0.0f; // Per-character tuning — set after construction, before first update float walkSpeed = 3.0f; float rotationSpeed = 4.0f; float modelScale = 0.12f; // Applied after scale, fixes model-space orientation (e.g. Blender Z-up exports) Eigen::Quaternionf modelCorrectionRotation = Eigen::Quaternionf::Identity(); // NPC Gift Item giftItem; std::string npcId; std::string npcName; bool giftReceived = false; int battle_state = 0; bool resetAnim = false; int attack = 0; AnimationState currentState = AnimationState::STAND; float attack_cooldown = 0.f; bool canAttack = false; Character* attackTarget = nullptr; bool isPlayer = false; private: struct AnimationData { BoneSystem model; VertexRenderStruct modelMutable; float currentFrame = 0.f; int lastFrame = -1; int totalFrames = 1; }; std::map animations; std::shared_ptr texture; Eigen::Vector3f walkTarget = Eigen::Vector3f(0.f, 0.f, 0.f); Eigen::Vector3f requestedWalkTarget = Eigen::Vector3f(0.f, 0.f, 0.f); std::vector pathWaypoints; size_t currentWaypointIndex = 0; PathPlanner pathPlanner; float targetFacingAngle = 0.0f; std::function onArrivedCallback; static constexpr float WALK_THRESHOLD = 0.05f; static constexpr float TARGET_REPLAN_THRESHOLD = 0.25f; // Returns the animation state to actually play/draw, falling back to IDLE // if the requested state has no loaded animation. AnimationState resolveActiveState() const; }; } // namespace ZL