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

Unity 3D中玩家网格定位与基于网格的移动实现问题

解决方案

1. 世界坐标与网格位置的转换逻辑

你的网格每个瓦片的间距是10单位(生成时用i*10和j*10计算世界坐标),所以可以通过简单的数学运算实现坐标互转:

世界坐标转网格位置

// 根据玩家世界坐标获取对应的网格(i,j)
public Vector2Int GetGridPosition(Vector3 worldPos)
{
    // 用RoundToInt取最近的网格坐标,若需严格判断当前所在网格可改用FloorToInt
    int gridI = Mathf.RoundToInt(worldPos.x / 10f);
    int gridJ = Mathf.RoundToInt(worldPos.z / 10f);
    // 确保坐标不超出网格范围
    gridI = Mathf.Clamp(gridI, 0, height - 1);
    gridJ = Mathf.Clamp(gridJ, 0, width - 1);
    return new Vector2Int(gridI, gridJ);
}

网格位置转世界坐标

// 根据网格(i,j)获取对应的世界坐标
public Vector3 GetWorldPosition(int i, int j)
{
    return new Vector3(i * 10f, 0f, j * 10f);
}

2. 整合到你的项目中

为了避免硬编码数值、方便脚本间共享网格数据,推荐给GridCreation添加单例模式,再编写玩家移动脚本实现WASD控制:

修改GridCreation脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GridCreation : MonoBehaviour
{
    public static GridCreation Instance; // 单例,供其他脚本直接调用
    public int height = 7;
    public int width = 7;
    public float tileSize = 10f; // 把瓦片间距设为变量,后续修改更方便
    public GameObject prefabPlane;
    public GameObject prefabPlane2;

    void Awake()
    {
        Instance = this;
    }

    void Start()
    {
        GameObject newObject;
        for (int i = 0; i < height; i++)
        {
            for (int j = 0; j < width; j++)
            {
                newObject = Instantiate(
                    (i + j) % 2 == 0 ? prefabPlane : prefabPlane2,
                    GetWorldPosition(i, j),
                    Quaternion.identity
                );
                newObject.name = $"{i},{j}";
            }
        }
    }

    // 对外暴露的坐标转换方法
    public Vector3 GetWorldPosition(int i, int j)
    {
        return new Vector3(i * tileSize, 0f, j * tileSize);
    }

    public Vector2Int GetGridPosition(Vector3 worldPos)
    {
        int gridI = Mathf.RoundToInt(worldPos.x / tileSize);
        int gridJ = Mathf.RoundToInt(worldPos.z / tileSize);
        gridI = Mathf.Clamp(gridI, 0, height - 1);
        gridJ = Mathf.Clamp(gridJ, 0, width - 1);
        return new Vector2Int(gridI, gridJ);
    }
}

玩家移动脚本示例

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    public float moveSpeed = 6f;
    private Vector3 targetPos;
    private bool isMoving = false;

    void Start()
    {
        // 初始化玩家到当前所在网格的中心
        Vector2Int startGrid = GridCreation.Instance.GetGridPosition(transform.position);
        targetPos = GridCreation.Instance.GetWorldPosition(startGrid.x, startGrid.y);
        transform.position = targetPos;
    }

    void Update()
    {
        if (isMoving)
        {
            // 平滑移动到目标位置
            transform.position = Vector3.MoveTowards(transform.position, targetPos, moveSpeed * Time.deltaTime);
            // 到达目标后停止移动
            if (Vector3.Distance(transform.position, targetPos) < 0.1f)
            {
                transform.position = targetPos;
                isMoving = false;
            }
            return;
        }

        // 处理WASD按键输入
        if (Input.GetKeyDown(KeyCode.W)) MoveGrid(0, 1);
        else if (Input.GetKeyDown(KeyCode.S)) MoveGrid(0, -1);
        else if (Input.GetKeyDown(KeyCode.A)) MoveGrid(-1, 0);
        else if (Input.GetKeyDown(KeyCode.D)) MoveGrid(1, 0);
    }

    void MoveGrid(int deltaI, int deltaJ)
    {
        Vector2Int currentGrid = GridCreation.Instance.GetGridPosition(transform.position);
        int targetI = currentGrid.x + deltaI;
        int targetJ = currentGrid.y + deltaJ;

        // 边界检查:防止玩家移出网格
        if (targetI >= 0 && targetI < GridCreation.Instance.height 
            && targetJ >= 0 && targetJ < GridCreation.Instance.width)
        {
            targetPos = GridCreation.Instance.GetWorldPosition(targetI, targetJ);
            isMoving = true;
        }
    }
}

关键说明

  • 单例模式让GridCreation的网格参数和转换方法可以被移动脚本直接调用,后续修改瓦片大小或网格尺寸时无需到处改代码。
  • 移动时加入边界检查,避免玩家超出网格范围。
  • 平滑移动用Vector3.MoveTowards实现,若需瞬间移动可直接设置transform.position = targetPos。

内容的提问来源于stack exchange,提问作者Chris W.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 21:00:59