A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
SphereLink.cc
1#include "SphereLink.hh"
2
3#include "game/field/CollisionDirector.hh"
4
5namespace Field {
6
7SphereLink::SphereLink() : m_prev(nullptr), m_next(nullptr) {}
8
9SphereLink::~SphereLink() = default;
10
12void SphereLink::initLinkLen(f32 length) {
13 m_linkLen = length;
14 init();
15}
16
17void SphereLink::init() {
18 m_pos.setZero();
19 m_vel.setZero();
20 m_springForce.setZero();
21 m_up = EGG::Vector3f::ey;
22 m_touchingGround = true;
23}
24
26void SphereLink::calcStiffness() {
27 constexpr f32 STIFFNESS = 0.15f;
28
29 ASSERT(!isLeader());
30
31 EGG::Vector3f dir = m_prev->m_pos - m_pos;
32 f32 dist = dir.normalise();
33
34 // Nothing to do if there is slack in the chain
35 if (dist < m_prev->m_linkLen) {
36 return;
37 }
38
39 EGG::Vector3f springForce = dir * (STIFFNESS * (dist - m_prev->m_linkLen));
40 EGG::Vector3f velDamping = dir * (-STIFFNESS * (m_prev->m_vel - m_vel).dot(dir));
41 EGG::Vector3f totalForce = springForce + velDamping;
42
43 m_springForce += totalForce;
44
45 if (!m_prev->isLeader()) {
46 m_prev->m_springForce -= totalForce;
47 }
48}
49
51void SphereLink::calc() {
52 if (isLeader()) {
53 return;
54 }
55
56 if (!m_next) {
57 EGG::Vector3f dir = m_prev->m_pos - m_pos;
58 f32 dist = dir.normalise();
59
60 if (dist > m_prev->m_linkLen) {
61 m_springForce += dir * 2.0f;
62 }
63
64 calcStiffness();
65 } else {
66 calcSpring();
67 calcStiffness();
68 }
69}
70
72void SphereLink::calcConstraints(f32 scale) {
73 constexpr f32 MIN_PITCH_ANGLE = DEG2FIDX * -75.0f;
74 STATIC_ASSERT(MIN_PITCH_ANGLE == -53.333336f);
75
76 ASSERT(!isLeader());
77
78 EGG::Vector3f back = m_prev->m_pos - m_pos;
79 f32 dist = back.normalise();
80 f32 scaledLen = m_prev->m_linkLen * scale;
81
82 // Nothing to do if there is slack in the chain
83 if (dist <= scaledLen) {
84 return;
85 }
86
87 EGG::Vector3f forward = -back;
88 f32 minPitch = EGG::Mathf::SinFIdx(MIN_PITCH_ANGLE);
89
90 if (forward.y > minPitch && !m_touchingGround) {
91 EGG::Vector3f horiz = forward;
92 if (forward.y >= 0.0f) {
93 horiz.x *= -1.0f;
94 horiz.z *= -1.0f;
95 }
96 horiz.y = 0.0f;
97 horiz.normalise2();
98
99 EGG::Vector3f axis = forward.cross(horiz);
100 axis.normalise2();
101 EGG::Matrix34f mat = EGG::Matrix34f::ident;
102 mat.setAxisRotation(0.0f, axis);
103 EGG::Vector3f newForward = mat.ps_multVector(forward);
104 newForward.normalise2();
105
106 m_vel.setZero();
107 m_pos = m_prev->m_pos + newForward * scaledLen;
108 } else {
109 // Wiggler is falling steeply. Snap towards previous link.
110 m_vel.setZero();
111 m_pos += back * (dist - scaledLen);
112 }
113}
114
116void SphereLink::checkCollision() {
117 constexpr f32 RADIUS = 55.0f;
118
119 EGG::Vector3f floorNrm = EGG::Vector3f::ey;
120
121 CollisionInfo info;
122 KCLTypeMask mask;
123 EGG::Vector3f pos = m_pos + m_up * RADIUS;
124
125 auto *colDir = CollisionDirector::Instance();
126 m_touchingGround = colDir->checkSphereFullPush(RADIUS, pos, EGG::Vector3f::inf, KCL_TYPE_FLOOR,
127 &info, &mask, 0);
128
129 if (m_touchingGround) {
130 EGG::Vector3f tangentOff = info.tangentOff;
131
132 if (tangentOff.squaredLength() > std::numeric_limits<f32>::epsilon()) {
133 tangentOff.normalise2();
134 }
135
136 if (EGG::Mathf::abs(tangentOff.y) > 0.7f) {
137 m_pos.y += info.tangentOff.y;
138 } else {
139 m_pos += info.tangentOff;
140 }
141
142 if (info.floorDist > -std::numeric_limits<f32>::min()) {
143 floorNrm = info.floorNrm;
144 }
145
146 m_vel = m_up * m_vel.dot(m_up) * 0.5f;
147 m_springForce = GRAVITY;
148 }
149
150 m_up += (floorNrm - m_up) * 0.1f;
151}
152
153void SphereLink::calcPos() {
154 m_vel += m_springForce - GRAVITY;
155 m_vel *= 0.9f;
156 m_pos += m_vel;
157 m_springForce.setZero();
158}
159
161void SphereLink::calcSpring() {
162 ASSERT(m_prev && m_next);
163
164 EGG::Vector3f dir = m_prev->m_pos - m_pos;
165 f32 dist = dir.normalise();
166
167 if (dist > m_prev->m_linkLen) {
168 m_springForce += dir * 2.0f;
169 }
170
171 dir = m_next->m_pos - m_pos;
172 f32 nextDist = dir.normalise();
173
174 if (nextDist > m_linkLen) {
175 m_springForce += dir * 2.0f;
176 }
177}
178
179} // namespace Field
#define KCL_TYPE_FLOOR
0x20E80FFF - Any KCL that the player or items can drive/land on.
A 3 x 4 matrix.
Definition Matrix.hh:8
void setAxisRotation(f32 angle, const Vector3f &axis)
Rotates the matrix about an axis.
Definition Matrix.cc:180
Vector3f ps_multVector(const Vector3f &vec) const
Paired-singles impl. of multVector.
Definition Matrix.cc:237
Pertains to collision.
A 3D float vector.
Definition Vector.hh:88
f32 normalise()
Normalizes the vector and returns the original length.
Definition Vector.cc:52
f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Definition Vector.hh:187
f32 squaredLength() const
The dot product between the vector and itself.
Definition Vector.hh:182