1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "rope_helpers.h"
#include "basetypes.h"
#include "mathlib/mathlib.h"
#include "rope_shared.h"
#include "rope_physics.h"
#include "networkvar.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CHangRope : public CRopePhysics<512>
{
DECLARE_CLASS( CHangRope, CRopePhysics<512> );
// CRopePhysics overrides.
public:
virtual void GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel )
{
pAccel->Init( ROPE_GRAVITY );
}
virtual void ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes )
{
// Apply spring forces.
BaseClass::ApplyConstraints( pNodes, nNodes );
// Lock the endpoints.
pNodes[0].m_vPos = m_vEndPoints[0];
pNodes[nNodes-1].m_vPos = m_vEndPoints[1];
// Calculate how far it is hanging down and adjust if necessary.
float flCurHangDist = 0;
for ( int i=0; i < NumNodes(); i++ )
{
float hang = fabs( m_flStartZ - GetNode(i)->m_vPos.z );
if ( hang > flCurHangDist )
flCurHangDist = hang;
}
// Adjust our spring length accordingly.
if ( flCurHangDist < m_flWantedHangDist )
m_flCurSlack += 1;
else
m_flCurSlack -= 1;
ApplyNewSpringLength();
}
// Helpers.
public:
void ApplyNewSpringLength()
{
ResetSpringLength( (m_flRopeLength + m_flCurSlack + ROPESLACK_FUDGEFACTOR) / (NumNodes() - 1) );
}
// Variables used to adjust the rope slack.
public:
Vector m_vEndPoints[2];
bool m_bAdjustSlack;
float m_flRopeLength;
float m_flCurSlack;
float m_flWantedHangDist;
float m_flStartZ;
};
void CalcRopeStartingConditions(
const Vector &vStartPos,
const Vector &vEndPos,
int const nNodes,
float const desiredHang,
float *pOutputLength,
float *pOutputSlack
)
{
CHangRope rope;
// Initialize the rope as a straight line with no slack as our first approximation.
// We then relax the rope by adding slack until it hangs to the desired height.
//
// The spring length equation is:
// springLength = (ropeLength + slack + ROPESLACK_FUDGEFACTOR) / (nNodes - 1)
//
// We want our rope to be a straight line, so:
// springLength = ropeLength / (nNodes-1)
//
// Therefore our initial slack is -ROPESLACK_FUDGEFACTOR
rope.m_flCurSlack = -ROPESLACK_FUDGEFACTOR;
rope.m_vEndPoints[0] = vStartPos;
rope.m_vEndPoints[1] = vEndPos;
rope.m_flRopeLength = (vEndPos - vStartPos).Length();
rope.m_flWantedHangDist = desiredHang;
rope.m_flStartZ = MIN( vStartPos.z, vEndPos.z ); // Calculate hang as the Z distance from the
// lowest endpoint to the bottom of the rope.
rope.SetNumNodes( nNodes );
// Set the node positions.
for ( int i=0; i < rope.NumNodes(); i++ )
{
CSimplePhysics::CNode *pNode = rope.GetNode( i );
float t = (float)i / (rope.NumNodes() - 1);
VectorLerp( vStartPos, vEndPos, t, pNode->m_vPos );
pNode->m_vPrevPos = pNode->m_vPos;
}
// Now simulate a little and stretch out to let it hang down.
rope.Restart();
rope.Simulate( 3 );
// Set outputs.
*pOutputLength = rope.m_flRopeLength;
*pOutputSlack = rope.m_flCurSlack;
}
|