Unity 2019 C# Сценарий двойного касания для Input.GetAxisRaw («Горизонтальный») - Чудовищный код - Как сжать / очистить мой беспорядок? - PullRequest
0 голосов
/ 24 января 2020

Не удалось найти понятный скрипт двойного касания, который использует функцию ввода Unity. GetAxisRaw («Горизонтально»). Ниже приведено мое чудовищное решение для левой и правой горизонтальной оси, которое заняло у меня слишком много часов ... Это служит моей цели, хотя все еще позволяет игроку нажимать sh в направлении, противоположном направлению движения, если у него быстрые пальцы .

Если кто-нибудь может показать мне более чистое решение или у него есть какой-нибудь совет, он будет очень признателен? Предпочтительно решение, которое может быть легко реализовано и для другой оси. Если бы кто-нибудь знал о стандартной функции единства, которая могла бы обеспечить такое же поведение двойного нажатия, это было бы еще лучше.

Если вы прикрепите скрипт к кубу, вы увидите поведение двойного касания, которое я ищу. Прикрепленное изображение показывает сигнал logi c поведения двойного нажатия.

Logi c сигнал Double Tap

using System.Collections;
using UnityEngine;

public class DoubleTap : MonoBehaviour
{

float translationSpeedX = 20;
float translationSpeedY = 20;
Vector3 playerPosition;

float maxKeyDownTime = 0.2f;
float maxKeyUpTime = 0.2f;
float delayBetweenDoubleTaps = 0.4f;
bool doubleTapped = false;

bool firstLeftDown = false;
bool firstLeftUp = false;
bool prevLeftDown = false;

bool firstRightDown = false;
bool firstRightUp = false;
bool prevRightDown = false;


// Start is called before the first frame update
void Start()
{
    playerPosition = transform.position;
    StartCoroutine(KeyInputBuffer());
}

// Update is called once per frame
void Update()
{

    //Take keyboard input and translate the player in X and Y directions
    playerPosition.x += Input.GetAxis("Horizontal") * translationSpeedX * Time.deltaTime;
    playerPosition.x = Mathf.Clamp(playerPosition.x, -100, 100);
    playerPosition.y += Input.GetAxis("Vertical") * translationSpeedY * Time.deltaTime;
    playerPosition.y = Mathf.Clamp(playerPosition.y, -100, 100);
    transform.position = playerPosition;


    //Double tap left
    if (firstLeftUp && Input.GetAxisRaw("Horizontal") < 0) 
    {
        Debug.Log("Double Tap Left!");
        playerPosition.x -= 10f;
        firstLeftDown = false;
        firstLeftUp = false;
        StartCoroutine(DoubleTapDelayTimer());
    }
    else if (!firstLeftUp && firstLeftDown && Input.GetAxisRaw("Horizontal") == 0)
    {
        Debug.Log("firstLeftUp Left!");
        firstLeftUp = true;
        StartCoroutine(KeyUpTimer());
    }
    else if (!doubleTapped && !firstLeftDown && !prevLeftDown && Input.GetAxisRaw("Horizontal") < 0) 
    {
        Debug.Log("firstLeftDown Left!");
        firstLeftDown = true;
        StartCoroutine(KeyDownTimer());
    }


    //Double tap right
    if (firstRightUp  && Input.GetAxisRaw("Horizontal") > 0) 
    {
        Debug.Log("Double Tap Right!");
        playerPosition.x += 10f;
        firstRightDown = false;
        firstRightUp = false;
        StartCoroutine(DoubleTapDelayTimer());
    }
    else if (!firstRightUp && firstRightDown && Input.GetAxisRaw("Horizontal") == 0)
    {
        Debug.Log("firstRightUp Right!");
        firstRightUp = true;
        StartCoroutine(KeyRightUpTimer());
    }
    else if (!doubleTapped && !firstRightDown && !prevRightDown && Input.GetAxisRaw("Horizontal") > 0)
    {
        Debug.Log("firstRightDown Right!");
        firstRightDown = true;
        StartCoroutine(KeyRightDownTimer());
    }
}

//Timer which controlls the minimun time between double taps
IEnumerator DoubleTapDelayTimer()
{
    doubleTapped = true;
    yield return new WaitForSeconds(delayBetweenDoubleTaps);
    doubleTapped = false;
}

//Timers for the left horizontal axis
IEnumerator KeyDownTimer()
{
    yield return new WaitForSeconds(maxKeyDownTime);
    firstLeftDown = false;
}

IEnumerator KeyUpTimer()
{
    yield return new WaitForSeconds(maxKeyUpTime);
    firstLeftUp = false;
}


//Timers for the right horizontal axis
IEnumerator KeyRightDownTimer()
{
    yield return new WaitForSeconds(maxKeyDownTime);
    firstRightDown = false;
}

IEnumerator KeyRightUpTimer()
{
    yield return new WaitForSeconds(maxKeyUpTime);
    firstRightUp = false;
}

//Store the raw input conditions for the horizontal axis as reference in next frame
IEnumerator KeyInputBuffer()
{
    while(true)
    {
       yield return new WaitForEndOfFrame();

       if (Input.GetAxisRaw("Horizontal") > 0)
       {
           prevLeftDown = false;
           prevRightDown = true;
       }
       else if (Input.GetAxisRaw("Horizontal") < 0)
       {
           prevLeftDown = true;
           prevRightDown = false;
       }
       else
       {
           prevLeftDown = false;
           prevRightDown = false;
       }
    }
  }}

