Minor code change for CharacterState

This commit is contained in:
Vladislav Khorev 2026-06-18 20:22:25 +03:00
parent 0eb9d0be25
commit 0ca00f965d
3 changed files with 62 additions and 80 deletions

View File

@ -108,7 +108,7 @@ namespace ZL
// Load NPCs from JSON. Aggressive (canAttack) NPCs need a player target // Load NPCs from JSON. Aggressive (canAttack) NPCs need a player target
// and hit sparks; peaceful NPCs don't take damage from the player so // and hit sparks; peaceful NPCs don't take damage from the player so
// they don't need either. // they don't need either.
npcs = GameObjectLoader::loadAndCreate_Npcs(params.npcsJsonPath, CONST_ZIP_FILE); npcs = GameObjectLoader::loadAndCreate_Npcs(params.npcsJsonPath, renderer, CONST_ZIP_FILE);
for (auto& npc : npcs) { for (auto& npc : npcs) {
if (!npc) continue; if (!npc) continue;
npc->state.homePosition = Eigen::Vector3f(npc->state.position.x(), 0.f, npc->state.position.z()); npc->state.homePosition = Eigen::Vector3f(npc->state.position.x(), 0.f, npc->state.position.z());

View File

@ -312,97 +312,73 @@ namespace ZL {
return npcs; return npcs;
} }
CharacterState NpcData::toCharacterState() const {
CharacterState st;
// Identity + game state
st.npcId = id;
st.npcName = name;
st.position = Eigen::Vector3f(positionX, positionY, positionZ);
st.facingAngle = facingAngle;
st.walkSpeed = walkSpeed;
st.rotationSpeed = rotationSpeed;
st.modelScale = modelScale;
st.setHp(hp);
st.initialHp = hp;
st.canAttack = canAttack;
st.enabled = enabled;
st.interactionRadius = interactionRadius;
Eigen::Quaternionf corrRot = Eigen::Quaternionf::Identity();
if (modelCorrectionRotX != 0.0f)
corrRot = Eigen::Quaternionf(Eigen::AngleAxisf(modelCorrectionRotX, Eigen::Vector3f::UnitX())) * corrRot;
if (modelCorrectionRotY != 0.0f)
corrRot = Eigen::Quaternionf(Eigen::AngleAxisf(modelCorrectionRotY, Eigen::Vector3f::UnitY())) * corrRot;
if (modelCorrectionRotZ != 0.0f)
corrRot = Eigen::Quaternionf(Eigen::AngleAxisf(modelCorrectionRotZ, Eigen::Vector3f::UnitZ())) * corrRot;
st.modelCorrectionRotation = corrRot;
// Creation info: animation paths
CharacterCreationInfo& info = st.creationInfo;
auto addAnim = [&](AnimationState animState, const std::string& path) {
if (!path.empty())
info.animationPaths.emplace_back(animState, path);
};
addAnim(AnimationState::STAND, animationIdlePath);
addAnim(AnimationState::WALK, animationWalkPath);
addAnim(AnimationState::ACTION_IDLE, animationActionIdlePath);
addAnim(AnimationState::ACTION_ATTACK, animationActionAttackPath);
addAnim(AnimationState::STAND_TO_ACTION, animationStandToActionPath);
addAnim(AnimationState::ACTION_TO_STAND, animationActionToStandPath);
addAnim(AnimationState::ACTION_TO_DEATH, animationActionToDeathPath);
addAnim(AnimationState::DEATH_IDLE, animationDeathIdlePath);
// Creation info: textures
info.meshTexturePaths = std::unordered_map<std::string, std::string>(meshTextures.begin(), meshTextures.end());
info.singleTexturePath = texturePath;
return st;
}
std::vector<std::unique_ptr<Character>> GameObjectLoader::loadAndCreate_Npcs( std::vector<std::unique_ptr<Character>> GameObjectLoader::loadAndCreate_Npcs(
const std::string& jsonPath, const std::string& jsonPath,
Renderer& renderer,
const std::string& zipPath) const std::string& zipPath)
{ {
std::vector<std::unique_ptr<Character>> npcs; std::vector<std::unique_ptr<Character>> npcs;
for (const auto& npcData : loadNpcsFromJson(jsonPath, zipPath)) { for (const auto& npcData : loadNpcsFromJson(jsonPath, zipPath)) {
std::cout << "Loading NPC: " << npcData.name << std::endl; std::cout << "Loading NPC: " << npcData.name << std::endl;
auto npc = std::make_unique<Character>();
try { try {
if (npcData.animationIdlePath.substr(npcData.animationIdlePath.size() - 5) == ".anim") auto npc = Character::createFromState(npcData.toCharacterState(), renderer, zipPath.c_str());
npc->loadBinaryAnimation(AnimationState::STAND, npcData.animationIdlePath, zipPath); if (npc) {
else std::cout << "Successfully loaded NPC: " << npcData.name << " at ("
npc->loadAnimation(AnimationState::STAND, npcData.animationIdlePath, zipPath); << npcData.positionX << ", " << npcData.positionY << ", " << npcData.positionZ << ")" << std::endl;
std::cout << " Loaded IDLE animation: " << npcData.animationIdlePath << std::endl; npcs.push_back(std::move(npc));
} catch (const std::exception& e) {
std::cerr << "GameObjectLoader: Failed to load IDLE animation for '" << npcData.name << "': " << e.what() << std::endl;
continue;
}
try {
if (npcData.animationWalkPath.substr(npcData.animationWalkPath.size() - 5) == ".anim")
npc->loadBinaryAnimation(AnimationState::WALK, npcData.animationWalkPath, zipPath);
else
npc->loadAnimation(AnimationState::WALK, npcData.animationWalkPath, zipPath);
std::cout << " Loaded WALK animation: " << npcData.animationWalkPath << std::endl;
} catch (const std::exception& e) {
std::cerr << "GameObjectLoader: Failed to load WALK animation for '" << npcData.name << "': " << e.what() << std::endl;
continue;
}
auto loadOptionalAnim = [&](AnimationState animState, const std::string& path, const char* label) {
if (path.empty()) return;
try {
if (path.size() >= 5 && path.substr(path.size() - 5) == ".anim")
npc->loadBinaryAnimation(animState, path, zipPath);
else
npc->loadAnimation(animState, path, zipPath);
std::cout << " Loaded " << label << " animation: " << path << std::endl;
} catch (const std::exception& e) {
std::cerr << "GameObjectLoader: Failed to load " << label
<< " animation for '" << npcData.name << "': " << e.what() << std::endl;
} }
};
loadOptionalAnim(AnimationState::ACTION_IDLE, npcData.animationActionIdlePath, "ACTION_IDLE");
loadOptionalAnim(AnimationState::ACTION_ATTACK, npcData.animationActionAttackPath, "ACTION_ATTACK");
loadOptionalAnim(AnimationState::STAND_TO_ACTION, npcData.animationStandToActionPath, "STAND_TO_ACTION");
loadOptionalAnim(AnimationState::ACTION_TO_STAND, npcData.animationActionToStandPath, "ACTION_TO_STAND");
loadOptionalAnim(AnimationState::ACTION_TO_DEATH, npcData.animationActionToDeathPath, "ACTION_TO_DEATH");
loadOptionalAnim(AnimationState::DEATH_IDLE, npcData.animationDeathIdlePath, "DEATH_IDLE");
try {
for (const auto& entry : npcData.meshTextures) {
npc->setTexture(entry.first, std::make_shared<Texture>(CreateTextureDataFromPng(entry.second, zipPath.c_str())));
std::cout << " -> mesh '" << entry.first << "'" << std::endl;
}
} catch (const std::exception& e) { } catch (const std::exception& e) {
std::cerr << "GameObjectLoader: Failed to load texture for '" << npcData.name << "': " << e.what() << std::endl; std::cerr << "GameObjectLoader: Failed to load NPC '" << npcData.name << "': " << e.what() << std::endl;
continue;
} }
npc->state.walkSpeed = npcData.walkSpeed;
npc->state.rotationSpeed = npcData.rotationSpeed;
npc->state.modelScale = npcData.modelScale;
npc->state.position = Eigen::Vector3f(npcData.positionX, npcData.positionY, npcData.positionZ);
npc->state.facingAngle = npcData.facingAngle;
npc->state.setHp(npcData.hp);
npc->state.initialHp = npcData.hp;
npc->state.canAttack = npcData.canAttack;
npc->state.enabled = npcData.enabled;
npc->state.interactionRadius = npcData.interactionRadius;
npc->state.npcId = npcData.id;
npc->state.npcName = npcData.name;
Eigen::Quaternionf corrRot = Eigen::Quaternionf::Identity();
if (npcData.modelCorrectionRotX != 0.0f)
corrRot = Eigen::Quaternionf(Eigen::AngleAxisf(npcData.modelCorrectionRotX, Eigen::Vector3f::UnitX())) * corrRot;
if (npcData.modelCorrectionRotY != 0.0f)
corrRot = Eigen::Quaternionf(Eigen::AngleAxisf(npcData.modelCorrectionRotY, Eigen::Vector3f::UnitY())) * corrRot;
if (npcData.modelCorrectionRotZ != 0.0f)
corrRot = Eigen::Quaternionf(Eigen::AngleAxisf(npcData.modelCorrectionRotZ, Eigen::Vector3f::UnitZ())) * corrRot;
npc->state.modelCorrectionRotation = corrRot;
npc->setTarget(npc->state.position);
npcs.push_back(std::move(npc));
std::cout << "Successfully loaded NPC: " << npcData.name << " at ("
<< npcData.positionX << ", " << npcData.positionY << ", " << npcData.positionZ << ")" << std::endl;
} }
std::cout << "Total NPCs loaded: " << npcs.size() << std::endl; std::cout << "Total NPCs loaded: " << npcs.size() << std::endl;

View File

@ -7,6 +7,7 @@
#include "external/nlohmann/json.hpp" #include "external/nlohmann/json.hpp"
#include "TextModel.h" #include "TextModel.h"
#include "InteractiveObject.h" #include "InteractiveObject.h"
#include "../CharacterState.h"
namespace ZL { namespace ZL {
@ -71,6 +72,10 @@ namespace ZL {
bool canAttack = false; bool canAttack = false;
bool enabled = true; bool enabled = true;
float interactionRadius = 0.0f; float interactionRadius = 0.0f;
// Converts this JSON-parsed descriptor into a fully-populated CharacterState
// (including creationInfo) ready for Character::createFromState().
CharacterState toCharacterState() const;
}; };
class GameObjectLoader { class GameObjectLoader {
@ -89,6 +94,7 @@ namespace ZL {
static std::vector<std::unique_ptr<ZL::Character>> loadAndCreate_Npcs( static std::vector<std::unique_ptr<ZL::Character>> loadAndCreate_Npcs(
const std::string& jsonPath, const std::string& jsonPath,
Renderer& renderer,
const std::string& zipPath = "" const std::string& zipPath = ""
); );