From 0d108bc44aa0be343b7a0fbdae04d16888561e4d Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Tue, 4 Jul 2023 03:09:52 -0400 Subject: [PATCH] =?UTF-8?q?Character=20controller=20now=20moving!=20?= =?UTF-8?q?=F0=9F=8F=83=E2=80=8D=E2=99=82=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added character controller transform syncing Jolt -> Scene - Physic system code cleanup - Fixed crash with WrenScript loading - Fixed Normalize() returning NaN vector when lenght is 0 --- Editor/resources/Scripts/Math.wren | 12 +- Nuake/Engine.h | 1 + .../src/Core/Physics/CharacterController.cpp | 11 +- Nuake/src/Core/Physics/CharacterController.h | 2 +- Nuake/src/Core/Physics/DynamicWorld.cpp | 123 +++++++++++++++--- Nuake/src/Core/Physics/DynamicWorld.h | 10 +- Nuake/src/Core/Physics/PhysicsManager.cpp | 1 - .../Scene/Components/WrenScriptComponent.h | 5 +- Nuake/src/Scene/Entities/Entity.h | 2 +- Nuake/src/Scripting/Modules/MathModule.h | 2 +- Nuake/src/Scripting/Modules/SceneModule.h | 1 - 11 files changed, 134 insertions(+), 36 deletions(-) diff --git a/Editor/resources/Scripts/Math.wren b/Editor/resources/Scripts/Math.wren index 6dd389f7..c0b0818f 100644 --- a/Editor/resources/Scripts/Math.wren +++ b/Editor/resources/Scripts/Math.wren @@ -108,10 +108,14 @@ class Vector3 { Normalize() { var length = this.Length() - var x = _x / length - var y = _y / length - var z = _z / length - return Vector3.new(x, y, z) + if(length > 0.0) { + var x = _x / length + var y = _y / length + var z = _z / length + return Vector3.new(x, y, z) + } + + return Vector3.new(0, 0, 0) } Angle(vec) { diff --git a/Nuake/Engine.h b/Nuake/Engine.h index 076b2c74..2a30f0a7 100644 --- a/Nuake/Engine.h +++ b/Nuake/Engine.h @@ -11,6 +11,7 @@ * Scripting API for editing UI maybe * Launch game standalone * Fix physics system +* --play argument rendering in framebuffer */ // Welcome to the Nuake source code. diff --git a/Nuake/src/Core/Physics/CharacterController.cpp b/Nuake/src/Core/Physics/CharacterController.cpp index 3a1347eb..93c8518c 100644 --- a/Nuake/src/Core/Physics/CharacterController.cpp +++ b/Nuake/src/Core/Physics/CharacterController.cpp @@ -2,6 +2,8 @@ #include "src/Core/Physics/PhysicsManager.h" #include "src/Core/Physics/RaycastResult.h" +#include "src/Core/Physics/PhysicsManager.h" + namespace Nuake { namespace Physics @@ -23,12 +25,9 @@ namespace Nuake return Owner; } - void CharacterController::MoveAndSlide(glm::vec3 velocity) + void CharacterController::MoveAndSlide(const Vector3& velocity) { - IsOnGround = false; - ParseGhostContacts(); - UpdatePosition(); - UpdateVelocity(); + PhysicsManager::Get().GetWorld()->MoveAndSlideCharacterController(Owner, velocity); } void CharacterController::ParseGhostContacts() @@ -44,8 +43,6 @@ namespace Nuake void CharacterController::UpdateVelocity() { - - // Decelerate //m_manualVelocity -= m_manualVelocity * m_deceleration * m_pPhysicsWorld->GetScene()->m_frameTimer.GetTimeMultiplier(); diff --git a/Nuake/src/Core/Physics/CharacterController.h b/Nuake/src/Core/Physics/CharacterController.h index ba906174..b76097b9 100644 --- a/Nuake/src/Core/Physics/CharacterController.h +++ b/Nuake/src/Core/Physics/CharacterController.h @@ -37,7 +37,7 @@ namespace Nuake void SetEntity(Entity& ent); Entity GetEntity() const; - void MoveAndSlide(glm::vec3 velocity); + void MoveAndSlide(const Vector3& velocity); bool IsOnFloor() { diff --git a/Nuake/src/Core/Physics/DynamicWorld.cpp b/Nuake/src/Core/Physics/DynamicWorld.cpp index 49328988..7c32c9c1 100644 --- a/Nuake/src/Core/Physics/DynamicWorld.cpp +++ b/Nuake/src/Core/Physics/DynamicWorld.cpp @@ -4,6 +4,8 @@ #include "src/Core/Core.h" #include "src/Core/Logger.h" #include +#include "src/Scene/Components/TransformComponent.h" +#include "src/Scene/Components/CharacterControllerComponent.h" #include #include "src/Vendors/glm/gtx/matrix_decompose.hpp" @@ -198,6 +200,9 @@ namespace Nuake { DynamicWorld::DynamicWorld() : _stepCount(0) { + _registeredCharacters = std::map(); + + // Initialize Jolt Physics const uint32_t MaxBodies = 1024; const uint32_t NumBodyMutexes = 0; const uint32_t MaxBodyPairs = 1024; @@ -265,8 +270,8 @@ namespace Nuake bodySettings.mUserData = rb->GetEntity().GetID(); // Create the actual rigid body - JPH::BodyID floor = _JoltBodyInterface->CreateAndAddBody(bodySettings, JPH::EActivation::Activate); // Note that if we run out of bodies this can return nullptr - _registeredBodies.push_back((uint32_t)floor.GetIndexAndSequenceNumber()); + JPH::BodyID body = _JoltBodyInterface->CreateAndAddBody(bodySettings, JPH::EActivation::Activate); // Note that if we run out of bodies this can return nullptr + _registeredBodies.push_back((uint32_t)body.GetIndexAndSequenceNumber()); } void DynamicWorld::AddGhostbody(Ref gb) @@ -286,6 +291,9 @@ namespace Nuake JPH::Character* character = new JPH::Character(settings, joltPos, JPH::Quat::sIdentity(), cc->GetEntity().GetID() , _JoltPhysicsSystem.get()); character->AddToPhysicsSystem(JPH::EActivation::Activate); + + // To get the jolt character control from a scene entity. + _registeredCharacters[cc->Owner.GetHandle()] = character; } RaycastResult DynamicWorld::Raycast(glm::vec3 from, glm::vec3 to) @@ -304,12 +312,9 @@ namespace Nuake return result; } - void DynamicWorld::StepSimulation(Timestep ts) + void DynamicWorld::SyncEntitiesTranforms() { - // Next step - ++_stepCount; const auto& bodyInterface = _JoltPhysicsSystem->GetBodyInterface(); - for (const auto& body : _registeredBodies) { auto bodyId = static_cast(body); @@ -339,14 +344,52 @@ namespace Nuake transformComponent.SetLocalRotation(Quat(bodyRotation.GetW(), bodyRotation.GetX(), bodyRotation.GetY(), bodyRotation.GetZ())); transformComponent.SetLocalTransform(transform); transformComponent.Dirty = false; - - /* Logging - const std::string& name = entity.GetComponent().Name; - const std::string& posStr = "(" + std::to_string(pos.x) + ", " + std::to_string(pos.y) + ", " + std::to_string(pos.z) + ")"; - const std::string& logMsg = "Physics pos: " + name + " at " + posStr; - Logger::Log(logMsg); - */ } + } + + void DynamicWorld::SyncCharactersTransforms() + { + // TODO(ANTO): Finish this to connect updated jolt transforms back to the entity. + // The problem was that I dont know yet how to go from jolt body ptr to the entity + // Combinations of find and iterators etc. I do not have the brain power rn zzz. + // const auto& bodyInterface = _JoltPhysicsSystem->GetBodyInterface(); + + for (const auto& e : _registeredCharacters) + { + Entity entity { (entt::entity)e.first, Engine::GetCurrentScene().get()}; + + JPH::Character* characterController = e.second; + JPH::Mat44 joltTransform = characterController->GetWorldTransform(); + const auto bodyRotation = characterController->GetRotation(); + + Matrix4 transform = glm::mat4( + joltTransform(0, 0), joltTransform(1, 0), joltTransform(2, 0), joltTransform(3, 0), + joltTransform(0, 1), joltTransform(1, 1), joltTransform(2, 1), joltTransform(3, 1), + joltTransform(0, 2), joltTransform(1, 2), joltTransform(2, 2), joltTransform(3, 2), + joltTransform(0, 3), joltTransform(1, 3), joltTransform(2, 3), joltTransform(3, 3) + ); + + Vector3 scale = Vector3(); + Quat rotation = Quat(); + Vector3 pos = Vector3(); + Vector3 skew = Vector3(); + Vector4 pesp = Vector4(); + glm::decompose(transform, scale, rotation, pos, skew, pesp); + + auto& transformComponent = entity.GetComponent(); + transformComponent.SetLocalPosition(pos); + transformComponent.SetLocalRotation(Quat(bodyRotation.GetW(), bodyRotation.GetX(), bodyRotation.GetY(), bodyRotation.GetZ())); + transformComponent.SetLocalTransform(transform); + transformComponent.Dirty = false; + } + } + + void DynamicWorld::StepSimulation(Timestep ts) + { + // Next step + ++_stepCount; + SyncEntitiesTranforms(); + SyncCharactersTransforms(); // If you take larger steps than 1 / 60th of a second you need to do multiple collision steps in order to keep the simulation stable. // Do 1 collision step per 1 / 60th of a second (round up). @@ -364,6 +407,7 @@ namespace Nuake _JoltPhysicsSystem->Update(ts, collisionSteps, subSteps, new JPH::TempAllocatorMalloc(), _JoltJobSystem); } + void DynamicWorld::Clear() { _stepCount = 0; @@ -377,6 +421,54 @@ namespace Nuake _registeredBodies.clear(); } + void DynamicWorld::MoveAndSlideCharacterController(const Entity& entity, const Vector3 velocity) + { + const uint32_t entityHandle = entity.GetHandle(); + if (_registeredCharacters.find(entityHandle) != _registeredCharacters.end()) + { + auto& characterController = _registeredCharacters[entityHandle]; + characterController->SetLinearVelocity(JPH::Vec3(velocity.x, velocity.y, velocity.z)); + } + } + + const Matrix4& DynamicWorld::GetCharacterControllerSimulatedTransform(const Entity& entity) + { + const uint32_t entityHandle = entity.GetHandle(); + if (_registeredCharacters.find(entityHandle) != _registeredCharacters.end()) + { + auto& characterController = _registeredCharacters[entityHandle]; + + JPH::Mat44 joltTransform = characterController->GetWorldTransform(); + const auto bodyRotation = characterController->GetRotation(); + + Matrix4 transform = glm::mat4( + joltTransform(0, 0), joltTransform(1, 0), joltTransform(2, 0), joltTransform(3, 0), + joltTransform(0, 1), joltTransform(1, 1), joltTransform(2, 1), joltTransform(3, 1), + joltTransform(0, 2), joltTransform(1, 2), joltTransform(2, 2), joltTransform(3, 2), + joltTransform(0, 3), joltTransform(1, 3), joltTransform(2, 3), joltTransform(3, 3) + ); + + + return transform; + + //Vector3 scale = Vector3(); + //Quat rotation = Quat(); + //Vector3 pos = Vector3(); + //Vector3 skew = Vector3(); + //Vector4 pesp = Vector4(); + //glm::decompose(transform, scale, rotation, pos, skew, pesp); + + //auto& transformComponent = entity.GetComponent(); + //transformComponent.SetLocalPosition(pos); + //transformComponent.SetLocalRotation(Quat(bodyRotation.GetW(), bodyRotation.GetX(), bodyRotation.GetY(), bodyRotation.GetZ())); + //transformComponent.SetLocalTransform(transform); + //transformComponent.Dirty = false; + } + + assert("Shouldn't have reached here!"); + return Matrix4(1.0); + } + JPH::Ref DynamicWorld::GetJoltShape(const Ref shape) { JPH::ShapeSettings::ShapeResult result; @@ -426,8 +518,8 @@ namespace Nuake JPH::TriangleList triangles; triangles.reserve(indices.size()); - Matrix4 transform; //rb->_transform; - transform[3] = Vector4(0, 0, 0, 1.0f); + auto transform = Matrix4(1.0f); + transform[3] = Vector4(0.0f, 0.0f, 0.0f, 1.0f); for (int i = 0; i < indices.size() - 3; i += 3) { const Vector3& p1 = vertices[indices[i]].position; @@ -448,7 +540,6 @@ namespace Nuake case CONVEX_HULL: { auto* convexHullShape = (Physics::ConvexHullShape*)shape.get(); - const auto& hullPoints = convexHullShape->GetPoints(); JPH::Array points; points.reserve(std::size(hullPoints)); diff --git a/Nuake/src/Core/Physics/DynamicWorld.h b/Nuake/src/Core/Physics/DynamicWorld.h index 58f45846..83a2e337 100644 --- a/Nuake/src/Core/Physics/DynamicWorld.h +++ b/Nuake/src/Core/Physics/DynamicWorld.h @@ -19,6 +19,7 @@ namespace JPH class BodyActivationListener; class BodyInterface; class Shape; + class Character; template class Ref; @@ -45,7 +46,7 @@ namespace Nuake BPLayerInterfaceImpl* _JoltBroadphaseLayerInterface; std::vector _registeredBodies; - std::vector _registeredCharacters; + std::map _registeredCharacters; public: DynamicWorld(); @@ -57,13 +58,18 @@ namespace Nuake void AddGhostbody(Ref gb); void AddCharacterController(Ref cc); + // This is going to be ugly. TODO: Find a better way that passing itself as a parameter + void MoveAndSlideCharacterController(const Entity& entity, const Vector3 velocity); + + const Matrix4& GetCharacterControllerSimulatedTransform(const Entity& entity); RaycastResult Raycast(glm::vec3 from, glm::vec3 to); void StepSimulation(Timestep ts); void Clear(); private: JPH::Ref GetJoltShape(const Ref shape); + void SyncEntitiesTranforms(); + void SyncCharactersTransforms(); }; } } - diff --git a/Nuake/src/Core/Physics/PhysicsManager.cpp b/Nuake/src/Core/Physics/PhysicsManager.cpp index 96ad26e0..7d5ebaf1 100644 --- a/Nuake/src/Core/Physics/PhysicsManager.cpp +++ b/Nuake/src/Core/Physics/PhysicsManager.cpp @@ -20,7 +20,6 @@ namespace Nuake void PhysicsManager::RegisterGhostBody(Ref rb) { m_World->AddGhostbody(rb); - } void PhysicsManager::RegisterCharacterController(Ref cc) diff --git a/Nuake/src/Scene/Components/WrenScriptComponent.h b/Nuake/src/Scene/Components/WrenScriptComponent.h index 36ddbe19..6ed39012 100644 --- a/Nuake/src/Scene/Components/WrenScriptComponent.h +++ b/Nuake/src/Scene/Components/WrenScriptComponent.h @@ -9,11 +9,12 @@ namespace Nuake { std::string Script; unsigned int mModule = 0; - Ref mWrenScript; + Ref mWrenScript = nullptr; void LoadScript(const std::string& path) { - Ref nuakeFile = Nuake::FileSystem::GetFile(Script); + Script = path; + Ref nuakeFile = Nuake::FileSystem::GetFile(path); mWrenScript = CreateRef(nuakeFile, true); auto modules = mWrenScript->GetModules(); if (modules.size() > 0) diff --git a/Nuake/src/Scene/Entities/Entity.h b/Nuake/src/Scene/Entities/Entity.h index de18739c..bbf073d3 100644 --- a/Nuake/src/Scene/Entities/Entity.h +++ b/Nuake/src/Scene/Entities/Entity.h @@ -17,7 +17,7 @@ namespace Nuake void AddChild(Entity ent); - int GetHandle() { return (int)m_EntityHandle; } + int GetHandle() const { return (int)m_EntityHandle; } int GetID() { return GetComponent().ID; } template diff --git a/Nuake/src/Scripting/Modules/MathModule.h b/Nuake/src/Scripting/Modules/MathModule.h index 5393ba42..f1e4e727 100644 --- a/Nuake/src/Scripting/Modules/MathModule.h +++ b/Nuake/src/Scripting/Modules/MathModule.h @@ -108,7 +108,7 @@ namespace Nuake { wrenGetSlotDouble(vm, 3)); float length = glm::length(v1); - wrenSetSlotDouble(vm, 0, glm::length(v1)); + wrenSetSlotDouble(vm, 0, length); } }; } diff --git a/Nuake/src/Scripting/Modules/SceneModule.h b/Nuake/src/Scripting/Modules/SceneModule.h index 8d92f39c..51de9366 100644 --- a/Nuake/src/Scripting/Modules/SceneModule.h +++ b/Nuake/src/Scripting/Modules/SceneModule.h @@ -77,7 +77,6 @@ namespace Nuake { if (name == "Transform") result = ent.HasComponent(); if (name == "Light") result = ent.HasComponent(); if (name == "QuakeMap") result = ent.HasComponent(); - if (name == "CharacterController") { result = ent.HasComponent();