C# Unity2D-以类似网格的定时方式移动2D对象

C# Unity2D-以类似网格的定时方式移动2D对象,c#,unity3d,unity5,unity2d,C#,Unity3d,Unity5,Unity2d,我已经尝试了一段时间,但我失败了 我有一个自上而下的二维平面中的刚体,我试着简单地沿着坐标移动它,平面是网格状的,所以一步/按钮按下就等于一个正方形。它应该只能在四个方向中的一个方向上行走,并且无论用户何时停止行走运动,它都应该以正方形结束。一款相当于我想要实现的游戏是lufia/火焰之息/任何类似的RPG系列。我曾尝试使用协程让更新函数在每个步骤后等待一秒钟,但这似乎不起作用。我最接近的是下面的代码。谢谢大家 public class PlayerMovement2D : MonoBehavi

我已经尝试了一段时间,但我失败了

我有一个自上而下的二维平面中的刚体,我试着简单地沿着坐标移动它,平面是网格状的,所以一步/按钮按下就等于一个正方形。它应该只能在四个方向中的一个方向上行走,并且无论用户何时停止行走运动,它都应该以正方形结束。一款相当于我想要实现的游戏是lufia/火焰之息/任何类似的RPG系列。我曾尝试使用协程让更新函数在每个步骤后等待一秒钟,但这似乎不起作用。我最接近的是下面的代码。谢谢大家

public class PlayerMovement2D : MonoBehaviour
{    
Rigidbody2D rbody;
Animator anim;    
float speed = 1.25f;
Vector2 pos;
void Start()
{
    rbody = GetComponent<Rigidbody2D>();
    anim = GetComponent<Animator>();
    pos = rbody.position;
}
void FixedUpdate()
{
    Vector2 movement_vector = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
    if (movement_vector.x != 0 || movement_vector.y != 0)
    {
        if (movement_vector.x > 0)
        {
            pos += Vector2.right;
            pos.y = 0;
        }          
        else if (movement_vector.x < 0)
        {
            pos += Vector2.left;
            pos.y = 0;
        }
        else if (movement_vector.y > 0)
        {
            pos += Vector2.up;
            pos.x = 0;
        }
        else if (movement_vector.y < 0)
        {
            pos += Vector2.down;
            pos.x = 0;
        }
        anim.SetBool("IsWalking", true);
        anim.SetFloat("Input_x", movement_vector.x);
        anim.SetFloat("Input_y", movement_vector.y);
    }
    else
    {
        anim.SetBool("IsWalking", false);
    }
    rbody.position = Vector2.MoveTowards(rbody.position, pos, speed * Time.deltaTime);
    //transform.position = Vector3.MoveTowards(transform.position, pos, Time.deltaTime * speed);
    pos = rbody.position;
    }
}

我认为您希望在一个协同程序中进行移动,当它处于活动状态时,禁用进一步的移动,直到完成为止

bool isIdle = true;

void Update() {
    if(isIdle) {
        // Your movement code that gives pos
        StartCoroutine(Move(pos));
    }
}


IEnumerator Move(Vector2 destination) {
    isIdle = false;
    do {
        transform.position = Vector2.MoveTowards(transform.position, destination, speed * Time.deltaTime);
        yield return new WaitForEndOfFrame();
    } while (transform.position != destination);
    isIdle = true;
}

如果您不理解,需要进一步澄清或此方法不起作用,请告诉我

我认为您希望在一个协同程序中进行移动,该程序处于活动状态时,禁用进一步的移动,直到完成为止

bool isIdle = true;

void Update() {
    if(isIdle) {
        // Your movement code that gives pos
        StartCoroutine(Move(pos));
    }
}


IEnumerator Move(Vector2 destination) {
    isIdle = false;
    do {
        transform.position = Vector2.MoveTowards(transform.position, destination, speed * Time.deltaTime);
        yield return new WaitForEndOfFrame();
    } while (transform.position != destination);
    isIdle = true;
}

如果您不理解,需要进一步澄清或此方法不起作用,请告诉我

我认为您尝试编写的程序与Unity网站教程集中的RogueLike游戏类似。首先查看介绍视频,确认这是您计划实现的目标

如果是这样,他们就是这样处理的:

