added load npcs from json

This commit is contained in:
Vlad 2026-04-11 15:30:29 +06:00
parent b3fda88784
commit 943b6b4d21
6 changed files with 208 additions and 4 deletions

View File

@ -0,0 +1,36 @@
{
"npcs": [
{
"id": "npc_01_default",
"name": "NPC Default Guard",
"texturePath": "resources/w/default_skin001.png",
"animationIdlePath": "resources/w/default_idle002.txt",
"animationWalkPath": "resources/w/default_walk001.txt",
"positionX": 0.0,
"positionY": 0.0,
"positionZ": -10.0,
"walkSpeed": 1.5,
"rotationSpeed": 8.0,
"modelScale": 0.01,
"modelCorrectionRotX": 0.0,
"modelCorrectionRotY": 180.0,
"modelCorrectionRotZ": 0.0
},
{
"id": "npc_02_ghost",
"name": "NPC Floating Ghost",
"texturePath": "resources/w/ghost_skin001.png",
"animationIdlePath": "resources/w/default_float001.txt",
"animationWalkPath": "resources/w/default_float001.txt",
"positionX": 0.0,
"positionY": 0.0,
"positionZ": -20.0,
"walkSpeed": 1.5,
"rotationSpeed": 8.0,
"modelScale": 0.01,
"modelCorrectionRotX": 0.0,
"modelCorrectionRotY": 180.0,
"modelCorrectionRotZ": 0.0
}
]
}

View File

@ -14,9 +14,9 @@ void Character::loadAnimation(AnimationState state, const std::string& filename,
} }
} }
void Character::setTexture(std::shared_ptr<Texture> tex) { /*void Character::setTexture(std::shared_ptr<Texture> tex) {
texture = tex; texture = tex;
} }*/
void Character::setTarget(const Eigen::Vector3f& target, void Character::setTarget(const Eigen::Vector3f& target,
std::function<void()> onArrived) { std::function<void()> onArrived) {

View File

@ -18,7 +18,10 @@ enum class AnimationState {
class Character { class Character {
public: public:
void loadAnimation(AnimationState state, const std::string& filename, const std::string& zipFile = ""); void loadAnimation(AnimationState state, const std::string& filename, const std::string& zipFile = "");
void setTexture(std::shared_ptr<Texture> texture); // void setTexture(std::shared_ptr<Texture> texture);
void setTexture(std::shared_ptr<Texture> texture) {
this->texture = texture;
}
void update(int64_t deltaMs); void update(int64_t deltaMs);
// onArrived is called once when the character reaches this target. // onArrived is called once when the character reaches this target.
// From Python you can chain further commands (walk, wait, trigger others). // From Python you can chain further commands (walk, wait, trigger others).

View File

@ -169,6 +169,13 @@ namespace ZL
Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitZ())); Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitZ()));
std::cout << "Load resurces step 9" << std::endl; std::cout << "Load resurces step 9" << std::endl;
// Load NPCs from JSON
npcs = GameObjectLoader::loadAndCreateNpcs("resources/config2/npcs.json", CONST_ZIP_FILE);
/*
// === СТАРЫЙ КОД - ЗАКОММЕНТИРОВАНО, НПС ТЕПЕРЬ ГРУЗЯТСЯ ИЗ JSON ===
auto defaultTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/default_skin001.png", CONST_ZIP_FILE)); auto defaultTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/default_skin001.png", CONST_ZIP_FILE));
auto npc01 = std::make_unique<Character>(); auto npc01 = std::make_unique<Character>();
@ -208,6 +215,9 @@ namespace ZL
std::cout << "Load resurces step 12" << std::endl; std::cout << "Load resurces step 12" << std::endl;
// === КОНЕЦ СТАРОГО КОДА ===
*/
loadingCompleted = true; loadingCompleted = true;
scriptEngine.init(this); scriptEngine.init(this);

View File

@ -244,4 +244,134 @@ namespace ZL {
return interactiveObjects; return interactiveObjects;
} }
std::vector<NpcData> GameObjectLoader::loadNpcsFromJson(const std::string& jsonPath, const std::string& zipPath)
{
std::vector<NpcData> npcs;
json j;
try {
std::ifstream file(jsonPath);
if (!file.is_open()) {
throw std::runtime_error("Could not open file: " + jsonPath);
}
if (file.peek() == std::ifstream::traits_type::eof()) {
throw std::runtime_error("JSON file is empty: " + jsonPath);
}
file >> j;
if (!j.contains("npcs") || !j["npcs"].is_array()) {
std::cerr << "Warning: 'npcs' array not found in " << jsonPath << std::endl;
return npcs;
}
for (const auto& item : j["npcs"]) {
NpcData data;
data.id = item.value("id", "npc_unknown");
data.name = item.value("name", "Unknown NPC");
data.texturePath = item.value("texturePath", "");
data.animationIdlePath = item.value("animationIdlePath", "");
data.animationWalkPath = item.value("animationWalkPath", "");
data.positionX = item.value("positionX", 0.0f);
data.positionY = item.value("positionY", 0.0f);
data.positionZ = item.value("positionZ", 0.0f);
data.walkSpeed = item.value("walkSpeed", 1.5f);
data.rotationSpeed = item.value("rotationSpeed", 8.0f);
data.modelScale = item.value("modelScale", 0.01f);
// Model correction rotation (in degrees, will convert to radians)
data.modelCorrectionRotX = item.value("modelCorrectionRotX", 0.0f) * static_cast<float>(M_PI) / 180.0f;
data.modelCorrectionRotY = item.value("modelCorrectionRotY", 0.0f) * static_cast<float>(M_PI) / 180.0f;
data.modelCorrectionRotZ = item.value("modelCorrectionRotZ", 0.0f) * static_cast<float>(M_PI) / 180.0f;
npcs.push_back(data);
}
std::cout << "Successfully loaded " << npcs.size() << " NPCs from " << jsonPath << std::endl;
} catch (const std::exception& e) {
std::cerr << "Error loading NPCs from JSON: " << e.what() << std::endl;
}
return npcs;
}
std::vector<std::unique_ptr<Character>> GameObjectLoader::loadAndCreateNpcs(
const std::string& jsonPath,
const std::string& zipPath)
{
std::vector<std::unique_ptr<Character>> npcs;
std::vector<NpcData> npcsData = loadNpcsFromJson(jsonPath, zipPath);
for (const auto& npcData : npcsData) {
std::cout << "Loading NPC: " << npcData.name << std::endl;
auto npc = std::make_unique<Character>();
// Load animations
try {
npc->loadAnimation(AnimationState::IDLE, npcData.animationIdlePath, zipPath);
std::cout << " Loaded IDLE animation: " << npcData.animationIdlePath << std::endl;
}
catch (const std::exception& e) {
std::cerr << "GameObjectLoader: Failed to load IDLE animation for '" << npcData.name << "': " << e.what() << std::endl;
continue;
}
try {
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;
}
// Load texture
try {
auto texture = std::make_shared<Texture>(CreateTextureDataFromPng(npcData.texturePath, zipPath.c_str()));
npc->setTexture(texture);
std::cout << " Loaded texture: " << npcData.texturePath << std::endl;
}
catch (const std::exception& e) {
std::cerr << "GameObjectLoader: Failed to load texture for '" << npcData.name << "': " << e.what() << std::endl;
continue;
}
// Set NPC properties
npc->walkSpeed = npcData.walkSpeed;
npc->rotationSpeed = npcData.rotationSpeed;
npc->modelScale = npcData.modelScale;
npc->position = Eigen::Vector3f(npcData.positionX, npcData.positionY, npcData.positionZ);
// Set model correction rotation
Eigen::Quaternionf corrRotQuat = Eigen::Quaternionf::Identity();
if (npcData.modelCorrectionRotX != 0.0f) {
corrRotQuat = Eigen::Quaternionf(Eigen::AngleAxisf(npcData.modelCorrectionRotX, Eigen::Vector3f::UnitX())) * corrRotQuat;
}
if (npcData.modelCorrectionRotY != 0.0f) {
corrRotQuat = Eigen::Quaternionf(Eigen::AngleAxisf(npcData.modelCorrectionRotY, Eigen::Vector3f::UnitY())) * corrRotQuat;
}
if (npcData.modelCorrectionRotZ != 0.0f) {
corrRotQuat = Eigen::Quaternionf(Eigen::AngleAxisf(npcData.modelCorrectionRotZ, Eigen::Vector3f::UnitZ())) * corrRotQuat;
}
npc->modelCorrectionRotation = corrRotQuat;
// Set initial target to current position
npc->setTarget(npc->position);
npcs.push_back(std::move(npc));
std::cout << "Successfully loaded NPC: " << npcData.name << " at position ("
<< npcData.positionX << ", " << npcData.positionY << ", " << npcData.positionZ << ")" << std::endl;
}
std::cout << "Total NPCs loaded: " << npcs.size() << std::endl;
return npcs;
}
} // namespace ZL } // namespace ZL

