Peoplemon  0.1.0
Peoplemon 3 game source documentation
Flight.cpp
Go to the documentation of this file.
2 
3 #include <BLIB/Cameras.hpp>
4 #include <BLIB/Logging.hpp>
5 #include <BLIB/Math.hpp>
6 #include <Core/Properties.hpp>
8 #include <cmath>
9 
10 namespace core
11 {
12 namespace system
13 {
14 namespace
15 {
16 constexpr float RiseHeight = 32.5 * 5.f;
17 constexpr float RiseRate = RiseHeight / 2.f;
18 constexpr float RotateTime = 0.65f;
19 constexpr float MaxSpeed = 32.f * 38.f;
20 constexpr float MinFlyTime = 2.5f;
21 constexpr float ShakesPerSec = 18.f;
22 constexpr float ShakeMagnitude = 7.f;
23 constexpr float ShadowSize = 17.f;
24 constexpr float ShadowShrinkage = ShadowSize * 0.3f;
25 constexpr float HoldTime = 1.5f;
26 
27 float distSqrd(const glm::vec2& p1, const glm::vec2& p2) {
28  const float dx = p1.x - p2.x;
29  const float dy = p1.y - p2.y;
30  return dx * dx + dy * dy;
31 }
32 
33 float distSqrd(const bl::tmap::Position& p1, const glm::vec2& p2) {
34  return distSqrd(p1.transform->getGlobalPosition(), p2);
35 }
36 
37 } // namespace
38 
40 : owner(s)
41 , state(State::Idle)
42 , cameraShake(nullptr)
43 , playerPos(nullptr)
44 , playerAnim(nullptr) {}
45 
46 void Flight::init(bl::engine::Engine&) {}
47 
48 bool Flight::flying() const { return state != State::Idle; }
49 
50 bool Flight::startFlight(unsigned int spawn) {
51  if (!owner.world().activeMap().canFlyFromHere()) {
52  BL_LOG_WARN << "Tried to fly from non-flyable map";
53  return false;
54  }
55 
56  const bl::tmap::Position* spos = owner.world().activeMap().getSpawnPosition(spawn);
57  if (!spos) {
58  BL_LOG_ERROR << "Tried to fly to bad spawn: " << spawn;
59  return false;
60  }
61  destination = *spos;
62 
63  playerPos = owner.engine().ecs().getComponent<bl::tmap::Position>(owner.player().player());
64  playerAnim = owner.engine().ecs().getComponent<component::Renderable>(owner.player().player());
65  if (!playerPos) {
66  BL_LOG_CRITICAL << "Player position could not be found";
67  owner.engine().flags().set(bl::engine::Flags::Terminate);
68  return false;
69  }
70  if (!playerAnim) {
71  BL_LOG_CRITICAL << "Player animation could not be found";
72  owner.engine().flags().set(bl::engine::Flags::Terminate);
73  return false;
74  }
75 
76  // remove player control and face down
77  owner.player().removePlayerControlled(owner.player().player());
78  startPos = *playerPos;
79  playerPos->direction = bl::tmap::Direction::Down;
80  playerPos->level = std::max(playerPos->level, destination.level);
81  playerPos->transform->setDepth(owner.world().activeMap().getMinDepth());
82  rotatePlayer(bl::tmap::Direction::Down);
83 
84  // start flight
85  state = State::Rising;
86  riseState.height = 0.f;
87  riseState.startY = playerPos->transform->getGlobalPosition().y;
88 
89  return true;
90 }
91 
92 void Flight::update(std::mutex&, float dt, float, float, float) {
93  switch (state) {
94  case State::Rising:
95  riseState.height = std::min(riseState.height + RiseRate * dt, RiseHeight);
96  playerPos->transform->setPosition(playerPos->transform->getGlobalPosition().x,
97  riseState.startY - riseState.height);
98  owner.render().updateShadow(owner.player().player(),
99  riseState.height,
100  ShadowSize - (riseState.height / RiseHeight) * ShadowShrinkage);
101  if (riseState.height >= RiseHeight) {
102  if (startPos.position != destination.position) {
103  state = State::Rotating;
104  flightDest = destination.getWorldPosition(Properties::PixelsPerTile());
105  flightDest.y -= RiseHeight;
106  unitVelocity = flightDest - playerPos->transform->getGlobalPosition();
107  const float m =
108  std::sqrt(unitVelocity.x * unitVelocity.x + unitVelocity.y * unitVelocity.y);
109  unitVelocity.x /= m;
110  unitVelocity.y /= m;
111  rotateState.angle = 0.f;
112  rotateState.targetAngle =
113  bl::math::radiansToDegrees(
114  std::atan2(flightDest.y - playerPos->transform->getGlobalPosition().y,
115  flightDest.x - playerPos->transform->getGlobalPosition().x)) +
116  90.f;
117  rotateState.rotateRate = (rotateState.targetAngle - rotateState.angle) / RotateTime;
118  }
119  else {
120  state = State::Holding;
121  holdState.lookTime = 0.f;
122  }
123  }
124  break;
125 
126  case State::Rotating:
127  case State::UnRotating:
128  rotateState.angle += rotateState.rotateRate * dt;
129  playerAnim->setAngle(rotateState.angle);
130  if (std::abs(rotateState.angle - rotateState.targetAngle) < 1.5f) {
131  rotateState.angle = rotateState.targetAngle;
132  playerAnim->setAngle(rotateState.angle);
133 
134  if (state == State::Rotating) {
135  const float pa = rotateState.targetAngle;
136  state = State::Accelerating;
137  flyState.angle = pa; // probably not required but eh
138  flyState.velocity = 0.f;
139  flyState.ogDistSqrd = distSqrd(*playerPos, flightDest);
140  flyState.maxSpeed = std::min(std::sqrt(flyState.ogDistSqrd) / MinFlyTime, MaxSpeed);
141 
142  cameraShake = owner.engine()
143  .renderer()
144  .getObserver()
145  .getCurrentCamera<bl::cam::Camera2D>()
146  ->addAffector<bl::cam::c2d::CameraShake>(0.f, 0.f);
147  }
148  else {
149  state = State::Descending;
150  riseState.height = RiseHeight;
151  }
152  }
153  break;
154 
155  case State::Accelerating: {
156  movePlayer(dt);
157  const float cDist = distSqrd(*playerPos, flightDest);
158  const float percent = 1.f - (cDist / flyState.ogDistSqrd) + 0.005f;
159  flyState.velocity =
160  percent <= 0.125f ? percent * 8.f * flyState.maxSpeed : flyState.maxSpeed;
161  if (flyState.velocity >= flyState.maxSpeed) {
162  flyState.velocity = flyState.maxSpeed;
163  state = State::Flying;
164  }
165  if (cameraShake) {
166  cameraShake->setMagnitude(flyState.velocity / flyState.maxSpeed * ShakeMagnitude);
167  cameraShake->setShakesPerSecond(flyState.velocity / flyState.maxSpeed * ShakesPerSec);
168  }
169  } break;
170 
171  case State::Flying: {
172  movePlayer(dt);
173  const float cDist = distSqrd(*playerPos, flightDest);
174  const float percent = 1.f - cDist / flyState.ogDistSqrd;
175  if (percent >= 0.98f) { state = State::Deccelerating; }
176  } break;
177 
178  case State::Deccelerating: {
179  movePlayer(dt);
180  const float cDist = distSqrd(*playerPos, flightDest);
181  const float percent = 1.f - cDist / flyState.ogDistSqrd;
182  flyState.velocity = std::max((1.f - percent) * 50.f * flyState.maxSpeed, 32.f * 6.f);
183  if (cDist <= 3.4f || flyState.velocity == 0.f) {
184  if (cameraShake) { cameraShake->setMagnitude(0.f); }
185  playerPos->transform->setPosition(flightDest);
186  const float pa = flyState.angle;
187  state = State::UnRotating;
188  rotateState.angle = pa;
189  rotateState.targetAngle = 0.f;
190  rotateState.rotateRate = (rotateState.targetAngle - rotateState.angle) / RotateTime;
191 
192  owner.engine()
193  .renderer()
194  .getObserver()
195  .getCurrentCamera<bl::cam::Camera2D>()
196  ->removeAffector(cameraShake);
197  cameraShake = nullptr;
198  }
199  else if (cameraShake) {
200  cameraShake->setMagnitude(flyState.velocity / flyState.maxSpeed * ShakeMagnitude);
201  cameraShake->setShakesPerSecond(flyState.velocity / flyState.maxSpeed * ShakesPerSec);
202  }
203  } break;
204 
205  case State::Descending:
206  riseState.height = std::max(riseState.height - RiseRate * dt, 0.f);
207  playerPos->transform->setPosition(
208  playerPos->transform->getGlobalPosition().x,
209  destination.getWorldPosition(Properties::PixelsPerTile()).y - riseState.height);
210  owner.render().updateShadow(owner.player().player(),
211  riseState.height,
212  ShadowSize - (riseState.height / RiseHeight) * ShadowShrinkage);
213  if (riseState.height == 0.f) {
214  owner.render().removeShadow(owner.player().player());
215  playerPos->position = destination.position;
216  state = State::Idle;
217  owner.player().makePlayerControlled(owner.player().player());
218  if (startPos.position != destination.position) {
219  playerPos->syncTransform(Properties::PixelsPerTile());
220  bl::event::Dispatcher::dispatch<event::EntityMoved>(
221  {owner.player().player(), startPos, *playerPos});
222  bl::event::Dispatcher::dispatch<event::EntityMoveFinished>(
223  {owner.player().player(), *playerPos});
224  }
225  else {
226  owner.hud().displayMessage("...");
227  owner.hud().displayMessage("We're here");
228  }
229  }
230  break;
231 
232  case State::Holding:
233  holdState.lookTime += dt;
234  if (holdState.lookTime >= HoldTime) {
235  switch (playerPos->direction) {
236  case bl::tmap::Direction::Down:
237  rotatePlayer(bl::tmap::Direction::Right);
238  holdState.lookTime = 0.f;
239  break;
240  case bl::tmap::Direction::Right:
241  rotatePlayer(bl::tmap::Direction::Left);
242  holdState.lookTime = 0.f;
243  break;
244  case bl::tmap::Direction::Left:
245  default:
246  rotatePlayer(bl::tmap::Direction::Down);
247  state = State::Descending;
248  riseState.height = RiseHeight;
249  break;
250  }
251  }
252  break;
253 
254  case State::Idle:
255  default:
256  break;
257  }
258 }
259 
260 void Flight::movePlayer(float dt) {
261  playerPos->transform->move(unitVelocity * flyState.velocity * dt);
262 }
263 
264 void Flight::rotatePlayer(bl::tmap::Direction dir) {
265  bl::event::Dispatcher::dispatch<event::EntityRotated>(
266  {owner.player().player(), dir, playerPos->direction});
267  playerPos->direction = dir;
268 }
269 
270 } // namespace system
271 } // namespace core
Core classes and functionality for both the editor and game.
Adding this component to an entity will allow it to be rendered.
Definition: Renderable.hpp:28
void setAngle(float angle)
Sets the angle to render the entity at.
Definition: Renderable.cpp:108
float getMinDepth() const
Returns the maximum depth possible for this map. Maximum is always 0.f. Minimum is negative,...
Definition: Map.cpp:775
const bl::tmap::Position * getSpawnPosition(unsigned int spawnId) const
Returns the position of the given player spawn, or nullptr if not found.
Definition: Map.cpp:605
bool canFlyFromHere() const
Returns whether or not the player can fly from this map.
Definition: Map.cpp:603
static int PixelsPerTile()
Definition: Properties.cpp:279
bool startFlight(unsigned int destSpawn)
Starts flight to the given spawn.
Definition: Flight.cpp:50
Flight(Systems &systems)
Construct a new Flight system.
Definition: Flight.cpp:39
bool flying() const
Returns whether or not the player is currently flying.
Definition: Flight.cpp:48
FlyState flyState
Definition: Flight.hpp:96
RiseState riseState
Definition: Flight.hpp:94
HoldState holdState
Definition: Flight.hpp:97
RotateState rotateState
Definition: Flight.hpp:95
void displayMessage(const std::string &message, const Callback &cb=[](const std::string &) {})
Displays a message in the HUD textbox. Messages are queued in order that they arrive.
Definition: HUD.cpp:92
void removePlayerControlled(bl::ecs::Entity entity)
Removes the PlayerControlled component from the given entity, if any.
Definition: Player.cpp:91
bl::ecs::Entity player() const
Returns the id of the player entity.
Definition: Player.cpp:55
bool makePlayerControlled(bl::ecs::Entity entity)
Makes the given entity controlled by the player. Only one entity may be player controlled at a time.
Definition: Player.cpp:76
void removeShadow(bl::ecs::Entity entity)
Removes the shadow from the given entity.
Definition: Render.cpp:97
void updateShadow(bl::ecs::Entity entity, float distance, float radius)
Adds or updates the shadow of the given entity.
Definition: Render.cpp:58
Owns all primary systems and a reference to the engine.
Definition: Systems.hpp:47
const bl::engine::Engine & engine() const
Const accessor for the Engine.
Definition: Systems.cpp:35
Render & render()
Returns the render system.
Definition: Systems.cpp:87
Player & player()
Returns the player system.
Definition: Systems.cpp:59
HUD & hud()
Returns the HUD.
Definition: Systems.cpp:69
World & world()
Modifiable accessor for the world system.
Definition: Systems.cpp:43
map::Map & activeMap()
Returns a reference to the active map.
Definition: World.cpp:84