예제 #1
0
        /// <summary>
        /// Registers a calculated axis from a button. The axis' value changes between 0 and 1 as the user hits the button or releases it.
        /// The time it takes to change the value can be set.
        /// </summary>
        /// <param name="origButtonId">The original button identifier.</param>
        /// <param name="direction">The direction the new axis is heading towards.</param>
        /// <param name="rampUpTime">The time it takes to change the value from 0 to 1 (in seconds).</param>
        /// <param name="rampDownTime">The time it takes to change the value from 1 to 0 (in seconds).</param>
        /// <param name="buttonAxisId">The new identifier of the button axis. Note this value must be bigger than all existing axis Ids. Leave this value
        /// zero to have a new identifier calculated automatically.</param>
        /// <param name="name">The name of the new axis.</param>
        /// <returns>The axis description of the newly created calculated axis.</returns>
        /// <remarks>
        ///   Button axes are useful to simulate a trigger or thrust panel with the help of individual buttons. There is a user-defineable acceleration and
        ///   deceleration period, so a simulation resulting on this input delivers a feeling of inertance.
        /// </remarks>
        public AxisDescription RegisterSingleButtonAxis(int origButtonId, AxisDirection direction = AxisDirection.Unknown, float rampUpTime = 0.2f, float rampDownTime = 0.2f, int buttonAxisId = 0, string name = null)
        {
            ButtonDescription origButtonDesc;

            if (!_buttons.TryGetValue(origButtonId, out origButtonDesc))
            {
                throw new InvalidOperationException($"Button Id {origButtonId} is not known. Cannot register button axis based on unknown button.");
            }

            // Ramp cannot be 90° as this would require special case handling
            if (rampUpTime <= float.MinValue)
            {
                rampUpTime = 2 * float.MinValue;
            }
            if (rampDownTime <= float.MinValue)
            {
                rampDownTime = 2 * float.MinValue;
            }

            bool  closureLastBtnState      = GetButton(origButtonId);
            float closureLastAxisValue     = 0;
            float closureAnimDirection     = 0;
            AxisValueCalculator calculator = delegate(float deltaTime)
            {
                float ret;
                bool  newBtnState = GetButton(origButtonId);
                if (newBtnState != closureLastBtnState)
                {
                    // The state of the button has changed
                    closureAnimDirection = (newBtnState ? 0 : 1) - (closureLastBtnState ? 0 : 1);
                    closureLastBtnState  = newBtnState;
                }

                if (closureAnimDirection > 0)
                {
                    ret = closureLastAxisValue + deltaTime / rampUpTime;
                    if (ret >= 1)
                    {
                        closureAnimDirection = 0;
                        ret = 1;
                    }
                }
                else if (closureAnimDirection < 0)
                {
                    ret = closureLastAxisValue - deltaTime / rampDownTime;
                    if (ret < 0)
                    {
                        closureAnimDirection = 0;
                        ret = 0;
                    }
                }
                else
                {
                    ret = closureLastAxisValue;
                }

                closureLastAxisValue = ret;
                return(ret);
            };

            int id = _nextAxisId + 1;

            if (buttonAxisId > id)
            {
                id = buttonAxisId;
            }

            var calculatedAxisDesc = new AxisDescription
            {
                Id = id, Name = name ?? $"{origButtonDesc.Name} Axis", Bounded = AxisBoundedType.Constant, Direction = direction, Nature = AxisNature.Speed, MaxValueOrAxis = 1.0f, MinValueOrAxis = 0.0f
            };

            RegisterCalculatedAxis(calculatedAxisDesc, calculator);
            return(calculatedAxisDesc);
        }
