#include "ENT_Player.h" #include "CEngine.h" #include "U_ShortAPI.h" #include "CPhysicalEntity.h" #include "CDrawableEntity.h" #include "CGame.h" #include "CTransformable.h" #include "glm/gtx/norm.hpp" #include "CBulletPhysics.h" void ENT_Player::V_Init() { if(!IsConnectedClient()) { AddInitParam("modelname", new CWrapable("gordon.emdl")); AddInitParam("spaceid", new CWrapable(0)); AddInitParam("phys_worldid", new CWrapable(0)); AddInitParam("phys_collision", new CWrapable("player.ecol")); AddInitParam("phys_type", new CWrapable("ghost")); AddInitParam("phys_mass", new CWrapable(0.0f)); } SetEntityModel(this); Components.CreateComponent(false); auto drawable = Components.GetComponentTyped(); auto physical = Components.GetComponentTyped(); if(drawable) { drawable->Init(); } if(physical) { physical->Init(); } } void ENT_Player::V_Update() { float deltaTime = CEngine::GetInstance()->Time.GetDeltaTime(); auto physical = Components.GetComponentTyped(); if(!physical || !physical->WorldUnit) { return; } if(!onGround) { velocity = physical->WorldUnit->GetWorld()->GetGravity() * deltaTime; } if(glm::length(userMovement) > 0.001f) { velocity += userMovement; } glm::vec3 move = velocity * deltaTime; //applying deltaTime two times? StepMove(move); DetectGround(); } void ENT_Player::DetectGround() { auto game = CEngine::GetInstance()->Components.GetComponentTyped(); auto& physEngine = game->PhysicsEngine; auto physical = Components.GetComponentTyped(); auto transformable = Components.GetComponentTyped(); auto _thisUnit = physical->WorldUnit; auto thisUnit = dynamic_cast(_thisUnit); auto thisRigidUnit = dynamic_cast(_thisUnit); auto thisKinematicUnit = dynamic_cast(_thisUnit); //Log::Instance() << "_thisUnit: " << _thisUnit << Log::Endl; //Log::Instance() << "thisUnit: " << thisUnit << Log::Endl; //Log::Instance() << "thisRigidUnit: " << thisRigidUnit << Log::Endl; //Log::Instance() << "thisKinematicUnit: " << thisKinematicUnit << Log::Endl; CTransform start = transformable->Transform; CTransform end = start; auto world = physEngine->GetWorld(0); onGround = false; groundNormal = glm::vec3(0.0f, 1.0f, 0.0f); //btWorld->BulletWorld->updateSingleAabb(_btGhost); //btWorld->BulletWorld->performDiscreteCollisionDetection(); auto overlaps = world->V_GetGhostOverlaps(thisUnit); int numOverlaps = overlaps->GetNumOverlappingUnits(); glm::vec3 upVector(0.0f, 1.0f, 0.0f); float kGroundEpsilon = 0.05f; float bestDot = -1.0f; glm::vec3 bestNormal = upVector; for (int i = 0; i < numOverlaps; ++i) { auto overlapUnit = overlaps->GetOverlappingUnit(i); auto overlapRigid = dynamic_cast(overlapUnit); if(!overlapRigid) { continue; } auto manifolds = overlaps->GetContactManifolds(overlapUnit); //Log::Instance() << "Overlap #" << i << " with nmanifolds: " << manifolds.size() << " overlapping rigid " << overlapRigid->GetCollision()->Name << Log::Endl; for (int m = 0; m < manifolds.size(); ++m) { auto& manifold = manifolds.at(m); int ncontacts = manifold->GetNumContacts(); //Log::Instance() << "Manifold #" << i << ":" << m << " with ncontacts: " << manifold->GetNumContacts() << Log::Endl; for (int p = 0; p < ncontacts; ++p) { //Log::Instance() << "Contact #" << i << ":" << m << ":" << p << Log::Endl; auto contact = manifold->GetContact(p); Log::Instance() << "Distance: " << contact->GetDistance() << Log::Endl; //Log::Instance() << "NormalWorldOnB: " << contact->GetNormalWorldOnB() << Log::Endl; if (contact->GetDistance() < kGroundEpsilon) { glm::vec3 n = contact->GetNormalWorldOnB(); if(manifold->GetUnitB() == physical->WorldUnit) { n = -n; } float dot = glm::dot(n, glm::vec3(0.0f, 1.0f, 0.0f)); if (dot > 0.6f && dot > bestDot) { bestDot = dot; bestNormal = n; } } } } } if (bestDot > 0.6f) { onGround = true; groundNormal = bestNormal; Log::Instance() << "ONGROUND\n"; velocity.y = 0.0f; } } size_t moves = 0; void ENT_Player::StepMove(const glm::vec3& _move) { moves++; auto game = CEngine::GetInstance()->Components.GetComponentTyped(); auto& physEngine = game->PhysicsEngine; auto physical = Components.GetComponentTyped(); auto transformable = Components.GetComponentTyped(); CTransform start = transformable->Transform; CTransform end = start; end.SetPosition(start.GetPosition() + velocity); auto world = physEngine->GetWorld(0); std::vector excludeList; excludeList.push_back(physical->WorldUnit); auto result = world->V_ConvexSweep(physical->WorldUnit->GetCollision(), start, end, nullptr, std::move(excludeList)); if(result->HasHit()) { auto& hit = result->GetHit(); //Log::Instance() << "HIT at point " << hit.HitPointWorld << " to unit " << ((hit.HitUnit && hit.HitUnit->GetCollision()) ? hit.HitUnit->GetCollision()->Name : "nullptr") << " with normal " << hit.HitNormalWorld << Log::Endl; float fraction = hit.HitFraction; glm::vec3 hitNormal = hit.HitNormalWorld; glm::vec3 newPos = start.GetPosition() + _move * fraction; glm::vec3 remaining = _move * (1.0f - fraction); glm::vec3 slide = remaining - hitNormal * glm::dot(remaining, hitNormal); if (glm::length2(slide) > 0.0001f && moves <= 100) { StepMove(slide); } else { //end.SetPosition(newPos); //transformable->Transform.SetPRS(end.GetPRS()); //Log::Instance() << "Should move2 to " << end.GetPosition() << " with velocity " << velocity << Log::Endl; } } else { transformable->Transform.SetPRS(end.GetPRS()); //Log::Instance() << "Should move to " << end.GetPosition() << " with velocity " << velocity << Log::Endl; } moves--; } LINK_ENTITY_TO_CLASS(ENT_Player, player);