A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
KartReject.cc
1#include "KartReject.hh"
2
3#include "game/kart/KartDynamics.hh"
4#include "game/kart/KartMove.hh"
5#include "game/kart/KartParam.hh"
6#include "game/kart/KartState.hh"
7
8#include "game/field/CollisionDirector.hh"
9#include "game/field/CourseColMgr.hh"
10
11#include <egg/math/Math.hh>
12#include <egg/math/Quat.hh>
13
14namespace Kart {
15
17KartReject::KartReject() = default;
18
20KartReject::~KartReject() = default;
21
23void KartReject::reset() {
24 m_rejectSign = 0.0f;
25}
26
28void KartReject::calcRejectRoad() {
29 auto &status = KartObjectProxy::status();
30
31 if (status.onBit(eStatus::InAction)) {
32 return;
33 }
34
36 EGG::Vector3f down = -EGG::Vector3f::ey;
37 down = down.perpInPlane(move()->up(), true);
38 f32 cos = down.dot(move()->lastDir());
39 f32 sin = down.cross(move()->lastDir()).length();
40 f32 angle = EGG::Mathf::atan2(sin, cos);
41 angle = angle > 0.0f ? angle : -angle;
42
43 f32 minAngle = 60.0f;
44 angle *= RAD2DEG;
45 f32 dVar11 = 1.0f;
46
47 if (move()->up().dot(EGG::Vector3f::ey) < -0.7f) {
48 minAngle *= 0.5f;
49 dVar11 *= 2.0f;
50 }
51
52 if (angle > minAngle) {
53 angle = 0.05f * (angle - 60.0f);
54 EGG::Quatf rot = EGG::Quatf::FromRPY(0.0f,
55 (1.0f + angle * move()->speedRatio()) * dVar11 * DEG2RAD * m_rejectSign, 0.0f);
56 EGG::Quatf local_78 = mainRot().multSwap(rot);
57 local_78.normalise();
58
59 dynamics()->setAngVel0(EGG::Vector3f::zero);
60 dynamics()->setFullRot(local_78);
61 dynamics()->setMainRot(local_78);
62 }
63
64 status.resetBit(eStatus::Hop);
65
66 bool didReject = calcRejection();
67
68 if (status.offBit(eStatus::NoSparkInvisibleWall) && !didReject) {
69 move()->clearRejectRoad();
70 }
71
72 return;
73 }
74
75 if (status.onBit(eStatus::RejectRoad) &&
78 EGG::Vector3f upXZ = move()->up();
79 upXZ.y = 0.0f;
80
81 if (upXZ.length() > 0.0f && speed() > 0.0f) {
82 upXZ.normalise();
83 EGG::Vector3f local_88 = move()->lastDir().perpInPlane(upXZ, true);
84
85 if (local_88.y > 0.0f) {
86 EGG::Vector3f upCross = EGG::Vector3f::ey.cross(local_88);
87 m_rejectSign = upCross.dot(move()->up()) > 0.0f ? 1.0f : -1.0f;
88
90 }
91 }
92 }
93}
94
96bool KartReject::calcRejection() {
98 Field::KCLTypeMask mask = KCL_NONE;
99 auto &status = KartObjectProxy::status();
100 status.resetBit(eStatus::NoSparkInvisibleWall);
101 EGG::Vector3f worldUpPos = dynamics()->pos() + bodyUp() * 100.0f;
102 f32 posScalar = 100.0f;
103 f32 radius = posScalar;
104
105 for (size_t i = 0; i < 2; ++i) {
106 EGG::Vector3f local_d0 = dynamics()->mainRot().rotateVector(EGG::Vector3f::ey);
107 EGG::Vector3f worldPos = pos() + (-posScalar * move()->scale().y) * local_d0;
108
109 auto *colDir = Field::CollisionDirector::Instance();
110 if (!colDir->checkSphereFullPush(radius, worldPos, worldUpPos, KCL_TYPE_B0E82DFF, &colInfo,
111 &mask, 0)) {
112 if (i == 0) {
113 posScalar = 0.0f;
114 }
115
116 continue;
117 }
118
119 EGG::Vector3f tangentOff = EGG::Vector3f::zero;
120
121 if (!calcCollision(colInfo, mask, tangentOff)) {
122 continue;
123 }
124
125 EGG::Vector3f tangentUp = (tangentOff - move()->up()) * 1.0f;
126 move()->setUp(move()->up() + tangentUp);
127 move()->setSmoothedUp(move()->up());
128
129 bool bVar15 = tangentOff.dot(EGG::Vector3f::ey) < -0.17f;
130 if (bVar15 || extVel().y < 0.0f || status.onBit(eStatus::NoSparkInvisibleWall)) {
131 radius = -radius;
132 colInfo.tangentOff += worldPos;
133
134 f32 yOffset = bsp().initialYPos * scale().y;
135 f32 speedScalar = bVar15 ?
136 1.0f :
137 static_cast<f32>(static_cast<f64>(EGG::Mathf::abs(speed()) * 0.01f) - 0.3d);
138 speedScalar = std::min(1.0f, std::max(0.0f, speedScalar));
139
140 EGG::Vector3f posOffset =
141 colInfo.tangentOff + radius * tangentOff + yOffset * tangentOff;
142 posOffset.y += move()->hopPosY();
143 posOffset -= pos();
144 setPos(pos() + posOffset * speedScalar);
145 }
146
147 EGG::Vector3f local_13c = move()->lastDir().perpInPlane(move()->smoothedUp(), true);
148 move()->setDir(local_13c);
149 move()->setVel1Dir(local_13c);
150
151 return true;
152 }
153
154 return false;
155}
156
157bool KartReject::calcCollision(Field::CollisionInfo &colInfo, Field::KCLTypeMask mask,
158 EGG::Vector3f &tangentOff) {
159 auto *colDir = Field::CollisionDirector::Instance();
160
161 if (mask & KCL_TYPE_INVISIBLE_WALL) {
162 if (colDir->findClosestCollisionEntry(&mask, KCL_TYPE_INVISIBLE_WALL) &&
163 colDir->closestCollisionEntry()->variant() == 0) {
164 tangentOff = colInfo.wallNrm;
165 status().setBit(eStatus::NoSparkInvisibleWall);
166 return true;
167 }
168 }
169
170 Field::KCLTypeMask halfPipeInvisMask = KCL_TYPE_BIT(COL_TYPE_HALFPIPE_INVISIBLE_WALL);
171 if (mask & halfPipeInvisMask) {
172 if (colDir->findClosestCollisionEntry(&mask, halfPipeInvisMask)) {
173 tangentOff = colInfo.wallNrm;
174 status().setBit(eStatus::NoSparkInvisibleWall);
175 return true;
176 }
177 }
178
179 if (mask & KCL_TYPE_DRIVER_FLOOR) {
180 if (colDir->findClosestCollisionEntry(&mask, KCL_TYPE_DRIVER_FLOOR) &&
181 colDir->closestCollisionEntry()->attribute.onBit(
182 Field::CollisionDirector::eCollisionAttribute::RejectRoad)) {
183 tangentOff = colInfo.floorNrm;
184 return true;
185 }
186 }
187
188 return false;
189}
190
191} // namespace Kart
@ COL_TYPE_HALFPIPE_INVISIBLE_WALL
Invisible wall after a half-pipe jump, like in BC.
#define KCL_TYPE_DRIVER_FLOOR
0x20E80DFF - Any KCL that the player can drive on.
#define KCL_TYPE_BIT(x)
#define KCL_TYPE_INVISIBLE_WALL
0x80002000
#define KCL_TYPE_B0E82DFF
0xB0E82DFF
constexpr bool offBit(Es... es) const
Checks if all of the corresponding bits for the provided enum values are off.
Definition BitFlag.hh:412
constexpr bool onBit(Es... es) const
Checks if any of the corresponding bits for the provided enum values are on.
Definition BitFlag.hh:379
constexpr TBitFlagExt< N, E > & resetBit(Es... es)
Resets the corresponding bits for the provided enum values.
Definition BitFlag.hh:355
constexpr TBitFlagExt< N, E > & setBit(Es... es)
Sets the corresponding bits for the provided enum values.
Definition BitFlag.hh:344
EGG::Vector3f bodyUp() const
Returns the second column of the rotation matrix, which is the "up" direction.
Pertains to kart-related functionality.
@ RejectRoad
Collision which causes a change in the player's pos and rot.
@ HalfPipeRamp
Set while colliding with zipper KCL.
@ Hop
Set while we are in a drift hop. Clears when we land.
@ RejectRoadTrigger
e.g. DK Summit ending, and Maple Treeway side walls.
@ OverZipper
Set while mid-air from a zipper.
@ ZipperInvisibleWall
Set when colliding with invisible wall above a zipper.
A quaternion, used to represent 3D rotation.
Definition Quat.hh:12
void normalise()
Scales the quaternion to a unit length.
Definition Quat.cc:28
Vector3f rotateVector(const Vector3f &vec) const
Rotates a vector based on the quat.
Definition Quat.cc:55
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 length() const
The square root of the vector's dot product.
Definition Vector.hh:192
Vector3f perpInPlane(const EGG::Vector3f &rhs, bool normalise) const
Calculates the orthogonal vector, based on the plane defined by this vector and rhs.
Definition Vector.cc:104