Added character physics but it does not work yet
This commit is contained in:
@@ -27,6 +27,7 @@ set(EDITSCENE_SOURCES
|
||||
systems/FurnitureLibrary.cpp
|
||||
systems/CharacterSlotSystem.cpp
|
||||
systems/AnimationTreeSystem.cpp
|
||||
systems/CharacterSystem.cpp
|
||||
ui/TransformEditor.cpp
|
||||
ui/RenderableEditor.cpp
|
||||
ui/PhysicsColliderEditor.cpp
|
||||
@@ -43,6 +44,7 @@ set(EDITSCENE_SOURCES
|
||||
ui/TriangleBufferEditor.cpp
|
||||
ui/CharacterSlotsEditor.cpp
|
||||
ui/AnimationTreeEditor.cpp
|
||||
ui/CharacterEditor.cpp
|
||||
ui/CellGridEditor.cpp
|
||||
ui/LotEditor.cpp
|
||||
ui/DistrictEditor.cpp
|
||||
@@ -65,6 +67,7 @@ set(EDITSCENE_SOURCES
|
||||
components/CharacterSlotsModule.cpp
|
||||
components/AnimationTreeModule.cpp
|
||||
components/AnimationTree.cpp
|
||||
components/CharacterModule.cpp
|
||||
components/CellGridModule.cpp
|
||||
components/CellGridEditorsModule.cpp
|
||||
components/CellGrid.cpp
|
||||
@@ -93,6 +96,7 @@ set(EDITSCENE_HEADERS
|
||||
components/TriangleBuffer.hpp
|
||||
components/CharacterSlots.hpp
|
||||
components/AnimationTree.hpp
|
||||
components/Character.hpp
|
||||
components/CellGrid.hpp
|
||||
systems/EditorUISystem.hpp
|
||||
systems/CellGridSystem.hpp
|
||||
@@ -102,6 +106,7 @@ set(EDITSCENE_HEADERS
|
||||
systems/ProceduralMeshSystem.hpp
|
||||
systems/CharacterSlotSystem.hpp
|
||||
systems/AnimationTreeSystem.hpp
|
||||
systems/CharacterSystem.hpp
|
||||
systems/ProceduralTextureSystem.hpp
|
||||
systems/StaticGeometrySystem.hpp
|
||||
systems/SceneSerializer.hpp
|
||||
@@ -128,6 +133,7 @@ set(EDITSCENE_HEADERS
|
||||
ui/TriangleBufferEditor.hpp
|
||||
ui/CharacterSlotsEditor.hpp
|
||||
ui/AnimationTreeEditor.hpp
|
||||
ui/CharacterEditor.hpp
|
||||
ui/CellGridEditor.hpp
|
||||
ui/LotEditor.hpp
|
||||
ui/DistrictEditor.hpp
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "systems/ProceduralMeshSystem.hpp"
|
||||
#include "systems/CharacterSlotSystem.hpp"
|
||||
#include "systems/AnimationTreeSystem.hpp"
|
||||
#include "systems/CharacterSystem.hpp"
|
||||
#include "systems/CellGridSystem.hpp"
|
||||
#include "systems/RoomLayoutSystem.hpp"
|
||||
#include "camera/EditorCamera.hpp"
|
||||
@@ -33,6 +34,7 @@
|
||||
#include "components/TriangleBuffer.hpp"
|
||||
#include "components/CharacterSlots.hpp"
|
||||
#include "components/AnimationTree.hpp"
|
||||
#include "components/Character.hpp"
|
||||
#include "components/CellGrid.hpp"
|
||||
#include "components/CellGridModule.hpp"
|
||||
#include <OgreRTShaderSystem.h>
|
||||
@@ -125,6 +127,7 @@ EditorApp::~EditorApp()
|
||||
// Release all systems
|
||||
m_characterSlotSystem.reset();
|
||||
m_animationTreeSystem.reset();
|
||||
m_characterSystem.reset();
|
||||
m_proceduralMeshSystem.reset();
|
||||
m_proceduralMaterialSystem.reset();
|
||||
m_proceduralTextureSystem.reset();
|
||||
@@ -239,6 +242,11 @@ void EditorApp::setup()
|
||||
m_world, m_sceneMgr);
|
||||
m_animationTreeSystem->initialize();
|
||||
|
||||
// Setup Character physics system
|
||||
m_characterSystem = std::make_unique<CharacterSystem>(
|
||||
m_world, m_sceneMgr);
|
||||
m_characterSystem->initialize();
|
||||
|
||||
// Setup CellGrid system
|
||||
m_cellGridSystem =
|
||||
std::make_unique<CellGridSystem>(m_world, m_sceneMgr);
|
||||
@@ -311,6 +319,9 @@ void EditorApp::setupECS()
|
||||
// Register AnimationTree component
|
||||
m_world.component<AnimationTreeComponent>();
|
||||
|
||||
// Register Character component
|
||||
m_world.component<CharacterComponent>();
|
||||
|
||||
// Register CellGrid/Town components
|
||||
CellGridModule::registerComponents(m_world);
|
||||
}
|
||||
@@ -436,6 +447,11 @@ 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);
|
||||
|
||||
@@ -23,6 +23,7 @@ class ProceduralMaterialSystem;
|
||||
class ProceduralMeshSystem;
|
||||
class CharacterSlotSystem;
|
||||
class AnimationTreeSystem;
|
||||
class CharacterSystem;
|
||||
class CellGridSystem;
|
||||
class RoomLayoutSystem;
|
||||
|
||||
@@ -120,6 +121,7 @@ private:
|
||||
std::unique_ptr<ProceduralMeshSystem> m_proceduralMeshSystem;
|
||||
std::unique_ptr<CharacterSlotSystem> m_characterSlotSystem;
|
||||
std::unique_ptr<AnimationTreeSystem> m_animationTreeSystem;
|
||||
std::unique_ptr<CharacterSystem> m_characterSystem;
|
||||
std::unique_ptr<CellGridSystem> m_cellGridSystem;
|
||||
std::unique_ptr<RoomLayoutSystem> m_roomLayoutSystem;
|
||||
|
||||
|
||||
37
src/features/editScene/components/Character.hpp
Normal file
37
src/features/editScene/components/Character.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef EDITSCENE_CHARACTER_HPP
|
||||
#define EDITSCENE_CHARACTER_HPP
|
||||
#pragma once
|
||||
|
||||
#include <Ogre.h>
|
||||
|
||||
/**
|
||||
* Character physics component
|
||||
*
|
||||
* Attaches a Jolt JPH::Character (kinematic capsule) to the entity.
|
||||
* The entity may also have CharacterSlotsComponent; the character
|
||||
* physics lives on the same entity as the visual character.
|
||||
*
|
||||
* Child entities can add extra collision shapes via PhysicsColliderComponent.
|
||||
*/
|
||||
struct CharacterComponent {
|
||||
/* Capsule dimensions */
|
||||
float radius = 0.3f;
|
||||
float height = 1.8f; /* cylinder height (excluding spherical caps) */
|
||||
|
||||
/* Offset from the entity's scene node */
|
||||
Ogre::Vector3 offset = Ogre::Vector3::ZERO;
|
||||
|
||||
/* Current linear velocity (m/s), applied each frame by CharacterSystem */
|
||||
Ogre::Vector3 linearVelocity = Ogre::Vector3::ZERO;
|
||||
|
||||
/* Enable/disable physics character */
|
||||
bool enabled = true;
|
||||
|
||||
/* Dirty flag — triggers rebuild of the Jolt character */
|
||||
bool dirty = true;
|
||||
|
||||
float getHalfHeight() const { return height * 0.5f; }
|
||||
float getTotalHeight() const { return height + 2.0f * radius; }
|
||||
};
|
||||
|
||||
#endif // EDITSCENE_CHARACTER_HPP
|
||||
20
src/features/editScene/components/CharacterModule.cpp
Normal file
20
src/features/editScene/components/CharacterModule.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "../ui/ComponentRegistration.hpp"
|
||||
#include "Character.hpp"
|
||||
#include "../ui/CharacterEditor.hpp"
|
||||
|
||||
REGISTER_COMPONENT_GROUP("Character Physics", "Physics",
|
||||
CharacterComponent, CharacterEditor)
|
||||
{
|
||||
registry.registerComponent<CharacterComponent>(
|
||||
"Character Physics", "Physics", std::make_unique<CharacterEditor>(),
|
||||
// Adder
|
||||
[](flecs::entity e) {
|
||||
if (!e.has<CharacterComponent>())
|
||||
e.set<CharacterComponent>({});
|
||||
},
|
||||
// Remover
|
||||
[](flecs::entity e) {
|
||||
if (e.has<CharacterComponent>())
|
||||
e.remove<CharacterComponent>();
|
||||
});
|
||||
}
|
||||
@@ -446,6 +446,10 @@ Ogre::Vector3 convert(const JPH::Vec3Arg &vec)
|
||||
{
|
||||
return { vec[0], vec[1], vec[2] };
|
||||
}
|
||||
Ogre::Vector3 convert(const JPH::RVec3Arg &vec)
|
||||
{
|
||||
return { (float)vec[0], (float)vec[1], (float)vec[2] };
|
||||
}
|
||||
JPH::RVec3 convert(const Ogre::Vector3 &vec)
|
||||
{
|
||||
return { vec.x, vec.y, vec.z };
|
||||
@@ -1002,6 +1006,26 @@ public:
|
||||
characters.insert(ch);
|
||||
return ch;
|
||||
}
|
||||
JPH::CharacterBase *createCharacter(Ogre::SceneNode *node,
|
||||
JPH::ShapeRefC shape)
|
||||
{
|
||||
JPH::CharacterSettings settings;
|
||||
settings.mLayer = Layers::MOVING;
|
||||
settings.mShape = shape;
|
||||
settings.mSupportingVolume =
|
||||
JPH::Plane(JPH::Vec3::sAxisY(), -0.2f);
|
||||
JPH::Character *ch = new JPH::Character(
|
||||
&settings,
|
||||
JoltPhysics::convert(node->_getDerivedPosition()),
|
||||
JoltPhysics::convert(node->_getDerivedOrientation()), 0,
|
||||
&physics_system);
|
||||
JPH::BodyID id = ch->GetBodyID();
|
||||
id2node[id] = node;
|
||||
node2id[node] = id;
|
||||
characterBodies.insert(id);
|
||||
characters.insert(ch);
|
||||
return ch;
|
||||
}
|
||||
JPH::ShapeRefC createBoxShape(Ogre::Vector3 extents)
|
||||
{
|
||||
JPH::Vec3 h(extents.x, extents.y, extents.z);
|
||||
@@ -1742,6 +1766,11 @@ JPH::CharacterBase *JoltPhysicsWrapper::createCharacter(Ogre::SceneNode *node,
|
||||
{
|
||||
return phys->createCharacter(node, characterHeight, characterRadius);
|
||||
}
|
||||
JPH::CharacterBase *JoltPhysicsWrapper::createCharacter(Ogre::SceneNode *node,
|
||||
JPH::ShapeRefC shape)
|
||||
{
|
||||
return phys->createCharacter(node, shape);
|
||||
}
|
||||
void JoltPhysicsWrapper::addShapeToCompound(JPH::Ref<JPH::Shape> compoundShape,
|
||||
JPH::ShapeRefC childShape,
|
||||
const Ogre::Vector3 &position,
|
||||
|
||||
@@ -54,6 +54,8 @@ template<class T> T convert(const Ogre::Vector3 &vec)
|
||||
{
|
||||
return { vec.x, vec.y, vec.z };
|
||||
}
|
||||
Ogre::Vector3 convert(const JPH::RVec3Arg &vec);
|
||||
JPH::RVec3 convert(const Ogre::Vector3 &vec);
|
||||
Ogre::Quaternion convert(const JPH::QuatArg &rot);
|
||||
JPH::Quat convert(const Ogre::Quaternion &rot);
|
||||
struct ShapeData;
|
||||
@@ -166,6 +168,8 @@ public:
|
||||
JPH::CharacterBase *createCharacter(Ogre::SceneNode *node,
|
||||
float characterHeight,
|
||||
float characterRadius);
|
||||
JPH::CharacterBase *createCharacter(Ogre::SceneNode *node,
|
||||
JPH::ShapeRefC shape);
|
||||
void addShapeToCompound(JPH::Ref<JPH::Shape> compoundShape,
|
||||
JPH::ShapeRefC childShape,
|
||||
const Ogre::Vector3 &position,
|
||||
|
||||
242
src/features/editScene/systems/CharacterSystem.cpp
Normal file
242
src/features/editScene/systems/CharacterSystem.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
#include "CharacterSystem.hpp"
|
||||
#include <Jolt/Physics/Character/Character.h>
|
||||
#include <OgreLogManager.h>
|
||||
|
||||
CharacterSystem::CharacterSystem(flecs::world &world,
|
||||
Ogre::SceneManager *sceneMgr)
|
||||
: m_world(world)
|
||||
, m_sceneMgr(sceneMgr)
|
||||
{
|
||||
m_world.observer<CharacterComponent>("CharacterCleanup")
|
||||
.event(flecs::OnRemove)
|
||||
.each([this](flecs::entity e, CharacterComponent &) {
|
||||
teardownEntity(e);
|
||||
});
|
||||
}
|
||||
|
||||
CharacterSystem::~CharacterSystem()
|
||||
{
|
||||
std::vector<flecs::entity_t> toRemove;
|
||||
for (auto &pair : m_states)
|
||||
toRemove.push_back(pair.first);
|
||||
for (auto id : toRemove)
|
||||
teardownEntity(m_world.entity(id));
|
||||
}
|
||||
|
||||
void CharacterSystem::initialize()
|
||||
{
|
||||
m_physics = JoltPhysicsWrapper::getSingletonPtr();
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
JPH::ShapeRefC CharacterSystem::createColliderShape(
|
||||
PhysicsColliderComponent &collider)
|
||||
{
|
||||
if (!collider.shapeDirty && collider.shape)
|
||||
return collider.shape;
|
||||
|
||||
JPH::ShapeRefC result;
|
||||
switch (collider.shapeType) {
|
||||
case PhysicsColliderComponent::ShapeType::Box:
|
||||
result = m_physics->createBoxShape(collider.parameters);
|
||||
break;
|
||||
case PhysicsColliderComponent::ShapeType::Sphere:
|
||||
result = m_physics->createSphereShape(collider.radius);
|
||||
break;
|
||||
case PhysicsColliderComponent::ShapeType::Capsule:
|
||||
result = m_physics->createCapsuleShape(collider.halfHeight,
|
||||
collider.radius);
|
||||
break;
|
||||
case PhysicsColliderComponent::ShapeType::Cylinder:
|
||||
result = m_physics->createCylinderShape(collider.halfHeight,
|
||||
collider.radius);
|
||||
break;
|
||||
case PhysicsColliderComponent::ShapeType::Mesh: {
|
||||
if (!collider.meshName.empty()) {
|
||||
try {
|
||||
result = m_physics->createMeshShape(collider.meshName);
|
||||
} catch (...) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Failed to create mesh shape: " + collider.meshName);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PhysicsColliderComponent::ShapeType::ConvexHull: {
|
||||
if (!collider.meshName.empty()) {
|
||||
try {
|
||||
result = m_physics->createConvexHullShape(
|
||||
collider.meshName);
|
||||
} catch (...) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Failed to create convex hull shape: " +
|
||||
collider.meshName);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
result = m_physics->createBoxShape(Ogre::Vector3(0.1f, 0.1f,
|
||||
0.1f));
|
||||
|
||||
if (collider.offset != Ogre::Vector3::ZERO ||
|
||||
collider.rotationOffset != Ogre::Quaternion::IDENTITY)
|
||||
result = m_physics->createRotatedTranslatedShape(
|
||||
collider.offset, collider.rotationOffset, result);
|
||||
|
||||
collider.shape = result;
|
||||
collider.shapeDirty = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
JPH::ShapeRefC CharacterSystem::buildCharacterShape(flecs::entity e,
|
||||
CharacterComponent &cc)
|
||||
{
|
||||
std::vector<JPH::ShapeRefC> shapes;
|
||||
std::vector<Ogre::Vector3> positions;
|
||||
std::vector<Ogre::Quaternion> rotations;
|
||||
|
||||
/* Main capsule */
|
||||
float halfHeight = cc.getHalfHeight();
|
||||
JPH::ShapeRefC capsule = m_physics->createCapsuleShape(halfHeight,
|
||||
cc.radius);
|
||||
/* Shift capsule so its bottom sits at y = 0 */
|
||||
Ogre::Vector3 capsulePos(0.0f, halfHeight + cc.radius, 0.0f);
|
||||
capsule = m_physics->createRotatedTranslatedShape(
|
||||
capsulePos + cc.offset, Ogre::Quaternion::IDENTITY,
|
||||
capsule);
|
||||
shapes.push_back(capsule);
|
||||
positions.push_back(Ogre::Vector3::ZERO);
|
||||
rotations.push_back(Ogre::Quaternion::IDENTITY);
|
||||
|
||||
/* Child colliders */
|
||||
e.children([&](flecs::entity child) {
|
||||
if (!child.has<PhysicsColliderComponent>() ||
|
||||
!child.has<TransformComponent>())
|
||||
return;
|
||||
auto &collider = child.get_mut<PhysicsColliderComponent>();
|
||||
auto &transform = child.get<TransformComponent>();
|
||||
|
||||
JPH::ShapeRefC shape = createColliderShape(collider);
|
||||
if (shape) {
|
||||
shapes.push_back(shape);
|
||||
positions.push_back(transform.position);
|
||||
rotations.push_back(transform.rotation);
|
||||
}
|
||||
});
|
||||
|
||||
if (shapes.size() == 1)
|
||||
return shapes[0];
|
||||
|
||||
return m_physics->createStaticCompoundShape(shapes, positions,
|
||||
rotations);
|
||||
}
|
||||
|
||||
void CharacterSystem::setupEntity(flecs::entity e,
|
||||
CharacterComponent &cc)
|
||||
{
|
||||
if (!m_physics)
|
||||
return;
|
||||
|
||||
if (!e.has<TransformComponent>())
|
||||
return;
|
||||
auto &transform = e.get<TransformComponent>();
|
||||
if (!transform.node)
|
||||
return;
|
||||
|
||||
teardownEntity(e);
|
||||
|
||||
JPH::ShapeRefC shape = buildCharacterShape(e, cc);
|
||||
if (!shape)
|
||||
return;
|
||||
|
||||
JPH::CharacterBase *base = m_physics->createCharacter(
|
||||
transform.node, shape);
|
||||
if (!base)
|
||||
return;
|
||||
|
||||
auto *ch = static_cast<JPH::Character *>(base);
|
||||
ch->AddToPhysicsSystem();
|
||||
|
||||
CharacterState state;
|
||||
state.character = ch;
|
||||
state.sceneNode = transform.node;
|
||||
m_states[e.id()] = state;
|
||||
|
||||
cc.dirty = false;
|
||||
}
|
||||
|
||||
void CharacterSystem::teardownEntity(flecs::entity e)
|
||||
{
|
||||
auto it = m_states.find(e.id());
|
||||
if (it == m_states.end())
|
||||
return;
|
||||
|
||||
CharacterState &state = it->second;
|
||||
if (state.character) {
|
||||
state.character->RemoveFromPhysicsSystem();
|
||||
m_physics->destroyCharacter(
|
||||
std::shared_ptr<JPH::Character>(state.character));
|
||||
}
|
||||
|
||||
m_states.erase(it);
|
||||
}
|
||||
|
||||
void CharacterSystem::update(float deltaTime)
|
||||
{
|
||||
if (!m_initialized || !m_physics)
|
||||
return;
|
||||
|
||||
m_world.query<CharacterComponent, TransformComponent>().each(
|
||||
[this, deltaTime](flecs::entity e,
|
||||
CharacterComponent &cc,
|
||||
TransformComponent &transform) {
|
||||
if (!cc.enabled) {
|
||||
teardownEntity(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cc.dirty) {
|
||||
setupEntity(e, cc);
|
||||
cc.dirty = false;
|
||||
}
|
||||
|
||||
auto it = m_states.find(e.id());
|
||||
if (it == m_states.end())
|
||||
return;
|
||||
|
||||
CharacterState &state = it->second;
|
||||
if (!state.character || !state.sceneNode)
|
||||
return;
|
||||
|
||||
/* Read current physics position */
|
||||
Ogre::Vector3 charPos = JoltPhysics::convert(
|
||||
state.character->GetPosition());
|
||||
Ogre::Vector3 nodePos =
|
||||
state.sceneNode->_getDerivedPosition();
|
||||
|
||||
/* If scene node was moved externally (editor gizmo),
|
||||
* teleport character there */
|
||||
Ogre::Vector3 diff = nodePos - charPos;
|
||||
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));
|
||||
}
|
||||
|
||||
/* Sync rotation from scene node */
|
||||
state.character->SetRotation(
|
||||
JoltPhysics::convert(
|
||||
state.sceneNode->_getDerivedOrientation()));
|
||||
});
|
||||
}
|
||||
52
src/features/editScene/systems/CharacterSystem.hpp
Normal file
52
src/features/editScene/systems/CharacterSystem.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef EDITSCENE_CHARACTERSYSTEM_HPP
|
||||
#define EDITSCENE_CHARACTERSYSTEM_HPP
|
||||
#pragma once
|
||||
|
||||
#include <flecs.h>
|
||||
#include <Ogre.h>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../../physics/physics.h"
|
||||
#include "../components/Character.hpp"
|
||||
#include "../components/Transform.hpp"
|
||||
#include "../components/PhysicsCollider.hpp"
|
||||
|
||||
/**
|
||||
* System that manages JPH::Character instances for entities with
|
||||
* CharacterComponent.
|
||||
*
|
||||
* - Creates a capsule shape (plus child colliders) for each character
|
||||
* - Integrates linearVelocity each frame
|
||||
* - Syncs position/rotation between physics and SceneNode
|
||||
*/
|
||||
class CharacterSystem {
|
||||
public:
|
||||
CharacterSystem(flecs::world &world, Ogre::SceneManager *sceneMgr);
|
||||
~CharacterSystem();
|
||||
|
||||
void initialize();
|
||||
void update(float deltaTime);
|
||||
|
||||
private:
|
||||
struct CharacterState {
|
||||
JPH::Character *character = nullptr;
|
||||
Ogre::SceneNode *sceneNode = nullptr;
|
||||
};
|
||||
|
||||
void setupEntity(flecs::entity e, CharacterComponent &cc);
|
||||
void teardownEntity(flecs::entity e);
|
||||
|
||||
JPH::ShapeRefC buildCharacterShape(flecs::entity e,
|
||||
CharacterComponent &cc);
|
||||
JPH::ShapeRefC createColliderShape(PhysicsColliderComponent &collider);
|
||||
|
||||
flecs::world &m_world;
|
||||
Ogre::SceneManager *m_sceneMgr;
|
||||
JoltPhysicsWrapper *m_physics = nullptr;
|
||||
bool m_initialized = false;
|
||||
|
||||
std::unordered_map<flecs::entity_t, CharacterState> m_states;
|
||||
};
|
||||
|
||||
#endif // EDITSCENE_CHARACTERSYSTEM_HPP
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "../components/TriangleBuffer.hpp"
|
||||
#include "../components/LodSettings.hpp"
|
||||
#include "../components/CharacterSlots.hpp"
|
||||
#include "../components/Character.hpp"
|
||||
#include "../components/AnimationTree.hpp"
|
||||
#include "../components/CellGrid.hpp"
|
||||
#include "../ui/TransformEditor.hpp"
|
||||
@@ -629,6 +630,13 @@ void EditorUISystem::renderComponentList(flecs::entity entity)
|
||||
componentCount++;
|
||||
}
|
||||
|
||||
// Render Character if present
|
||||
if (entity.has<CharacterComponent>()) {
|
||||
auto &cc = entity.get_mut<CharacterComponent>();
|
||||
m_componentRegistry.render<CharacterComponent>(entity, cc);
|
||||
componentCount++;
|
||||
}
|
||||
|
||||
// Render CharacterSlots if present
|
||||
if (entity.has<CharacterSlotsComponent>()) {
|
||||
auto &cs = entity.get_mut<CharacterSlotsComponent>();
|
||||
|
||||
50
src/features/editScene/ui/CharacterEditor.cpp
Normal file
50
src/features/editScene/ui/CharacterEditor.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include "CharacterEditor.hpp"
|
||||
#include <imgui.h>
|
||||
|
||||
bool CharacterEditor::renderComponent(flecs::entity entity,
|
||||
CharacterComponent &cc)
|
||||
{
|
||||
(void)entity;
|
||||
bool modified = false;
|
||||
|
||||
if (ImGui::Checkbox("Enabled", &cc.enabled))
|
||||
modified = true;
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Capsule");
|
||||
|
||||
if (ImGui::SliderFloat("Radius", &cc.radius, 0.05f, 2.0f,
|
||||
"%.2f")) {
|
||||
modified = true;
|
||||
}
|
||||
if (ImGui::SliderFloat("Height", &cc.height, 0.1f, 5.0f,
|
||||
"%.2f")) {
|
||||
modified = true;
|
||||
}
|
||||
|
||||
ImGui::TextDisabled("Total: %.2f m",
|
||||
cc.getTotalHeight());
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Offset");
|
||||
float off[3] = { cc.offset.x, cc.offset.y, cc.offset.z };
|
||||
if (ImGui::InputFloat3("Position", off, "%.2f")) {
|
||||
cc.offset = Ogre::Vector3(off[0], off[1], off[2]);
|
||||
modified = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Velocity");
|
||||
float vel[3] = { cc.linearVelocity.x, cc.linearVelocity.y,
|
||||
cc.linearVelocity.z };
|
||||
if (ImGui::InputFloat3("Linear (m/s)", vel, "%.2f")) {
|
||||
cc.linearVelocity = Ogre::Vector3(vel[0], vel[1],
|
||||
vel[2]);
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (modified)
|
||||
cc.dirty = true;
|
||||
|
||||
return modified;
|
||||
}
|
||||
18
src/features/editScene/ui/CharacterEditor.hpp
Normal file
18
src/features/editScene/ui/CharacterEditor.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef EDITSCENE_CHARACTEREDITOR_HPP
|
||||
#define EDITSCENE_CHARACTEREDITOR_HPP
|
||||
#pragma once
|
||||
|
||||
#include "ComponentEditor.hpp"
|
||||
#include "../components/Character.hpp"
|
||||
|
||||
/**
|
||||
* Editor for CharacterComponent
|
||||
*/
|
||||
class CharacterEditor : public ComponentEditor<CharacterComponent> {
|
||||
public:
|
||||
bool renderComponent(flecs::entity entity,
|
||||
CharacterComponent &cc) override;
|
||||
const char *getName() const override { return "Character Physics"; }
|
||||
};
|
||||
|
||||
#endif // EDITSCENE_CHARACTEREDITOR_HPP
|
||||
Reference in New Issue
Block a user