找到播放器左侧或右侧的下一个转换

时间:2018-04-09 21:18:08

标签: unity3d vector coroutine

我有一个具有公共变换数组的类,这些变换是角色可以移动到的点。每当玩家击中A或D键时,他们的角色将平稳地向左或向右移动到下一个位置,具体取决于他们是否击中A或D.

我尝试此操作的方法是在播放器按下键盘上的A或D键时启动协同程序。然后,协程将立即找到数组中的下一个左转换点,并开始使用while循环移动到那里。

现在我遇到的问题是能够找到最近的左/右点..我该怎么做呢?

到目前为止,这是我的代码:

public Transform[] positions;

    public int StartPosition = 0;

    private void Awake()
    {
        //set the start position, change the index to the one you would like the player to start at
        transform.position = positions[StartPosition].position;
    }

    private void Update()
    {
        //Register Key Events
        if (Input.GetKeyDown(KeyCode.A))
        {
            StartCoroutine(Move("Left", transform.position));
        }
        if (Input.GetKeyDown(KeyCode.D))
        {
            StartCoroutine(Move("Right", transform.position));
        }
    }

    /// <summary>
    /// Moves the player character to the next position to the left or right
    /// </summary>
    IEnumerator Move(string dir, Vector2 currentPosition)
    {
        if(dir == "Left")
        {
            //Find and store next left position if it exists
            // HOW DO I DO THIS??????

            // Go To Next Left Position
            while (transform.position.x > nextLeftPos.position.x)
            {
                transform.position = Vector3.MoveTowards(transform.position, nextLeftPos.position, moveSpeed * Time.deltaTime);
                //Come back next frame
                yield return null;
            }

        }
    }

这是我的玩家动作组件:

enter image description here

提前致谢

4 个答案:

答案 0 :(得分:0)

您可以使用Transform.right向量完成此测试,该向量指向播放器的右侧。

通过创建从玩家到位置的单位向量,并减去Transform.forward向量,您将获得一个向量,允许您测试该点是在左侧还是右侧播放器。

Vector3 f = transform.forward;
Vector3 r = transform.right;
foreach (Transform t in Positions) {
    Vector3 pos = t.position;
    Vector3 sideTest = (pos - f).normalized;

    if(Vector3.Dot(sideTest, r)) >= 0.0) {
        // This position its on the right
    } else {
        // This position is on the left
    }
}

在开始游戏之前将所有这些信息预先计算到树中会更有效率,因为您可以获得接下来的2个位置来测试而不是遍历所有阵列。

答案 1 :(得分:0)

我认为在比赛期间你的位置不会改变。

创建一个整数作为玩家位置。以屏幕中间为起点,忘记玩家当前的transform.position。计算数组中的位置。

例如;如果你的玩家留在阵列的第三个元素。然后向右移动应该到第四个。因此,第四个元素位置已经在数组中定义为Transform。

enter image description here

粗略的脚本在这里;

 public int whichRoad;
    public float roadChangeSpeed = 5.0f;
    Vector2 roadMinusOne = new Vector2(-2.4f, -3.44f); // -1. Left road coordinates
    Vector2 roadZero = new Vector2(0f, -3.44f);       // 0.  Middle road coordinates
    Vector2 roadOne = new Vector2(2.44f, -3.44f);      // 1. Right road coordinates
    Vector2 choosenRoad;


void SwipeLeft(){

bla bla bla swipe left
whichRoad--;

}

void SwipeRight(){

bla bla bla swipe right
whichRoad++;

}

void FixedUpdate()
{

ChangeRoad();
}


    void ChangeRoad() 
        {
            if (whichRoad == -1)

            {

              choosenRoad = roadMinusOne;

            }

            else if (whichRoad == 0)

            {

                choosenRoad = roadZero;

            }

            else if (whichRoad == 1)

            {

                choosenRoad = roadOne;

            }


                transform.position = Vector2.Lerp(transform.position, choosenRoad, Time.deltaTime * roadChangeSpeed);

答案 2 :(得分:0)

你不应该使用while循环来检查这一点,因为性能一般非常低。建议的方法是使用Raycast和collider。

enter image description here

将球体对撞机添加到所有&#34;点&#34;,即候选游戏对象与当前玩家发生碰撞,并使用下面的片段:

using UnityEngine;

public class ExampleClass : MonoBehaviour
{
    RaycastHit hit;
    void FixedUpdate()
    {
        Vector3 left = transform.TransformDirection(Vector3.left);

        if (Physics.Raycast(transform.position, left, out hit, Mathf.Infinity))
            Debug.Log(hit.transform.position); // <--- this is what you want
    }
} 

可以找到一个好的教程here

答案 3 :(得分:0)

感谢所有帮助。我找到了一个使用Update()中的移动标记和Vector3.MoveTowards()组合的解决方案。为了在玩家到达下一个目的地点时停止玩家,我有一个在每次移动呼叫之后调用的功能,该功能检测玩家是否接触到阵列中的任何移动点。如果是这样,它将移动标志设置为false并存储玩家当前位置索引。

这是我的班级:

public class PlayerMovementStepper : MonoBehaviour
    {
        [Tooltip("From furthest left to furthest right...")]
        public Transform[] Points;

        [Tooltip("How fast the player moves between points")]
        public float MoveSpeed;

        [Tooltip("On which point index does the player start?")]
        public int StartPointIndex;

        //This is going to be so we can tell which point to move towards
        private int currentIndex;

        //Moving flags for update function
        private bool movingLeft = false;
        private bool movingRight = false;

        private void Awake()
        {
            transform.position = Points[StartPointIndex].position;
            currentIndex = StartPointIndex;
        }

        private void Update()
        {
            //Check for movement flags
            if (movingLeft)
            {
                if (currentIndex > 0)
                {
                    transform.position = Vector3.MoveTowards(transform.position, Points[currentIndex - 1].position, MoveSpeed * Time.deltaTime);
                }
                StopPlayerIfOnPoint();
            }

            if (movingRight)
            {
                if (currentIndex < Points.Length - 1)
                {
                    transform.position = Vector3.MoveTowards(transform.position, Points[currentIndex + 1].position, MoveSpeed * Time.deltaTime);
                }
                StopPlayerIfOnPoint();
            }
        }

        public void MoveToNextLeft()
        {
            movingLeft = true;
            movingRight = false;
        }

        public void MoveToNextRight()
        {
            movingLeft = false;
            movingRight = true;
        }

        /// <summary>
        /// This Function calls after every move call (if any) to check
        /// whether or not the player hit the next point. If the player did hit 
        /// then it will stop the player from moving and then store its current 
        /// position.
        /// </summary>
        private void StopPlayerIfOnPoint()
        {
            var i = 0;
            foreach (Transform pos in Points)
            {
                //Check for collisions
                if (transform.position == pos.position)
                {
                    if (movingLeft || movingRight)
                    {
                        currentIndex = i;
                    }
                    movingLeft = false;
                    movingRight = false;
                }
                i++;
            }
        }

    }

此类允许用户附加玩家可以移动的多个位置点,只要他们从最左边到最右边添加它们:

enter image description here

我希望我能为此解决方案获得所有输入。有一点我注意到我需要马上改变的是我在玩家到达下一个目的地时的方式。现在它依赖于玩家角色在点数组中的一个点完全位置。我宁愿让目标点存储在一个变量中,当角色移动时,我可以检查玩家是否在该点的某个半径范围内,以便停止它并将玩家捕捉到该点。

反正。让我知道你们都在想什么。提前谢谢。