You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在四方向(上下左右)2D游戏中实现基于网格的移动?

搞定2D四方向网格移动的解决方案

嘿,我来帮你解决这个网格移动的问题!先看看你当前代码里的几个核心问题,再一步步调整到符合网格移动的逻辑:

原代码的问题点

  • 用了else if+GetKey:GetKey会持续触发,导致角色平滑滑动而不是“按一次动一格”;else if虽然不影响四方向,但核心问题是持续输入的逻辑完全不符合网格移动的需求
  • 没有移动锁定和网格对齐:网格移动需要确保角色精准停在网格节点上,且移动过程中不能重复触发新的移动请求

修改后的完整Player类代码

using UnityEngine;
using System.Collections;

public class Player : Character {
    public float moveSpeed = 2f; // 控制移动的平滑速度
    public float tileSize = 1f; // 你的网格每个格子的大小,比如1x1就设为1
    private bool isMoving = false; // 标记是否正在移动,防止重复触发

    /// <summary>
    /// 重写角色的Update函数,以便执行自定义功能
    /// </summary>
    protected override void Update() {
        GetInput();
        base.Update();
    }

    /// <summary>
    /// 监听玩家输入,触发网格移动
    /// </summary>
    private void GetInput() {
        // 如果正在移动,直接跳过输入处理,避免位置错乱
        if (isMoving) return;

        var direction = Vector2.zero;
        // 用GetKeyDown检测单次按键,实现"按一次动一格"的逻辑
        if (Input.GetKeyDown(KeyCode.UpArrow)) {
            direction = Vector2.up;
        } else if (Input.GetKeyDown(KeyCode.LeftArrow)) {
            direction = Vector2.left;
        } else if (Input.GetKeyDown(KeyCode.DownArrow)) {
            direction = Vector2.down;
        } else if (Input.GetKeyDown(KeyCode.RightArrow)) {
            direction = Vector2.right;
        }

        // 有有效输入时启动移动协程
        if (direction != Vector2.zero) {
            StartCoroutine(MoveToTargetTile(direction));
        }
    }

    /// <summary>
    /// 协程处理平滑网格移动,确保对齐网格节点
    /// </summary>
    private IEnumerator MoveToTargetTile(Vector2 moveDirection) {
        isMoving = true;
        // 计算目标位置:当前位置 + 方向*网格大小,确保落在网格节点上
        Vector2 targetPosition = (Vector2)transform.position + moveDirection * tileSize;

        // 平滑移动到目标位置
        while (Vector2.Distance(transform.position, targetPosition) > 0.01f) {
            transform.position = Vector2.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
            yield return null;
        }

        // 最后强制对齐到目标位置,避免浮点精度误差
        transform.position = targetPosition;
        isMoving = false;
    }
}

关键逻辑说明

  1. 移动锁定(isMoving):确保角色在移动过程中不会响应新的输入,避免出现一次按键触发多次移动、位置偏移的问题
  2. 单次输入检测(GetKeyDown):只在按键按下的第一帧触发移动,完美匹配网格移动“按一次动一格”的交互逻辑
  3. 网格对齐计算:通过tileSize控制每个格子的大小,目标位置直接基于当前网格节点计算,确保角色始终停在网格上
  4. 平滑移动协程:用协程实现平滑的移动动画,如果想要即时瞬移(无动画),可以去掉循环部分,直接设置transform.position = targetPosition

额外优化建议

  • 障碍物检测:在启动协程前,添加碰撞检测(比如Physics2D.OverlapCircle)检查目标位置是否有障碍物,有则取消移动
  • 八方向支持:如果后续要扩展八方向,只需要把else if改成单独的if,允许同时检测两个方向键(比如上+右)
  • 输入配置化:把方向键改成Unity的Input System轴输入,方便后续支持手柄、自定义按键

内容的提问来源于stack exchange,提问作者Neizhel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:52:14