/// <summary> /// Springs a Vector3 towards a target value /// </summary> /// <param name="currentValue">the current value to spring, passed as a ref</param> /// <param name="targetValue">the target value we're aiming for</param> /// <param name="velocity">a velocity value, passed as ref, used to compute the current speed of the springed value</param> /// <param name="damping">the damping, between 0.01f and 1f, the higher the daming, the less springy it'll be</param> /// <param name="frequency">the frequency, in Hz, so the amount of periods the spring should go over in 1 second</param> /// <param name="speed">the speed (between 0 and 1) at which the spring should operate</param> /// <param name="deltaTime">the delta time (usually Time.deltaTime or Time.unscaledDeltaTime)</param> public static void Spring(ref Vector3 currentValue, Vector3 targetValue, ref Vector3 velocity, float damping, float frequency, float speed, float deltaTime) { Vector3 initialVelocity = velocity; velocity.x = SpringVelocity(currentValue.x, targetValue.x, velocity.x, damping, frequency, speed, deltaTime); velocity.y = SpringVelocity(currentValue.y, targetValue.y, velocity.y, damping, frequency, speed, deltaTime); velocity.z = SpringVelocity(currentValue.z, targetValue.z, velocity.z, damping, frequency, speed, deltaTime); velocity.x = MMMaths.Lerp(initialVelocity.x, velocity.x, speed, Time.deltaTime); velocity.y = MMMaths.Lerp(initialVelocity.y, velocity.y, speed, Time.deltaTime); velocity.z = MMMaths.Lerp(initialVelocity.z, velocity.z, speed, Time.deltaTime); currentValue += deltaTime * velocity; }
/// <summary> /// Rotates the camera around the object /// </summary> protected virtual void Rotation() { if (!RotationEnabled) { return; } if (Mode == Modes.Touch && (Input.touchCount > 0)) { if ((Input.touches[0].phase == TouchPhase.Moved) && (Input.touchCount == 1)) { float screenHeight = Screen.currentResolution.height; if (Input.touches[0].position.y < screenHeight / 4) { return; } float swipeSpeed = Input.touches[0].deltaPosition.magnitude / Input.touches[0].deltaTime; _angleX += Input.touches[0].deltaPosition.x * RotationSpeed.x * Time.deltaTime * swipeSpeed * 0.00001f; _angleY -= Input.touches[0].deltaPosition.y * RotationSpeed.y * Time.deltaTime * swipeSpeed * 0.00001f; _stepBuffer += Input.touches[0].deltaPosition.x; _angleY = MMMaths.ClampAngle(_angleY, MinVerticalAngleLimit, MaxVerticalAngleLimit); _desiredRotation = Quaternion.Euler(_angleY, _angleX, 0); _currentRotation = transform.rotation; _rotation = Quaternion.Lerp(_currentRotation, _desiredRotation, Time.deltaTime * ZoomDampening); transform.rotation = _rotation; } else if (Input.touchCount == 1 && Input.touches[0].phase == TouchPhase.Began) { _desiredRotation = transform.rotation; } if (transform.rotation != _desiredRotation) { _rotation = Quaternion.Lerp(transform.rotation, _desiredRotation, Time.deltaTime * ZoomDampening); transform.rotation = _rotation; } } else if (Mode == Modes.Mouse) { _angleX += Input.GetAxis("Mouse X") * RotationSpeed.x * Time.deltaTime; _angleY += -Input.GetAxis("Mouse Y") * RotationSpeed.y * Time.deltaTime; _angleY = Mathf.Clamp(_angleY, MinVerticalAngleLimit, MaxVerticalAngleLimit); _desiredRotation = Quaternion.Euler(new Vector3(_angleY, _angleX, 0)); _currentRotation = transform.rotation; _rotation = Quaternion.Lerp(_currentRotation, _desiredRotation, Time.deltaTime * ZoomDampening); transform.rotation = _rotation; } }
/// <summary> /// Updates the bar's values based on the specified parameters /// </summary> /// <param name="currentValue">Current value.</param> /// <param name="minValue">Minimum value.</param> /// <param name="maxValue">Max value.</param> public virtual void UpdateBar(float currentValue, float minValue, float maxValue) { _newPercent = MMMaths.Remap(currentValue, minValue, maxValue, StartValue, EndValue); if ((_newPercent != BarProgress) && !Bumping) { Bump(); } BarProgress = _newPercent; _targetFill = _newPercent; _lastUpdateTimestamp = (TimeScale == TimeScales.Time) ? Time.time : Time.unscaledTime; _lastPercent = _newPercent; }
/// <summary> /// Sets the specified level /// </summary> /// <param name="receiver"></param> /// <param name="property"></param> /// <param name="level"></param> public override void SetLevel(MMPropertyReceiver receiver, MMProperty property, float level) { base.SetLevel(receiver, property, level); _newValue = (int)MMMaths.Remap(level, 0f, 1f, receiver.IntRemapZero, receiver.IntRemapOne); if (receiver.RelativeValue) { _newValue = _initialValue + _newValue; } SetValueOptimized(property, _newValue); }
/// <summary> /// Follows the target, lerping the position or not based on what's been defined in the inspector /// </summary> protected virtual void FollowTargetPosition() { if (Target == null) { return; } if (!FollowPosition) { return; } _newTargetPosition = Target.position + Offset; if (!FollowPositionX) { _newTargetPosition.x = _initialPosition.x; } if (!FollowPositionY) { _newTargetPosition.y = _initialPosition.y; } if (!FollowPositionZ) { _newTargetPosition.z = _initialPosition.z; } float trueDistance = 0f; _direction = (_newTargetPosition - this.transform.position).normalized; trueDistance = Vector3.Distance(this.transform.position, _newTargetPosition); float interpolatedDistance = trueDistance; if (InterpolatePosition) { interpolatedDistance = MMMaths.Lerp(0f, trueDistance, FollowPositionSpeed); } if (UseMinimumDistanceBeforeFollow && (trueDistance - interpolatedDistance < MinimumDistanceBeforeFollow)) { interpolatedDistance = 0f; } if (UseMaximumDistance && (trueDistance - interpolatedDistance >= MaximumDistance)) { interpolatedDistance = trueDistance - MaximumDistance; } this.transform.Translate(_direction * interpolatedDistance, Space.World); }
RaycastData RaycastAtAngle(float angle) { Vector3 direction = MMMaths.DirectionFromAngle(angle, 0f); RaycastHit hit; if (Physics.Raycast(Center, direction, out hit, VisionRadius, ObstacleMask)) { return(new RaycastData(true, hit.point, hit.distance, angle)); } else { return(new RaycastData(false, Center + direction * VisionRadius, VisionRadius, angle)); } }
RaycastData RaycastAtAngle(float angle) { Vector3 direction = MMMaths.DirectionFromAngle2D(angle, 0f); RaycastHit2D hit2D = Physics2D.Raycast(this.transform.position, direction, VisionRadius, ObstacleMask); if (hit2D) { return(new RaycastData(true, hit2D.point, hit2D.distance, angle)); } else { return(new RaycastData(false, this.transform.position + direction * VisionRadius, VisionRadius, angle)); } }
/// <summary> /// Sets the level /// </summary> /// <param name="receiver"></param> /// <param name="property"></param> /// <param name="level"></param> public override void SetLevel(MMPropertyReceiver receiver, MMProperty property, float level) { base.SetLevel(receiver, property, level); _newValue.x = receiver.ModifyX ? MMMaths.Remap(level, 0f, 1f, receiver.Vector3RemapZero.x, receiver.Vector3RemapOne.x) : 0f; _newValue.y = receiver.ModifyY ? MMMaths.Remap(level, 0f, 1f, receiver.Vector3RemapZero.y, receiver.Vector3RemapOne.y) : 0f; _newValue.z = receiver.ModifyZ ? MMMaths.Remap(level, 0f, 1f, receiver.Vector3RemapZero.z, receiver.Vector3RemapOne.z) : 0f; if (receiver.RelativeValue) { _newValue = _initialValue + _newValue; } SetValueOptimized(property, _newValue); }
/// <summary> /// Call this method to update the fill amount based on a currentValue between minValue and maxValue /// </summary> /// <param name="currentValue">Current value.</param> /// <param name="minValue">Minimum value.</param> /// <param name="maxValue">Max value.</param> public virtual void UpdateBar(float currentValue, float minValue, float maxValue) { _newPercent = MMMaths.Remap(currentValue, minValue, maxValue, StartValue, EndValue); if (_radialImage == null) { return; } _radialImage.fillAmount = _newPercent; if (_radialImage.fillAmount > 1 - Tolerance) { _radialImage.fillAmount = 1; } if (_radialImage.fillAmount < Tolerance) { _radialImage.fillAmount = 0; } }
/// <summary> /// Computes the current aim direction /// </summary> public virtual Vector2 GetCurrentAim() { switch (AimControl) { case AimControls.Off: _currentAim = Vector2.zero; break; case AimControls.Script: break; case AimControls.PrimaryMovement: _currentAim = PrimaryMovement; break; case AimControls.SecondaryMovement: _currentAim = SecondaryMovement; break; case AimControls.Mouse: _mousePosition = Input.mousePosition; _mousePosition.z = 10; _direction = _mainCamera.ScreenToWorldPoint(_mousePosition); _direction.z = CurrentPosition.z; _currentAim = _direction - CurrentPosition; break; default: _currentAim = Vector2.zero; break; } float currentAngle = Mathf.Atan2(_currentAim.y, _currentAim.x) * Mathf.Rad2Deg; if (RotationMode == RotationModes.Strict4Directions || RotationMode == RotationModes.Strict8Directions) { currentAngle = MMMaths.RoundToClosest(currentAngle, _possibleAngleValues); } CurrentAngle = Mathf.Clamp(CurrentAngle, MinimumAngle, MaximumAngle); _currentAim = (_currentAim.magnitude == 0f) ? Vector2.zero : MMMaths.RotateVector2(Vector2.right, currentAngle); return(_currentAim); }
/// <summary> /// Handles the text's life cycle, movement, scale, color, opacity, alignment and billboard /// </summary> protected virtual void UpdateFloatingText() { _elapsedTime = GetTime() - _startedAt; _remappedTime = MMMaths.Remap(_elapsedTime, 0f, _lifetime, 0f, 1f); // lifetime if (_elapsedTime > _lifetime) { TurnOff(); } HandleMovement(); HandleColor(); HandleOpacity(); HandleScale(); HandleAlignment(); HandleBillboard(); }
/// <summary> /// Moves cameras around based on gyro input /// </summary> protected virtual void MoveCameras() { foreach (MMGyroCam cam in Cams) { float newX = MMMaths.Remap(LerpedCalibratedGyroscopeGravity.x, 0.5f, -0.5f, cam.MinRotation.x, cam.MaxRotation.x); float newY = MMMaths.Remap(LerpedCalibratedGyroscopeGravity.y, 0.5f, -0.5f, cam.MinRotation.y, cam.MaxRotation.y); _newAngles = cam.InitialAngles; _newAngles.x += newX; _newAngles.z += newY; cam.Cam.transform.position = cam.InitialPosition; cam.Cam.transform.localEulerAngles = cam.InitialAngles; cam.Cam.transform.RotateAround(cam.RotationCenter.transform.position, cam.RotationCenter.transform.up, _newAngles.x); cam.Cam.transform.RotateAround(cam.RotationCenter.transform.position, cam.RotationCenter.transform.right, _newAngles.z); cam.Cam.transform.LookAt(cam.RotationCenter.transform); } }
/// <summary> /// On Shake, we shake our level if needed /// </summary> protected override void Shake() { base.Shake(); if (!Playing) { return; } if (SignalMode == SignalModes.OneTime) { float elapsedTime = TimescaleTime - _shakeStartedTimestamp; CurrentLevel = Evaluate(MMMaths.Remap(elapsedTime, 0f, Duration, 0f, 1f)); } else { CurrentLevel = Evaluate(DriverTime); } }
/// <summary> /// Spawns a random object from the pool of choices /// </summary> public virtual void InstantiateRandomObject() { // if the pool is empty we do nothing and exit if (RandomPool.Count == 0) { return; } // pick a random object and instantiates it int randomIndex = Random.Range(0, RandomPool.Count); GameObject obj = Instantiate(RandomPool[randomIndex], this.transform.position, this.transform.rotation); SceneManager.MoveGameObjectToScene(obj.gameObject, this.gameObject.scene); // we pick a random point within the bounds then move it to account for rotation/scale obj.transform.position = MMBoundsExtensions.MMRandomPointInBounds(_collider.bounds); obj.transform.position = _collider.ClosestPoint(obj.transform.position); // we name and parent our object obj.name = InstantiatedObjectName; if (ParentInstantiatedToThisObject) { obj.transform.SetParent(this.transform); } // we rescale the object switch (ScaleMode) { case ScaleModes.Uniform: float newScale = Random.Range(MinScale, MaxScale); obj.transform.localScale = Vector3.one * newScale; break; case ScaleModes.Vector3: _newScale = MMMaths.RandomVector3(MinVectorScale, MaxVectorScale); obj.transform.localScale = _newScale; break; } // we add it to our list _instantiatedGameObjects.Add(obj); }
protected virtual void ComputeVelocityAndDirection() { Velocity = Vector3.zero; if (Mode == Modes.Rigidbody) { Velocity = _rigidbody.velocity; } if (Mode == Modes.Rigidbody2D) { Velocity = _rigidbody.velocity; } if (Mode == Modes.Position) { Velocity = (_previousPosition - this.transform.position); } VelocityMagnitude = Velocity.magnitude; RemappedVelocity = MMMaths.Remap(VelocityMagnitude, 0f, MaximumVelocity, 0f, 1f); _direction = Vector3.Normalize(Velocity); }
/// <summary> /// Triggers the bound pointer up action /// </summary> public virtual void OnPointerUp(PointerEventData data) { _destination = Input.mousePosition; _deltaSwipe = _destination - _firstTouchPosition; _length = _deltaSwipe.magnitude; // if the swipe has been long enough if (_length > MinimalSwipeLength) { _angle = MMMaths.AngleBetween(_deltaSwipe, Vector2.right); _swipeDirection = AngleToSwipeDirection(_angle); Swipe(); } // if it's just a press if (_deltaSwipe.magnitude < MaximumPressLength) { Press(); } }
/// <summary> /// Sends progress value via UnityEvents /// </summary> protected virtual void UpdateProgress() { if (!_setRealtimeProgressValueIsNull) { SetRealtimeProgressValue.Invoke(_loadProgress); } if (_interpolateProgress) { _interpolatedLoadProgress = MMMaths.Approach(_interpolatedLoadProgress, _loadProgress, Time.unscaledDeltaTime * _progressInterpolationSpeed); if (!_setInterpolatedProgressValueIsNull) { SetInterpolatedProgressValue.Invoke(_interpolatedLoadProgress); } } else { SetInterpolatedProgressValue.Invoke(_loadProgress); } }
/// <summary> /// Determines the current velocity and direction of the parent object /// </summary> protected virtual void ComputeVelocityAndDirection() { Velocity = Vector3.zero; switch (Mode) { case Modes.Rigidbody: Velocity = _rigidbody.velocity; break; case Modes.Rigidbody2D: Velocity = _rigidbody2D.velocity; break; case Modes.Position: Velocity = (_previousPosition - _parentTransform.position) / TimescaleDeltaTime; break; } VelocityMagnitude = Velocity.magnitude; RemappedVelocity = MMMaths.Remap(VelocityMagnitude, 0f, MaximumVelocity, 0f, 1f); _direction = Vector3.Normalize(Velocity); if (AutoSquashOnStop) { // if we've moved fast enough and have now stopped, we trigger a squash if (VelocityMagnitude > SquashVelocityThreshold) { _movementStarted = true; _lastVelocity = Mathf.Clamp(VelocityMagnitude, 0f, MaximumVelocity); } else if (_movementStarted) { _movementStarted = false; _squashing = true; float duration = MMMaths.Remap(_lastVelocity, 0f, MaximumVelocity, SquashDuration.x, SquashDuration.y); float intensity = MMMaths.Remap(_lastVelocity, 0f, MaximumVelocity, SquashIntensity.x, SquashIntensity.y); Squash(duration, intensity); } } }
/// <summary> /// Moves the text along the specified curves /// </summary> protected virtual void HandleMovement() { // position movement if (_animateMovement) { this.transform.up = Direction; _newPosition.x = _animateX ? MMMaths.Remap(_animateXCurve.Evaluate(_remappedTime), 0f, 1, _remapXZero, _remapXOne) : 0f; _newPosition.y = _animateY ? MMMaths.Remap(_animateYCurve.Evaluate(_remappedTime), 0f, 1, _remapYZero, _remapYOne) : 0f; _newPosition.z = _animateZ ? MMMaths.Remap(_animateZCurve.Evaluate(_remappedTime), 0f, 1, _remapZZero, _remapZOne) : 0f; // we move the moving part MovingPart.transform.localPosition = _newPosition; // we store the last position if (Vector3.Distance(_movingPartPositionLastFrame, MovingPart.position) > 0.5f) { _movingPartPositionLastFrame = MovingPart.position; } } }
/// <summary> /// Sets the specified level /// </summary> /// <param name="receiver"></param> /// <param name="property"></param> /// <param name="level"></param> public override void SetLevel(MMPropertyReceiver receiver, MMProperty property, float level) { base.SetLevel(receiver, property, level); _newValue.x = receiver.ModifyX ? MMMaths.Remap(level, 0f, 1f, receiver.Vector2RemapZero.x, receiver.Vector2RemapOne.x) : 0f; _newValue.y = receiver.ModifyY ? MMMaths.Remap(level, 0f, 1f, receiver.Vector2RemapZero.y, receiver.Vector2RemapOne.y) : 0f; if (receiver.RelativeValue) { _newValue = _initialValue + _newValue; } if (_getterSetterInitialized) { SetVector2Delegate(_newValue); } else { SetPropertyValue(property, _newValue); } }
protected virtual void OnSceneGUI() { // draws a circle around the character to represent the cone of vision's radius _coneOfVision = (MMConeOfVision2D)target; Handles.color = Color.yellow; Handles.DrawWireArc(_coneOfVision.transform.position, -Vector3.forward, Vector3.up, 360f, _coneOfVision.VisionRadius); // draws two lines to mark the vision angle Vector3 visionAngleLeft = MMMaths.DirectionFromAngle2D(-_coneOfVision.VisionAngle / 2f, _coneOfVision.EulerAngles.y); Vector3 visionAngleRight = MMMaths.DirectionFromAngle2D(_coneOfVision.VisionAngle / 2f, _coneOfVision.EulerAngles.y); Handles.DrawLine(_coneOfVision.transform.position, _coneOfVision.transform.position + visionAngleLeft * _coneOfVision.VisionRadius); Handles.DrawLine(_coneOfVision.transform.position, _coneOfVision.transform.position + visionAngleRight * _coneOfVision.VisionRadius); foreach (Transform visibleTarget in _coneOfVision.VisibleTargets) { Handles.color = Colors.Orange; Handles.DrawLine(_coneOfVision.transform.position, visibleTarget.position); } }
RaycastData RaycastAtAngle(float angle) { _direction = MMMaths.DirectionFromAngle(angle, 0f); if (Physics.Raycast(Center, _direction, out _raycastAtAngleHit, VisionRadius, ObstacleMask)) { _returnRaycastData.Hit = true; _returnRaycastData.Point = _raycastAtAngleHit.point; _returnRaycastData.Distance = _raycastAtAngleHit.distance; _returnRaycastData.Angle = angle; } else { _returnRaycastData.Hit = false; _returnRaycastData.Point = Center + _direction * VisionRadius; _returnRaycastData.Distance = VisionRadius; _returnRaycastData.Angle = angle; } return(_returnRaycastData); }
/// <summary> /// On Update, we shake our values if needed, or reset if our shake has ended /// </summary> protected virtual void Update() { ProcessUpdate(); if (SignalMode == SignalModes.Driven) { ProcessDrivenMode(); } else if (SignalMode == SignalModes.Persistent) { _signalTime += TimescaleDeltaTime; if (_signalTime > Duration) { _signalTime = 0f; } DriverTime = MMMaths.Remap(_signalTime, 0f, Duration, 0f, 1f); } else if (SignalMode == SignalModes.OneTime) { } if (Playing || (SignalMode == SignalModes.Driven)) { Shake(); } if ((SignalMode == SignalModes.OneTime) && Playing && (TimescaleTime - _shakeStartedTimestamp > Duration)) { ShakeComplete(); } if ((_levelLastFrame != Level) && (OnValueChange != null)) { OnValueChange.Invoke(Level); } _levelLastFrame = Level; }
/// <summary> /// Invoked when the slider value changes /// </summary> public void ValueChangeCheck() { bool valueChanged = true; SliderValue = MMMaths.Remap(TargetSlider.value, 0f, 1f, RemapZero, RemapOne); if (Mode == Modes.Int) { SliderValue = Mathf.Round(SliderValue); if (SliderValue == SliderValueInt) { valueChanged = false; } SliderValueInt = (int)SliderValue; } if (valueChanged) { SliderValueText.text = (Mode == Modes.Int) ? SliderValue.ToString() : SliderValue.ToString("F3"); TriggerSliderEvent(SliderValue); } }
protected virtual float ComputeNewFill(bool lerpBar, float barSpeed, float barDuration, AnimationCurve barCurve, float delay, float lastPercent, out float t) { float newFill = 0f; t = 0f; if (lerpBar) { float delta = 0f; float timeSpent = _time - _lastUpdateTimestamp - delay; float speed = barSpeed; if (speed == 0f) { speed = 1f; } float duration = (BarFillMode == BarFillModes.FixedDuration) ? barDuration : (Mathf.Abs(_newPercent - lastPercent)) / speed; delta = MMMaths.Remap(timeSpent, 0f, duration, 0f, 1f); delta = Mathf.Clamp(delta, 0f, 1f); t = delta; if (t < 1f) { delta = barCurve.Evaluate(delta); newFill = Mathf.LerpUnclamped(lastPercent, _newPercent, delta); } else { newFill = _newPercent; } } else { newFill = _newPercent; } newFill = Mathf.Clamp(newFill, 0f, 1f); return(newFill); }
/// <summary> /// Applies a bias to a time value /// </summary> /// <param name="t"></param> /// <param name="bias"></param> /// <returns></returns> public virtual float ApplyBias(float t, float bias) { if (bias == 0.5f) { return(t); } bias = MMMaths.Remap(bias, 0f, 1f, 1f, 0f); float a = bias * 2.0f - 1.0f; if (a < 0) { t = 1 - Mathf.Pow(1.0f - t, Mathf.Max(1 + a, .01f)); } else { t = Mathf.Pow(t, Mathf.Max(1 - a, .01f)); } return(t); }
RaycastData RaycastAtAngle(float angle) { _direction = MMMaths.DirectionFromAngle2D(angle, 0f); _raycastAtAngleHit2D = Physics2D.Raycast(this.transform.position, _direction, VisionRadius, ObstacleMask); if (_raycastAtAngleHit2D) { _returnRaycastData.Hit = true; _returnRaycastData.Point = _raycastAtAngleHit2D.point; _returnRaycastData.Distance = _raycastAtAngleHit2D.distance; _returnRaycastData.Angle = angle; } else { _returnRaycastData.Hit = false; _returnRaycastData.Point = this.transform.position + _direction * VisionRadius; _returnRaycastData.Distance = VisionRadius; _returnRaycastData.Angle = angle; } return(_returnRaycastData); }
/// <summary> /// Makes the object follow its target's rotation /// </summary> protected virtual void FollowTargetRotation() { if (Target == null) { return; } if (!FollowRotation) { return; } _newTargetRotation = Target.rotation; if (InterpolateRotation) { this.transform.rotation = MMMaths.Lerp(this.transform.rotation, _newTargetRotation, FollowRotationSpeed); } else { this.transform.rotation = _newTargetRotation; } }
/// <summary> /// Sets the bar value to the normalized value set in parameter /// </summary> /// <param name="newPercent"></param> public virtual void SetBar01(float newPercent) { if (!_initialized) { Initialization(); } newPercent = MMMaths.Remap(newPercent, 0f, 1f, MinimumBarFillValue, MaximumBarFillValue); BarProgress = newPercent; DelayedBarDecreasingProgress = newPercent; DelayedBarIncreasingProgress = newPercent; //_newPercent = newPercent; BarTarget = newPercent; _percentLastTimeBarWasUpdated = newPercent; _delayedBarDecreasingProgress = DelayedBarDecreasingProgress; _delayedBarIncreasingProgress = DelayedBarIncreasingProgress; SetBarInternal(newPercent, ForegroundBar, _foregroundImage, _initialBarSize); SetBarInternal(newPercent, DelayedBarDecreasing, _delayedDecreasingImage, _initialBarSize); SetBarInternal(newPercent, DelayedBarIncreasing, _delayedIncreasingImage, _initialBarSize); UpdateText(); _coroutineShouldRun = false; CurrentState = MMProgressBarStates.Idle; }
/// <summary> /// Fades an audiosource in or out, optionnally stopping it at the end /// </summary> /// <param name="source"></param> /// <param name="duration"></param> /// <param name="initialVolume"></param> /// <param name="endVolume"></param> /// <param name="stopAtTheEnd"></param> /// <returns></returns> protected virtual IEnumerator Fade(int index, float duration, float initialVolume, float endVolume, bool stopAtTheEnd) { float startTimestamp = Time.time; float progress = 0f; Songs[index].Fading = true; while ((Time.time - startTimestamp < duration) && (Songs[index].Fading)) { progress = MMMaths.Remap(Time.time - startTimestamp, 0f, duration, 0f, 1f); Songs[index].TargetAudioSource.volume = Mathf.Lerp(initialVolume, endVolume, progress); yield return(null); } Songs[index].TargetAudioSource.volume = endVolume; if (stopAtTheEnd) { Songs[index].TargetAudioSource.Stop(); Songs[index].Playing = false; Songs[index].Fading = false; } }