using UnityEngine;
using System.Collections;

    //The abstract keyword enables you to create classes and class members that are incomplete and must be implemented in a derived class.
    public abstract class MovingObject : MonoBehaviour
    {
        public float moveTime = 0.1f;           //Time it will take object to move, in seconds.
        public LayerMask blockingLayer;         //Layer on which collision will be checked.


        private BoxCollider2D boxCollider;      //The BoxCollider2D component attached to this object.
        private Rigidbody2D rb2D;               //The Rigidbody2D component attached to this object.
        private float inverseMoveTime;          //Used to make movement more efficient.


        //Protected, virtual functions can be overridden by inheriting classes.
        protected virtual void Start ()
        {
            //Get a component reference to this object's BoxCollider2D
            boxCollider = GetComponent <BoxCollider2D> ();

            //Get a component reference to this object's Rigidbody2D
            rb2D = GetComponent <Rigidbody2D> ();

            //By storing the reciprocal of the move time we can use it by multiplying instead of dividing, this is more efficient.
            inverseMoveTime = 1f / moveTime;
        }


        //Move returns true if it is able to move and false if not. 
        //Move takes parameters for x direction, y direction and a RaycastHit2D to check collision.
        protected bool Move (int xDir, int yDir, out RaycastHit2D hit)
        {
            //Store start position to move from, based on objects current transform position.
            Vector2 start = transform.position;

            // Calculate end position based on the direction parameters passed in when calling Move.
            Vector2 end = start + new Vector2 (xDir, yDir);

            //Disable the boxCollider so that linecast doesn't hit this object's own collider.
            boxCollider.enabled = false;

            //Cast a line from start point to end point checking collision on blockingLayer.
            hit = Physics2D.Linecast (start, end, blockingLayer);

            //Re-enable boxCollider after linecast
            boxCollider.enabled = true;

            //Check if anything was hit
            if(hit.transform == null)
            {
                //If nothing was hit, start SmoothMovement co-routine passing in the Vector2 end as destination
                StartCoroutine (SmoothMovement (end));

                //Return true to say that Move was successful
                return true;
            }

            //If something was hit, return false, Move was unsuccesful.
            return false;
        }


        //Co-routine for moving units from one space to next, takes a parameter end to specify where to move to.
        protected IEnumerator SmoothMovement (Vector3 end)
        {
            //Calculate the remaining distance to move based on the square magnitude of the difference between current position and end parameter. 
            //Square magnitude is used instead of magnitude because it's computationally cheaper.
            float sqrRemainingDistance = (transform.position - end).sqrMagnitude;

            //While that distance is greater than a very small amount (Epsilon, almost zero):
            while(sqrRemainingDistance > float.Epsilon)
            {
                //Find a new position proportionally closer to the end, based on the moveTime
                Vector3 newPostion = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);

                //Call MovePosition on attached Rigidbody2D and move it to the calculated position.
                rb2D.MovePosition (newPostion);

                //Recalculate the remaining distance after moving.
                sqrRemainingDistance = (transform.position - end).sqrMagnitude;

                //Return and loop until sqrRemainingDistance is close enough to zero to end the function
                yield return null;
            }
        }


        //The virtual keyword means AttemptMove can be overridden by inheriting classes using the override keyword.
        //AttemptMove takes a generic parameter T to specify the type of component we expect our unit to interact with if blocked (Player for Enemies, Wall for Player).
        protected virtual void AttemptMove <T> (int xDir, int yDir)
            where T : Component
        {
            //Hit will store whatever our linecast hits when Move is called.
            RaycastHit2D hit;

            //Set canMove to true if Move was successful, false if failed.
            bool canMove = Move (xDir, yDir, out hit);

            //Check if nothing was hit by linecast
            if(hit.transform == null)
                //If nothing was hit, return and don't execute further code.
                return;

            //Get a component reference to the component of type T attached to the object that was hit
            T hitComponent = hit.transform.GetComponent <T> ();

            //If canMove is false and hitComponent is not equal to null, meaning MovingObject is blocked and has hit something it can interact with.
            if(!canMove && hitComponent != null)

                //Call the OnCantMove function and pass it hitComponent as a parameter.
                OnCantMove (hitComponent);
        }


        //The abstract modifier indicates that the thing being modified has a missing or incomplete implementation.
        //OnCantMove will be overriden by functions in the inheriting classes.
        protected abstract void OnCantMove <T> (T component)
            where T : Component;
    }
链接到本教程的这一部分:

我认为您尝试编写的程序类似于Unity网站教程集中的RogueLike游戏。首先查看介绍视频,确认这是您计划实现的目标

如果是这样,他们就是这样处理的:

