C# Unity2D-以类似网格的定时方式移动2D对象
我已经尝试了一段时间,但我失败了 我有一个自上而下的二维平面中的刚体,我试着简单地沿着坐标移动它,平面是网格状的,所以一步/按钮按下就等于一个正方形。它应该只能在四个方向中的一个方向上行走,并且无论用户何时停止行走运动,它都应该以正方形结束。一款相当于我想要实现的游戏是lufia/火焰之息/任何类似的RPG系列。我曾尝试使用协程让更新函数在每个步骤后等待一秒钟,但这似乎不起作用。我最接近的是下面的代码。谢谢大家C# Unity2D-以类似网格的定时方式移动2D对象,c#,unity3d,unity5,unity2d,C#,Unity3d,Unity5,Unity2d,我已经尝试了一段时间,但我失败了 我有一个自上而下的二维平面中的刚体,我试着简单地沿着坐标移动它,平面是网格状的,所以一步/按钮按下就等于一个正方形。它应该只能在四个方向中的一个方向上行走,并且无论用户何时停止行走运动,它都应该以正方形结束。一款相当于我想要实现的游戏是lufia/火焰之息/任何类似的RPG系列。我曾尝试使用协程让更新函数在每个步骤后等待一秒钟,但这似乎不起作用。我最接近的是下面的代码。谢谢大家 public class PlayerMovement2D : MonoBehavi
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循环。我尝试简单地使用协程位,并对其进行更改,使其适合我的代码,但效果不如下面的解决方案。无论如何,谢谢你的帮助!嘿,谢谢你的建议!我的一位同事在我发布到这里之后就提出了这个建议,所以我本来打算去看看。我可以用另一条评论修改我的代码,但我肯定也会阅读/观看这篇文章。谢谢嘿,谢谢你的建议!我的一位同事在我发布到这里之后就提出了这个建议,所以我本来打算去看看。我可以用另一条评论修改我的代码,但我肯定也会阅读/观看这篇文章。谢谢