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

Unity国际象棋开发皇后穿过友方棋子移动的逻辑修复问题

国际象棋皇后移动阻挡逻辑修复方案

问题根源

你用normalized.Equals判断方向失效的核心原因是浮点数精度误差,Unity的Vector2是浮点类型,归一化计算后会存在微小的精度偏差,直接调用Equals方法会因为这些微小偏差返回false,而国际象棋的棋盘坐标全是整数,完全可以用整数方向判断规避这个问题。

除此之外你的原有逻辑还有三个明显问题:

  • 遍历legalMoves的过程中直接修改legalMoves的值,会导致迭代器异常或者遍历遗漏元素
  • 边生成trail边删除trail的逻辑效率极低,反复调用GameObject.FindGameObjectsWithTag会带来不必要的性能开销
  • 每次遇到阻挡点就全量遍历所有移动点的逻辑,时间复杂度很高,逻辑也容易出错

修复方案

我们可以先把所有移动点按整数最简方向分组,同一方向的点按距离棋子的远近排序,再依次校验阻挡,逻辑清晰且完全规避浮点精度问题。

实现代码

首先写一个求最大公约数的工具方法,用来计算最简整数方向:

// 计算最大公约数,用来约分方向向量
private int GCD(int a, int b) {
    a = Mathf.Abs(a);
    b = Mathf.Abs(b);
    while (b != 0) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a == 0 ? 1 : a;
}

然后是主逻辑:

// 替换为你当前棋子的整数棋盘坐标
Vector2Int piecePos = 你的棋子当前棋盘坐标;
List<Vector2> finalLegalMoves = new List<Vector2>();
// 用来按方向分组存储移动点
Dictionary<(int dirX, int dirY), List<Vector2>> dirGroups = new Dictionary<(int dirX, int dirY), List<Vector2>>();

// 第一步:预处理所有移动点,按方向分组
foreach (var move in legalMoves) {
    // 先筛掉棋盘外的点
    if (move.x < 0 || move.x > 7 || move.y < 0 || move.y > 7) continue;
    int dx = (int)move.x - piecePos.x;
    int dy = (int)move.y - piecePos.y;
    // 跳过棋子自身的位置
    if (dx == 0 && dy == 0) continue;

    // 计算最简整数方向
    int gcd = GCD(dx, dy);
    var dirKey = (dx / gcd, dy / gcd);

    if (!dirGroups.ContainsKey(dirKey)) {
        dirGroups[dirKey] = new List<Vector2>();
    }
    dirGroups[dirKey].Add(move);
}

// 第二步:逐个方向校验阻挡
foreach (var group in dirGroups) {
    // 同一方向的点按距离棋子从近到远排序
    var sortedMoves = group.Value.OrderBy(move => 
        Mathf.Pow(move.x - piecePos.x, 2) + Mathf.Pow(move.y - piecePos.y, 2)
    ).ToList();

    bool isBlocked = false;
    foreach (var move in sortedMoves) {
        if (isBlocked) continue;

        var currentPiece = board[(int)move.x, (int)move.y].getPiece();
        if (currentPiece == null) {
            // 空位,保留移动点
            finalLegalMoves.Add(move);
        } else {
            // 有棋子,判断是否是敌方,是敌方可以吃所以保留
            if (currentPiece.isEnemy) {
                finalLegalMoves.Add(move);
            }
            // 不管是友方还是敌方,后面的点全部被阻挡
            isBlocked = true;
        }
    }
}

// 第三步:统一生成移动轨迹,不需要边删边加
foreach (var move in finalLegalMoves) {
    Instantiate(trail, move, Quaternion.identity);
}

// 更新合法移动点数组
legalMoves = finalLegalMoves.ToArray();

方案优势

  • 用整数方向判断,完全规避浮点数精度问题,方向识别准确率100%
  • 先预处理再校验的逻辑结构清晰,不会出现遍历过程中修改集合的异常
  • 时间复杂度更低,不需要反复遍历全量移动点和查找游戏对象
  • 兼容了吃子规则,遇到敌方棋子可以吃但后面的点仍然被阻挡,完全符合国际象棋的移动规则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 06:30:05