| 135 | } |
| 136 | |
| 137 | void UpdateBubbles() |
| 138 | { |
| 139 | constexpr auto LIFE_FULL_SCALE = std::max(BUBBLE_LIFE_MAX - 0.25f, 0.0f); |
| 140 | constexpr auto LIFE_START_FADING = std::min(1.0f, BUBBLE_LIFE_MAX); |
| 141 | constexpr int ROOM_UPDATE_INTERVAL = 10; |
| 142 | |
| 143 | if (Bubbles.empty()) |
| 144 | return; |
| 145 | |
| 146 | for (auto& bubble : Bubbles) |
| 147 | { |
| 148 | if (bubble.Life <= 0.0f) |
| 149 | continue; |
| 150 | |
| 151 | bubble.StoreInterpolationData(); |
| 152 | |
| 153 | int prevRoomNumber = bubble.RoomNumber; |
| 154 | |
| 155 | int updateOffset = (int)(bubble.Position.x + bubble.Position.y + bubble.Position.z) % ROOM_UPDATE_INTERVAL; |
| 156 | if (GlobalCounter % ROOM_UPDATE_INTERVAL == updateOffset) |
| 157 | { |
| 158 | auto roomVector = RoomVector(bubble.RoomNumber, int(bubble.Position.y - bubble.Gravity)); |
| 159 | auto testPosition = Vector3i(bubble.Position.x, bubble.Position.y - bubble.Gravity, bubble.Position.z); |
| 160 | bubble.RoomNumber = GetRoomVector(roomVector, testPosition).RoomNumber;; |
| 161 | } |
| 162 | |
| 163 | // Out of water. |
| 164 | if (bubble.RoomNumber != prevRoomNumber && !TestEnvironment(ENV_FLAG_WATER, bubble.RoomNumber)) |
| 165 | { |
| 166 | // Hit water surface; spawn ripple. |
| 167 | SpawnRipple( |
| 168 | Vector3(bubble.Position.x, g_Level.Rooms[prevRoomNumber].TopHeight, bubble.Position.z), |
| 169 | bubble.RoomNumber, |
| 170 | ((bubble.SizeMax.x + bubble.SizeMax.y) / 2) * 0.5f, |
| 171 | (int)RippleFlags::SlowFade); |
| 172 | |
| 173 | bubble.Life = 0.0f; |
| 174 | continue; |
| 175 | } |
| 176 | // Hit ceiling. NOTE: This is a hacky check. New collision fetching should provide fast info on a need-to-know basis. |
| 177 | else if (bubble.RoomNumber == prevRoomNumber && bubble.Position.y <= g_Level.Rooms[prevRoomNumber].TopHeight) |
| 178 | { |
| 179 | bubble.Life = 0.0f; |
| 180 | continue; |
| 181 | } |
| 182 | |
| 183 | // Oscillate size according to period. |
| 184 | bubble.OscillationPeriod += bubble.OscillationVelocity; |
| 185 | bubble.Size = Vector2( |
| 186 | (bubble.SizeMin.x / 2) + ((bubble.SizeMax.x - bubble.SizeMin.x) * (0.5f + (0.5f * sin(bubble.OscillationPeriod)))), |
| 187 | (bubble.SizeMin.y / 2) + ((bubble.SizeMax.y - bubble.SizeMin.y) * (0.5f + (0.5f * cos(bubble.OscillationPeriod + 1.0f))))); |
| 188 | bubble.Size *= Lerp(0.0f, 1.0f, bubble.Life / std::round(LIFE_FULL_SCALE * FPS)); |
| 189 | |
| 190 | // Update opacity. |
| 191 | float alpha = 1.0f - (bubble.Life / std::round(LIFE_START_FADING * FPS)); |
| 192 | float opacity = Lerp(bubble.OpacityStart, 0.0f, alpha); |
| 193 | bubble.Color.w = opacity; |
| 194 |
no test coverage detected