3232
3333namespace rigel ::game_logic {
3434
35+ namespace {
36+
3537using engine::components::Active;
3638using engine::components::BoundingBox;
39+ using engine::components::MovingBody;
3740using engine::components::Sprite;
3841using engine::components::WorldPosition;
3942using game_logic::components::ItemContainer;
4043
44+ constexpr int ITEM_BOUNCE_SEQUENCE [] = {-3 , -2 , -1 , 0 , 1 , 2 , 3 , -1 , 1 };
45+
46+
47+ struct ItemBounceEffect {
48+ explicit ItemBounceEffect (const float fallVelocity)
49+ : mFallVelocity(fallVelocity)
50+ {
51+ }
52+
53+ int mFramesElapsed = 1 ;
54+ float mFallVelocity = 0 .0f ;
55+ };
56+
57+ }
58+
4159
4260ItemContainerSystem::ItemContainerSystem (
4361 entityx::EntityManager* pEntityManager,
62+ const engine::CollisionChecker* pCollisionChecker,
4463 entityx::EventManager& events
4564)
4665 : mpEntityManager(pEntityManager)
66+ , mpCollisionChecker(pCollisionChecker)
4767{
4868 events.subscribe <events::ShootableKilled>(*this );
4969}
@@ -62,8 +82,7 @@ void ItemContainerSystem::update(entityx::EntityManager& es) {
6282 }
6383
6484 contents.assign <WorldPosition>(*entity.component <WorldPosition>());
65-
66- entity.destroy ();
85+ return contents;
6786 };
6887
6988 for (auto & entity : mShotContainersQueue ) {
@@ -72,15 +91,26 @@ void ItemContainerSystem::update(entityx::EntityManager& es) {
7291 switch (container.mStyle ) {
7392 case RS ::Default:
7493 releaseItem (entity, container.mContainedComponents );
94+ entity.destroy ();
7595 break ;
7696
7797 case RS ::ItemBox:
98+ case RS ::ItemBoxNoBounce:
7899 ++container.mFramesElapsed ;
79100
80101 if (container.mFramesElapsed == 1 ) {
81102 entity.component <Sprite>()->flashWhite ();
82103 } else if (container.mFramesElapsed == 2 ) {
83- releaseItem (entity, container.mContainedComponents );
104+ auto item = releaseItem (entity, container.mContainedComponents );
105+
106+ if (container.mStyle != RS ::ItemBoxNoBounce) {
107+ const auto fallVelocity =
108+ entity.component <MovingBody>()->mVelocity .y ;
109+ item.assign <ItemBounceEffect>(fallVelocity);
110+ item.component <WorldPosition>()->y += ITEM_BOUNCE_SEQUENCE [0 ];
111+ }
112+
113+ entity.destroy ();
84114 }
85115 break ;
86116
@@ -97,6 +127,7 @@ void ItemContainerSystem::update(entityx::EntityManager& es) {
97127 entity.component <Sprite>()->mShow = false ;
98128 } else if (container.mFramesElapsed == 4 ) {
99129 releaseItem (entity, container.mContainedComponents );
130+ entity.destroy ();
100131 }
101132 break ;
102133 }
@@ -111,6 +142,35 @@ void ItemContainerSystem::update(entityx::EntityManager& es) {
111142}
112143
113144
145+ void ItemContainerSystem::updateItemBounce (entityx::EntityManager& es) {
146+ es.each <WorldPosition, BoundingBox, MovingBody, ItemBounceEffect>(
147+ [this ](
148+ entityx::Entity entity,
149+ WorldPosition& position,
150+ const BoundingBox& bbox,
151+ MovingBody& body,
152+ ItemBounceEffect& state
153+ ) {
154+ position.y += ITEM_BOUNCE_SEQUENCE [state.mFramesElapsed ];
155+
156+ const auto hasLanded =
157+ mpCollisionChecker->isOnSolidGround (position, bbox);
158+ if (
159+ (state.mFramesElapsed == 7 && !hasLanded) ||
160+ state.mFramesElapsed == 9
161+ ) {
162+ body.mGravityAffected = true ;
163+ body.mVelocity .y = state.mFallVelocity ;
164+ }
165+
166+ ++state.mFramesElapsed ;
167+ if (state.mFramesElapsed == 9 ) {
168+ entity.remove <ItemBounceEffect>();
169+ }
170+ });
171+ }
172+
173+
114174void ItemContainerSystem::receive (const events::ShootableKilled& event) {
115175 auto entity = event.mEntity ;
116176 if (entity.has_component <ItemContainer>()) {
@@ -194,7 +254,7 @@ void NapalmBomb::explode(GlobalDependencies& d, entityx::Entity entity) {
194254 mState = NapalmBomb::State::SpawningFires;
195255 mFramesElapsed = 0 ;
196256 entity.component <Sprite>()->mShow = false ;
197- entity.remove <engine::components:: MovingBody>();
257+ entity.remove <MovingBody>();
198258 entity.remove <game_logic::components::AppearsOnRadar>();
199259
200260 // Once the bomb explodes, it counts towards bonus 6. This means we need to
0 commit comments