Characters are fully functional now
This commit is contained in:
@@ -447,71 +447,57 @@ bool EditorApp::frameRenderingQueued(const Ogre::FrameEvent &evt)
|
||||
m_camera->update(evt.timeSinceLastFrame);
|
||||
}
|
||||
|
||||
// Update character physics (before main physics step)
|
||||
if (m_characterSystem) {
|
||||
m_characterSystem->update(evt.timeSinceLastFrame);
|
||||
}
|
||||
|
||||
// Update physics
|
||||
if (m_physicsSystem) {
|
||||
m_physicsSystem->update(evt.timeSinceLastFrame);
|
||||
}
|
||||
|
||||
// Update lights
|
||||
if (m_lightSystem) {
|
||||
m_lightSystem->update();
|
||||
}
|
||||
|
||||
// Update cameras
|
||||
if (m_cameraSystem) {
|
||||
m_cameraSystem->update();
|
||||
}
|
||||
|
||||
// Update LOD system
|
||||
if (m_lodSystem) {
|
||||
m_lodSystem->update();
|
||||
}
|
||||
|
||||
// Update StaticGeometry system
|
||||
if (m_staticGeometrySystem) {
|
||||
m_staticGeometrySystem->update();
|
||||
}
|
||||
|
||||
// Update ProceduralTexture system
|
||||
if (m_proceduralTextureSystem) {
|
||||
m_proceduralTextureSystem->update();
|
||||
}
|
||||
|
||||
// Update ProceduralMaterial system
|
||||
if (m_proceduralMaterialSystem) {
|
||||
m_proceduralMaterialSystem->update();
|
||||
}
|
||||
|
||||
// Update CharacterSlot system
|
||||
/* --- Visual mesh setup (must run before animation) --- */
|
||||
if (m_characterSlotSystem) {
|
||||
m_characterSlotSystem->update();
|
||||
}
|
||||
|
||||
// Update AnimationTree system
|
||||
/* --- Animation / procedural generation --- */
|
||||
if (m_animationTreeSystem) {
|
||||
m_animationTreeSystem->update(evt.timeSinceLastFrame);
|
||||
}
|
||||
|
||||
// Update ProceduralMesh system
|
||||
if (m_proceduralMeshSystem) {
|
||||
m_proceduralMeshSystem->update();
|
||||
}
|
||||
|
||||
// Update RoomLayout system FIRST (generates cells for CellGrid)
|
||||
/* --- Static world generation (meshes + physics) --- */
|
||||
if (m_roomLayoutSystem) {
|
||||
m_roomLayoutSystem->update();
|
||||
}
|
||||
|
||||
// Update CellGrid system (builds mesh from cells)
|
||||
if (m_cellGridSystem) {
|
||||
m_cellGridSystem->update();
|
||||
}
|
||||
|
||||
/* --- Dynamic physics (characters after static world) --- */
|
||||
if (m_characterSystem) {
|
||||
m_characterSystem->update(evt.timeSinceLastFrame);
|
||||
}
|
||||
|
||||
/* --- Main physics step --- */
|
||||
if (m_physicsSystem) {
|
||||
m_physicsSystem->update(evt.timeSinceLastFrame);
|
||||
}
|
||||
|
||||
/* --- Rendering support systems --- */
|
||||
if (m_lightSystem) {
|
||||
m_lightSystem->update();
|
||||
}
|
||||
if (m_cameraSystem) {
|
||||
m_cameraSystem->update();
|
||||
}
|
||||
if (m_lodSystem) {
|
||||
m_lodSystem->update();
|
||||
}
|
||||
if (m_staticGeometrySystem) {
|
||||
m_staticGeometrySystem->update();
|
||||
}
|
||||
if (m_proceduralTextureSystem) {
|
||||
m_proceduralTextureSystem->update();
|
||||
}
|
||||
if (m_proceduralMaterialSystem) {
|
||||
m_proceduralMaterialSystem->update();
|
||||
}
|
||||
|
||||
// Don't call base class - it crashes when iterating input listeners
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -145,6 +145,9 @@ struct CellGridComponent {
|
||||
std::string roofTopRectName;
|
||||
std::string roofSideRectName;
|
||||
|
||||
// Physics properties for generated colliders
|
||||
float friction = 0.5f;
|
||||
|
||||
// Dirty flag - triggers rebuild
|
||||
bool dirty = true;
|
||||
unsigned int version = 0;
|
||||
@@ -419,6 +422,9 @@ struct LotComponent {
|
||||
// Texture rectangle name from ProceduralTexture for UV mapping
|
||||
std::string textureRectName;
|
||||
|
||||
// Physics properties for generated colliders
|
||||
float friction = 0.5f;
|
||||
|
||||
// Dirty flag
|
||||
bool dirty = true;
|
||||
|
||||
@@ -451,6 +457,9 @@ struct DistrictComponent {
|
||||
// Texture rectangle name from ProceduralTexture for UV mapping
|
||||
std::string textureRectName;
|
||||
|
||||
// Physics properties for generated colliders
|
||||
float friction = 0.5f;
|
||||
|
||||
// Dirty flag
|
||||
bool dirty = true;
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@ struct CharacterComponent {
|
||||
/* Dirty flag — triggers rebuild of the Jolt character */
|
||||
bool dirty = true;
|
||||
|
||||
/* Floor detection: raycast downward to find ground before enabling gravity */
|
||||
bool hasFloor = false;
|
||||
float floorCheckDistance = 2.0f;
|
||||
bool useGravity = true;
|
||||
|
||||
float getHalfHeight() const { return height * 0.5f; }
|
||||
float getTotalHeight() const { return height + 2.0f * radius; }
|
||||
};
|
||||
|
||||
@@ -560,6 +560,7 @@ class Physics {
|
||||
std::set<JPH::Character *> characters;
|
||||
std::set<JPH::BodyID> characterBodies;
|
||||
bool debugDraw;
|
||||
JPH::Vec3 gravity = JPH::Vec3(0.0f, -9.8f, 0.0f);
|
||||
|
||||
public:
|
||||
class ActivationListener : public JPH::BodyActivationListener {
|
||||
@@ -720,7 +721,7 @@ public:
|
||||
body_interface.RemoveBody(floor->GetID());
|
||||
body_interface.DestroyBody(floor->GetID());
|
||||
#endif
|
||||
physics_system.SetGravity(JPH::Vec3(0, -0.1f, 0));
|
||||
physics_system.SetGravity(gravity);
|
||||
}
|
||||
~Physics()
|
||||
{
|
||||
@@ -767,7 +768,7 @@ public:
|
||||
if (debugDraw)
|
||||
cCollisionSteps = 4;
|
||||
while (timeAccumulator >= fixedDeltaTime) {
|
||||
physics_system.Update(dt, cCollisionSteps,
|
||||
physics_system.Update(fixedDeltaTime, cCollisionSteps,
|
||||
&temp_allocator, &job_system);
|
||||
timeAccumulator -= fixedDeltaTime;
|
||||
}
|
||||
@@ -789,8 +790,13 @@ public:
|
||||
node->_setDerivedOrientation(JoltPhysics::convert(q));
|
||||
}
|
||||
for (JPH::Character *ch : characters) {
|
||||
if (body_interface.IsAdded(ch->GetBodyID()))
|
||||
if (body_interface.IsAdded(ch->GetBodyID())) {
|
||||
ch->PostSimulation(0.1f);
|
||||
Ogre::SceneNode *node = id2node[ch->GetBodyID()];
|
||||
if (node)
|
||||
node->_setDerivedPosition(
|
||||
JoltPhysics::convert(ch->GetPosition()));
|
||||
}
|
||||
}
|
||||
|
||||
if (debugDraw)
|
||||
@@ -811,6 +817,15 @@ public:
|
||||
{
|
||||
debugDraw = enable;
|
||||
}
|
||||
JPH::Vec3 getGravity() const
|
||||
{
|
||||
return gravity;
|
||||
}
|
||||
void setGravity(const JPH::Vec3 &g)
|
||||
{
|
||||
gravity = g;
|
||||
physics_system.SetGravity(gravity);
|
||||
}
|
||||
static JPH::ShapeRefC createBoxShape(float x, float y, float z)
|
||||
{
|
||||
return new JPH::BoxShape(JPH::Vec3(x, y, z));
|
||||
@@ -1531,6 +1546,15 @@ public:
|
||||
return physics_system.GetBodyInterface().SetFriction(id,
|
||||
friction);
|
||||
}
|
||||
float getGravityFactor(JPH::BodyID id)
|
||||
{
|
||||
return physics_system.GetBodyInterface().GetGravityFactor(id);
|
||||
}
|
||||
void setGravityFactor(JPH::BodyID id, float factor)
|
||||
{
|
||||
return physics_system.GetBodyInterface().SetGravityFactor(id,
|
||||
factor);
|
||||
}
|
||||
void broadphaseQuery(float dt, const Ogre::Vector3 &position,
|
||||
std::set<JPH::BodyID> &inWater)
|
||||
{
|
||||
@@ -1790,6 +1814,14 @@ void JoltPhysicsWrapper::setDebugDraw(bool enable)
|
||||
{
|
||||
phys->setDebugDraw(enable);
|
||||
}
|
||||
Ogre::Vector3 JoltPhysicsWrapper::getGravity() const
|
||||
{
|
||||
return JoltPhysics::convert(phys->getGravity());
|
||||
}
|
||||
void JoltPhysicsWrapper::setGravity(const Ogre::Vector3 &gravity)
|
||||
{
|
||||
phys->setGravity(JoltPhysics::convert<JPH::Vec3>(gravity));
|
||||
}
|
||||
void JoltPhysicsWrapper::broadphaseQuery(float dt,
|
||||
const Ogre::Vector3 &position,
|
||||
std::set<JPH::BodyID> &inWater)
|
||||
@@ -1870,6 +1902,14 @@ void JoltPhysicsWrapper::setFriction(JPH::BodyID id, float friction)
|
||||
{
|
||||
phys->setFriction(id, friction);
|
||||
}
|
||||
float JoltPhysicsWrapper::getGravityFactor(JPH::BodyID id)
|
||||
{
|
||||
return phys->getGravityFactor(id);
|
||||
}
|
||||
void JoltPhysicsWrapper::setGravityFactor(JPH::BodyID id, float factor)
|
||||
{
|
||||
phys->setGravityFactor(id, factor);
|
||||
}
|
||||
void JoltPhysicsWrapper::addAngularImpulse(const JPH::BodyID &id,
|
||||
const Ogre::Vector3 &impulse)
|
||||
{
|
||||
|
||||
@@ -177,6 +177,8 @@ public:
|
||||
void removeBody(const JPH::BodyID &id);
|
||||
void destroyBody(const JPH::BodyID &id);
|
||||
void setDebugDraw(bool enable);
|
||||
Ogre::Vector3 getGravity() const;
|
||||
void setGravity(const Ogre::Vector3 &gravity);
|
||||
void broadphaseQuery(float dt, const Ogre::Vector3 &position,
|
||||
std::set<JPH::BodyID> &inWater);
|
||||
void applyBuoyancyImpulse(JPH::BodyID id,
|
||||
@@ -210,6 +212,8 @@ public:
|
||||
Ogre::Vector3 getAngularVelocity(JPH::BodyID id);
|
||||
float getFriction(JPH::BodyID id);
|
||||
void setFriction(JPH::BodyID id, float friction);
|
||||
float getGravityFactor(JPH::BodyID id);
|
||||
void setGravityFactor(JPH::BodyID id, float factor);
|
||||
void addAngularImpulse(const JPH::BodyID &id,
|
||||
const Ogre::Vector3 &impulse);
|
||||
void setDispatch(std::function<void(const JoltPhysics::ContactListener::
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
#include "../components/Transform.hpp"
|
||||
#include "../components/Renderable.hpp"
|
||||
#include "../components/CharacterSlots.hpp"
|
||||
#include "../components/Character.hpp"
|
||||
#include <OgreEntity.h>
|
||||
#include <OgreLogManager.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
AnimationTreeSystem::AnimationTreeSystem(flecs::world &world,
|
||||
Ogre::SceneManager *sceneMgr)
|
||||
@@ -70,17 +72,23 @@ Ogre::Entity *AnimationTreeSystem::findAnimatedEntity(flecs::entity e)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AnimationTreeSystem::setupEntity(flecs::entity e,
|
||||
bool AnimationTreeSystem::setupEntity(flecs::entity e,
|
||||
AnimationTreeComponent &at)
|
||||
{
|
||||
Ogre::Entity *ent = findAnimatedEntity(e);
|
||||
std::cout << "AnimationTreeSystem::setupEntity: entity=" << e.id()
|
||||
<< " ent=" << ent
|
||||
<< " hasSkeleton=" << (ent ? ent->hasSkeleton() : false)
|
||||
<< std::endl;
|
||||
if (!ent || !ent->hasSkeleton()) {
|
||||
teardownEntity(e);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityAnimTreeState &state = m_states[e.id()];
|
||||
state.ogreEntity = ent;
|
||||
state.rootBone = nullptr;
|
||||
state.animations.clear();
|
||||
|
||||
Ogre::SkeletonInstance *skel = ent->getSkeleton();
|
||||
|
||||
@@ -161,6 +169,10 @@ void AnimationTreeSystem::setupEntity(flecs::entity e,
|
||||
|
||||
/* Initialize default state machine states */
|
||||
initializeTreeStates(at.root, at);
|
||||
std::cout << " setupEntity done: animations=" << state.animations.size()
|
||||
<< " rootBone=" << (state.rootBone ? state.rootBone->getName() : "null")
|
||||
<< std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AnimationTreeSystem::teardownEntity(flecs::entity e)
|
||||
@@ -225,14 +237,27 @@ void AnimationTreeSystem::update(float deltaTime)
|
||||
[this, deltaTime](flecs::entity e,
|
||||
AnimationTreeComponent &at) {
|
||||
if (at.dirty) {
|
||||
setupEntity(e, at);
|
||||
at.dirty = false;
|
||||
if (setupEntity(e, at))
|
||||
at.dirty = false;
|
||||
}
|
||||
|
||||
auto it = m_states.find(e.id());
|
||||
if (it == m_states.end())
|
||||
return;
|
||||
|
||||
/* Validate cached entity pointer -
|
||||
* CharacterSlotSystem rebuilds can destroy and
|
||||
* recreate the Ogre::Entity */
|
||||
Ogre::Entity *currentEnt = findAnimatedEntity(e);
|
||||
if (currentEnt != it->second.ogreEntity) {
|
||||
if (!setupEntity(e, at)) {
|
||||
return;
|
||||
}
|
||||
it = m_states.find(e.id());
|
||||
if (it == m_states.end())
|
||||
return;
|
||||
}
|
||||
|
||||
EntityAnimTreeState &state = it->second;
|
||||
if (!state.ogreEntity)
|
||||
return;
|
||||
@@ -323,9 +348,22 @@ void AnimationTreeSystem::update(float deltaTime)
|
||||
}
|
||||
}
|
||||
|
||||
if (at.useRootMotion && sceneNode)
|
||||
sceneNode->translate(totalRootMotion,
|
||||
if (at.useRootMotion && sceneNode) {
|
||||
if (e.has<CharacterComponent>()) {
|
||||
auto &cc = e.get_mut<CharacterComponent>();
|
||||
if (deltaTime > 0.0000001f) {
|
||||
float safeDelta = Ogre::Math::Clamp(deltaTime, 0.005f, 0.99f);
|
||||
Ogre::Quaternion worldRot = sceneNode->_getDerivedOrientation();
|
||||
cc.linearVelocity = worldRot * totalRootMotion / safeDelta;
|
||||
cc.linearVelocity.x = Ogre::Math::Clamp(cc.linearVelocity.x, -16.0f, 16.0f);
|
||||
cc.linearVelocity.z = Ogre::Math::Clamp(cc.linearVelocity.z, -16.0f, 16.0f);
|
||||
cc.linearVelocity.y = Ogre::Math::Clamp(cc.linearVelocity.y, -10.5f, 10.0f);
|
||||
}
|
||||
} else {
|
||||
sceneNode->translate(totalRootMotion,
|
||||
Ogre::Node::TS_LOCAL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset root bone to binding pose */
|
||||
if (state.rootBone) {
|
||||
|
||||
@@ -82,7 +82,7 @@ private:
|
||||
std::vector<std::pair<Ogre::String, Ogre::String>> endChecks;
|
||||
};
|
||||
|
||||
void setupEntity(flecs::entity e, AnimationTreeComponent &at);
|
||||
bool setupEntity(flecs::entity e, AnimationTreeComponent &at);
|
||||
void teardownEntity(flecs::entity e);
|
||||
void disableAllAnimations(EntityAnimTreeState &state);
|
||||
void initializeTreeStates(const AnimationTreeNode &node,
|
||||
|
||||
@@ -2682,7 +2682,10 @@ void CellGridSystem::buildPhysicsColliders(flecs::entity entity)
|
||||
physicsParent.child_of(entity);
|
||||
physicsParent.set<TransformComponent>({nullptr, parentPos, parentRot,
|
||||
parentScale});
|
||||
physicsParent.set<RigidBodyComponent>(RigidBodyComponent());
|
||||
RigidBodyComponent cellGridRb;
|
||||
if (entity.has<CellGridComponent>())
|
||||
cellGridRb.friction = entity.get<CellGridComponent>().friction;
|
||||
physicsParent.set<RigidBodyComponent>(cellGridRb);
|
||||
physicsParent.add<GeneratedPhysicsTag>();
|
||||
meshData.physicsParentEntity = physicsParent;
|
||||
|
||||
@@ -2741,7 +2744,10 @@ void CellGridSystem::buildPhysicsColliders(flecs::entity entity)
|
||||
physicsParent.child_of(entity);
|
||||
physicsParent.set<TransformComponent>({nullptr, parentPos, parentRot,
|
||||
parentScale});
|
||||
physicsParent.set<RigidBodyComponent>(RigidBodyComponent());
|
||||
RigidBodyComponent plazaRb;
|
||||
if (entity.has<DistrictComponent>())
|
||||
plazaRb.friction = entity.get<DistrictComponent>().friction;
|
||||
physicsParent.set<RigidBodyComponent>(plazaRb);
|
||||
physicsParent.add<GeneratedPhysicsTag>();
|
||||
plazaIt->second.physicsParentEntity = physicsParent;
|
||||
addPhysicsCollider(physicsParent, plazaIt->second.meshName,
|
||||
@@ -2760,7 +2766,10 @@ void CellGridSystem::buildPhysicsColliders(flecs::entity entity)
|
||||
physicsParent.child_of(entity);
|
||||
physicsParent.set<TransformComponent>({nullptr, parentPos, parentRot,
|
||||
parentScale});
|
||||
physicsParent.set<RigidBodyComponent>(RigidBodyComponent());
|
||||
RigidBodyComponent lotRb;
|
||||
if (entity.has<LotComponent>())
|
||||
lotRb.friction = entity.get<LotComponent>().friction;
|
||||
physicsParent.set<RigidBodyComponent>(lotRb);
|
||||
physicsParent.add<GeneratedPhysicsTag>();
|
||||
lotIt->second.physicsParentEntity = physicsParent;
|
||||
addPhysicsCollider(physicsParent, lotIt->second.meshName,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "CharacterSlotSystem.hpp"
|
||||
#include "../components/Transform.hpp"
|
||||
#include "../components/AnimationTree.hpp"
|
||||
#include <OgreDataStream.h>
|
||||
#include <OgreEntity.h>
|
||||
#include <OgreLogManager.h>
|
||||
@@ -218,6 +219,14 @@ void CharacterSlotSystem::buildCharacter(flecs::entity e,
|
||||
cs.masterEntity = masterEnt;
|
||||
std::cout << " master loaded: " << masterEnt->getName()
|
||||
<< std::endl;
|
||||
std::cout << " node=" << transform.node->getName()
|
||||
<< " pos=" << transform.node->_getDerivedPosition()
|
||||
<< " attached=" << transform.node->numAttachedObjects()
|
||||
<< std::endl;
|
||||
|
||||
/* Notify AnimationTreeSystem that entity changed */
|
||||
if (e.has<AnimationTreeComponent>())
|
||||
e.get_mut<AnimationTreeComponent>().dirty = true;
|
||||
} catch (const Ogre::Exception &ex) {
|
||||
std::cout << " FAILED to load master mesh: "
|
||||
<< ex.getDescription() << std::endl;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "CharacterSystem.hpp"
|
||||
#include <Jolt/Physics/Character/Character.h>
|
||||
#include <OgreLogManager.h>
|
||||
#include <iostream>
|
||||
|
||||
CharacterSystem::CharacterSystem(flecs::world &world,
|
||||
Ogre::SceneManager *sceneMgr)
|
||||
@@ -159,6 +160,11 @@ void CharacterSystem::setupEntity(flecs::entity e,
|
||||
|
||||
auto *ch = static_cast<JPH::Character *>(base);
|
||||
ch->AddToPhysicsSystem();
|
||||
m_physics->setGravityFactor(ch->GetBodyID(), 0.0f);
|
||||
cc.hasFloor = false;
|
||||
std::cout << "CharacterSystem::setupEntity: entity=" << e.id()
|
||||
<< " nodePos=" << transform.node->_getDerivedPosition()
|
||||
<< std::endl;
|
||||
|
||||
CharacterState state;
|
||||
state.character = ch;
|
||||
@@ -223,15 +229,38 @@ void CharacterSystem::update(float deltaTime)
|
||||
if (diff.squaredLength() > 0.001f) {
|
||||
state.character->SetPosition(
|
||||
JoltPhysics::convert(nodePos));
|
||||
charPos = nodePos;
|
||||
}
|
||||
|
||||
/* Integrate velocity */
|
||||
if (cc.linearVelocity.squaredLength() > 0.0f) {
|
||||
Ogre::Vector3 newPos = charPos +
|
||||
cc.linearVelocity * deltaTime;
|
||||
state.character->SetPosition(
|
||||
JoltPhysics::convert(newPos));
|
||||
/* Apply velocity via Jolt linear velocity (matches
|
||||
* original game code) */
|
||||
state.character->SetLinearVelocity(
|
||||
JoltPhysics::convert<JPH::Vec3>(
|
||||
cc.linearVelocity));
|
||||
if (cc.linearVelocity.squaredLength() > 0.0001f) {
|
||||
std::cout << "CharacterSystem::update: entity=" << e.id()
|
||||
<< " vel=" << cc.linearVelocity
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
/* Floor detection: raycast downward to find ground */
|
||||
if (cc.useGravity && !cc.hasFloor) {
|
||||
Ogre::Vector3 rayStart = charPos;
|
||||
Ogre::Vector3 rayEnd =
|
||||
rayStart +
|
||||
Ogre::Vector3(0.0f, -cc.floorCheckDistance, 0.0f);
|
||||
Ogre::Vector3 hitPos;
|
||||
JPH::BodyID hitBody;
|
||||
if (m_physics->raycastQuery(rayStart, rayEnd,
|
||||
hitPos, hitBody)) {
|
||||
cc.hasFloor = true;
|
||||
m_physics->setGravityFactor(
|
||||
state.character->GetBodyID(), 1.0f);
|
||||
std::cout << "CharacterSystem::floor detected: entity="
|
||||
<< e.id()
|
||||
<< " dist="
|
||||
<< (charPos - hitPos).length()
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sync rotation from scene node */
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../../physics/physics.h"
|
||||
#include "../physics/physics.h"
|
||||
#include "../components/Character.hpp"
|
||||
#include "../components/Transform.hpp"
|
||||
#include "../components/PhysicsCollider.hpp"
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "../components/ProceduralMaterial.hpp"
|
||||
#include "../components/Primitive.hpp"
|
||||
#include "../components/TriangleBuffer.hpp"
|
||||
#include "../components/Character.hpp"
|
||||
#include "../components/CharacterSlots.hpp"
|
||||
#include "../components/AnimationTree.hpp"
|
||||
#include "../components/CellGrid.hpp"
|
||||
@@ -180,6 +181,10 @@ nlohmann::json SceneSerializer::serializeEntity(flecs::entity entity)
|
||||
json["triangleBuffer"] = serializeTriangleBuffer(entity);
|
||||
}
|
||||
|
||||
if (entity.has<CharacterComponent>()) {
|
||||
json["character"] = serializeCharacter(entity);
|
||||
}
|
||||
|
||||
if (entity.has<CharacterSlotsComponent>()) {
|
||||
json["characterSlots"] = serializeCharacterSlots(entity);
|
||||
}
|
||||
@@ -304,6 +309,10 @@ void SceneSerializer::deserializeEntity(const nlohmann::json& json, flecs::entit
|
||||
deserializePrimitive(entity, json["primitive"]);
|
||||
}
|
||||
|
||||
if (json.contains("character")) {
|
||||
deserializeCharacter(entity, json["character"]);
|
||||
}
|
||||
|
||||
if (json.contains("characterSlots")) {
|
||||
deserializeCharacterSlots(entity, json["characterSlots"]);
|
||||
}
|
||||
@@ -1281,6 +1290,49 @@ void SceneSerializer::deserializeTriangleBuffer(flecs::entity entity, const nloh
|
||||
}
|
||||
|
||||
|
||||
nlohmann::json SceneSerializer::serializeCharacter(flecs::entity entity)
|
||||
{
|
||||
auto& cc = entity.get<CharacterComponent>();
|
||||
nlohmann::json json;
|
||||
|
||||
json["enabled"] = cc.enabled;
|
||||
json["radius"] = cc.radius;
|
||||
json["height"] = cc.height;
|
||||
json["offset"] = {
|
||||
cc.offset.x, cc.offset.y, cc.offset.z
|
||||
};
|
||||
json["linearVelocity"] = {
|
||||
cc.linearVelocity.x, cc.linearVelocity.y, cc.linearVelocity.z
|
||||
};
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
void SceneSerializer::deserializeCharacter(flecs::entity entity, const nlohmann::json& json)
|
||||
{
|
||||
CharacterComponent cc;
|
||||
cc.enabled = json.value("enabled", true);
|
||||
cc.radius = json.value("radius", 0.3f);
|
||||
cc.height = json.value("height", 1.8f);
|
||||
if (json.contains("offset") && json["offset"].is_array() &&
|
||||
json["offset"].size() >= 3) {
|
||||
cc.offset = Ogre::Vector3(
|
||||
json["offset"][0].get<float>(),
|
||||
json["offset"][1].get<float>(),
|
||||
json["offset"][2].get<float>());
|
||||
}
|
||||
if (json.contains("linearVelocity") &&
|
||||
json["linearVelocity"].is_array() &&
|
||||
json["linearVelocity"].size() >= 3) {
|
||||
cc.linearVelocity = Ogre::Vector3(
|
||||
json["linearVelocity"][0].get<float>(),
|
||||
json["linearVelocity"][1].get<float>(),
|
||||
json["linearVelocity"][2].get<float>());
|
||||
}
|
||||
cc.dirty = true;
|
||||
entity.set<CharacterComponent>(cc);
|
||||
}
|
||||
|
||||
nlohmann::json SceneSerializer::serializeCharacterSlots(flecs::entity entity)
|
||||
{
|
||||
auto& cs = entity.get<CharacterSlotsComponent>();
|
||||
@@ -1409,6 +1461,7 @@ nlohmann::json SceneSerializer::serializeCellGrid(flecs::entity entity)
|
||||
json["intWindowFrameRectName"] = grid.intWindowFrameRectName;
|
||||
json["roofTopRectName"] = grid.roofTopRectName;
|
||||
json["roofSideRectName"] = grid.roofSideRectName;
|
||||
json["friction"] = grid.friction;
|
||||
|
||||
// Serialize cells
|
||||
nlohmann::json cellsJson = nlohmann::json::array();
|
||||
@@ -1482,6 +1535,7 @@ nlohmann::json SceneSerializer::serializeDistrict(flecs::entity entity)
|
||||
json["lotTemplateNames"] = district.lotTemplateNames;
|
||||
json["proceduralMaterialEntityId"] = district.proceduralMaterialEntityId;
|
||||
json["textureRectName"] = district.textureRectName;
|
||||
json["friction"] = district.friction;
|
||||
|
||||
return json;
|
||||
}
|
||||
@@ -1500,6 +1554,7 @@ nlohmann::json SceneSerializer::serializeLot(flecs::entity entity)
|
||||
json["templateName"] = lot.templateName;
|
||||
json["proceduralMaterialEntityId"] = lot.proceduralMaterialEntityId;
|
||||
json["textureRectName"] = lot.textureRectName;
|
||||
json["friction"] = lot.friction;
|
||||
|
||||
return json;
|
||||
}
|
||||
@@ -1609,6 +1664,7 @@ void SceneSerializer::deserializeCellGrid(flecs::entity entity, const nlohmann::
|
||||
grid.intWindowFrameRectName = json.value("intWindowFrameRectName", "");
|
||||
grid.roofTopRectName = json.value("roofTopRectName", "");
|
||||
grid.roofSideRectName = json.value("roofSideRectName", "");
|
||||
grid.friction = json.value("friction", 0.5f);
|
||||
|
||||
// Deserialize cells
|
||||
if (json.contains("cells") && json["cells"].is_array()) {
|
||||
@@ -1702,6 +1758,7 @@ void SceneSerializer::deserializeDistrict(flecs::entity entity, const nlohmann::
|
||||
district.isPlaza = json.value("isPlaza", false);
|
||||
district.proceduralMaterialEntityId = json.value("proceduralMaterialEntityId", "");
|
||||
district.textureRectName = json.value("textureRectName", "");
|
||||
district.friction = json.value("friction", 0.5f);
|
||||
|
||||
// Resolve material entity reference
|
||||
if (!district.proceduralMaterialEntityId.empty()) {
|
||||
@@ -1741,6 +1798,7 @@ void SceneSerializer::deserializeLot(flecs::entity entity, const nlohmann::json&
|
||||
lot.templateName = json.value("templateName", "");
|
||||
lot.proceduralMaterialEntityId = json.value("proceduralMaterialEntityId", "");
|
||||
lot.textureRectName = json.value("textureRectName", "");
|
||||
lot.friction = json.value("friction", 0.5f);
|
||||
|
||||
// Resolve material entity reference
|
||||
if (!lot.proceduralMaterialEntityId.empty()) {
|
||||
|
||||
@@ -54,6 +54,7 @@ private:
|
||||
nlohmann::json serializeProceduralMaterial(flecs::entity entity);
|
||||
nlohmann::json serializePrimitive(flecs::entity entity);
|
||||
nlohmann::json serializeTriangleBuffer(flecs::entity entity);
|
||||
nlohmann::json serializeCharacter(flecs::entity entity);
|
||||
nlohmann::json serializeCharacterSlots(flecs::entity entity);
|
||||
nlohmann::json serializeAnimationTree(flecs::entity entity);
|
||||
|
||||
@@ -83,6 +84,7 @@ private:
|
||||
void deserializeProceduralMaterial(flecs::entity entity, const nlohmann::json& json);
|
||||
void deserializePrimitive(flecs::entity entity, const nlohmann::json& json);
|
||||
void deserializeTriangleBuffer(flecs::entity entity, const nlohmann::json& json);
|
||||
void deserializeCharacter(flecs::entity entity, const nlohmann::json& json);
|
||||
void deserializeCharacterSlots(flecs::entity entity, const nlohmann::json& json);
|
||||
void deserializeAnimationTree(flecs::entity entity, const nlohmann::json& json);
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@ bool CellGridEditor::renderComponent(flecs::entity entity, CellGridComponent& gr
|
||||
if (ImGui::DragFloat("Cell Height", &grid.cellHeight, 0.1f, 0.5f, 20.0f)) {
|
||||
modified = true;
|
||||
}
|
||||
if (ImGui::SliderFloat("Friction", &grid.friction, 0.0f, 1.0f, "%.2f")) {
|
||||
modified = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
|
||||
@@ -7,18 +7,18 @@ bool CharacterEditor::renderComponent(flecs::entity entity,
|
||||
(void)entity;
|
||||
bool modified = false;
|
||||
|
||||
if (ImGui::Checkbox("Enabled", &cc.enabled))
|
||||
if (ImGui::Checkbox("Enabled##Character", &cc.enabled))
|
||||
modified = true;
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Capsule");
|
||||
|
||||
if (ImGui::SliderFloat("Radius", &cc.radius, 0.05f, 2.0f,
|
||||
"%.2f")) {
|
||||
if (ImGui::SliderFloat("Radius##Character", &cc.radius, 0.05f, 2.0f,
|
||||
"%.2f")) {
|
||||
modified = true;
|
||||
}
|
||||
if (ImGui::SliderFloat("Height", &cc.height, 0.1f, 5.0f,
|
||||
"%.2f")) {
|
||||
if (ImGui::SliderFloat("Height##Character", &cc.height, 0.1f, 5.0f,
|
||||
"%.2f")) {
|
||||
modified = true;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ bool CharacterEditor::renderComponent(flecs::entity entity,
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Offset");
|
||||
float off[3] = { cc.offset.x, cc.offset.y, cc.offset.z };
|
||||
if (ImGui::InputFloat3("Position", off, "%.2f")) {
|
||||
if (ImGui::InputFloat3("Position##Character", off, "%.2f")) {
|
||||
cc.offset = Ogre::Vector3(off[0], off[1], off[2]);
|
||||
modified = true;
|
||||
}
|
||||
@@ -37,12 +37,26 @@ bool CharacterEditor::renderComponent(flecs::entity entity,
|
||||
ImGui::Text("Velocity");
|
||||
float vel[3] = { cc.linearVelocity.x, cc.linearVelocity.y,
|
||||
cc.linearVelocity.z };
|
||||
if (ImGui::InputFloat3("Linear (m/s)", vel, "%.2f")) {
|
||||
if (ImGui::InputFloat3("Linear (m/s)##Character", vel, "%.2f")) {
|
||||
cc.linearVelocity = Ogre::Vector3(vel[0], vel[1],
|
||||
vel[2]);
|
||||
modified = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Floor Detection");
|
||||
if (ImGui::Checkbox("Use Gravity##Character", &cc.useGravity)) {
|
||||
modified = true;
|
||||
}
|
||||
if (ImGui::Checkbox("Has Floor##Character", &cc.hasFloor)) {
|
||||
modified = true;
|
||||
}
|
||||
if (ImGui::SliderFloat("Check Distance##Character",
|
||||
&cc.floorCheckDistance, 0.1f, 10.0f,
|
||||
"%.2f")) {
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (modified)
|
||||
cc.dirty = true;
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ bool DistrictEditor::renderComponent(flecs::entity entity, DistrictComponent& di
|
||||
"DistrictEditor: Is Plaza changed to " + std::string(district.isPlaza ? "true" : "false") +
|
||||
" for entity " + std::to_string(entity.id()));
|
||||
}
|
||||
if (ImGui::SliderFloat("Friction", &district.friction, 0.0f, 1.0f, "%.2f")) {
|
||||
modified = true;
|
||||
}
|
||||
|
||||
// District material and texture settings
|
||||
ImGui::Separator();
|
||||
|
||||
@@ -32,6 +32,9 @@ bool LotEditor::renderComponent(flecs::entity entity, LotComponent& lot)
|
||||
if (ImGui::DragFloat("Offset Z", &lot.offsetZ, 0.1f)) {
|
||||
modified = true;
|
||||
}
|
||||
if (ImGui::SliderFloat("Friction", &lot.friction, 0.0f, 1.0f, "%.2f")) {
|
||||
modified = true;
|
||||
}
|
||||
|
||||
// Template
|
||||
char templateName[128] = {0};
|
||||
|
||||
Reference in New Issue
Block a user