我正在努力为我的角色融入基于图块的运动,目标是让角色与运动方向上的下一个图块对齐。目前,存在一个问题,即无论输入方向如何,玩家都会始终捕捉到顶部和右侧的单元格。因此,当我向左或底部移动角色时,它会捕捉到右侧或上部的单元格,而不是沿预期方向的下一个单元格。我正在使用新的玩家输入系统。
当前逻辑:
目标网格位置是根据当前玩家位置(rb.position)除以网格大小计算得出的。这给出了玩家当前所在的网格单元。 通过将movementInput向量添加到目标网格位置来计算移动方向上下一个图块的中心。 然后使用 rb.MovePosition 方法将玩家平滑地移动到下一个图块的计算中心。它使用 Vector2.Lerp 在当前位置和目标位置之间进行插值。 nextTileCenter * gridSize 将网格位置转换回世界空间。 添加新的 Vector2(gridSize / 2, gridSize / 2) 以确保玩家移动到下一个图块的中心。
`script:
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
public float moveSpeed = 1f;
public float snapSpeed = 10.0f;
public LayerMask collisionLayer;
Vector2 movementInput;
SpriteRenderer spriteRenderer;
Rigidbody2D rb;
Animator animator;
Transform gridTransform; // Reference to the grid game object
bool canMove = true;
float gridSize = 0.16f;
void Start()
{
rb = GetComponent<Rigidbody2D>();
animator = GetComponent<Animator>();
spriteRenderer = GetComponent<SpriteRenderer>();
// Find the grid game object
gridTransform = GameObject.Find("Grid").transform;
}
private void FixedUpdate()
{
if (canMove)
{
// Get raw input without normalization
Vector2 rawInput = movementInput;
// Normalize the input vector to limit diagonal movement
movementInput = new Vector2(Mathf.Round(rawInput.x), Mathf.Round(rawInput.y)).normalized;
if (movementInput != Vector2.zero)
{
// Calculate the target position on the grid
Vector2 targetPosition = CalculateTargetPosition(rb.position, movementInput);
// Check for potential collisions
RaycastHit2D hit = Physics2D.Raycast(targetPosition, Vector2.zero, gridSize, collisionLayer);
if (hit.collider == null)
{
// Move towards the target position using Rigidbody2D.MovePosition()
rb.MovePosition(rb.position + movementInput * moveSpeed * Time.deltaTime);
}
else
{
// Player hit something, try to snap to the grid smoothly
SmoothSnapToGrid();
}
animator.SetBool("isMoving", true);
}
else
{
// Player is not moving, try to snap to the grid smoothly
SmoothSnapToGrid();
animator.SetBool("isMoving", false);
}
// Set direction of sprite to movement direction
if (movementInput.x < 0)
{
spriteRenderer.flipX = true;
}
else if (movementInput.x > 0)
{
spriteRenderer.flipX = false;
}
}
}
private void SmoothSnapToGrid()
{
// Calculate the target grid position
Vector2 targetGridPosition = new Vector2(
Mathf.Round(rb.position.x / gridSize),
Mathf.Round(rb.position.y / gridSize)
);
// Calculate the center of the next tile in the movement direction
Vector2 nextTileCenter = targetGridPosition + movementInput;
// Smoothly move towards the center of the next tile in the movement direction
rb.MovePosition(Vector2.Lerp(rb.position, nextTileCenter * gridSize + new Vector2(gridSize / 2, gridSize / 2), snapSpeed * Time.deltaTime));
}
private Vector2 CalculateTargetPosition(Vector2 currentPosition, Vector2 direction)
{
// Calculate the target position based on the movement direction
Vector2 targetPosition = currentPosition + direction * moveSpeed * Time.deltaTime;
return targetPosition;
}
void OnMove(InputValue movementValue)
{
Vector2 rawInput = movementValue.Get<Vector2>();
float horizontal = Mathf.Round(rawInput.x);
float vertical = Mathf.Round(rawInput.y);
// Ensure only one direction is considered
if (Mathf.Abs(horizontal) > Mathf.Abs(vertical))
{
movementInput = new Vector2(horizontal, 0f).normalized;
}
else
{
movementInput = new Vector2(0f, vertical).normalized;
}
}
public void LockMovement()
{
canMove = false;
}
public void UnlockMovement()
{
canMove = true;
}
}`
有人可以帮忙吗? 谢谢你
Mathf.Round函数四舍五入到最接近的整数,这意味着如果玩家的位置恰好位于两个单元格的中间,则可能不会四舍五入到预期方向。这可能会导致顶部和右侧单元格一致对齐。
要解决此问题,您可以修改SmoothSnapToGrid 方法以在计算目标网格位置时考虑移动方向。您可以使用 Mathf.Floor 或 Mathf.Ceil,而不是使用 Mathf.Round,具体取决于移动方向:
private void SmoothSnapToGrid()
{
// Use Floor or Ceil depending on the direction to ensure snapping to the correct cell
Vector2 targetGridPosition = new Vector2(
(movementInput.x > 0) ? Mathf.Floor(rb.position.x / gridSize) : Mathf.Ceil(rb.position.x / gridSize),
(movementInput.y > 0) ? Mathf.Floor(rb.position.y / gridSize) : Mathf.Ceil(rb.position.y / gridSize)
);
// Calculate the center of the next tile in the movement direction
Vector2 nextTileCenter = targetGridPosition + movementInput;
// Smoothly move towards the center of the next tile in the movement direction
rb.MovePosition(Vector2.Lerp(rb.position, nextTileCenter * gridSize + new Vector2(gridSize / 2, gridSize / 2), snapSpeed * Time.deltaTime));
}
此更改可确保向左或向下移动时(movementInput.x 0 或 movingInput.y > 0),Mathf.Floor 用于捕捉到右侧或顶部单元格。< 0 or movementInput.y < 0), Mathf.Ceil is used to get the upper bound, effectively snapping to the left or bottom cell. Conversely, when moving right or up (movementInput.x >
此外,确保您的 OnMove 方法正确设置 movingInput 也很重要。如果您遇到对角线移动问题或想确保一次仅移动一个轴,那么您当前的实现似乎是正确的。最后,始终确保您的网格大小(gridSize)与游戏世界中图块的实际大小相匹配。如果不匹配,可能会导致错误的捕捉。