Ниже приведено улучшение ( и отлаженный код), предложенный derHU GO. Я действительно поражен тем, сколько кода требуется для такой малой функциональности.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum Axis
{
    X,
    Y
}

public enum AxisDirection
{
    Right,
    Left,
    Up,
    Down
}

public class DoubleTap : MonoBehaviour  //StackOverFlow
{
    // With [SerializeField] these are now configured directly via the Inspector 
    // in unity without having to recompile
    // This way you can play with them in Playmode until you have the values the fit your needs
    // For restring to the defaults simply hit Reset in the Context menu of the component
    [SerializeField] private float translationSpeedX = 20;
    [SerializeField] private float translationSpeedY = 20;
    [SerializeField] private float maxKeyDownTime = 0.2f;
    [SerializeField] private float maxKeyUpTime = 0.2f;
    [SerializeField] private float delayBetweenDoubleTaps = 0.4f;
private Dictionary<Axis, string> axisName = new Dictionary<Axis, string>
{
    {Axis.X, "Horizontal"},
    {Axis.Y, "Vertical"}
};

private Dictionary<Axis, AxisDirection> axisPositive = new Dictionary<Axis, AxisDirection>
{
    {Axis.X, AxisDirection.Right},
    {Axis.Y, AxisDirection.Up}
};

private Dictionary<Axis, AxisDirection> axisNegative = new Dictionary<Axis, AxisDirection>
{
    {Axis.X, AxisDirection.Left},
    {Axis.Y, AxisDirection.Down}
};

private Vector3 playerPosition;
private bool doubleTapped = false;

private Dictionary<AxisDirection, bool> axisFirstDown = new Dictionary<AxisDirection, bool>();
private Dictionary<AxisDirection, bool> axisFirstUp = new Dictionary<AxisDirection, bool>();
private Dictionary<AxisDirection, bool> axisPrevDown = new Dictionary<AxisDirection, bool>();

private Dictionary<AxisDirection, Action> doubleTapActions = new Dictionary<AxisDirection, Action>();   //MOD

// Start is called before the first frame update
private void Start()
{
    doubleTapActions.Add(AxisDirection.Left, LeftDoubleTapAction);  //MOD
    doubleTapActions.Add(AxisDirection.Right, RightDoubleTapAction);//MOD
    doubleTapActions.Add(AxisDirection.Up, UpDoubleTapAction);      //MOD
    doubleTapActions.Add(AxisDirection.Down, DownDoubleTapAction);  //MOD

    foreach (var axis in (AxisDirection[])Enum.GetValues(typeof(AxisDirection)))
    {
        axisFirstDown.Add(axis, false);
        axisFirstUp.Add(axis, false);
        axisPrevDown.Add(axis, false);
    }

    playerPosition = transform.position;
    StartCoroutine(KeyInputBuffer());
}

// Update is called once per frame
private void Update()
{
    foreach (var axis in (Axis[])Enum.GetValues(typeof(Axis)))
    {
        // positive
        if (axisFirstUp[axisPositive[axis]] && Input.GetAxisRaw(axisName[axis]) > 0) //MOD  axisFirstUp || axisFirstDown
        {
            Debug.Log($"Double Tap {axisPositive[axis]}!");
            doubleTapActions[axisPositive[axis]].Invoke(); //MOD
            axisFirstDown[axisPositive[axis]] = false;
            axisFirstUp[axisPositive[axis]] = false;
            StartCoroutine(DoubleTapDelayTimer());
            return;
        }
        else if (!axisFirstUp[axisPositive[axis]] && axisFirstDown[axisPositive[axis]] && Input.GetAxisRaw(axisName[axis]) == 0)
        {
            Debug.Log($"firstUp {axisPositive[axis]}!");
            axisFirstUp[axisPositive[axis]] = true;
            StartCoroutine(KeyUpTimer(axisPositive[axis])); //MOD axisPositive[axis]) || axis
        }
        else if (!doubleTapped && !axisFirstDown[axisPositive[axis]] && !axisPrevDown[axisPositive[axis]] && Input.GetAxisRaw(axisName[axis]) > 0)
        {
            Debug.Log($"firstDown {axisPositive[axis]}!");
            axisFirstDown[axisPositive[axis]] = true;
            StartCoroutine(KeyDownTimer(axisPositive[axis])); //MOD axisPositive[axis]) || axis
        }

        // negative
        if (axisFirstUp[axisNegative[axis]] && Input.GetAxisRaw(axisName[axis]) < 0) //MOD  axisFirstUp || axisFirstDown //MOD2 if || else if
        {
            Debug.Log($"Double Tap {axisNegative[axis]}!");
            doubleTapActions[axisNegative[axis]].Invoke(); //MOD
            axisFirstDown[axisNegative[axis]] = false;
            axisFirstUp[axisNegative[axis]] = false;
            StartCoroutine(DoubleTapDelayTimer());
            return;
        }
        else if (!axisFirstUp[axisNegative[axis]] && axisFirstDown[axisNegative[axis]] && Input.GetAxisRaw(axisName[axis]) == 0)
        {
            Debug.Log($"firstUp {axisNegative[axis]}!");
            axisFirstUp[axisNegative[axis]] = true;
            StartCoroutine(KeyUpTimer(axisNegative[axis])); //MOD axisPositive[axis]) || axis
        }
        else if (!doubleTapped && !axisFirstDown[axisNegative[axis]] && !axisPrevDown[axisNegative[axis]] && Input.GetAxisRaw(axisName[axis]) < 0)
        {
            Debug.Log($"firstDown {axisNegative[axis]}!");
            axisFirstDown[axisNegative[axis]] = true;
            StartCoroutine(KeyDownTimer(axisNegative[axis])); //MOD axisPositive[axis]) || axis
        }
    }

    // Do only process the input as movement if there was no double tap this frame

    //Take keyboard input and translate the player in X and Y directions
    playerPosition.x += Input.GetAxis("Horizontal") * translationSpeedX * Time.deltaTime; //MOD || UnityEgine.
    playerPosition.x = Mathf.Clamp(playerPosition.x, -100, 100);
    playerPosition.y += Input.GetAxis("Vertical") * translationSpeedY * Time.deltaTime; //MOD || UnityEgine.
    playerPosition.y = Mathf.Clamp(playerPosition.y, -100, 100);
    transform.position = playerPosition;

    Debug.Log("update");
}


//Timer which controlls the minimun time between double taps
IEnumerator DoubleTapDelayTimer()
{
    doubleTapped = true;
    yield return new WaitForSeconds(delayBetweenDoubleTaps);
    doubleTapped = false;

}


//Timers for the axis
IEnumerator KeyDownTimer(AxisDirection axis)
{
    yield return new WaitForSeconds(maxKeyDownTime);
    axisFirstDown[axis] = false;
}

IEnumerator KeyUpTimer(AxisDirection axis)
{
    yield return new WaitForSeconds(maxKeyUpTime);
    axisFirstUp[axis] = false;
}


//Store the raw input conditions for the horizontal axis as reference in next frame
IEnumerator KeyInputBuffer()
{
    while (true)
    {
        Debug.Log("coroutine");
        yield return new WaitForEndOfFrame();

        foreach (var axis in (Axis[])Enum.GetValues(typeof(Axis)))
        {
            axisPrevDown[axisPositive[axis]] = false;
            axisPrevDown[axisNegative[axis]] = false;

            if (Input.GetAxisRaw(axisName[axis]) > 0) //MOD || UnityEgine.
            {
                axisPrevDown[axisPositive[axis]] = true;
            }
            else if (Input.GetAxisRaw(axisName[axis]) < 0) //MOD || UnityEgine.
            {
                axisPrevDown[axisNegative[axis]] = true;
            }
        }
    }
}


//Double tap actions
private void LeftDoubleTapAction()
{
    playerPosition.x -= 10f;
}
private void RightDoubleTapAction()
{
    playerPosition.x += 10f;
}
private void UpDoubleTapAction()
{
    playerPosition.y += 10f;
}
private void DownDoubleTapAction()
{
    playerPosition.y -= 10f;
}

}

