首页 文章

“Axiom工作室的Venkat请帮助”任何人都知道我将如何在unity3D for Android中使用手势来跟踪2指V动作

提问于
浏览
0

好的,这是我的问题,

我试图弄清楚我将如何能够注册用户使用两个手指在屏幕上制作V(手指起始点将是用户用两个手指触摸的位置,然后通过在移动时传播两个手指使用Unity 3d for android,制作V形 .

我之前从未做过涉及形状的手势,因此我将非常感谢任何有关如何做到这一点的建议,链接或示例

在此先感谢格雷姆

编辑:所以我一直在试图解决这个问题,等待有人帮助我 .

这是我到目前为止所做的,它不是按照我想要的方式工作但是我不确定我做错了什么,因为我之前从未试图做过这样的事情 . 任何帮助都将非常感激

再次感谢格雷姆

using UnityEngine;

使用System.Collections;

公共课Pinchv:MonoBehaviour {

public Vector2 leftFingerStartPosition;
public Vector2 leftFingerEndPosition;

public Vector2 rightFingerStartPosition;
public Vector2 rightFingerEndPosition;

void Update () {

    foreach(Touch touch in Input.touches)
    {
        if(touch.phase == TouchPhase.Began){

            Touch leftFinger = Input.GetTouch (0);
            Touch rightFinger = Input.GetTouch (1);

            leftFingerStartPosition = Input.GetTouch (0).position;
            leftFingerEndPosition = Input.GetTouch(0).position;

            rightFingerStartPosition = Input.GetTouch(1).position;
            rightFingerEndPosition = Input.GetTouch(1).position;


            if(Input.touchCount == 2 && Mathf.Abs(leftFingerEndPosition.x + Screen.width - leftFingerStartPosition.x) > 20 &&
               Mathf.Abs(leftFingerEndPosition.y + Screen.height - leftFingerStartPosition.y) > 60){

                if(Input.touchCount == 2 && Mathf.Abs(rightFingerEndPosition.x + Screen.width - rightFingerStartPosition.x) > 20 &&
                   Mathf.Abs(rightFingerEndPosition.y + Screen.height - rightFingerStartPosition.y) > 60){
                    Debug.Log ("its a v ");
                }
            }
            if(touch.phase == TouchPhase.Ended){
                leftFingerStartPosition = Vector2.zero;
                leftFingerEndPosition = Vector2.zero;


                rightFingerStartPosition = Vector2.zero;
                rightFingerEndPosition = Vector2.zero;  
            }
        }
    }
}

}

EDIT

所以我接受了你的建议并尝试了不同的东西,但不幸的是它根本不起作用 .

如果我不能解决这个问题,我即将开始拔头发 . 这里是我试图创建的新代码,不起作用可以有人请帮我解决这个问题,它现在让我疯了3天大声笑 .

在Axiom工作室的@Venkat你可以再次帮助我,我将不胜感激:)

耐心等待格雷姆

using UnityEngine;

使用System.Collections;

公共课Pinchv:MonoBehaviour {

public Vector2 fingerOneStartPosition;
public Vector2 fingerOneEndPosition;

public Vector2 fingerTwoStartPosition;
public Vector2 fingerTwoEndPosition;

void Update () {

    foreach(Touch touch in Input.touches)
    {
        if(touch.phase == TouchPhase.Began){

        //  Touch leftFinger = Input.GetTouch (0);
        //  Touch rightFinger = Input.GetTouch (1);

            fingerOneStartPosition = Input.GetTouch (0).position;
            fingerOneEndPosition = Input.GetTouch(0).position;

            fingerTwoStartPosition = Input.GetTouch(1).position;
            fingerTwoEndPosition = Input.GetTouch(1).position;

            if(Input.touchCount == 2 && Mathf.Abs(fingerOneStartPosition.x - fingerOneEndPosition.x) > 700 &&
               Mathf.Abs(fingerOneStartPosition.y - fingerOneEndPosition.y) > 120){
                if(Input.touchCount == 2 && Mathf.Abs(fingerTwoStartPosition.x - fingerTwoEndPosition.x) > 700 &&
                   Mathf.Abs(fingerTwoStartPosition.y - fingerTwoEndPosition.y) > 120){

                    Debug.Log ("its a v ");
                }
            }
        }
            if(touch.phase == TouchPhase.Ended){
                fingerOneStartPosition = fingerOneEndPosition;
                fingerOneEndPosition = Vector2.zero;


                fingerTwoStartPosition = fingerTwoEndPosition;
                fingerTwoEndPosition = Vector2.zero;    
            }
        }
    }

public void OnGUI(){

    GUILayout.Label("Where am i fingerone X : " + fingerOneStartPosition + "end position" + fingerOneEndPosition);
    GUILayout.Label("Where am i fingerone X : " + fingerTwoStartPosition + "end position" + fingerTwoEndPosition);
}

}

