using System; using Content.Shared.GameObjects.Components.Mobs; using SS14.Client.GameObjects; using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.Interfaces.Network; using SS14.Shared.Maths; namespace Content.Client.GameObjects.Components.Mobs { public sealed class CameraRecoilComponent : SharedCameraRecoilComponent { // Maximum rate of magnitude restore towards 0 kick. private const float RestoreRateMax = 1.5f; // Minimum rate of magnitude restore towards 0 kick. private const float RestoreRateMin = 0.5f; // Time in seconds since the last kick that lerps RestoreRateMin and RestoreRateMax private const float RestoreRateRamp = 0.05f; // The maximum magnitude of the kick applied to the camera at any point. private const float KickMagnitudeMax = 0.25f; private Vector2 _currentKick; private float _lastKickTime; private EyeComponent _eye; public override void Initialize() { base.Initialize(); _eye = Owner.GetComponent(); } public override void Kick(Vector2 recoil) { // Use really bad math to "dampen" kicks when we're already kicked. var existing = _currentKick.Length; var dampen = existing/KickMagnitudeMax; _currentKick += recoil * (1-dampen); if (_currentKick.Length > KickMagnitudeMax) { _currentKick = _currentKick.Normalized * KickMagnitudeMax; } _lastKickTime = 0; _updateEye(); } public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null) { base.HandleMessage(message, netChannel, component); switch (message) { case RecoilKickMessage msg: Kick(msg.Recoil); break; } } public void FrameUpdate(float frameTime) { var magnitude = _currentKick.Length; if (magnitude <= 0.005f) { _currentKick = Vector2.Zero; _updateEye(); return; } // Continually restore camera to 0. var normalized = _currentKick.Normalized; var restoreRate = FloatMath.Lerp(RestoreRateMin, RestoreRateMax, Math.Min(1, _lastKickTime/RestoreRateRamp)); var restore = normalized * restoreRate * frameTime; _currentKick -= restore; _updateEye(); } private void _updateEye() { _eye.Offset = _currentKick; } } }