1 Ответ

0 голосов
/ 24 января 2020

Одной из причин может быть использование правильных словарей для ваших bools et c и enum для осей, чтобы вам не приходилось реализовывать одно и то же несколько раз, и вы можете легко добавить новую ось, например,

public enum Axis
{
    X,
    Y
}

public enum AxisDirection
{
    Right,
    Left,
    Up,
    Down
}

public class DoubleTap : MonoBehaviour
{
    // With [SerializeField] these are now configured directly via the Inspector 
    // in unity without having to recompile
    // This way you can play with them in Playmode until you have the values the fit your needs
    // For restring to the defaults simply hit Reset in the Context menu of the component
    [SerializeField] private float translationSpeedX = 20;
    [SerializeField] private float translationSpeedY = 20;
    [SerializeField] private float maxKeyDownTime = 0.2f;
    [SerializeField] private float maxKeyUpTime = 0.2f;
    [SerializeField] private float delayBetweenDoubleTaps = 0.4f;


    private Dictionary<Axis, string> axisName = new Dictionary<Axis, string>
    {
        {Axis.X, "Horizontal"},
        {Axis.Y, "Vertical"}
    };

    private Dictionary<Axis, AxisDirection> axisPositive = new Dictionary<Axis, AxisDirection>
    {
        {Axis.X, AxisDirection.Right},
        {Axis.Y, AxisDirection.Up}
    };