1 回答

  • 1

    @Graeme

    好吧,我想出了一些部分hacky代码 . 它绝不是一个很棒的代码,但它应该让你对如何处理问题有一个相当清晰的想法 .

    该代码确实有效(使用Moto G 1st Gen,Unity 4.6进行测试),但它仍然会给出一些不正确的结果 .
    我已经评论了我看到潜在问题的课程部分,所以你可以用它作为一个不错的起点 .

    尝试一下,让我知道 . 肯定有比这个更优雅的解决方案,事实上我几个月前正在为Unity制作一个手势识别库 . 我应该把它弄脏并完成它:P

    Unity C# code

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    public class DetectVGesture : MonoBehaviour {
    
    //Note : This was tested on a 1st Gen Moto G (1280 x 720 resolution, IIRC)
    // and an orthographic size of 5.
    //Why this matters :
    //The Vector2 minimumDeltas uses Screen units, so resolution matters here
    //The float maxDistBetInitPos uses World units, so if the camera's ortho size is larger, this value becomes larger as well
    
    //Therefore, some trial and error in these values will be needed to get it to work right
    
    //TODO : Write some code to take into account screen resolution and camera size / FOV.
    //If anyone feels like editing that portion in, please feel free
    
    //The touches used are maintained in these two lists
    private List<Touch> firstTouches = new List<Touch>();
    private List<Touch> secondTouches = new List<Touch>();
    
    //This is the minimum distance in SCREEN units 
    //of touch.deltaTouch for a new touch in TouchPhase.Moved to register
    public Vector2 minimumDeltas = new Vector2(1, 1);
    
    //This is the maximum distance between the two initial touches
    //in WORLD units for the algorithm to work
    public float maxDistBetInitPos = 3f;
    
    //These are the minimum and maximum angles between the two
    //"ARMS" of the "V" for a V gesture to be recognized
    public Vector2 vAnglesMinMax = new Vector2(15, 60);
    
    
    // Use this for initialization
    void Start () {
    
    }
    
    
    void OnGUI () {
    
    
        GUI.Label(new Rect(10, 10, 100, 50), "Touches "+Input.touchCount.ToString());
    
        if(Input.touchCount > 0)
            GUI.Label(new Rect(110, 10, 100, 50), "Touch1 "+Input.touches[0].position.ToString());
    
        if(Input.touchCount > 1)
            GUI.Label(new Rect(210, 10, 100, 50), "Touch2 "+Input.touches[1].position.ToString());
    
    }
    
    // Update is called once per frame
    void Update () {
    
    
        //For this sample, we're only interested in a "V" created with 
        //2 fingers, so we'l ignore the rest
        if(Input.touchCount == 2) {
    
            foreach(Touch touch in Input.touches) {
    
                //The below two lines are to allow for an early
                //exit if EITHER of the fingers is stationary. 
                //Uncomment the lines if you want touches to be registered
                //only when BOTH fingers move.
                //if(touch.phase == TouchPhase.Stationary)
                    //return;
    
                //This is the first time TWO fingers are registered,
                //so we can use this as our starting point, where the
                //touches are closest to each other. 
                //From here on, I'll refer this to as the BOTTOM of the "V"
                if(touch.phase == TouchPhase.Began) {
                    CheckTouchAndAdd(Input.touches[0], Input.touches[1]);
                }
    
                //There was some movement, so let's check what it is
                if(touch.phase == TouchPhase.Moved) {
    
                    //The movement in this touch is at least as much as we want
                    //So, we add both the touches, and we move to the next iteration
                    //Here, I want both the X & Y delta positions to meet my minimum
                    //delta distance. You can change this to either X or Y.
                    if(Mathf.Abs(touch.deltaPosition.x) >= minimumDeltas.x &&
                       Mathf.Abs(touch.deltaPosition.y) >= minimumDeltas.y) {
                        CheckTouchAndAdd(Input.touches[0], Input.touches[1]);
                    }
    
                    else {
                        Debug.Log("There was too less of delta!");
                    }
    
                }
    
                //The touch / touches have ended. 
                //So let's clear the lists for the next trial
                if(touch.phase == TouchPhase.Ended) {
                    firstTouches.Clear();
                    secondTouches.Clear();
                }
    
            }//Iterate over touches in Input.touches ends
        }//Input.touchCount == 2 ends
    }
    
    private void CheckTouchAndAdd (Touch touch1, Touch touch2) {
        if(!firstTouches.Contains(touch1) && !secondTouches.Contains(touch2)) {
            firstTouches.Add(touch1);
            secondTouches.Add(touch2);
            CheckForV();
        }
    
    }
    
    
    private void CheckForV () {
    
        if(firstTouches.Count < 5 || secondTouches.Count < 5) {
            Debug.Log("Not enough touches to perform the check! ");
            return;
        }
    
    
        //First, let's check if the two initial touch points
        //were relatively close enough to warrant a "V"
        //If they're not, we'll have an early exit
        Vector3 firstTouchInitPos = Camera.main.ScreenToWorldPoint(firstTouches[0].position);
        Vector3 secondTouchInitPos = Camera.main.ScreenToWorldPoint(secondTouches[0].position);
    
        //First we check if the X distance falls within our limit of maximum distance
        if(Mathf.Abs(secondTouchInitPos.x - firstTouchInitPos.x) > maxDistBetInitPos) {
            Debug.Log (string.Format("The X values were too far apart! Exiting check First {0}," +
                                     "Second {1}, Distance {2}", 
                                     new object[] { firstTouchInitPos.x, secondTouchInitPos.x, 
            Mathf.Abs(secondTouchInitPos.x - firstTouchInitPos.x)} ));
            return;
        }
    
        //Then we check the same for Y
        if(Mathf.Abs(secondTouchInitPos.y - firstTouchInitPos.y) > maxDistBetInitPos) {
            Debug.Log (string.Format("The Y values were too far apart! Exiting check First {0}," +
                                     "Second {1}, Distance {2}", 
                                     new object[] { firstTouchInitPos.y, secondTouchInitPos.y, 
                Mathf.Abs(secondTouchInitPos.y - firstTouchInitPos.y)} ));
            return;
        }
    
    
        //If we reach this point, both the X & the Y positions are within the maximum distance
        //we want. So, they're close enough that we can calculate the average between the two Vectors
        //and assume that both these Vectors intersect at the average point. (i.e. the average point
        //is the corner at the BOTTOM of the "V")
    
        //Note that there are more elegant ways of doing this. You can always use trignometry to do so
        //but for the sake of this example, this should yield fairly good results.
    
        Vector3 bottomCornerPoint = new Vector3( (firstTouchInitPos.x + secondTouchInitPos.x) * 0.5f, 
                                                (firstTouchInitPos.y + secondTouchInitPos.y) * 0.5f );
    
    
        //Now that we have our bottom point, we then calculate the Vector between this common
        //bottom point, and the last touch point added to each list. From this point
        //I'll refer to these two Vectors as the ARMS of the "V" 
        Vector3 arm1 = new Vector3( firstTouches[firstTouches.Count - 1].position.x - bottomCornerPoint.x,
                                   firstTouches[firstTouches.Count - 1].position.y - bottomCornerPoint.y );
    
        Vector3 arm2 = new Vector3( secondTouches[secondTouches.Count - 1].position.x - bottomCornerPoint.x,
                                   secondTouches[secondTouches.Count - 1].position.y - bottomCornerPoint.y );
    
    
        //Now let's calculate the angle between the ARMS of the "V".
        //If the angle is too small (< 15 degrees), or too large (> 60 degrees), 
        //it's not really a "V", so we'll exit
    
        //Note: Vector2.Angle / Vector3.Angle perform a DOT product of the two vectors
        //Therefore in certain cases, you're going to get incorrect results.
        //TODO : If anyone can, please change the below to use a cross product
        //to calculate the angle between the Vectors.
    
    
        if(Vector3.Angle(arm1, arm2) < vAnglesMinMax.x ||
           Vector3.Angle(arm1, arm2) > vAnglesMinMax.y) {
    
            Debug.Log (string.Format("The angle was outside the allowed range! Angle {0}", 
                                     new object[] { Vector3.Angle(arm1, arm2) } ));
            return;
        }
    
        //If we reach this point, everything's great, we have a "V"!
        Debug.Log ("There's a V gesture here!");
    }
    
    
    }
    

    The logic behind the code

    我假设了以下内容

    • "V"始终是用两个手指靠近开始绘制的,并且彼此远离 .

    • 当手指彼此远离时,它们在一个轴上以相同方向移动,而在另一个轴上以相反方向移动 . (例如,如果"V"的绘制方式与字母完全相同,则两个手指在正Y轴上移动,一个手指向负X轴移动,另一个手指向正X轴移动)

    • 手指相对靠近在一起,因此两点的平均值可以用作"V"的两个臂相交的点 . (请阅读替代机制的代码)

    Lousy attempt at graphically representing my thoughts below

    enter image description here

相关问题