using UnityEngine;
using System.Collections;

    //The abstract keyword enables you to create classes and class members that are incomplete and must be implemented in a derived class.
    public abstract class MovingObject : MonoBehaviour
    {
        public float moveTime = 0.1f;           //Time it will take object to move, in seconds.
        public LayerMask blockingLayer;         //Layer on which collision will be checked.


        private BoxCollider2D boxCollider;      //The BoxCollider2D component attached to this object.
        private Rigidbody2D rb2D;               //The Rigidbody2D component attached to this object.
        private float inverseMoveTime;          //Used to make movement more efficient.


        //Protected, virtual functions can be overridden by inheriting classes.
        protected virtual void Start ()
        {
            //Get a component reference to this object's BoxCollider2D
            boxCollider = GetComponent <BoxCollider2D> ();

            //Get a component reference to this object's Rigidbody2D
            rb2D = GetComponent <Rigidbody2D> ();

            //By storing the reciprocal of the move time we can use it by multiplying instead of dividing, this is more efficient.
            inverseMoveTime = 1f / moveTime;
        }


        //Move returns true if it is able to move and false if not. 
        //Move takes parameters for x direction, y direction and a RaycastHit2D to check collision.
        protected bool Move (int xDir, int yDir, out RaycastHit2D hit)
        {
            //Store start position to move from, based on objects current transform position.
            Vector2 start = transform.position;

            // Calculate end position based on the direction parameters passed in when calling Move.
            Vector2 end = start + new Vector2 (xDir, yDir);

            //Disable the boxCollider so that linecast doesn't hit this object's own collider.
            boxCollider.enabled = false;

            //Cast a line from start point to end point checking collision on blockingLayer.
            hit = Physics2D.Linecast (start, end, blockingLayer);

            //Re-enable boxCollider after linecast
            boxCollider.enabled = true;

            //Check if anything was hit
            if(hit.transform == null)
            {
                //If nothing was hit, start SmoothMovement co-routine passing in the Vector2 end as destination
                StartCoroutine (SmoothMovement (end));

                //Return true to say that Move was successful
                return true;
            }

            //If something was hit, return false, Move was unsuccesful.
            return false;
        }


        //Co-routine for moving units from one space to next, takes a parameter end to specify where to move to.
        protected IEnumerator SmoothMovement (Vector3 end)
        {
            //Calculate the remaining distance to move based on the square magnitude of the difference between current position and end parameter. 
            //Square magnitude is used instead of magnitude because it's computationally cheaper.
            float sqrRemainingDistance = (transform.position - end).sqrMagnitude;

            //While that distance is greater than a very small amount (Epsilon, almost zero):
            while(sqrRemainingDistance > float.Epsilon)
            {
                //Find a new position proportionally closer to the end, based on the moveTime
                Vector3 newPostion = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);

                //Call MovePosition on attached Rigidbody2D and move it to the calculated position.
                rb2D.MovePosition (newPostion);

                //Recalculate the remaining distance after moving.
                sqrRemainingDistance = (transform.position - end).sqrMagnitude;

                //Return and loop until sqrRemainingDistance is close enough to zero to end the function
                yield return null;
            }
        }


        //The virtual keyword means AttemptMove can be overridden by inheriting classes using the override keyword.
        //AttemptMove takes a generic parameter T to specify the type of component we expect our unit to interact with if blocked (Player for Enemies, Wall for Player).
        protected virtual void AttemptMove <T> (int xDir, int yDir)
            where T : Component
        {
            //Hit will store whatever our linecast hits when Move is called.
            RaycastHit2D hit;

            //Set canMove to true if Move was successful, false if failed.
            bool canMove = Move (xDir, yDir, out hit);

            //Check if nothing was hit by linecast
            if(hit.transform == null)
                //If nothing was hit, return and don't execute further code.
                return;

            //Get a component reference to the component of type T attached to the object that was hit
            T hitComponent = hit.transform.GetComponent <T> ();

            //If canMove is false and hitComponent is not equal to null, meaning MovingObject is blocked and has hit something it can interact with.
            if(!canMove && hitComponent != null)

                //Call the OnCantMove function and pass it hitComponent as a parameter.
                OnCantMove (hitComponent);
        }


        //The abstract modifier indicates that the thing being modified has a missing or incomplete implementation.
        //OnCantMove will be overriden by functions in the inheriting classes.
        protected abstract void OnCantMove <T> (T component)
            where T : Component;
    }
链接到本教程的这一部分:

您可以将该方法与Unity的协同程序系统结合使用

此方法假定您可以按指定的方向移动。但在开始移动协同程序之前,您仍然应该检查您的新位置是否可以行走。

您可以结合Unity的协同程序系统使用该方法


此方法假定您可以按指定的方向移动。但在开始移动合作程序之前,您仍应检查您的新职位是否可以行走。

如果您尝试了任何方法或接受了解决问题的答案,请务必告知我们。如果您尝试了任何方法或接受了解决问题的答案,请务必告知我们。谢谢!我想我的合作项目有一些错误,这一个工作得很好。正如你所说,我仍然需要消除碰撞,以前的代码简单地使用碰撞器和刚体似乎可以工作,现在我的角色可以穿墙了。谢谢!我想我的合作项目有一些错误,这一个工作得很好。正如你所说,我仍然需要消除碰撞,以前的代码仅仅使用碰撞器和刚体似乎可以工作,现在我的角色可以穿墙了。嘿,弗雷德里克,很抱歉我没有更快地回答。我试过你的代码,但它自己崩溃了Unity/陷入了一个while循环。我尝试简单地使用协程位,并对其进行更改,使其适合我的代码,但效果不如下面的解决方案。无论如何,谢谢你的帮助!嘿,弗雷德里克,很抱歉我没有更快地回答。我试过你的代码,但它自己崩溃了Unity/陷入了一个while循环。我尝试简单地使用协程位,并对其进行更改,使其适合我的代码,但效果不如下面的解决方案。无论如何,谢谢你的帮助!嘿,谢谢你的建议!我的一位同事在我发布到这里之后就提出了这个建议,所以我本来打算去看看。我可以用另一条评论修改我的代码,但我肯定也会阅读/观看这篇文章。谢谢嘿,谢谢你的建议!我的一位同事在我发布到这里之后就提出了这个建议,所以我本来打算去看看。我可以用另一条评论修改我的代码,但我肯定也会阅读/观看这篇文章。谢谢