From 82e0a30100cf6008baf539127ff06ba4de4b8b1b Mon Sep 17 00:00:00 2001 From: EyeGuy <vanya619@list.ru> Date: Wed, 18 May 2022 22:20:40 +0300 Subject: [PATCH 1/6] Ladder first part --- source/game/BaseCharacter.cpp | 23 +- source/game/BaseCharacter.h | 7 + source/game/FuncLadder.cpp | 223 +++++++++++++++++- source/game/FuncLadder.h | 36 ++- source/game/Player.cpp | 43 +++- source/physics/CharacterController.cpp | 10 +- source/physics/CharacterController.h | 10 +- .../xcommon/physics/IXCharacterController.h | 10 +- source/xcommon/physics/IXCollisionObject.h | 1 + 9 files changed, 335 insertions(+), 28 deletions(-) diff --git a/source/game/BaseCharacter.cpp b/source/game/BaseCharacter.cpp index 7c080032c..6eb31fba5 100644 --- a/source/game/BaseCharacter.cpp +++ b/source/game/BaseCharacter.cpp @@ -8,6 +8,7 @@ See the license in LICENSE #include "GameData.h" #include "BaseTool.h" #include "BaseWeapon.h" +#include "FuncLadder.h" #include <aigrid/sxaigrid.h> @@ -128,6 +129,26 @@ CBaseCharacter::~CBaseCharacter() } } +void CBaseCharacter::mountToLadder(CFuncLadder *pLadder) +{ + if(m_pLadder == pLadder) + { + return; + } + m_pLadder = pLadder; + float3 vStart = m_pLadder->getPos(), vEnd = m_pLadder->getUpPos(); + + float3 vPointOnLadder = SMProjectPointOnLine(getPos(), vEnd, vEnd - vStart); + setPos(vPointOnLadder); + m_uMoveDir |= PM_LADDER; + m_pCharacter->setGravity({0, 0, 0}); + m_pCharacter->setVelocityForTimeInterval({0, 0, 0}, 0); +} + +void CBaseCharacter::dismountFromLadder() +{ + m_pLadder = NULL; +} void CBaseCharacter::attack(BOOL state) { @@ -528,7 +549,7 @@ void CBaseCharacter::use(bool start) float3 end = start + dir * 2.0f; CClosestNotMeRayResultCallback cb(m_pGhostObject); - GetPhysWorld()->rayTest(start, end, &cb); + GetPhysWorld()->rayTest(start, end, &cb, CG_CHARACTER, CG_ALL ^ (CG_HITBOX | CG_STATIC | CG_TRIGGER | CG_WATER)); if(cb.hasHit() && cb.m_result.pCollisionObject->getUserPointer() && cb.m_result.pCollisionObject->getUserTypeId() == 1) { diff --git a/source/game/BaseCharacter.h b/source/game/BaseCharacter.h index 1b93d64e6..a4cebf3e3 100644 --- a/source/game/BaseCharacter.h +++ b/source/game/BaseCharacter.h @@ -36,10 +36,12 @@ enum PLAYER_MOVE PM_RUN = 0x40, //!< бежать PM_CRAWL = 0x80, //!< лежать PM_OBSERVER = 0x100, //!< наблюдатель + PM_LADDER = 0x200, //!< лестница PM_STOP = 0xFFFF }; +class CFuncLadder; class CHUDcontroller; class CBaseCharacter; @@ -134,6 +136,10 @@ public: void onPostLoad() override; + void mountToLadder(CFuncLadder *pLadder); + + void dismountFromLadder(); + protected: //! Фонарик CLightDirectional* m_flashlight; @@ -184,6 +190,7 @@ protected: virtual float3 getHeadOffset(); + CFuncLadder *m_pLadder = NULL; private: static IEventChannel<XEventPhysicsStep> *m_pTickEventChannel; CCharacterPhysicsTickEventListener m_physicsTicker; diff --git a/source/game/FuncLadder.cpp b/source/game/FuncLadder.cpp index c969b8b66..f6a9442eb 100644 --- a/source/game/FuncLadder.cpp +++ b/source/game/FuncLadder.cpp @@ -1,4 +1,5 @@ #include "FuncLadder.h" +#include "BaseCharacter.h" BEGIN_PROPTABLE(CInfoLadderDismount) @@ -30,10 +31,51 @@ END_PROPTABLE() REGISTER_ENTITY(CFuncLadder, func_ladder); +IEventChannel<XEventPhysicsStep> *CFuncLadder::m_pTickEventChannel = NULL; + +CFuncLadder::CFuncLadder(): + m_physicsTicker(this) +{ + if(!m_pTickEventChannel) + { + m_pTickEventChannel = Core_GetIXCore()->getEventChannel<XEventPhysicsStep>(EVENT_PHYSICS_STEP_GUID); + } +} + +CFuncLadder::~CFuncLadder() +{ + disable(); + mem_release(m_pCollideShape); + mem_release(m_pGhostObject); +} + void CFuncLadder::setUpPoint(const float3 &vUp) { m_isUpSet = true; m_vUpPoint = vUp; + + initPhysics(); +} + +void CFuncLadder::createPhysBody() +{ + if(!m_pGhostObject) + { + GetPhysics()->newGhostObject(&m_pGhostObject); + m_pGhostObject->setPosition(getPos()); + m_pGhostObject->setUserPointer(this); + m_pGhostObject->setUserTypeId(1); + m_pGhostObject->setCollisionFlags(m_pGhostObject->getCollisionFlags() ^ XCF_NO_CONTACT_RESPONSE); + m_pGhostObject->setCollisionShape(m_pCollideShape); + if(m_isEnabled) + { + GetPhysWorld()->addCollisionObject(m_pGhostObject, CG_LADDER, CG_CHARACTER); + } + } + else + { + m_pGhostObject->setCollisionShape(m_pCollideShape); + } } void CFuncLadder::setPos(const float3 &pos) @@ -42,27 +84,111 @@ void CFuncLadder::setPos(const float3 &pos) if(!m_isUpSet) { m_vUpPoint = (float3)(pos + float3(0.0f, 2.0f, 0.0f)); + initPhysics(); } + SAFE_CALL(m_pGhostObject, setPosition, pos); } void CFuncLadder::updateFlags() { BaseClass::updateFlags(); - m_isEnabled = !(getFlags() & LADDER_INITIALLY_DISABLED); + if(getFlags() & LADDER_INITIALLY_DISABLED) + { + disable(); + } + else + { + enable(); + } } void CFuncLadder::turnOn(inputdata_t *pInputdata) { - m_isEnabled = true; + enable(); } + void CFuncLadder::turnOff(inputdata_t *pInputdata) { - m_isEnabled = false; + disable(); } + void CFuncLadder::toggle(inputdata_t *pInputdata) { - m_isEnabled = !m_isEnabled; + if(m_isEnabled) + { + turnOff(pInputdata); + } + else + { + turnOn(pInputdata); + } +} + +void CFuncLadder::initPhysics() +{ + //TODO: сделать обработку ситуации когда m_vUpPoint ниже getPos + mem_release(m_pCollideShape); + + float3 vDelta = m_vUpPoint - getPos(); + float3 vMin, vMax; + float3 vMinDelta, vMaxDelta; + getMinMax(&vMin, &vMax); + + float3_t aPointsBot[] = { + { vMin.x, vMax.y, vMin.z }, + { vMax.x, vMax.y, vMin.z }, + { vMin.x, vMax.y, vMax.z }, + { vMax.x, vMax.y, vMax.z } + }; + + vMinDelta = vMin + vDelta; + vMaxDelta = vMax + vDelta; + + float3_t aPointsTop[] = { + { vMinDelta.x, vMinDelta.y, vMinDelta.z }, + { vMaxDelta.x, vMinDelta.y, vMinDelta.z }, + { vMinDelta.x, vMinDelta.y, vMaxDelta.z }, + { vMaxDelta.x, vMinDelta.y, vMaxDelta.z } + }; + + const UINT c_uSize = 14; + UINT uIndex = 0; + float3_t aShapePoints[c_uSize] = {}; + + if(vDelta.x > 0.0f || vDelta.z > 0.0f) + { + aShapePoints[uIndex++] = aPointsBot[0]; + aShapePoints[uIndex++] = aPointsTop[3]; + } + if(vDelta.x < 0.0f || vDelta.z < 0.0f) + { + aShapePoints[uIndex++] = aPointsBot[3]; + aShapePoints[uIndex++] = aPointsTop[0]; + } + if(vDelta.x < 0.0f || vDelta.z > 0.0f) + { + aShapePoints[uIndex++] = aPointsBot[1]; + aShapePoints[uIndex++] = aPointsTop[2]; + } + if(vDelta.x > 0.0f || vDelta.z < 0.0f) + { + aShapePoints[uIndex++] = aPointsBot[2]; + aShapePoints[uIndex++] = aPointsTop[1]; + } + + aShapePoints[uIndex++] = vMin; + aShapePoints[uIndex++] = {vMin.x, vMin.y ,vMax.z}; + aShapePoints[uIndex++] = {vMax.x, vMin.y, vMax.z}; + aShapePoints[uIndex++] = {vMax.x, vMin.y, vMin.z}; + + aShapePoints[uIndex++] = vMaxDelta; + aShapePoints[uIndex++] = {vMaxDelta.x, vMaxDelta.y, vMinDelta.z}; + aShapePoints[uIndex++] = {vMinDelta.x, vMaxDelta.y, vMinDelta.z}; + aShapePoints[uIndex++] = {vMinDelta.x, vMaxDelta.y, vMaxDelta.z}; + + GetPhysics()->newConvexHullShape(uIndex, aShapePoints, &m_pCollideShape, sizeof(float3_t), false); + createPhysBody(); } void CFuncLadder::renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer *pRenderer) @@ -105,3 +231,92 @@ bool CFuncLadder::rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOu return(false); } + +void CFuncLadder::onUse(CBaseEntity *pUser) +{ + connectToLadder(pUser); + BaseClass::onUse(pUser); +} + +float3 CFuncLadder::getUpPos() +{ + return m_vUpPoint; +} + +void CFuncLadder::connectToLadder(CBaseEntity *pEntity) +{ + if(fstrcmp(pEntity->getClassName(), "player")) + { + return; + } + CBaseCharacter *pCharacter = (CBaseCharacter*)pEntity; + pCharacter->mountToLadder(this); +} + +void CFuncLadder::onPhysicsStep() +{ + if(!m_pGhostObject || !m_isEnabled) + { + return; + } + + for(UINT i = 0, l = m_pGhostObject->getOverlappingPairCount(); i < l; ++i) + { + IXCollisionPair *pair = m_pGhostObject->getOverlappingPair(i); + + for(UINT j = 0, jl = pair->getContactManifoldCount(); j < jl; ++j) + { + IXContactManifold *pManifold = pair->getContactManifold(j); + if(pManifold->getContactCount() > 0) + { + IXCollisionObject *p0 = pair->getObject0(); + IXCollisionObject *p1 = pair->getObject1(); + + const IXCollisionObject *pObject = p0 == m_pGhostObject ? p1 : p0; + + if(pObject->getUserPointer() && pObject->getUserTypeId() == 1) + { + CBaseEntity *pEnt = (CBaseEntity*)pObject->getUserPointer(); + if(pEnt) + { + connectToLadder(pEnt); + //printf("touched %s\n", pEnt->getClassName()); + } + } + break; + } + } + } +} + + +void CFuncLadder::enable() +{ + if(!m_isEnabled) + { + if(m_pGhostObject) + { + GetPhysWorld()->addCollisionObject(m_pGhostObject, CG_LADDER, CG_CHARACTER); + } + m_pTickEventChannel->addListener(&m_physicsTicker); + m_isEnabled = true; + } +} + +void CFuncLadder::disable() +{ + if(m_isEnabled) + { + if(m_pGhostObject) + { + GetPhysWorld()->removeCollisionObject(m_pGhostObject); + } + m_pTickEventChannel->removeListener(&m_physicsTicker); + m_isEnabled = false; + } +} + +void CPhysicsLadderTickEventListener::onEvent(const XEventPhysicsStep *pData) +{ + m_pLadder->onPhysicsStep(); +} diff --git a/source/game/FuncLadder.h b/source/game/FuncLadder.h index ad349f999..78530c7ac 100644 --- a/source/game/FuncLadder.h +++ b/source/game/FuncLadder.h @@ -15,12 +15,28 @@ public: #define LADDER_INITIALLY_DISABLED ENT_FLAG_0 +class CFuncLadder; +class CPhysicsLadderTickEventListener final : public IEventListener<XEventPhysicsStep> +{ +public: + CPhysicsLadderTickEventListener(CFuncLadder *pLadder) : + m_pLadder(pLadder) + { + } + void onEvent(const XEventPhysicsStep *pData) override; + +private: + CFuncLadder *m_pLadder; +}; + class CFuncLadder: public CPointEntity { DECLARE_CLASS(CFuncLadder, CPointEntity); DECLARE_PROPTABLE(); + friend class CPhysicsLadderTickEventListener; public: - DECLARE_TRIVIAL_CONSTRUCTOR(); + DECLARE_CONSTRUCTOR(); + ~CFuncLadder(); void setPos(const float3 &pos) override; @@ -30,21 +46,37 @@ public: bool rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut = NULL, float3 *pvNormal = NULL, bool isRayInWorldSpace = true, bool bReturnNearestPoint = false) override; + void onUse(CBaseEntity *pUser) override; + + float3 getUpPos(); + private: + void connectToLadder(CBaseEntity *pEntity); + void createPhysBody(); void setUpPoint(const float3 &vUp); void updateFlags() override; void turnOn(inputdata_t *pInputdata); void turnOff(inputdata_t *pInputdata); void toggle(inputdata_t *pInputdata); + void initPhysics(); + void enable(); + void disable(); + void onPhysicsStep(); private: float3_t m_vUpPoint; bool m_isUpSet = false; - bool m_isEnabled = true; + bool m_isEnabled = false; output_t m_onPlayerGetOn; output_t m_onPlayerGetOff; + + IXGhostObject *m_pGhostObject = NULL; + IXConvexHullShape *m_pCollideShape = NULL; + static IEventChannel<XEventPhysicsStep> *m_pTickEventChannel; + CPhysicsLadderTickEventListener m_physicsTicker; + }; #endif diff --git a/source/game/Player.cpp b/source/game/Player.cpp index 17e2832e5..a63d6cfca 100644 --- a/source/game/Player.cpp +++ b/source/game/Player.cpp @@ -8,6 +8,7 @@ See the license in LICENSE #include "Player.h" #include "LightDirectional.h" #include "BaseAmmo.h" +#include "FuncLadder.h" #include "BaseWeapon.h" @@ -195,7 +196,7 @@ void CPlayer::updateInput(float dt) { //dt *= 5.0f; } - dt *= 10.0f; + //dt *= 10.0f; float3 dir; bool mov = false; if(m_uMoveDir & PM_FORWARD) @@ -224,7 +225,7 @@ void CPlayer::updateInput(float dt) if(m_uMoveDir & PM_CROUCH || (m_fCurrentHeight < 0.99f && !m_pCharacter->canStandUp((m_fCapsHeight - m_fCapsRadius * 2.0f) * (1.0f - m_fCurrentHeight)))) { - m_fCurrentHeight -= dt; + m_fCurrentHeight -= dt * 10.0f; float fMinHeight = (m_fCapsHeightCrouch - m_fCapsRadius * 2.0f) / (m_fCapsHeight - m_fCapsRadius * 2.0f); if(m_fCurrentHeight < fMinHeight) { @@ -233,7 +234,7 @@ void CPlayer::updateInput(float dt) } else { - m_fCurrentHeight += dt; + m_fCurrentHeight += dt* 10.0f; if(m_fCurrentHeight > 1.0f) { m_fCurrentHeight = 1.0f; @@ -243,7 +244,37 @@ void CPlayer::updateInput(float dt) if(m_uMoveDir & PM_OBSERVER) { - setPos(getPos() + m_pHeadEnt->getOrient() * (SMVector3Normalize(dir) * dt)); + setPos(getPos() + m_pHeadEnt->getOrient() * (SMVector3Normalize(dir) * dt * 10.0f)); + } + else if(m_uMoveDir & PM_LADDER) + { + if(m_uMoveDir & PM_FORWARD) + { + float3 vSpeed(0.0f, 3.0f, 0.0f); + float3 fNewPos = getPos() + vSpeed * dt; + if(m_pLadder->getUpPos().y >= fNewPos.y) + { + setPos(fNewPos); + } + else + { + setPos(m_pLadder->getUpPos()); + } + } + else if(m_uMoveDir & PM_BACKWARD) + { + float3 vSpeed(0.0f, -3.0f, 0.0f); + float3 fNewPos = getPos() + vSpeed * dt; + if(m_pLadder->getPos().y <= fNewPos.y) + { + setPos(fNewPos); + } + else + { + setPos(m_pLadder->getPos()); + } + } + m_vCurrentSpeed = {0.0f, 0.0f, 0.0f}; } else { @@ -302,7 +333,7 @@ void CPlayer::updateInput(float dt) } else { - m_vCurrentSpeed = (float3)(m_vCurrentSpeed + SMVector3Normalize(fAccelDir) * fAccel * dt); + m_vCurrentSpeed = (float3)(m_vCurrentSpeed + SMVector3Normalize(fAccelDir) * fAccel * dt * 10.0f); if(SMVector3Dot(m_vCurrentSpeed, m_vTargetSpeed) > SM_PIDIV2 && SMVector3Length2(m_vCurrentSpeed) > SMVector3Length2(m_vTargetSpeed)) { @@ -328,7 +359,7 @@ void CPlayer::updateInput(float dt) - m_fViewbobStep += dt * *cl_bob_period * fBobCoeff; + m_fViewbobStep += dt * 10.0f * *cl_bob_period * fBobCoeff; /*if(m_uMoveDir & PM_RUN) diff --git a/source/physics/CharacterController.cpp b/source/physics/CharacterController.cpp index 6af897f2e..b7dee7a3a 100644 --- a/source/physics/CharacterController.cpp +++ b/source/physics/CharacterController.cpp @@ -65,23 +65,23 @@ void XMETHODCALLTYPE CCharacterController::unregisterInWorld() } } -void XMETHODCALLTYPE CCharacterController::setMaxJumpHeight(float fHeight) const +void XMETHODCALLTYPE CCharacterController::setMaxJumpHeight(float fHeight) { m_pController->setMaxJumpHeight(fHeight); } -void XMETHODCALLTYPE CCharacterController::setJumpSpeed(float fSpeed) const +void XMETHODCALLTYPE CCharacterController::setJumpSpeed(float fSpeed) { m_pController->setJumpSpeed(fSpeed); } -void XMETHODCALLTYPE CCharacterController::setGravity(const float3_t &vSpeed) const +void XMETHODCALLTYPE CCharacterController::setGravity(const float3_t &vSpeed) { m_pController->setGravity(F3_BTVEC(vSpeed)); } -void XMETHODCALLTYPE CCharacterController::setFallSpeed(float fSpeed) const +void XMETHODCALLTYPE CCharacterController::setFallSpeed(float fSpeed) { m_pController->setFallSpeed(fSpeed); } -void XMETHODCALLTYPE CCharacterController::setMaxPenetrationDepth(float fMaxDepth) const +void XMETHODCALLTYPE CCharacterController::setMaxPenetrationDepth(float fMaxDepth) { m_pController->setMaxPenetrationDepth(fMaxDepth); } diff --git a/source/physics/CharacterController.h b/source/physics/CharacterController.h index 24cbe4061..f3af6e1cb 100644 --- a/source/physics/CharacterController.h +++ b/source/physics/CharacterController.h @@ -24,11 +24,11 @@ public: void XMETHODCALLTYPE registerInWorld(IXPhysicsWorld *pWorld) override; void XMETHODCALLTYPE unregisterInWorld() override; - void XMETHODCALLTYPE setMaxJumpHeight(float fHeight) const override; - void XMETHODCALLTYPE setJumpSpeed(float fSpeed) const override; - void XMETHODCALLTYPE setGravity(const float3_t &vSpeed) const override; - void XMETHODCALLTYPE setFallSpeed(float fSpeed) const override; - void XMETHODCALLTYPE setMaxPenetrationDepth(float fMaxDepth) const override; + void XMETHODCALLTYPE setMaxJumpHeight(float fHeight) override; + void XMETHODCALLTYPE setJumpSpeed(float fSpeed) override; + void XMETHODCALLTYPE setGravity(const float3_t &vSpeed) override; + void XMETHODCALLTYPE setFallSpeed(float fSpeed) override; + void XMETHODCALLTYPE setMaxPenetrationDepth(float fMaxDepth) override; private: btKinematicCharacterController *m_pController; diff --git a/source/xcommon/physics/IXCharacterController.h b/source/xcommon/physics/IXCharacterController.h index ac56270ab..4f35e0c5a 100644 --- a/source/xcommon/physics/IXCharacterController.h +++ b/source/xcommon/physics/IXCharacterController.h @@ -20,11 +20,11 @@ public: virtual void XMETHODCALLTYPE registerInWorld(IXPhysicsWorld *pWorld) = 0; virtual void XMETHODCALLTYPE unregisterInWorld() = 0; - virtual void XMETHODCALLTYPE setMaxJumpHeight(float fHeight) const = 0; - virtual void XMETHODCALLTYPE setJumpSpeed(float fSpeed) const = 0; - virtual void XMETHODCALLTYPE setGravity(const float3_t &vSpeed) const = 0; - virtual void XMETHODCALLTYPE setFallSpeed(float fSpeed) const = 0; - virtual void XMETHODCALLTYPE setMaxPenetrationDepth(float fMaxDepth) const = 0; + virtual void XMETHODCALLTYPE setMaxJumpHeight(float fHeight) = 0; + virtual void XMETHODCALLTYPE setJumpSpeed(float fSpeed) = 0; + virtual void XMETHODCALLTYPE setGravity(const float3_t &vSpeed) = 0; + virtual void XMETHODCALLTYPE setFallSpeed(float fSpeed) = 0; + virtual void XMETHODCALLTYPE setMaxPenetrationDepth(float fMaxDepth) = 0; /* diff --git a/source/xcommon/physics/IXCollisionObject.h b/source/xcommon/physics/IXCollisionObject.h index 7b0747039..2592ff18b 100644 --- a/source/xcommon/physics/IXCollisionObject.h +++ b/source/xcommon/physics/IXCollisionObject.h @@ -21,6 +21,7 @@ enum COLLISION_GROUP CG_BULLETFIRE = BIT(8), CG_NPCVIEW = BIT(9), CG_DOOR = BIT(10), + CG_LADDER = BIT(11), CG_ALL = 0xFFFFFFFF }; -- GitLab From 79611009ef392882b91e3b7de8c83ca9d1ae23b6 Mon Sep 17 00:00:00 2001 From: D-AIRY <admin@ds-servers.com> Date: Fri, 20 Dec 2024 20:39:33 +0300 Subject: [PATCH 2/6] Added movement controllers --- proj/sxgame/vs2013/sxgame.vcxproj | 3 + proj/sxgame/vs2013/sxgame.vcxproj.filters | 17 +- source/game/BaseCharacter.cpp | 38 +++-- source/game/BaseCharacter.h | 19 +-- source/game/FuncLadder.cpp | 187 +++++++++++++++++++--- source/game/FuncLadder.h | 3 + source/game/IMovementController.h | 19 +++ source/game/LadderMovementController.cpp | 119 ++++++++++++++ source/game/LadderMovementController.h | 32 ++++ source/game/Player.cpp | 67 +++----- source/game/Player.h | 1 + 11 files changed, 407 insertions(+), 98 deletions(-) create mode 100644 source/game/IMovementController.h create mode 100644 source/game/LadderMovementController.cpp create mode 100644 source/game/LadderMovementController.h diff --git a/proj/sxgame/vs2013/sxgame.vcxproj b/proj/sxgame/vs2013/sxgame.vcxproj index 5f6b91c46..b70be725f 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj +++ b/proj/sxgame/vs2013/sxgame.vcxproj @@ -210,6 +210,7 @@ <ClCompile Include="..\..\..\source\game\GUIInventoryController.cpp" /> <ClCompile Include="..\..\..\source\game\HUDcontroller.cpp" /> <ClCompile Include="..\..\..\source\game\InfoParticlePlayer.cpp" /> + <ClCompile Include="..\..\..\source\game\LadderMovementController.cpp" /> <ClCompile Include="..\..\..\source\game\LightDirectional.cpp" /> <ClCompile Include="..\..\..\source\game\LightPoint.cpp" /> <ClCompile Include="..\..\..\source\game\LightSun.cpp" /> @@ -291,7 +292,9 @@ <ClInclude Include="..\..\..\source\game\GUIInventoryController.h" /> <ClInclude Include="..\..\..\source\game\HUDcontroller.h" /> <ClInclude Include="..\..\..\source\game\IGameState.h" /> + <ClInclude Include="..\..\..\source\game\IMovementController.h" /> <ClInclude Include="..\..\..\source\game\InfoParticlePlayer.h" /> + <ClInclude Include="..\..\..\source\game\LadderMovementController.h" /> <ClInclude Include="..\..\..\source\game\LightSun.h" /> <ClInclude Include="..\..\..\source\game\LogicAuto.h" /> <ClInclude Include="..\..\..\source\game\LogicConsole.h" /> diff --git a/proj/sxgame/vs2013/sxgame.vcxproj.filters b/proj/sxgame/vs2013/sxgame.vcxproj.filters index e9732da19..912083c6e 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj.filters +++ b/proj/sxgame/vs2013/sxgame.vcxproj.filters @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="Source Files"> @@ -115,6 +115,12 @@ <Filter Include="Header Files\ents\info"> <UniqueIdentifier>{93ee5d69-dabd-4584-8e15-0acd713e614f}</UniqueIdentifier> </Filter> + <Filter Include="Header Files\character_movement"> + <UniqueIdentifier>{3852670f-3617-4451-bfc1-c0aba9c194fa}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\character_movement"> + <UniqueIdentifier>{7f56c9eb-5a04-4d29-ab96-b7e3d8d368f1}</UniqueIdentifier> + </Filter> </ItemGroup> <ItemGroup> <ClCompile Include="..\..\..\source\game\sxgame_dll.cpp"> @@ -360,6 +366,9 @@ <ClCompile Include="..\..\..\source\game\CraftSystem.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\game\LadderMovementController.cpp"> + <Filter>Source Files\character_movement</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\source\game\sxgame.h"> @@ -629,6 +638,12 @@ <ClInclude Include="..\..\..\source\game\CraftSystem.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\game\IMovementController.h"> + <Filter>Header Files\character_movement</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\game\LadderMovementController.h"> + <Filter>Header Files\character_movement</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\..\..\source\game\sxgame.rc"> diff --git a/source/game/BaseCharacter.cpp b/source/game/BaseCharacter.cpp index 9fe180197..89dd1892c 100644 --- a/source/game/BaseCharacter.cpp +++ b/source/game/BaseCharacter.cpp @@ -124,31 +124,20 @@ CBaseCharacter::~CBaseCharacter() mem_release(m_pHandsModelResource); + mem_release(m_pMovementController); + if(m_idQuadCurr >= 0) { //SAIG_QuadSetState(m_idQuadCurr, AIQUAD_STATE_FREE); } } -void CBaseCharacter::mountToLadder(CFuncLadder *pLadder) -{ - if(m_pLadder == pLadder) - { - return; - } - m_pLadder = pLadder; - float3 vStart = m_pLadder->getPos(), vEnd = m_pLadder->getUpPos(); - - float3 vPointOnLadder = SMProjectPointOnLine(getPos(), vEnd, vEnd - vStart); - setPos(vPointOnLadder); - m_uMoveDir |= PM_LADDER; - m_pCharacter->setGravity({0, 0, 0}); - m_pCharacter->setVelocityForTimeInterval({0, 0, 0}, 0); -} - -void CBaseCharacter::dismountFromLadder() +void CBaseCharacter::setMovementController(IMovementController *pController) { - m_pLadder = NULL; + mem_release(m_pMovementController); + m_pMovementController = pController; + add_ref(m_pMovementController); + SAFE_CALL(m_pMovementController, setCharacter, this); } void CBaseCharacter::attack(BOOL state) @@ -471,8 +460,12 @@ void CBaseCharacter::onPhysicsStep() { return; } - float3 vPos = m_pGhostObject->getPosition(); - setPos(vPos - float3(0.0f, m_fCapsHeight * m_fCurrentHeight * 0.5f, 0.0f)); + + if(!m_pMovementController) + { + float3 vPos = m_pGhostObject->getPosition(); + setPos(vPos - float3(0.0f, m_fCapsHeight * m_fCurrentHeight * 0.5f, 0.0f)); + } m_pHeadEnt->setOffsetPos(getHeadOffset()); @@ -558,6 +551,11 @@ void CBaseCharacter::use(bool start) if(start) { + if(m_pMovementController && m_pMovementController->handleUse()) + { + return; + } + float3 start = getHead()->getPos(); float3 dir = getHead()->getOrient() * float3(0.0f, 0.0f, 1.0f); float3 end = start + dir * 2.0f; diff --git a/source/game/BaseCharacter.h b/source/game/BaseCharacter.h index bdd0670bc..ad1cbcb3d 100644 --- a/source/game/BaseCharacter.h +++ b/source/game/BaseCharacter.h @@ -20,6 +20,7 @@ See the license in LICENSE #include "LightDirectional.h" #include "CharacterInventory.h" #include "PointEntity.h" +#include "IMovementController.h" class CBaseTool; @@ -36,12 +37,10 @@ enum PLAYER_MOVE PM_RUN = 0x40, //!< бежать PM_CRAWL = 0x80, //!< лежать PM_OBSERVER = 0x100, //!< наблюдатель - PM_LADDER = 0x200, //!< лестница PM_STOP = 0xFFFF }; -class CFuncLadder; class CHUDcontroller; class CBaseCharacter; @@ -138,17 +137,14 @@ public: void onPostLoad() override; - void mountToLadder(CFuncLadder *pLadder); - - void dismountFromLadder(); + void setMovementController(IMovementController *pController); void renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer *pRenderer) override; - void mountToLadder(CFuncLadder *pLadder); - - void dismountFromLadder(); - - void renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer *pRenderer) override; + IXCharacterController* getCharacterController() + { + return(m_pCharacter); + } protected: //! Фонарик @@ -200,7 +196,8 @@ protected: virtual float3 getHeadOffset(); - CFuncLadder *m_pLadder = NULL; + IMovementController *m_pMovementController = NULL; + private: static IEventChannel<XEventPhysicsStep> *m_pTickEventChannel; CCharacterPhysicsTickEventListener m_physicsTicker; diff --git a/source/game/FuncLadder.cpp b/source/game/FuncLadder.cpp index f6a9442eb..d8e859d99 100644 --- a/source/game/FuncLadder.cpp +++ b/source/game/FuncLadder.cpp @@ -1,5 +1,6 @@ #include "FuncLadder.h" #include "BaseCharacter.h" +#include "LadderMovementController.h" BEGIN_PROPTABLE(CInfoLadderDismount) @@ -131,19 +132,18 @@ void CFuncLadder::initPhysics() mem_release(m_pCollideShape); float3 vDelta = m_vUpPoint - getPos(); - float3 vMin, vMax; + SMAABB aabb = getBound(); float3 vMinDelta, vMaxDelta; - getMinMax(&vMin, &vMax); float3_t aPointsBot[] = { - { vMin.x, vMax.y, vMin.z }, - { vMax.x, vMax.y, vMin.z }, - { vMin.x, vMax.y, vMax.z }, - { vMax.x, vMax.y, vMax.z } + {aabb.vMin.x, aabb.vMax.y, aabb.vMin.z }, + {aabb.vMax.x, aabb.vMax.y, aabb.vMin.z }, + {aabb.vMin.x, aabb.vMax.y, aabb.vMax.z }, + {aabb.vMax.x, aabb.vMax.y, aabb.vMax.z } }; - vMinDelta = vMin + vDelta; - vMaxDelta = vMax + vDelta; + vMinDelta = aabb.vMin + vDelta; + vMaxDelta = aabb.vMax + vDelta; float3_t aPointsTop[] = { { vMinDelta.x, vMinDelta.y, vMinDelta.z }, @@ -177,10 +177,10 @@ void CFuncLadder::initPhysics() aShapePoints[uIndex++] = aPointsTop[1]; } - aShapePoints[uIndex++] = vMin; - aShapePoints[uIndex++] = {vMin.x, vMin.y ,vMax.z}; - aShapePoints[uIndex++] = {vMax.x, vMin.y, vMax.z}; - aShapePoints[uIndex++] = {vMax.x, vMin.y, vMin.z}; + aShapePoints[uIndex++] = aabb.vMin; + aShapePoints[uIndex++] = {aabb.vMin.x, aabb.vMin.y, aabb.vMax.z}; + aShapePoints[uIndex++] = {aabb.vMax.x, aabb.vMin.y, aabb.vMax.z}; + aShapePoints[uIndex++] = {aabb.vMax.x, aabb.vMin.y, aabb.vMin.z}; aShapePoints[uIndex++] = vMaxDelta; aShapePoints[uIndex++] = {vMaxDelta.x, vMaxDelta.y, vMinDelta.z}; @@ -199,8 +199,7 @@ void CFuncLadder::renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer pRenderer->setColor(c_vLineColor); pRenderer->setLineWidth(is3D ? 0.02f : 1.0f); - SMAABB aabb; - getMinMax(&aabb.vMin, &aabb.vMax); + SMAABB aabb = getBound(); pRenderer->drawAABB(aabb + getPos()); pRenderer->drawAABB(aabb + m_vUpPoint); pRenderer->jumpTo(getPos()); @@ -210,24 +209,152 @@ void CFuncLadder::renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer void CFuncLadder::getMinMax(float3 *min, float3 *max) { + SMAABB aabb = getBound(); + aabb = SMAABBConvex(aabb, aabb + (getUpPos() - getPos())); + if(min) { - min->x = -0.25f; - min->y = 0.0f; - min->z = -0.25f; + *min = aabb.vMin; } if(max) { - max->x = 0.25f; - max->y = 1.8f; - max->z = 0.25f; + *max = aabb.vMax; + } +} + +SMAABB CFuncLadder::getBound() +{ + return(SMAABB(float3(-0.25f, 0.0f, -0.25f), float3(0.25f, 1.8f, 0.25f))); +} + +bool SMAABBIntersectLine(const SMAABB &aabb, const float3 &vStart, const float3 &vEnd, float3 *pvOut, float3 *pvNormal) +{ + float min_t = 0.0f; + float max_t = 1.0f; + + float3 vDir = vEnd - vStart; + + for(int i = 0; i < 3; ++i) + { + if(SMIsZero(vDir[i])) + { + if(vStart[i] < aabb.vMin[i] || vStart[i] > aabb.vMax[i]) + { + return(false); + } + } + + float t1 = (aabb.vMin[i] - vStart[i]) / vDir[i]; + float t2 = (aabb.vMax[i] - vStart[i]) / vDir[i]; + + float tmin = min(t1, t2); + float tmax = max(t1, t2); + + min_t = max(min_t, tmin); + max_t = min(max_t, tmax); + + if(min_t > max_t) + { + return(false); + } + } + + if(pvOut) + { + *pvOut = vStart + min_t * vDir; + } + + if(pvNormal) + { + *pvNormal = 0.0f; + + if(SMIsZero(aabb.vMin.x - pvOut->x)) + { + pvNormal->x = -1.0f; + } + else if(SMIsZero(aabb.vMax.x - pvOut->x)) + { + pvNormal->x = 1.0f; + } + else if(SMIsZero(aabb.vMin.y - pvOut->y)) + { + pvNormal->y = -1.0f; + } + else if(SMIsZero(aabb.vMax.y - pvOut->y)) + { + pvNormal->y = 1.0f; + } + else if(SMIsZero(aabb.vMin.z - pvOut->z)) + { + pvNormal->z = -1.0f; + } + else + { + pvNormal->z = 1.0f; + } } } bool CFuncLadder::rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut, float3 *pvNormal, bool isRayInWorldSpace, bool bReturnNearestPoint) { - // TODO Implement me! + assert(isRayInWorldSpace); + + SMAABB aabb = getBound(); + + if(bReturnNearestPoint) + { + bool b0, b1; + float3 vPos0, vPos1; + float3 vNormal0, vNormal1; + float3 *pvNormal0 = NULL, *pvNormal1 = NULL; + if(pvNormal) + { + pvNormal0 = &vNormal0; + pvNormal1 = &vNormal1; + } + + b0 = SMAABBIntersectLine(aabb + getPos(), vStart, vEnd, &vPos0, pvNormal0); + b1 = SMAABBIntersectLine(aabb + getUpPos(), vStart, vEnd, &vPos1, pvNormal1); + + if(b0 && b1) + { + if(SMVector3Length2(vPos0 - vStart) > SMVector3Length2(vPos1 - vStart)) + { + b0 = false; + } + else + { + b1 = false; + } + } + + if(b0) + { + *pvOut = vPos0; + if(pvNormal) + { + *pvNormal = vNormal0; + } + } + else if(b1) + { + *pvOut = vPos1; + if(pvNormal) + { + *pvNormal = vNormal1; + } + } + + return(b0 || b1); + } + else + { + if(SMAABBIntersectLine(aabb + getPos(), vStart, vEnd, pvOut, pvNormal) || SMAABBIntersectLine(aabb + getUpPos(), vStart, vEnd, pvOut, pvNormal)) + { + return(true); + } + } return(false); } @@ -240,7 +367,7 @@ void CFuncLadder::onUse(CBaseEntity *pUser) float3 CFuncLadder::getUpPos() { - return m_vUpPoint; + return(m_vUpPoint); } void CFuncLadder::connectToLadder(CBaseEntity *pEntity) @@ -250,7 +377,9 @@ void CFuncLadder::connectToLadder(CBaseEntity *pEntity) return; } CBaseCharacter *pCharacter = (CBaseCharacter*)pEntity; - pCharacter->mountToLadder(this); + CLadderMovementController *pController = new CLadderMovementController(this); + pCharacter->setMovementController(pController); + mem_release(pController); } void CFuncLadder::onPhysicsStep() @@ -260,6 +389,8 @@ void CFuncLadder::onPhysicsStep() return; } + Array<CBaseEntity*> aCurrentTouchingEntities(m_aTouchedEntities.size()); + for(UINT i = 0, l = m_pGhostObject->getOverlappingPairCount(); i < l; ++i) { IXCollisionPair *pair = m_pGhostObject->getOverlappingPair(i); @@ -279,14 +410,20 @@ void CFuncLadder::onPhysicsStep() CBaseEntity *pEnt = (CBaseEntity*)pObject->getUserPointer(); if(pEnt) { - connectToLadder(pEnt); - //printf("touched %s\n", pEnt->getClassName()); + aCurrentTouchingEntities.push_back(pEnt); + if(m_aTouchedEntities.indexOf(pEnt) < 0) + { + connectToLadder(pEnt); + //printf("touched %s\n", pEnt->getClassName()); + } } } break; } } } + + m_aTouchedEntities = aCurrentTouchingEntities; } diff --git a/source/game/FuncLadder.h b/source/game/FuncLadder.h index 78530c7ac..520bae843 100644 --- a/source/game/FuncLadder.h +++ b/source/game/FuncLadder.h @@ -64,6 +64,8 @@ private: void disable(); void onPhysicsStep(); + SMAABB getBound(); + private: float3_t m_vUpPoint; bool m_isUpSet = false; @@ -77,6 +79,7 @@ private: static IEventChannel<XEventPhysicsStep> *m_pTickEventChannel; CPhysicsLadderTickEventListener m_physicsTicker; + Array<CBaseEntity*> m_aTouchedEntities; }; #endif diff --git a/source/game/IMovementController.h b/source/game/IMovementController.h new file mode 100644 index 000000000..cf98817c7 --- /dev/null +++ b/source/game/IMovementController.h @@ -0,0 +1,19 @@ +#ifndef __IMOVEMENTCONTROLLER_H +#define __IMOVEMENTCONTROLLER_H + +#include <gdefines.h> + +class CBaseCharacter; +class IMovementController: public IXUnknown +{ +public: + virtual void setCharacter(CBaseCharacter *pCharacter) = 0; + + virtual void handleMove(const float3 &vDir) = 0; + virtual void handleJump() = 0; + virtual bool handleUse() = 0; + + virtual void update(float fDt) = 0; +}; + +#endif diff --git a/source/game/LadderMovementController.cpp b/source/game/LadderMovementController.cpp new file mode 100644 index 000000000..6152853f6 --- /dev/null +++ b/source/game/LadderMovementController.cpp @@ -0,0 +1,119 @@ +#include "LadderMovementController.h" +#include "BaseCharacter.h" +#include "FuncLadder.h" +#include "Player.h" + +CLadderMovementController::CLadderMovementController(CFuncLadder *pLadder) +{ + m_vLadderPoint[0] = pLadder->getPos(); + m_vLadderPoint[1] = pLadder->getUpPos(); + + m_vLadderDir = SMVector3Normalize(m_vLadderPoint[1] - m_vLadderPoint[0]); +} +CLadderMovementController::~CLadderMovementController() +{ + if(m_pCharacter) + { + m_pCharacter->getCharacterController()->setGravity(float3(0.0f, -10.0f, 0.0f)); + } +} + +float3 SMProjectPointOnLine(const float3 &vPos, const float3 &vStart, const float3 &vEnd) +{ + float3 vN = SMVector3Normalize(vEnd - vStart); + float fDot0 = SMVector3Dot(vN, vPos - vStart); + if(fDot0 <= 0.0f) + { + return(vStart); + } + + float fDot1 = SMVector3Dot(vN, vPos - vEnd); + if(fDot1 >= 0.0f) + { + return(vEnd); + } + + return(vStart + vN * fDot0); +} + +void CLadderMovementController::setCharacter(CBaseCharacter *pCharacter) +{ + m_pCharacter = pCharacter; + + IXCharacterController *pCharacterController = pCharacter->getCharacterController(); + + pCharacterController->setGravity(float3(0.0f, 0.0f, 0.0f)); + pCharacterController->setVelocityForTimeInterval(float3(0.0f, 0.0f, 0.0f), 0.0f); + + TODO("Make move smoother"); + float3 vPointOnLadder = SMProjectPointOnLine(m_pCharacter->getPos(), m_vLadderPoint[0], m_vLadderPoint[1]); + m_pCharacter->setPos(vPointOnLadder); +} + +void CLadderMovementController::handleMove(const float3 &vDir) +{ + m_vMoveDir = vDir; +} + +void CLadderMovementController::handleJump() +{ + m_bWillDismount = true; +} + +bool CLadderMovementController::handleUse() +{ + m_bWillDismount = true; + return(true); +} + +void CLadderMovementController::update(float fDt) +{ + if(m_bWillDismount) + { + ((CPlayer*)m_pCharacter)->m_vCurrentSpeed = m_vMoveDir; + m_pCharacter->setMovementController(NULL); + } + else if(!SMIsZero(SMVector3Length2(m_vMoveDir))) + { + float fDot = SMVector3Dot(m_vLadderDir, m_vMoveDir); + + float3 vSpeed = m_vLadderDir * 3.0f; + float3 vNewPos; + + if(fDot > /*-SM_PIDIV4*/ -SMToRadian(10.0f)) + { + if(SMIsZero(SMVector3Length2(m_vLadderPoint[1] - m_pCharacter->getPos()))) + { + m_bWillDismount = true; + } + else + { + vNewPos = m_pCharacter->getPos() + vSpeed * fDt; + if(SMVector3Length2(vNewPos - m_vLadderPoint[0]) > SMVector3Length2(m_vLadderPoint[1] - m_vLadderPoint[0])) + { + vNewPos = m_vLadderPoint[1]; + } + } + } + else + { + if(SMIsZero(SMVector3Length2(m_vLadderPoint[0] - m_pCharacter->getPos()))) + { + m_bWillDismount = true; + } + else + { + vNewPos = m_pCharacter->getPos() - vSpeed * fDt; + if(SMVector3Length2(vNewPos - m_vLadderPoint[1]) > SMVector3Length2(m_vLadderPoint[1] - m_vLadderPoint[0])) + { + vNewPos = m_vLadderPoint[0]; + } + } + } + + if(!m_bWillDismount) + { + m_pCharacter->setPos(vNewPos); + } + } +} diff --git a/source/game/LadderMovementController.h b/source/game/LadderMovementController.h new file mode 100644 index 000000000..a41cc4ac2 --- /dev/null +++ b/source/game/LadderMovementController.h @@ -0,0 +1,32 @@ +#ifndef __LADDERMOVEMENTCONTROLLER_H +#define __LADDERMOVEMENTCONTROLLER_H + +#include "IMovementController.h" + +class CFuncLadder; +class CLadderMovementController: public IXUnknownImplementation<IMovementController> +{ +public: + CLadderMovementController(CFuncLadder *pLadder); + ~CLadderMovementController(); + + void setCharacter(CBaseCharacter *pCharacter) override; + + void handleMove(const float3 &vDir) override; + void handleJump() override; + bool handleUse() override; + + void update(float fDt) override; + +private: + CBaseCharacter *m_pCharacter; + + float3_t m_vLadderPoint[2]; + float3_t m_vLadderDir; + + float3_t m_vMoveDir; + + bool m_bWillDismount = false; +}; + +#endif diff --git a/source/game/Player.cpp b/source/game/Player.cpp index acf1e85c2..3268ecebb 100644 --- a/source/game/Player.cpp +++ b/source/game/Player.cpp @@ -150,6 +150,7 @@ void CPlayer::updateInput(float dt) // m_vWpnShakeAngles = (float3)(m_vWpnShakeAngles * 0.4f); m_vWpnShakeAngles = (float3)(m_vWpnShakeAngles / (1.05f + dt)); + // Handle look if(!*editor_mode || SSInput_GetKeyState(SIM_LBUTTON)) { SSInput_GetMouseDelta(&x, &y); @@ -236,61 +237,43 @@ void CPlayer::updateInput(float dt) mov = true; } - if(m_uMoveDir & PM_CROUCH || (m_fCurrentHeight < 0.99f && !m_pCharacter->canStandUp((m_fCapsHeight - m_fCapsRadius * 2.0f) * (1.0f - m_fCurrentHeight)))) + if(m_uMoveDir & PM_OBSERVER) { - m_fCurrentHeight -= dt * 10.0f; - float fMinHeight = (m_fCapsHeightCrouch - m_fCapsRadius * 2.0f) / (m_fCapsHeight - m_fCapsRadius * 2.0f); - if(m_fCurrentHeight < fMinHeight) - { - m_fCurrentHeight = fMinHeight; - } + setPos(getPos() + m_pHeadEnt->getOrient() * (SMVector3Normalize(dir) * dt * 10.0f)); } - else + else if(m_pMovementController) { - m_fCurrentHeight += dt * 10.0f; - if(m_fCurrentHeight > 1.0f) + m_vCurrentSpeed = {0.0f, 0.0f, 0.0f}; + + if(m_uMoveDir & PM_JUMP) { - m_fCurrentHeight = 1.0f; + m_pMovementController->handleJump(); } + m_pMovementController->handleMove(m_pHeadEnt->getOrient() * SMVector3Normalize(dir)); + m_pMovementController->update(dt); } - m_pCollideShape->setLocalScaling(float3(1.0f, m_fCurrentHeight, 1.0f)); - - if(m_uMoveDir & PM_OBSERVER) - { - setPos(getPos() + m_pHeadEnt->getOrient() * (SMVector3Normalize(dir) * dt * 10.0f)); - } - else if(m_uMoveDir & PM_LADDER) + else { - if(m_uMoveDir & PM_FORWARD) + if(m_uMoveDir & PM_CROUCH || (m_fCurrentHeight < 0.99f && !m_pCharacter->canStandUp((m_fCapsHeight - m_fCapsRadius * 2.0f) * (1.0f - m_fCurrentHeight)))) { - float3 vSpeed(0.0f, 3.0f, 0.0f); - float3 fNewPos = getPos() + vSpeed * dt; - if(m_pLadder->getUpPos().y >= fNewPos.y) + m_fCurrentHeight -= dt * 10.0f; + float fMinHeight = (m_fCapsHeightCrouch - m_fCapsRadius * 2.0f) / (m_fCapsHeight - m_fCapsRadius * 2.0f); + if(m_fCurrentHeight < fMinHeight) { - setPos(fNewPos); - } - else - { - setPos(m_pLadder->getUpPos()); + m_fCurrentHeight = fMinHeight; } } - else if(m_uMoveDir & PM_BACKWARD) + else { - float3 vSpeed(0.0f, -3.0f, 0.0f); - float3 fNewPos = getPos() + vSpeed * dt; - if(m_pLadder->getPos().y <= fNewPos.y) + m_fCurrentHeight += dt * 10.0f; + if(m_fCurrentHeight > 1.0f) { - setPos(fNewPos); - } - else - { - setPos(m_pLadder->getPos()); + m_fCurrentHeight = 1.0f; } } - m_vCurrentSpeed = {0.0f, 0.0f, 0.0f}; - } - else - { + m_pCollideShape->setLocalScaling(float3(1.0f, m_fCurrentHeight, 1.0f)); + + dir = SMQuaternion(m_vPitchYawRoll.y, 'y') * (SMVector3Normalize(dir)/* * dt*/); dir *= 3.5f; if(m_uMoveDir & PM_CROUCH) @@ -411,7 +394,7 @@ void CPlayer::updateInput(float dt) //vel = getDiscreteLinearVelocity(); //printf("%f, %f, %f\n", vel.x, vel.y, vel.z); - m_vWpnShakeAngles.x += -vel.y * 0.05f; + m_vWpnShakeAngles.x += -vel.y * 0.01f; const float fMaxAng = SM_PI * 0.1f; m_vWpnShakeAngles.x = clampf(m_vWpnShakeAngles.x, -fMaxAng, fMaxAng); } @@ -492,6 +475,8 @@ void CPlayer::spawn() m_uMoveDir &= ~PM_OBSERVER; m_pCrosshair->enable(); + setMovementController(NULL); + GameData::m_pHUDcontroller->setPlayerRot(m_vPitchYawRoll); GameData::m_pHUDcontroller->setPlayerPos(getPos()); GameData::m_pHUDcontroller->setPlayerHealth(m_fHealth); diff --git a/source/game/Player.h b/source/game/Player.h index 797497644..34ab93672 100644 --- a/source/game/Player.h +++ b/source/game/Player.h @@ -25,6 +25,7 @@ See the license in LICENSE //! Класс игрока \ingroup cbaseanimating class CPlayer: public CBaseCharacter { + friend class CLadderMovementController; DECLARE_CLASS(CPlayer, CBaseCharacter); DECLARE_PROPTABLE(); public: -- GitLab From 1b67a09bb90ab7ab9fe0cf88e444943d37eeaeff Mon Sep 17 00:00:00 2001 From: D-AIRY <admin@ds-servers.com> Date: Sun, 22 Dec 2024 00:45:23 +0300 Subject: [PATCH 3/6] make XPET_POINTCOORD relative --- build/demos/levels/demo_ladder/demo_ladder.ent | 6 +++--- source/game/FuncLadder.cpp | 17 ++++++----------- source/game/FuncLadder.h | 3 +-- source/terrax/mainWindow.cpp | 5 +++-- 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/build/demos/levels/demo_ladder/demo_ladder.ent b/build/demos/levels/demo_ladder/demo_ladder.ent index 25b90276a..f762571a8 100644 --- a/build/demos/levels/demo_ladder/demo_ladder.ent +++ b/build/demos/levels/demo_ladder/demo_ladder.ent @@ -68,7 +68,7 @@ name = model = is_static = 1 glow_color_ref = -glow_color = 0.000000 0.000000 0.000000 +glow_color = 0.000000 0.273974 0.827866 flags = 0 classname = prop_static auto_physbox = 1 @@ -130,10 +130,10 @@ OnTurnOn = OnTurnOff = [{F7FAD41B-4168-41D2-9E82-51DA455F22B6}] -up_point = 12.860000 5.000000 10.004517 +up_point = 0.000000 4.000000 0.000001 rotation = 0.000000 0.000000 0.000000 1.000000 parent = -origin = 12.858377 1.000000 10.004519 +origin = 12.849999 1.000000 9.999999 name = flags = 0 classname = func_ladder diff --git a/source/game/FuncLadder.cpp b/source/game/FuncLadder.cpp index d8e859d99..e6dd9e1ba 100644 --- a/source/game/FuncLadder.cpp +++ b/source/game/FuncLadder.cpp @@ -52,7 +52,6 @@ CFuncLadder::~CFuncLadder() void CFuncLadder::setUpPoint(const float3 &vUp) { - m_isUpSet = true; m_vUpPoint = vUp; initPhysics(); @@ -82,11 +81,7 @@ void CFuncLadder::createPhysBody() void CFuncLadder::setPos(const float3 &pos) { BaseClass::setPos(pos); - if(!m_isUpSet) - { - m_vUpPoint = (float3)(pos + float3(0.0f, 2.0f, 0.0f)); - initPhysics(); - } + initPhysics(); SAFE_CALL(m_pGhostObject, setPosition, pos); } @@ -131,7 +126,7 @@ void CFuncLadder::initPhysics() //TODO: сделать обработку ситуации когда m_vUpPoint ниже getPos mem_release(m_pCollideShape); - float3 vDelta = m_vUpPoint - getPos(); + float3 vDelta = getOrient() * m_vUpPoint; SMAABB aabb = getBound(); float3 vMinDelta, vMaxDelta; @@ -201,16 +196,16 @@ void CFuncLadder::renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer SMAABB aabb = getBound(); pRenderer->drawAABB(aabb + getPos()); - pRenderer->drawAABB(aabb + m_vUpPoint); + pRenderer->drawAABB(aabb + getUpPos()); pRenderer->jumpTo(getPos()); - pRenderer->lineTo(m_vUpPoint); + pRenderer->lineTo(getUpPos()); } } void CFuncLadder::getMinMax(float3 *min, float3 *max) { SMAABB aabb = getBound(); - aabb = SMAABBConvex(aabb, aabb + (getUpPos() - getPos())); + aabb = SMAABBConvex(aabb, aabb + getUpPos() - getPos()); if(min) { @@ -367,7 +362,7 @@ void CFuncLadder::onUse(CBaseEntity *pUser) float3 CFuncLadder::getUpPos() { - return(m_vUpPoint); + return(getOrient() * m_vUpPoint + getPos()); } void CFuncLadder::connectToLadder(CBaseEntity *pEntity) diff --git a/source/game/FuncLadder.h b/source/game/FuncLadder.h index 520bae843..5ea6f958b 100644 --- a/source/game/FuncLadder.h +++ b/source/game/FuncLadder.h @@ -67,8 +67,7 @@ private: SMAABB getBound(); private: - float3_t m_vUpPoint; - bool m_isUpSet = false; + float3_t m_vUpPoint = float3_t(0.0f, 2.0f, 0.0f); bool m_isEnabled = false; output_t m_onPlayerGetOn; diff --git a/source/terrax/mainWindow.cpp b/source/terrax/mainWindow.cpp index 6996e46fb..2b9b8270d 100644 --- a/source/terrax/mainWindow.cpp +++ b/source/terrax/mainWindow.cpp @@ -4532,15 +4532,16 @@ XDECLARE_PROP_GIZMO(Radius, void XMETHODCALLTYPE onChange(float fNewRadius, IXEd XDECLARE_PROP_GIZMO(Handle, void XMETHODCALLTYPE moveTo(const float3 &vNewPos, IXEditorGizmoHandle *pGizmo) override { pGizmo->setPos(vNewPos); + float3_t vTmp = m_pObj->getOrient().Conjugate() * (vNewPos - m_pObj->getPos()); char tmp[64]; - sprintf(tmp, "%f %f %f", vNewPos.x, vNewPos.y, vNewPos.z); + sprintf(tmp, "%f %f %f", vTmp.x, vTmp.y, vTmp.z); m_pCommand->setKV(m_field.szKey, tmp); }, void init() { float3_t vec; if(sscanf(m_pObj->getKV(m_field.szKey), "%f %f %f", &vec.x, &vec.y, &vec.z)) { - m_pGizmo->setPos(vec); + m_pGizmo->setPos(m_pObj->getOrient() * vec + m_pObj->getPos()); } }); -- GitLab From 4238a7238684f49f7ce627d888b5713b3183d241 Mon Sep 17 00:00:00 2001 From: D-AIRY <admin@ds-servers.com> Date: Mon, 23 Dec 2024 15:36:57 +0300 Subject: [PATCH 4/6] Animate ladder mounting --- source/game/LadderMovementController.cpp | 19 +++++++++++++++---- source/game/LadderMovementController.h | 9 +++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/source/game/LadderMovementController.cpp b/source/game/LadderMovementController.cpp index 6152853f6..ef824bf04 100644 --- a/source/game/LadderMovementController.cpp +++ b/source/game/LadderMovementController.cpp @@ -45,9 +45,10 @@ void CLadderMovementController::setCharacter(CBaseCharacter *pCharacter) pCharacterController->setGravity(float3(0.0f, 0.0f, 0.0f)); pCharacterController->setVelocityForTimeInterval(float3(0.0f, 0.0f, 0.0f), 0.0f); - TODO("Make move smoother"); - float3 vPointOnLadder = SMProjectPointOnLine(m_pCharacter->getPos(), m_vLadderPoint[0], m_vLadderPoint[1]); - m_pCharacter->setPos(vPointOnLadder); + m_mounting.is = true; + m_mounting.fFrac = 0.0f; + m_mounting.vStartPos = m_pCharacter->getPos(); + m_mounting.vTargetPos = SMProjectPointOnLine(m_pCharacter->getPos(), m_vLadderPoint[0], m_vLadderPoint[1]); } void CLadderMovementController::handleMove(const float3 &vDir) @@ -68,7 +69,17 @@ bool CLadderMovementController::handleUse() void CLadderMovementController::update(float fDt) { - if(m_bWillDismount) + if(m_mounting.is) + { + m_mounting.fFrac += 7.0f * fDt; + if(m_mounting.fFrac > 1.0f) + { + m_mounting.fFrac = 1.0f; + m_mounting.is = false; + } + m_pCharacter->setPos(vlerp(m_mounting.vStartPos, m_mounting.vTargetPos, m_mounting.fFrac)); + } + else if(m_bWillDismount) { ((CPlayer*)m_pCharacter)->m_vCurrentSpeed = m_vMoveDir; m_pCharacter->setMovementController(NULL); diff --git a/source/game/LadderMovementController.h b/source/game/LadderMovementController.h index a41cc4ac2..0b34f2256 100644 --- a/source/game/LadderMovementController.h +++ b/source/game/LadderMovementController.h @@ -26,6 +26,15 @@ private: float3_t m_vMoveDir; + struct + { + bool is = false; + float fFrac = 0.0f; + float3_t vStartPos; + float3_t vTargetPos; + } + m_mounting; + bool m_bWillDismount = false; }; -- GitLab From 384709661283526a34e4833706b45a865f1a2a85 Mon Sep 17 00:00:00 2001 From: D-AIRY <admin@ds-servers.com> Date: Tue, 24 Dec 2024 14:05:45 +0300 Subject: [PATCH 5/6] Prevent spawning proxy object when target is not found --- source/terrax/terrax.cpp | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/source/terrax/terrax.cpp b/source/terrax/terrax.cpp index 56df65475..3c256fea7 100644 --- a/source/terrax/terrax.cpp +++ b/source/terrax/terrax.cpp @@ -1278,28 +1278,33 @@ int main(int argc, char **argv) } CProxyObject *pProxy = new CProxyObject(guid); - pProxy->setDstObject(guidTarget); - - for(UINT k = 0, kl = pSArr->size(); k < kl; ++k) + if(pProxy->setDstObject(guidTarget)) { - szGUID = pSArr->at(k)->getString(); - if(!szGUID || !XGUIDFromString(&guid, szGUID)) + for(UINT k = 0, kl = pSArr->size(); k < kl; ++k) { - LibReport(REPORT_MSG_LEVEL_ERROR, "Invalid model '%u' guid in proxy '%u' in '%s'. '%s'\n", k, j, szFile, szGUID ? szGUID : ""); - continue; + szGUID = pSArr->at(k)->getString(); + if(!szGUID || !XGUIDFromString(&guid, szGUID)) + { + LibReport(REPORT_MSG_LEVEL_ERROR, "Invalid model '%u' guid in proxy '%u' in '%s'. '%s'\n", k, j, szFile, szGUID ? szGUID : ""); + continue; + } + + pProxy->addSrcModel(guid); } - pProxy->addSrcModel(guid); - } - - g_apProxies.push_back(pProxy); + g_apProxies.push_back(pProxy); - //pProxy->build(); + //pProxy->build(); - add_ref(pProxy); - g_pLevelObjects.push_back(pProxy); + add_ref(pProxy); + g_pLevelObjects.push_back(pProxy); - isLoaded = true; + isLoaded = true; + } + else + { + mem_release(pProxy); + } } } } @@ -1849,7 +1854,7 @@ void XRender3D() pvData = NULL; XEnumerateObjects([&](IXEditorObject *pObj, bool isProxy, ICompoundObject *pParent){ - float3_t vPos = pObj->getPos(); + //float3_t vPos = pObj->getPos(); TODO("Add visibility check"); /*if(fViewportBorders.x > vPos.x || fViewportBorders.z < vPos.x || fViewportBorders.y < vPos.z) // not visible { -- GitLab From b07c08018491c15be1f859a1b39630553cf23f82 Mon Sep 17 00:00:00 2001 From: D-AIRY <admin@ds-servers.com> Date: Tue, 24 Dec 2024 15:32:09 +0300 Subject: [PATCH 6/6] Updated SMAABBIntersectLine --- source/game/FuncLadder.cpp | 98 ++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/source/game/FuncLadder.cpp b/source/game/FuncLadder.cpp index e6dd9e1ba..d738af4db 100644 --- a/source/game/FuncLadder.cpp +++ b/source/game/FuncLadder.cpp @@ -225,77 +225,83 @@ SMAABB CFuncLadder::getBound() bool SMAABBIntersectLine(const SMAABB &aabb, const float3 &vStart, const float3 &vEnd, float3 *pvOut, float3 *pvNormal) { - float min_t = 0.0f; - float max_t = 1.0f; + float3 vPoint; + SMPLANE plane; - float3 vDir = vEnd - vStart; - - for(int i = 0; i < 3; ++i) + plane = SMPLANE(float3(1.0f, 0.0f, 0.0f), -aabb.vMax.x); + if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) { - if(SMIsZero(vDir[i])) + *pvOut = vPoint; + if(pvNormal) { - if(vStart[i] < aabb.vMin[i] || vStart[i] > aabb.vMax[i]) - { - return(false); - } + *pvNormal = float3(1.0f, 0.0f, 0.0f); } - - float t1 = (aabb.vMin[i] - vStart[i]) / vDir[i]; - float t2 = (aabb.vMax[i] - vStart[i]) / vDir[i]; - - float tmin = min(t1, t2); - float tmax = max(t1, t2); - - min_t = max(min_t, tmin); - max_t = min(max_t, tmax); - - if(min_t > max_t) + return(true); + } + + plane = SMPLANE(float3(-1.0f, 0.0f, 0.0f), aabb.vMin.x); + if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) + { + *pvOut = vPoint; + if(pvNormal) { - return(false); + *pvNormal = float3(-1.0f, 0.0f, 0.0f); } + return(true); } - if(pvOut) + plane = SMPLANE(float3(0.0f, 1.0f, 0.0f), -aabb.vMax.y); + if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) { - *pvOut = vStart + min_t * vDir; + *pvOut = vPoint; + if(pvNormal) + { + *pvNormal = float3(0.0f, 1.0f, 0.0f); + } + return(true); } - if(pvNormal) + plane = SMPLANE(float3(0.0f, -1.0f, 0.0f), aabb.vMin.y); + if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) { - *pvNormal = 0.0f; - - if(SMIsZero(aabb.vMin.x - pvOut->x)) - { - pvNormal->x = -1.0f; - } - else if(SMIsZero(aabb.vMax.x - pvOut->x)) - { - pvNormal->x = 1.0f; - } - else if(SMIsZero(aabb.vMin.y - pvOut->y)) - { - pvNormal->y = -1.0f; - } - else if(SMIsZero(aabb.vMax.y - pvOut->y)) + *pvOut = vPoint; + if(pvNormal) { - pvNormal->y = 1.0f; + *pvNormal = float3(0.0f, -1.0f, 0.0f); } - else if(SMIsZero(aabb.vMin.z - pvOut->z)) + return(true); + } + + plane = SMPLANE(float3(0.0f, 0.0f, 1.0f), -aabb.vMax.z); + if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) + { + *pvOut = vPoint; + if(pvNormal) { - pvNormal->z = -1.0f; + *pvNormal = float3(0.0f, 0.0f, 1.0f); } - else + return(true); + } + + plane = SMPLANE(float3(0.0f, 0.0f, -1.0f), aabb.vMin.z); + if(plane.intersectLine(&vPoint, vStart, vEnd) && SMIsAABBInsideAABB(SMAABB(vPoint, vPoint), aabb)) + { + *pvOut = vPoint; + if(pvNormal) { - pvNormal->z = 1.0f; + *pvNormal = float3(0.0f, 0.0f, -1.0f); } + return(true); } + + return(false); } bool CFuncLadder::rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut, float3 *pvNormal, bool isRayInWorldSpace, bool bReturnNearestPoint) { assert(isRayInWorldSpace); - SMAABB aabb = getBound(); + SMAABB aabb = getBound(); if(bReturnNearestPoint) { -- GitLab