A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
CollisionGroup.cc
1#include "CollisionGroup.hh"
2
3namespace Kinoko::Kart {
4
6void CollisionData::reset() {
7 tangentOff.setZero();
8 floorNrm.setZero();
9 wallNrm.setZero();
10 vel.setZero();
11 relPos.setZero();
12 movement.setZero();
13 roadVelocity.setZero();
14 speedFactor = 1.0f;
15 rotFactor = 0.0f;
17 closestFloorSettings = 0xffffffff;
19 closestFloorSettings = 0xffffffff;
20 intensity = 0.0f;
21 colPerpendicularity = 0.0f;
22
23 bFloor = false;
24 bWall = false;
25 bInvisibleWall = false;
26 bTrickable = false;
28 bWall3 = false;
29 bInvisibleWallOnly = false;
31 bSoftWall = false;
34 bHasRoadVel = false;
35 bWallAtLeftCloser = false;
36 bWallAtRightCloser = false;
38}
39
41Hitbox::Hitbox() : m_bspHitbox(nullptr), m_ownsBSP(false) {}
42
44Hitbox::~Hitbox() {
45 if (m_ownsBSP) {
46 delete m_bspHitbox;
47 }
48}
49
52void Hitbox::calc(f32 totalScale, f32 sinkDepth, const EGG::Vector3f &scale, const EGG::Quatf &rot,
53 const EGG::Vector3f &pos) {
54 f32 fVar1 = 0.0f;
55 if (scale.y < totalScale) {
56 fVar1 = (totalScale - scale.y) * m_bspHitbox->radius;
57 }
58
59 EGG::Vector3f scaledPos = m_bspHitbox->position * scale;
60 scaledPos.y = (m_bspHitbox->position.y + sinkDepth) * scale.y + fVar1;
61
62 m_relPos = rot.rotateVector(scaledPos);
63 m_worldPos = m_relPos + pos;
64}
65
67void Hitbox::reset() {
68 m_worldPos.setZero();
69 m_lastPos.setZero();
70 m_relPos.setZero();
71}
72
74void Hitbox::setLastPos(const EGG::Vector3f &scale, const EGG::Matrix34f &pose) {
75 f32 yScaleFactor = scale.y;
76 EGG::Vector3f scaledPos = m_bspHitbox->position;
77 scaledPos.x *= scale.x;
78 scaledPos.z *= scale.z;
79
80 if (scale.y != scale.z && scale.y < 1.0f) {
81 scaledPos.y += (1.0f - scale.y) * m_radius;
82 yScaleFactor = scale.z;
83 }
84
85 scaledPos.y *= yScaleFactor;
86 m_lastPos = pose.ps_multVector(scaledPos);
87}
88
90CollisionGroup::CollisionGroup() : m_hitboxScale(1.0f) {
91 m_collisionData.reset();
92}
93
94CollisionGroup::~CollisionGroup() = default;
95
103f32 CollisionGroup::initHitboxes(const std::array<BSP::Hitbox, 16> &hitboxes) {
104 u16 bspHitboxCount = 0;
105
106 for (const auto &hitbox : hitboxes) {
107 if (parse<u16>(hitbox.enable)) {
108 ++bspHitboxCount;
109 }
110 }
111
112 m_hitboxes = owning_span<Hitbox>(bspHitboxCount);
113 u16 hitboxIdx = 0;
114
115 for (const auto &bspHitbox : hitboxes) {
116 if (parse<u16>(bspHitbox.enable)) {
117 m_hitboxes[hitboxIdx++].setBspHitbox(&bspHitbox);
118 }
119 }
120
121 return computeCollisionLimits();
122}
123
128 EGG::Vector3f max = EGG::Vector3f::zero;
129
130 for (const auto &hitbox : m_hitboxes) {
131 const BSP::Hitbox *bspHitbox = hitbox.bspHitbox();
132
133 if (bspHitbox->enable == 0) {
134 continue;
135 }
136
137 max = max.maximize(bspHitbox->position.abs() + bspHitbox->radius);
138 }
139
140 // Get largest component of the vector
141 f32 maxComponent = max.z;
142
143 if (max.x <= max.y) {
144 if (max.z < max.y) {
145 maxComponent = max.y;
146 }
147 } else if (max.z < max.x) {
148 maxComponent = max.x;
149 }
150
151 m_boundingRadius = maxComponent;
152
153 return max.z * 0.5f;
154}
155
159void CollisionGroup::createSingleHitbox(f32 radius, const EGG::Vector3f &relPos) {
160 m_hitboxes = owning_span<Hitbox>(1);
161
162 // TODO: Do we need for loop if this is just one?
163 // And how exactly will we identify to free the BSP::Hitbox on destruction?
164 for (auto &hitbox : m_hitboxes) {
165 hitbox.reset();
166 BSP::Hitbox *bspHitbox = new BSP::Hitbox;
167 hitbox.setBspHitbox(bspHitbox, true);
168 bspHitbox->position = relPos;
169 bspHitbox->radius = radius;
170 hitbox.setRadius(radius);
171 }
172 m_boundingRadius = radius;
173}
174
176void CollisionGroup::reset() {
177 m_collisionData.reset();
178
179 for (auto &hitbox : m_hitboxes) {
180 hitbox.reset();
181 hitbox.setRadius(hitbox.bspHitbox()->radius * m_hitboxScale);
182 }
183}
184
185void CollisionGroup::resetCollision() {
186 m_collisionData.reset();
187}
188
190void CollisionGroup::setHitboxScale(f32 scale) {
191 m_hitboxScale = scale;
192
193 for (auto &hitbox : m_hitboxes) {
194 hitbox.setRadius(hitbox.bspHitbox()->radius * m_hitboxScale);
195 }
196}
197
198} // namespace Kinoko::Kart
A 3 x 4 matrix.
Definition Matrix.hh:10
constexpr Vector3f ps_multVector(const Vector3f &vec) const
Paired-singles impl. of multVector.
Definition Matrix.hh:273
f32 computeCollisionLimits()
Sets the bounding radius.
f32 initHitboxes(const std::array< BSP::Hitbox, 16 > &hitboxes)
Initializes the hitbox array based on the KartParam's BSP hitboxes.
void createSingleHitbox(f32 radius, const EGG::Vector3f &relPos)
Creates a hitbox to represent a tire.
A contiguous storage container that manages the lifecycle of a buffer of a given size.
Definition Types.hh:29
Pertains to kart-related functionality.
A quaternion, used to represent 3D rotation.
Definition Quat.hh:12
constexpr Vector3f rotateVector(const Vector3f &vec) const
Rotates a vector based on the quat.
Definition Quat.hh:136
A 3D float vector.
Definition Vector.hh:107
constexpr Vector3f abs() const
Returns the absolute value of each element of the vector.
Definition Vector.hh:239
constexpr Vector3f maximize(const Vector3f &rhs) const
Returns a vector whose elements are the max of the elements of both vectors.
Definition Vector.hh:315
Represents one of the many hitboxes that make up a vehicle.
Definition KartParam.hh:10
EGG::Vector3f position
The relative position of the hitbox.
Definition KartParam.hh:12
u16 enable
Specifies if this is an active hitbox (since BSP always has 16).
Definition KartParam.hh:11
bool bWall3
Set if colliding with COL_TYPE_WALL_2.
Field::KCLTypeMask closestFloorFlags
The colliding floor KCL flag's KColType.
bool bMovingWaterDecaySpeed
Player speed will drop if not in mushroom.
bool bMovingWaterStickyRoad
KC pipe vertical water section.
s32 intensity
The KCL flag's "wheel depth".
bool bMovingWaterVertical
KC last turn vertical water.
bool bMovingWaterMomentum
Player will maintain speed for a bit after leaving KCL.
bool bFloor
Set if colliding with KCL which satisfies KCL_TYPE_FLOOR.
bool bMovingWaterDisableAccel
KC last turn prevents mini-turbo acceleration.
u32 closestFloorSettings
The colliding floor KCL flag's "variant".
bool bWall
Set if colliding with KCL which satisfies KCL_TYPE_WALL.
Field::KCLTypeMask closestWallFlags
The colliding wall KCL flag's KColType.