The triggers on XBox controller are axis, and when switching between mouse triggers and XBox, they do not behave the same way, because the XBox triggers are basically Input.GetButton, which causes the firing of weapons to shoot repeatedly.
With the GetAxisRaw function you get either 0 or 1/-1 (depending on axis). So it does work like the GetButton function. If you want it to work as the GetButtonDown function, you need to add little more code.
In this very simple example, you see that the event function will be called once,
eventhough the axis-button keeps being pressed down. And when the axis-button is no longer pressed, the check gets restored, so that next input it will fire your event function again. I hope this example helps you.
I was not so happy with those solutions, and I think that could exist one that is clear to read and easy to reuse. So I did the following code:
using UnityEngine;
public abstract class BaseJoystickInputs : ScriptableObject
{
bool _lastInputAxisState;
/// <summary>
/// Gets the axis input like an on key down event, returning <c>true</c> only
/// on the first press, after this return <c>false</c> until the next press.
/// Only works for axis between 0 (zero) to 1 (one).
/// </summary>
/// <param name="axisName">Axis name configured on input manager.</param>
protected bool GetAxisInputLikeOnKeyDown(string axisName)
{
var currentInputValue = Input.GetAxis(axisName) > 0.1;
// prevent keep returning true when axis still pressed.
if (currentInputValue && _lastInputAxisState)
{
return false;
}
_lastInputAxisState = currentInputValue;
return currentInputValue;
}
}
using System.Collections.Generic;
using UnityEngine;
public class MyInput
{
private static Dictionary<string,float> lastDict = new Dictionary<string, float>();
public enum Dir { POSITIVE, NEGATIVE }
public static float wait = 0.4f; //min time to wait between returning true 400ms
public static float switchvalue = 0.8f; //how deep do we need to press
public static bool repeat=true;
//shortcuts
public static bool GetAxisAsButtonNegative(string axisName) => GetAxisAsButton(axisName, Dir.POSITIVE);
public static bool GetAxisAsButtonPositive(string axisName) => GetAxisAsButton(axisName, Dir.NEGATIVE);
public static bool GetAxisAsButton(string axisName, Dir direction)
{
float value = Input.GetAxis(axisName);
string key = axisName + "." + direction; //key for the dictionary
float last = 0;
lastDict.TryGetValue(key, out last); //last time we returned "true" for this query
float dur = Time.time - last; //time since we returned "true" for this query
//not pressed, reset wait time to be able to "press" this button repeatedly and faster as wait
if (Mathf.Abs(value) < switchvalue/2f)
{
lastDict[key] = 0;
return false;
}
//waiting time between pressed already passed (repeat mode) or button already had been released (no repeat mode)?
if ((dur > wait && repeat) || (!repeat && last==0)) {
//retrun true axis is in the matching direction
if (direction == Dir.NEGATIVE && value < -switchvalue || direction == Dir.POSITIVE && value > switchvalue)
{
//save time
lastDict[key] = Time.time;
return true;
}
} else
{
//must still wait, call again in next loop
}
return false;
}
}
I edited @CoderMasterMike’s reply to avoid stupid sensitivity issues the Axis button has
Now the script will work only when the button is pushed all the way down. I achieved this by rounding the Input values using Mathf.Round(MyValue)
if (Mathf.Round(Input.GetAxisRaw("Fire1")) != 0)
{
if (m_isAxisInUse == false)
{
// Call your event function here.
m_isAxisInUse = true;
}
}
if (Mathf.Round(Input.GetAxisRaw("Fire1")) == 0)
{
m_isAxisInUse = false;
}
I have come with the same solution though I use this in a game object and read the publicbools instead of reading the input axes.
Is like an input axis translator that will send a value only for the rest of the frame so it works as an Input.GetAxisDown().
You have to put it in a game object and from the player read the output of this script.
This works for a DPad PS4 controller on a windows machine.
It looks like in macOS and Linux we can read the input directly from the PS4 controller mapped as a button but I’m not sure about this, please let us know if someone has a better approach which do not rely in the approach of all the posts here. Cheers!
public class DPadManager : MonoBehaviour
{
public int up_buttonDown;
public int up_buton;
public float up_axis;
[SerializeField] private bool up_chkDown;
public int down_buttonDown;
public int down_buton;
public float down_axis;
[SerializeField] private bool down_chkDown;
public int right_buttonDown;
public int right_buton;
public float right_axis;
[SerializeField] private bool right_chkDown;
public int left_buttonDown;
public int left_buton;
public float left_axis;
[SerializeField] private bool left_chkDown;
private void Update() {
if(Input.GetAxis("vertical") > 0 && !up_chkDown) {
up_chkDown = true;
StartCoroutine(Up_ButtonDownCo());
} else if(Input.GetAxis("vertical") == 0) {
up_chkDown = false;
}
if(Input.GetAxis("vertical") < 0 && !down_chkDown) {
down_chkDown = true;
StartCoroutine(Down_ButtonDownCo());
} else if(Input.GetAxis("vertical") == 0) {
down_chkDown = false;
}
if(Input.GetAxis("horizontal") > 0 && !right_chkDown) {
right_chkDown = true;
StartCoroutine(Right_ButtonDownCo());
} else if(Input.GetAxis("horizontal") == 0) {
right_chkDown = false;
}
if(Input.GetAxis("horizontal") < 0 && !left_chkDown) {
left_chkDown = true;
StartCoroutine(Left_ButtonDownCo());
} else if(Input.GetAxis("horizontal") == 0) {
left_chkDown = false;
}
}
IEnumerator Up_ButtonDownCo() {
up_buttonDown = 1;
yield return new WaitForEndOfFrame();
up_buttonDown = 0;
}
IEnumerator Down_ButtonDownCo() {
down_buttonDown = 1;
yield return new WaitForEndOfFrame();
down_buttonDown = 0;
}
IEnumerator Right_ButtonDownCo() {
right_buttonDown = 1;
yield return new WaitForEndOfFrame();
right_buttonDown = 0;
}
IEnumerator Left_ButtonDownCo() {
left_buttonDown = 1;
yield return new WaitForEndOfFrame();
left_buttonDown = 0;
}
}
all these are disgusting decisions from unprofessional programmers - if you need stateless a step change in the axis, for example, gradually raise the muzzle of a tank or switch the gearbox on next speed… then don’t use axis reading - you have to read the additional trigger buttons Lt and Lb of the joystick because Unity can read them in two modes like axis GetAxis(9) and like buttons GetKeyDown(KeyCode.JoystickButton6) and JoystickButton8. but if you strongly want receive a long program then you must use additional state variable previouse_state and then do comapration (like proposed @KelvinRodri_lastInputAxisState) - but it’s called best crutches