0
\$\begingroup\$

The details of my particular problem are a bit convoluted, but take this similar scenario:

I want the player to be able to control the velocity of the character in some direction using only an analog trigger on a controller, being able to move forward and backward. In some sense this is very straightforward: the smallest value of the analog range of the trigger can correspond to the fastest possible backward velocity, and the highest value the fastest possible forward velocity (these being equal in magnitude), the rest can be linearly inrepolated.

The problem is that in the trigger's neutral position the value is already extremal. So with this approach, the player would have to keep the trigger about halfway pulled when they want to remain still, which is awkward to say the least. One solution I've thought about is is using a bumper or even some other button as a modifier. If the bumper is held, pulling the trigger moves the character backward, and if not, moves it forward.

But I'm already pressed for controller real-estate as is (in particular both sticks are non-negotiably taken). Can you think of a clever solution to this?

\$\endgroup\$
4
  • \$\begingroup\$ Why are you controlling movement with a trigger instead of a more common solution of controlling movement with an analog stick? Even if you only want the player to control velocity, you can use the stick's y-axis for velocity and ignore the x-axis. \$\endgroup\$ Commented May 15, 2023 at 19:45
  • \$\begingroup\$ As I've already said, the sticks are taken. I guess I can elaborate: regarding the player character as a rigid body, I want the player to have full, real time control of both the position and orientation in a 3d space. This requires six degrees of freedom, four are provided by the sticks. Two more would be provided by the triggers, except they can only conveniently give positive values. \$\endgroup\$ Commented May 16, 2023 at 12:16
  • \$\begingroup\$ Sorry, I guess I missed the last sentence. I've added some paragraph breaks and bolding to make the question easier to read. \$\endgroup\$ Commented May 16, 2023 at 17:22
  • \$\begingroup\$ The way I've usually seen 6 DOF handled is FPS style controls on the sticks (truck & dolly, yaw & pitch) bumpers to roll left/right, and two triggers to change elevation positively and negatively. That means sacrificing analog control granularity in roll, but it's usually the one we're adjusting the least. \$\endgroup\$ Commented May 17, 2023 at 7:48

2 Answers 2

1
\$\begingroup\$

If you absolutely must use only one trigger and want to avoid having to hold a precise intermediate value to stay still, without a discontinuity in the middle of the input domain, you can also opt to double-cover part of the output range:

Plot of output value vs input

In this version:

  • Leaving the trigger at its neutral position maps to zero output (stationary)

  • Slightly squeezing the trigger begins to accelerate backwards

  • Holding the trigger 1/3 of the way maps to 100% reverse speed

  • Pushing past 1/3 slows down again, until reaching 2/3 which is again zero output

  • Pushing past 2/3 of the way begins to accelerate forward

  • Holding the trigger at 100% maps to 100% forward speed

This is a bit awkward, but it means that rest and 100% forward speed, the outputs that a player will probably want to be using most often, map to the extremes that are easiest to hold, and there are no sudden discontinuities in between. 100% reverse speed is awkward to hold precisely, but hopefully it accounts for a minority of your gameplay.

A formula to achieve this is:

output = abs(input - 1f/3f) * 3f - 1f;

We can make it a little easier to hold the extremes (stationary, full forward, and full reverse) by flattening the curve where it crosses through those points (the "soft" version graphed above):

output = (0.5f * cos(3f * PI * input) - 0.5f) * (input < 2f/3f ? 1f : -1f);

Another option you could try is to use some hysteresis, where you use one of two different mapping curves depending on recent input history.

One version of this would be that with the trigger in the neutral position, you read zero output. If you gradually squeeze the trigger, you begin accelerating forward, and once you're in "forward mode" you can use the whole analog range of the trigger to vary your forward speed. But if you return to neutral, then snap the trigger to max quickly, you "shift gears" into reverse mode, and you can then feather-out the trigger to vary your reverse speed.

In the version below, I use a mapping where in reverse gear both 0% and 100% input map to zero, so you can snap the trigger without moving immediately, then gradually ramp up your reverse speed by letting go a little, and return to neutral / get ready to switch back to forward by letting it out all the way.

public float modeSwitchThreshold = 0.9f;
public int modeSwitchTicks = 2;
public float deadZoneMin = 0.05f;
public float deadZoneMax = 0.95f;

bool _currentModeIsReverse = false;
int _ticksSinceNonZero = 0;


float UpdateSignedDisplacement(float input) {
    float normalized = (input - deadZoneMin) / (deadZoneMax - deadZoneMin);
    normalized = max(0, min(input, 1));

    if (input == 0f) {
        _ticksSinceNonZero = 0;
        _currentModeIsReverse = false;
        return 0f;
    }

    _ticksSinceNonZero++
    
    if (_ticksSinceNonZero <= modeSwitchTicks && input > modeSwitchThreshold) {
        _currentModeIsReverse = true;
    }

    if (_currentModeIsReverse) {
        // Soft peak at 50% input -> -100% output, 
        // sloping smoothly to 0 at the extremes.
        return 4f * (0.5f - input) * (0.5f - input) - 1;
    } else {
        // Straight line from 0 -> 0 to 1 -> 1
        return input;
    }
}

The version presented above is just an experimental starting point, and will likely need a lot of iteration and playtesting to find a mapping that feels good. The aim is just to demonstrate the core idea of the mode switch, and how you can use it to map both positive and negative speeds to your liking.

\$\endgroup\$
2
  • \$\begingroup\$ I had actually thought of both of these, and was hoping for something even better, I probably should have mentioned them in the question :P Regardless I'll probably end up using one of these in the end (or let the player choose between them), so I'll accept this answer if no more arrive. \$\endgroup\$ Commented May 17, 2023 at 6:23
  • \$\begingroup\$ Yes, mentioning that would have saved me some time. \$\endgroup\$ Commented May 17, 2023 at 7:42
0
\$\begingroup\$

I can only think of two possibilities:

  1. Use one trigger for forward and the other for reverse

  2. As you noted, use a modifier button which reverses the thrust direction when held.

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.