    private Dictionary<Axis, AxisDirection> axisNegative = new Dictionary<Axis, AxisDirection>
    {
        {Axis.X, AxisDirection.Left},
        {Axis.Y, AxisDirection.Down}
    };

    private Vector3 playerPosition;
    private bool doubleTapped = false;

    private Dictionary<AxisDirection, bool> axisFirstDown = new Dictionary<AxisDirection, bool>();
    private Dictionary<AxisDirection, bool> axisFirstUp = new Dictionary<AxisDirection, bool>();
    private Dictionary<AxisDirection, bool> axisPrevDown = new Dictionary<AxisDirection, bool>();

    // Start is called before the first frame update
    private void Start()
    {
        // setup dictionaries
        foreach (var axis in (AxisDirection[])Enum.GetValues(typeof(AxisDirection)))
        {
            axisFirstDown.Add(axis, false);
            axisFirstUp.Add(axis, false);
            axisPrevDown.Add(axis, false);
        }

        playerPosition = transform.position;
        StartCoroutine(KeyInputBuffer());
    }

    // Update is called once per frame
    private void Update()
    {
        foreach (var axis in (Axis[])Enum.GetValues(typeof(Axis)))
        {
            // positive
            if (axisFirstDown[axisPositive[axis]] && Input.GetAxisRaw(axisName[axis]) > 0)
            {
                Debug.Log($"Double Tap {axisPositive[axis]}");
                playerPosition.x -= 10f;
                axisFirstDown[axisPositive[axis]] = false;
                axisFirstUp[axisPositive[axis]] = false;
                StartCoroutine(DoubleTapDelayTimer());
                return;
            }
            else if (!axisFirstUp[axisPositive[axis]] && axisFirstDown[axisPositive[axis]] && Input.GetAxisRaw(axisName[axis]) == 0)
            {
                Debug.Log($"firstUp {axisPositive[axis]}!");
                axisFirstUp[axisPositive[axis]] = true;
                StartCoroutine(KeyUpTimer(axis));
            }
            else if (!doubleTapped && !axisFirstDown[axisPositive[axis]] && !axisPrevDown[axisPositive[axis]] && Input.GetAxisRaw(axisName[axis]) > 0)
            {
                Debug.Log($"firstDown {axisPositive[axis]}!");
                axisFirstDown[axisPositive[axis]] = true;
                StartCoroutine(KeyDownTimer(axis));
            }

            // negative
            else if (axisFirstDown[axisNegative[axis]] && Input.GetAxisRaw(axisName[axis]) < 0)
            {
                Debug.Log($"Double Tap {axisNegative[axis]}");
                playerPosition.x -= 10f;
                axisFirstDown[axisNegative[axis]] = false;
                axisFirstUp[axisNegative[axis]] = false;
                StartCoroutine(DoubleTapDelayTimer());
                return;
            }
            else if (!axisFirstUp[axisNegative[axis]] && axisFirstDown[axisNegative[axis]] && Input.GetAxisRaw(axisName[axis]) == 0)
            {
                Debug.Log($"firstUp {axisNegative[axis]}!");
                axisFirstUp[axisNegative[axis]] = true;
                StartCoroutine(KeyUpTimer(axis));
            }
            else if (!doubleTapped && !axisFirstDown[axisNegative[axis]] && !axisPrevDown[axisNegative[axis]] && Input.GetAxisRaw(axisName[axis]) < 0)
            {
                Debug.Log($"firstDown {axisNegative[axis]}!");
                axisFirstDown[axisNegative[axis]] = true;
                StartCoroutine(KeyDownTimer(axis));
            }
        }

        // Do only process the input as movement if there was no double tap this frame

        //Take keyboard input and translate the player in X and Y directions
        playerPosition.x += UnityEngine.Input.GetAxis("Horizontal") * translationSpeedX * Time.deltaTime;
        playerPosition.x = Mathf.Clamp(playerPosition.x, -100, 100);
        playerPosition.y += UnityEngine.Input.GetAxis("Vertical") * translationSpeedY * Time.deltaTime;
        playerPosition.y = Mathf.Clamp(playerPosition.y, -100, 100);
        transform.position = playerPosition;

    }

