如何改善触摸屏控件的响应能力?

时间:2019-01-13 22:49:52

标签: c# unity3d touch multi-touch

以下是我的游戏片段: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 :(得分:1)

我遇到了同样的问题。问题是操作系统触摸输入的运行速度比游戏循环快。这类似于Windows每秒更新鼠标240次,游戏循环每秒运行30或60帧。

我的解决方案是在“活动”的public void OnTouchEvent(MotionEvent e)中实现自定义滑动代码。这样可以在触发时处理滑动,而无需跨多个游戏框架进行处理。

在方法中必须小心以使其尽可能紧。

OnTouchEvent是Android允许和Activity处理触摸事件的方法。在e中传递的参数的类型为MotionEvent

这些链接用于Java,将名称转换为C#时,只需将方法调用的首字母大写即可,例如,e.getY()变为e.GetY()。

public void OnTouchEvent(MotionEvent e)放在UnityActivity文件中。