View File

@ -6,12 +6,13 @@
#include "external/nlohmann/json.hpp" #include "external/nlohmann/json.hpp"
#include "TextModel.h" #include "TextModel.h"
#include "InteractiveObject.h" #include "InteractiveObject.h"
#include "Character.h"
namespace ZL { namespace ZL {
struct Texture; struct Texture;
struct VertexRenderStruct; struct VertexRenderStruct;
class Renderer; class Renderer;
class Character;
struct GameObjectData { struct GameObjectData {
std::string name; std::string name;
@ -32,6 +33,23 @@ namespace ZL {
float interactionRadius = 2.0f; float interactionRadius = 2.0f;
}; };
struct NpcData {
std::string id;
std::string name;
std::string texturePath;
std::string animationIdlePath;
std::string animationWalkPath;
float positionX = 0.0f;
float positionY = 0.0f;
float positionZ = 0.0f;
float walkSpeed = 1.5f;
float rotationSpeed = 8.0f;
float modelScale = 0.01f;
float modelCorrectionRotX = 0.0f;
float modelCorrectionRotY = 0.0f;
float modelCorrectionRotZ = 0.0f;
};
struct LoadedGameObject { struct LoadedGameObject {
std::shared_ptr<Texture> texture; std::shared_ptr<Texture> texture;
VertexRenderStruct mesh; VertexRenderStruct mesh;
@ -53,6 +71,13 @@ namespace ZL {
Renderer& renderer, Renderer& renderer,
const std::string& zipPath = "" const std::string& zipPath = ""
); );
static std::vector<std::unique_ptr<Character>> loadAndCreateNpcs(
const std::string& jsonPath,
const std::string& zipPath = ""
);
static std::vector<NpcData> loadNpcsFromJson(const std::string& jsonPath, const std::string& zipPath = "");
}; };
} // namespace ZL } // namespace ZL