    //Timer which controlls the minimun time between double taps
    private IEnumerator DoubleTapDelayTimer()
    {
        doubleTapped = true;
        yield return new WaitForSeconds(delayBetweenDoubleTaps);
        doubleTapped = false;
    }

    //Timers for the axis
    private IEnumerator KeyDownTimer(AxisDirection axis)
    {
        yield return new WaitForSeconds(maxKeyDownTime);
        axisFirstDown[axis] = false;
    }

    private IEnumerator KeyUpTimer(AxisDirection axis)
    {
        yield return new WaitForSeconds(maxKeyUpTime);
        axisFirstUp[axis] = false;
    }

    //Store the raw input conditions for the horizontal axis as reference in next frame
    private IEnumerator KeyInputBuffer()
    {
        yield return new WaitForEndOfFrame();

        foreach (var axis in (Axis[])Enum.GetValues(typeof(Axis)))
        {
            axisPrevDown[axisPositive[axis]] = false;
            axisPrevDown[axisNegative[axis]] = false;

            if (UnityEngine.Input.GetAxisRaw(axisName[axis]) > 0)
            {
                axisPrevDown[axisPositive[axis]] = true;
            }
            else if (UnityEngine.Input.GetAxisRaw(axisName[axis]) < 0)
            {
                axisPrevDown[axisNegative[axis]] = true;
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...