A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectPoihana.cc
1#include "ObjectPoihana.hh"
2
3#include "game/field/CollisionDirector.hh"
4
5namespace Field {
6
8ObjectPoihanaBase::ObjectPoihanaBase(const System::MapdataGeoObj &params)
9 : StateManager(this, {}), ObjectCollidable(params), m_walkState(WalkState::NeedTarget),
10 m_heightOffset(0.0f), m_radius(150.0f), m_targetPos(EGG::Vector3f::zero) {}
11
13ObjectPoihanaBase::~ObjectPoihanaBase() = default;
14
16void ObjectPoihanaBase::init() {
17 m_workMat = EGG::Matrix34f::ident;
18 m_accel.setZero();
19 m_extVel.setZero();
20 m_vel.setZero();
21 m_curRot = EGG::Vector3f::ey;
22 m_up = EGG::Vector3f::ez;
23 m_floorNrm = EGG::Vector3f::ey;
24 m_walkState = WalkState::NeedTarget;
25 m_workMat.setBase(3, m_pos);
26}
27
29ObjectPoihana::ObjectPoihana(const System::MapdataGeoObj &params)
30 : StateManager(this, STATE_ENTRIES), ObjectPoihanaBase(params) {}
31
33ObjectPoihana::~ObjectPoihana() = default;
34
36void ObjectPoihana::init() {
37 ObjectPoihanaBase::init();
38
39 m_initPos = curPos();
40 m_dir = EGG::Vector3f::ez;
41 m_targetVel.setZero();
42 m_accel = EGG::Vector3f(0.0f, -1.2f, 0.0f);
43 m_radius = 100.0f;
44 m_heightOffset = -160.0f;
45 m_nextStateId = 0;
46}
47
49void ObjectPoihana::calcCurRot(f32 t) {
50 m_curRot = Interpolate(t, m_curRot, m_floorNrm);
51 if (m_curRot.squaredLength() > std::numeric_limits<f32>::epsilon()) {
52 m_curRot.normalise2();
53 } else {
54 m_curRot = EGG::Vector3f::ey;
55 }
56}
57
59void ObjectPoihana::calcOrthonormalBasis() {
60 EGG::Vector3f side = m_curRot.cross(m_up);
61 side.normalise2();
62
63 if (side.squaredLength() <= std::numeric_limits<f32>::epsilon()) {
64 side = EGG::Vector3f::ex;
65 }
66
67 EGG::Vector3f up = side.cross(m_curRot);
68 up.normalise2();
69
70 m_workMat.setBase(0, side);
71 m_workMat.setBase(1, m_curRot);
72 m_workMat.setBase(2, up);
73}
74
76void ObjectPoihana::calcCollision() {
77 CollisionInfo info;
78 EGG::Vector3f pos = collisionPos();
79
80 bool hasCol = CollisionDirector::Instance()->checkSphereFull(m_radius, pos, EGG::Vector3f::inf,
81 KCL_TYPE_64EBDFFF, &info, nullptr, 0);
82
83 if (!hasCol) {
84 return;
85 }
86
87 m_workMat.setBase(3, m_workMat.base(3) + info.tangentOff);
88
89 if (info.wallDist > -std::numeric_limits<f32>::min()) {
90 m_extVel += Project(m_extVel, info.wallNrm) * -2.0f;
91 }
92
93 if (info.floorDist > -std::numeric_limits<f32>::min()) {
94 m_floorNrm = info.floorNrm;
95 m_extVel.setZero();
96 }
97}
98
100void ObjectPoihana::calcStep() {
101 constexpr f32 COARSE_SCALAR = 0.1f;
102 constexpr f32 FINE_SCALAR = 100.0f;
103 constexpr f32 CLAMP = 0.5f;
104 constexpr s32 MOD = 100;
105 constexpr f32 INV_MOD = 1.0f / static_cast<f32>(MOD);
106 constexpr f32 SPEED = 7.0f;
107 constexpr f32 RAND_POS_MAX = 2000.0f;
108 constexpr f32 RAND_POS_MIN = 1000.0f;
109 constexpr f32 RAND_POS_RANGE = RAND_POS_MAX - RAND_POS_MIN;
110 constexpr f32 TARGET_DIST_THRESHOLD = 200.0f;
111
112 if (m_walkState == WalkState::NeedTarget) {
113 // psuedo-random number generator based on current position of the Poihana
114 EGG::Vector3f pos = curPos();
115 f32 sum = EGG::Mathf::abs(pos.x + pos.z);
116 s32 tmp1 = static_cast<s32>(COARSE_SCALAR * sum);
117 s32 tmp2 = static_cast<s32>(FINE_SCALAR * sum);
118 s32 remSum = (tmp1 % MOD) + (tmp2 % MOD);
119 f32 x = INV_MOD * static_cast<f32>(remSum % MOD);
120 f32 z = INV_MOD * static_cast<f32>(remSum * 7 % MOD);
121
122 EGG::Vector3f dir = EGG::Vector3f(x - CLAMP, 0.0f, z - CLAMP);
123 dir.normalise2();
124
125 f32 scalar = RAND_POS_RANGE * (INV_MOD * static_cast<f32>(remSum * 3 % MOD)) + RAND_POS_MIN;
126 m_targetPos = m_initPos + dir * scalar;
127
128 calcDir();
129
130 m_walkState = WalkState::HasTarget;
131 }
132
133 if (m_walkState == WalkState::HasTarget) {
134 EGG::Vector3f delta = m_targetPos - curPos();
135 delta.y = 0.0f;
136
137 f32 len = 0.0f;
138 if (delta.squaredLength() > std::numeric_limits<f32>::epsilon()) {
139 len = delta.normalise();
140 }
141
142 m_targetVel = delta * SPEED;
143
144 if (len < TARGET_DIST_THRESHOLD) {
145 m_walkState = WalkState::NeedTarget;
146 }
147 }
148
149 calcCurRot(0.1f);
150 calcUp();
151
152 m_vel = Interpolate(0.05f, m_vel, m_targetVel);
153}
154
156void ObjectPoihana::calcDir() {
157 EGG::Vector3f delta = m_targetPos - curPos();
158 delta.y = 0.0f;
159 if (delta.squaredLength() > std::numeric_limits<f32>::epsilon()) {
160 delta.normalise2();
161 m_dir = delta;
162 }
163}
164
166void ObjectPoihana::calcUp() {
167 EGG::Vector3f up = Interpolate(0.1f, m_workMat.base(2), m_dir);
168 if (up.squaredLength() > std::numeric_limits<f32>::epsilon()) {
169 up.normalise2();
170 } else {
171 up = EGG::Vector3f::ez;
172 }
173
174 m_up = up;
175}
176
177} // namespace Field
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 squaredLength() const
The dot product between the vector and itself.
Definition Vector.hh:182