Unity推箱子类游戏多可推动物体移动异常问题求助
问题分析与解决方案
问题描述
- 已实现同时推动3个可推动物体,但队列末尾的可推动物体碰到障碍物时,第一个物体会与下一个物体重叠。
- 需求:只要队列最后一个可推动物体不会触碰障碍物,无论后方有多少可推动物体,都能推动任意数量的可推动物体。
现有代码问题
现有代码硬编码处理最多3个可推动物体的场景,逻辑嵌套复杂,且存在边检测边移动的错误逻辑——当检测到末端障碍时,前面的物体已经被移动,直接导致重叠。正确逻辑应该是先完整验证整个推动链的路径是否畅通,再一次性移动所有物体。
修改后的代码
// 尝试推动当前物体及后续的可推动物体链 public bool PushMove(Vector2 direction) { // 先检测整个推动链是否具备移动条件 List<Transform> pushChain = GetPushChain(transform.position, direction); if (pushChain == null) { return false; } // 一次性移动链条上的所有物体 foreach (var obj in pushChain) { obj.Translate(direction); } return true; } // 获取当前方向上的完整可推动物体链,若末端存在障碍物则返回null private List<Transform> GetPushChain(Vector3 startPos, Vector2 direction) { List<Transform> chain = new List<Transform>(); Vector2 currentPos = new Vector2(startPos.x, startPos.y); while (true) { currentPos += direction; // 检查当前位置是否是障碍物 if (IsObstacle(currentPos)) { return null; // 末端遇障,无法推动 } // 检查当前位置是否存在可推动物体 Transform pushable = GetPushableAtPosition(currentPos); if (pushable == null) { break; // 无更多可推动物体,链条检测完成 } // 防止循环检测同一物体 if (chain.Contains(pushable)) { return null; } chain.Add(pushable); } return chain; } // 检查指定位置是否存在障碍物 private bool IsObstacle(Vector2 pos) { foreach (var obstacle in NotMovableObj) { if (obstacle.transform.position.x == pos.x && obstacle.transform.position.y == pos.y) { return true; } } return false; } // 获取指定位置的可推动物体 private Transform GetPushableAtPosition(Vector2 pos) { foreach (var pushable in MovableObj) { if (pushable.transform.position.x == pos.x && pushable.transform.position.y == pos.y) { return pushable.transform; } } return null; }
代码说明
- GetPushChain方法:从起始位置出发,沿推动方向循环检测所有可推动物体,直到碰到空位置或障碍物。若遇障则返回null,表示无法推动;否则返回完整的可推动物体链。
- PushMove方法:先通过GetPushChain确认整个链条可移动,再一次性完成所有物体的移动,彻底避免边移边检测导致的重叠问题。
- 拆分辅助方法:将障碍物检测、可推动物体检测拆分为独立方法,简化主逻辑,提升代码可读性。
- 支持任意数量:不再限制可推动物体的数量,无论链条长度如何,只要末端无障碍物就能正常推动。
关键改进点
- 先检测后移动:确保整个推动路径完全畅通后再执行移动,从根源解决物体重叠问题。
- 动态生成推动链:通过循环自动识别所有可推动物体,适配任意长度的推动队列。
- 逻辑解耦:拆分重复检测逻辑,降低代码复杂度,便于后续维护和扩展。
内容的提问来源于stack exchange,提问作者Foxinetra
相关产品推荐
相关产品推荐

