Supermodel
Supermodel copied to clipboard
Analog positive/negative inputs are not implemented correctly
A user recently requested that it be possible to map analog axes to digital inputs that do not decay when released. After some digging, it appears this is not as simple as replacing:
int d = Clamp((int)decaySpeed, 1, 200);
With:
int d = Clamp((int)decaySpeed, 0, 200);
Analog axes are implemented by CAnalogAxesInput, which takes two digital input sources for the positive and negative sides. These maintain their own value which increments and then decays but this seems wrong. For example, when using digital inputs for the light gun axes, pressing left to move the cursor all the way to the left edge of the screen, releasing, and then pressing right before the decay has finished causing the positive and negative digital inputs to fight each other.
Here is the implementation:
void CAxisInput::Poll()
{
prevValue = value;
// Try getting value from analog inputs that represent negative and positive range of the axis first and then try the default input source
int intValue = value;
if ((m_negInput != NULL && m_negInput->HasValue()) || (m_posInput != NULL && m_posInput->HasValue()))
{
if (m_maxVal > m_minVal)
{
value = m_offVal;
if (m_posInput != NULL) value += (int)(m_posInput->ValueAsFraction() * (double)(m_maxVal - m_offVal));
if (m_negInput != NULL) value -= (int)(m_negInput->ValueAsFraction() * (double)(m_offVal - m_minVal));
}
else
{
value = m_offVal;
if (m_posInput != NULL) value -= (int)(m_posInput->ValueAsFraction() * (double)(m_offVal - m_maxVal));
if (m_negInput != NULL) value += (int)(m_negInput->ValueAsFraction() * (double)(m_minVal - m_offVal));
}
}
else if (m_source != NULL && m_source->GetValueAsAnalog(intValue, m_minVal, m_offVal, m_maxVal))
value = intValue;
else
value = m_offVal;
}
Instead of summing the contributions of both, the positive and negative inputs should both modify an underlying shared value, and that value should simply be returned. Instead of the following (Inputs.cpp):
CAnalogInput *gun1Left = AddAnalogInput("GunLeft", "P1 Gun Left", Game::INPUT_GUN1, "NONE");
CAnalogInput *gun1Right = AddAnalogInput("GunRight", "P1 Gun Right", Game::INPUT_GUN1, "NONE");
We should have something like:
CAnalogInputValue *gun1XAxisValue = std::make_shared<CAnalogInputValue>();
CAnalogInput *gun1Left = AddAnalogInput(gun1XAxisValue, "GunLeft", "P1 Gun Left", Game::INPUT_GUN1, "NONE");
CAnalogInput *gun1Right = AddAnalogInput(gun1XAxisValue, "GunRight", "P1 Gun Right", Game::INPUT_GUN1, "NONE");
I don't think that the value in Poll() should be incremented/decremented but simply obtained directly and then scaled accordingly in the range [m_minVal, m_offVal],[m_offVal,m_maxVal] (note the axis can be asymmetric). Lastly, HasValue() cannot simply check whether the underlying value != 0. Possibly, the positive/negative inputs can produce a single offset. That way, HasValue() can remain as is and when false indicates there is no offset to apply from digital inputs and that the axis input can be checked directly.