3 #include <BLIB/Cameras.hpp>
4 #include <BLIB/Logging.hpp>
5 #include <BLIB/Math.hpp>
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;
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;
33 float distSqrd(
const bl::tmap::Position& p1,
const glm::vec2& p2) {
34 return distSqrd(p1.transform->getGlobalPosition(), p2);
42 , cameraShake(nullptr)
44 , playerAnim(nullptr) {}
46 void Flight::init(bl::engine::Engine&) {}
52 BL_LOG_WARN <<
"Tried to fly from non-flyable map";
58 BL_LOG_ERROR <<
"Tried to fly to bad spawn: " << spawn;
63 playerPos = owner.
engine().ecs().getComponent<bl::tmap::Position>(owner.
player().
player());
66 BL_LOG_CRITICAL <<
"Player position could not be found";
67 owner.
engine().flags().set(bl::engine::Flags::Terminate);
71 BL_LOG_CRITICAL <<
"Player animation could not be found";
72 owner.
engine().flags().set(bl::engine::Flags::Terminate);
78 startPos = *playerPos;
79 playerPos->direction = bl::tmap::Direction::Down;
80 playerPos->level = std::max(playerPos->level, destination.level);
82 rotatePlayer(bl::tmap::Direction::Down);
85 state = State::Rising;
87 riseState.startY = playerPos->transform->getGlobalPosition().y;
92 void Flight::update(std::mutex&,
float dt,
float,
float,
float) {
96 playerPos->transform->setPosition(playerPos->transform->getGlobalPosition().x,
100 ShadowSize - (
riseState.height / RiseHeight) * ShadowShrinkage);
102 if (startPos.position != destination.position) {
103 state = State::Rotating;
105 flightDest.y -= RiseHeight;
106 unitVelocity = flightDest - playerPos->transform->getGlobalPosition();
108 std::sqrt(unitVelocity.x * unitVelocity.x + unitVelocity.y * unitVelocity.y);
113 bl::math::radiansToDegrees(
114 std::atan2(flightDest.y - playerPos->transform->getGlobalPosition().y,
115 flightDest.x - playerPos->transform->getGlobalPosition().x)) +
120 state = State::Holding;
126 case State::Rotating:
127 case State::UnRotating:
134 if (state == State::Rotating) {
136 state = State::Accelerating;
139 flyState.ogDistSqrd = distSqrd(*playerPos, flightDest);
140 flyState.maxSpeed = std::min(std::sqrt(
flyState.ogDistSqrd) / MinFlyTime, MaxSpeed);
142 cameraShake = owner.
engine()
145 .getCurrentCamera<bl::cam::Camera2D>()
146 ->addAffector<bl::cam::c2d::CameraShake>(0.f, 0.f);
149 state = State::Descending;
155 case State::Accelerating: {
157 const float cDist = distSqrd(*playerPos, flightDest);
158 const float percent = 1.f - (cDist /
flyState.ogDistSqrd) + 0.005f;
163 state = State::Flying;
166 cameraShake->setMagnitude(
flyState.velocity /
flyState.maxSpeed * ShakeMagnitude);
167 cameraShake->setShakesPerSecond(
flyState.velocity /
flyState.maxSpeed * ShakesPerSec);
171 case State::Flying: {
173 const float cDist = distSqrd(*playerPos, flightDest);
174 const float percent = 1.f - cDist /
flyState.ogDistSqrd;
175 if (percent >= 0.98f) { state = State::Deccelerating; }
178 case State::Deccelerating: {
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);
187 state = State::UnRotating;
195 .getCurrentCamera<bl::cam::Camera2D>()
196 ->removeAffector(cameraShake);
197 cameraShake =
nullptr;
199 else if (cameraShake) {
200 cameraShake->setMagnitude(
flyState.velocity /
flyState.maxSpeed * ShakeMagnitude);
201 cameraShake->setShakesPerSecond(
flyState.velocity /
flyState.maxSpeed * ShakesPerSec);
205 case State::Descending:
207 playerPos->transform->setPosition(
208 playerPos->transform->getGlobalPosition().x,
212 ShadowSize - (
riseState.height / RiseHeight) * ShadowShrinkage);
215 playerPos->position = destination.position;
218 if (startPos.position != destination.position) {
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});
235 switch (playerPos->direction) {
236 case bl::tmap::Direction::Down:
237 rotatePlayer(bl::tmap::Direction::Right);
240 case bl::tmap::Direction::Right:
241 rotatePlayer(bl::tmap::Direction::Left);
244 case bl::tmap::Direction::Left:
246 rotatePlayer(bl::tmap::Direction::Down);
247 state = State::Descending;
260 void Flight::movePlayer(
float dt) {
261 playerPos->transform->move(unitVelocity *
flyState.velocity * dt);
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;
Core classes and functionality for both the editor and game.
Adding this component to an entity will allow it to be rendered.
void setAngle(float angle)
Sets the angle to render the entity at.
float getMinDepth() const
Returns the maximum depth possible for this map. Maximum is always 0.f. Minimum is negative,...
const bl::tmap::Position * getSpawnPosition(unsigned int spawnId) const
Returns the position of the given player spawn, or nullptr if not found.
bool canFlyFromHere() const
Returns whether or not the player can fly from this map.
static int PixelsPerTile()
bool startFlight(unsigned int destSpawn)
Starts flight to the given spawn.
Flight(Systems &systems)
Construct a new Flight system.
bool flying() const
Returns whether or not the player is currently flying.
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.
void removePlayerControlled(bl::ecs::Entity entity)
Removes the PlayerControlled component from the given entity, if any.
bl::ecs::Entity player() const
Returns the id of the player entity.
bool makePlayerControlled(bl::ecs::Entity entity)
Makes the given entity controlled by the player. Only one entity may be player controlled at a time.
void removeShadow(bl::ecs::Entity entity)
Removes the shadow from the given entity.
void updateShadow(bl::ecs::Entity entity, float distance, float radius)
Adds or updates the shadow of the given entity.
Owns all primary systems and a reference to the engine.
const bl::engine::Engine & engine() const
Const accessor for the Engine.
Render & render()
Returns the render system.
Player & player()
Returns the player system.
HUD & hud()
Returns the HUD.
World & world()
Modifiable accessor for the world system.
map::Map & activeMap()
Returns a reference to the active map.