Как я могу улучшить отзывчивость элементов управления моего сенсорного экрана? - PullRequest
0 голосов
/ 14 января 2019

Вот небольшой клип моей игры: https://gfycat.com/DisfiguredImpressionableGalapagossealion

Правая сторона экрана (finId2) контролирует прицеливание и стрельбу, в то время как левая сторона экрана (finId1) используется для изменения выбранной полосы движения, проводя вверх и вниз.

Как видно, игровой процесс зависит от того, насколько быстро игрок может менять дорожки.

Я написал сценарий, который управляет обеими сторонами экрана, но сильно ударяют, и время от времени пропускают полностью.

Это потому, что я слишком часто перебираю все свайпы? Может ли кто-нибудь взглянуть на мою реализацию этого и предложить, как механизм смахивания можно сделать более отзывчивым?

int screenDivision;
int finId1 = -1;
int finId2 = -1;

bool tap, swipeUp, swipeDown;
bool isDraging = false;
Vector2 startTouch, swipeDelta;
int swipeDeadzone = 5;

void Start(){

        Input.multiTouchEnabled = true;
        screenDivision = Screen.width / 4;
        canAim = true;
        canFire = true;
    }

void Update()
    {
        tap = swipeUp = swipeDown = false;

        //update the arrow pointer rotation (which is used for shooting the arrow in a straight line w.r.t. the tower)

        if (Input.touchCount > 0)
        {
            // loop through every touch
            foreach (var touch in Input.touches)
            {
                if (touch.phase == TouchPhase.Began)
                {
                    //For left half screen
                    if (touch.position.x <= screenDivision && finId1 == -1)
                    {
                        isDraging = true;
                        tap = true;
                        startTouch = touch.position;
                        finId1 = touch.fingerId;        //store the fingerId of the left touch for as long as touch has not been ended though TouchPhase.Ended
                    }
                    //For right half screen
                    else if (touch.position.x > screenDivision && finId2 == -1)
                    {

                        mouseStart = touch.position.y;

                        if (EventSystem.current.IsPointerOverGameObject(touch.fingerId))
                            canAim = false;


                        finId2 = touch.fingerId;
                    }
                }
                //touchPhase.Ended for the archer firing is handled in LateUpdate() so here only the left finger will be handled, target only the left finger via finId1 which was set in TouchPhase.Began
                else if (touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled)
                {
                    if (touch.fingerId == finId1)
                    {
                        //Reset or release the fingerId for next touch
                        finId1 = -1;
                        isDraging = false;
                        Reset();
                    }
                }

            }
            //below if block if for the archer firing so only looking at fingerId2 here
            if (finId2 != -1)      //touch has begun and finId2 has been assigned  
            {
                //if right tap is detected this block will set the animation state of the archer, play the bow sound and make ready to fire

            }


        }

        //Below code handles the swiping mechanism of the left side of the screen.
        swipeDelta = Vector2.zero;
        if (isDraging)
        {
            foreach (var touch in Input.touches)
            {
                //looping through all touches but only care about finId1 which is used for left half of screen
                if (touch.fingerId == finId1)
                {
                    swipeDelta = touch.position - startTouch;
                }
            }
        }

        //Did we cross the deadZone?
        if (swipeDelta.magnitude > swipeDeadzone)
        {
            //which direction?
            float x = swipeDelta.x;
            float y = swipeDelta.y;
            if (Mathf.Abs(x) > Mathf.Abs(y))
            {
                // Left or Right Swipe
                //Unused in this game
            }
            else
            {
                //up or down swipe
                if (y < 0)
                {
                    swipeDown = true;
                    spawner.Rotate(false);
                }
                else
                {
                    swipeUp = true;
                    spawner.Rotate(true);
                }
            }

            Reset();
        }

    }

Механизм смахивания полностью обрабатывается в блоке Update(). Где в качестве окончательного состояния стрельбы стрелка обрабатывается в LateUpdate(), как сделано ниже:

void LateUpdate()
{
    //if the player can aim
    if (Input.touchCount > 0)
    {
        if (canAim)
        {
            foreach (var touch in Input.touches)
            {
                if (touch.fingerId == finId2)
                {
                    if (touch.phase == TouchPhase.Moved)
                    {
                        //code to move the line renderer showing arrow line prediction.


                    }
                    else if (touch.phase == TouchPhase.Ended)
                    {
                        zRotation = 0;
                    }

                }
            }
        }

        foreach (var touch in Input.touches)
        {
            if (touch.fingerId == finId2)
            {
                if (touch.phase == TouchPhase.Ended)
                {
                    finId2 = -1;

                    // code that handles arrow behaviour and shoots arrow

                    //can aim again
                    canAim = true;
                }
            }
        }

    }
}


private void Reset()
{
    startTouch = swipeDelta = Vector2.zero;
    isDraging = false;
}

Я знаю, что это может быть не самый элегантный способ достичь того, чего я хочу, но это то, что я мог бы собрать из чтения онлайн-документации для мультитача.

Будем весьма благодарны за любые рекомендации по улучшению этого.

1 Ответ

0 голосов
/ 14 января 2019

Я столкнулся с этой же проблемой. Проблема в том, что сенсорный ввод ОС работает быстрее, чем в игровом цикле. Это похоже на то, как Windows обновляет мышь 240 раз в секунду, а игровой цикл запускается со скоростью 30 или 60 кадров в секунду.

Мое решение состояло в том, чтобы внедрить пользовательский код свайпа в public void OnTouchEvent(MotionEvent e) в Activity. Это позволяет обрабатывать смахивания при запуске вместо нескольких игровых фреймов.

Необходимо соблюдать осторожность в методе, чтобы сделать его максимально плотным.

OnTouchEvent - это метод Android, позволяющий и Activity обрабатывать события касания. Переданный в e параметр имеет тип MotionEvent

Эти ссылки предназначены для Java, при преобразовании имен в C # просто используйте заглавную букву в первой букве вызовов метода, например, e.getY () становится e.GetY ().

Поместите public void OnTouchEvent(MotionEvent e) в файл UnityActivity.

...