예제 #2
0
        /// <summary>
        /// Registers a calculated axis from two buttons. The axis' value changes between -1 and 1 as the user hits the button or releases it.
        /// The time it takes to change the value can be set.
        /// </summary>
        /// <param name="origButtonIdNegative">The original button identifier for negative movements.</param>
        /// <param name="origButtonIdPositive">The original button identifier for positive movements.</param>
        /// <param name="direction">The direction the new axis is heading towards.</param>
        /// <param name="rampUpTime">The time it takes to change the value from 0 to 1 (or -1) (in seconds) when one of the buttons is pushed.</param>
        /// <param name="rampDownTime">The time it takes to change the value from -1 of 1 back to 0 (in seconds) when a pushed button is released.</param>
        /// <param name="buttonAxisId">The new identifier of the button axis. Note this value must be bigger than all existing axis Ids. Leave this value
        /// zero to have a new identifier calculated automatically.</param>
        /// <param name="name">The name of the new axis.</param>
        /// <returns>
        /// The axis description of the newly created calculated axis.
        /// </returns>
        /// <remarks>
        /// Button axes are useful to simulate one axis of a joypad or a joystick with the help of two individual buttons. One button acts as pushing the
        /// joystick into the positve direction along the given axis by animating the axis' value to 1 and the a second button acts as pushing the joystick
        /// into the negative direction by animating the value to -1. Releasing both buttons will animate the value to 0. Pushing both buttons simultaneously
        /// will stop the animation and keep the value at its current amount.
        /// There is a user-defineable acceleration and deceleration period, so a simulation resulting on this input delivers a feeling of inertance.
        /// </remarks>
        public AxisDescription RegisterTwoButtonAxis(int origButtonIdNegative, int origButtonIdPositive, AxisDirection direction = AxisDirection.Unknown, float rampUpTime = 0.15f, float rampDownTime = 0.35f, int buttonAxisId = 0, string name = null)
        {
            ButtonDescription origButtonDescPos;

            if (!_buttons.TryGetValue(origButtonIdPositive, out origButtonDescPos))
            {
                throw new InvalidOperationException($"Button Id {origButtonIdPositive} is not known. Cannot register button axis based on unknown button.");
            }

            ButtonDescription origButtonDescNeg;

            if (!_buttons.TryGetValue(origButtonIdNegative, out origButtonDescNeg))
            {
                throw new InvalidOperationException($"Button Id {origButtonIdNegative} is not known. Cannot register button axis based on unknown button.");
            }


            // Ramp cannot be 90° as this would require special case handling
            if (rampUpTime <= float.MinValue)
            {
                rampUpTime = 2 * float.MinValue;
            }
            if (rampDownTime <= float.MinValue)
            {
                rampDownTime = 2 * float.MinValue;
            }


            bool  closureLastBtnStatePos   = GetButton(origButtonIdPositive);
            bool  closureLastBtnStateNeg   = GetButton(origButtonIdNegative);
            float closureLastAxisValue     = 0;
            float closureAnimDirection     = 0;
            AxisValueCalculator calculator = delegate(float deltaTime)
            {
                float ret;
                bool  newBtnStatePos = GetButton(origButtonIdPositive);
                if (newBtnStatePos != closureLastBtnStatePos)
                {
                    // The state of the button has changed
                    closureAnimDirection   = (newBtnStatePos ? 1 : 0) - (closureLastBtnStatePos ? 1 : 0);
                    closureLastBtnStatePos = newBtnStatePos;
                }

                bool newBtnStateNeg = GetButton(origButtonIdNegative);
                if (newBtnStateNeg != closureLastBtnStateNeg)
                {
                    // The state of the button has changed
                    closureAnimDirection   = -((newBtnStateNeg ? 1 : 0) - (closureLastBtnStateNeg ? 1 : 0));
                    closureLastBtnStateNeg = newBtnStateNeg;
                }

                // No button pressed: Goal is 0 (middle) and speed is rampdown
                var animGoal = 0.0f;
                var animTime = rampDownTime;
                if (newBtnStatePos || newBtnStateNeg)
                {
                    // Some button pressed: Goal is -1 or 1 and speed is rampup
                    animGoal = closureAnimDirection;
                    animTime = rampUpTime;
                }

                if (closureAnimDirection > 0)
                {
                    ret = closureLastAxisValue + deltaTime / animTime;
                    if (ret >= animGoal)
                    {
                        closureAnimDirection = 0;
                        ret = animGoal;
                    }
                }
                else if (closureAnimDirection < 0)
                {
                    ret = closureLastAxisValue - deltaTime / animTime;
                    if (ret <= animGoal)
                    {
                        closureAnimDirection = 0;
                        ret = animGoal;
                    }
                }
                else
                {
                    ret = closureLastAxisValue;
                }

                closureLastAxisValue = ret;
                return(ret);
            };

            int id = _nextAxisId + 1;

            if (buttonAxisId > id)
            {
                id = buttonAxisId;
            }

            var calculatedAxisDesc = new AxisDescription
            {
                Id = id, Name = name ?? $"{origButtonDescPos.Name} {origButtonDescNeg.Name} Axis", Bounded = AxisBoundedType.Constant, Direction = direction, Nature = AxisNature.Speed, MaxValueOrAxis = 1.0f, MinValueOrAxis = -1.0f
            };

            RegisterCalculatedAxis(calculatedAxisDesc, calculator);
            return(calculatedAxisDesc);
        }
예제 #3
0
        /// <summary>
        /// Registers a calculated axis. Calculated axes behave like axes exposed by the underlying
        /// hardware device but can be calculated from one or more existing axes or buttons.
        /// </summary>
        /// <param name="calculatedAxisDescription">The axis description for the new calculated axis.</param>
        /// <param name="calculator">The calculator method performing the calculation once per frame.</param>
        /// <param name="initialValue">The initial value for the new axis.</param>
        /// <remarks>
        /// To register your own axis you need to provide a working <see cref="AxisValueCalculator"/>. This method
        /// is called whenever the axis value needs to be present.
        /// Any state the calculation depends upon should be queried from existing axes presented by the input device
        /// or "statically" stored in the closure around the calculator. The methodes
        /// <list type="bullet"></list>
        /// <item><see cref="RegisterSingleButtonAxis"/></item>
        /// <item><see cref="RegisterTwoButtonAxis"/></item>
        /// <item><see cref="RegisterVelocityAxis"/></item>
        /// </remarks>
        /// provide pre-defined calculators for certain purposes.
        public void RegisterCalculatedAxis(AxisDescription calculatedAxisDescription, AxisValueCalculator calculator, float initialValue = 0)
        {
            if (calculatedAxisDescription.Id < _nextAxisId)
            {
                throw new InvalidOperationException($"Invalid Id for calculated axis '{calculatedAxisDescription.Name}'. Id must be bigger or equal to {_nextAxisId}.");
            }

            _nextAxisId = calculatedAxisDescription.Id;


            var calculatedAxis = new CalculatedAxisDescription
            {
                AxisDesc         = calculatedAxisDescription,
                CurrentAxisValue = initialValue,
                Calculator       = calculator
            };

            // Calculated Axes are always to-be-polled axes.
            _calculatedAxes[calculatedAxisDescription.Id] = calculatedAxis;
            _axesToPoll[calculatedAxisDescription.Id]     = calculatedAxis.CurrentAxisValue;

            _axes[calculatedAxisDescription.Id] = calculatedAxisDescription;
        }