Unity Pacman左右移动碰撞后卡死及部分方向穿模问题求助
Pacman游戏开发问题
问题现象
- 角色左右移动时,一旦碰撞到Collider就会卡死,无法向任何方向移动,不确定是Collider还是移动脚本的问题。
- 若将Pacman对象的Circle Collider 2D组件的Is Trigger勾选为true,角色可移动但出现新问题:向左、向下移动时会穿透Collider并卡在内部,向右、向上移动则正常。
Pacman移动脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PacmanMove : MonoBehaviour { public float speed = 0.4f; Vector2 dest = Vector2.zero; void Start() { // 初始目标位置设为当前位置 dest = transform.position; } void FixedUpdate() { // 向目标位置移动 Vector2 p = Vector2.MoveTowards(transform.position, dest, speed); GetComponent<Rigidbody2D>().MovePosition(p); // 只有到达目标位置时才响应输入 if ((Vector2)transform.position == dest) { if (Input.GetKey(KeyCode.UpArrow) && valid(Vector2.up)) dest = (Vector2)transform.position + Vector2.up; if (Input.GetKey(KeyCode.RightArrow) && valid(Vector2.right)) dest = (Vector2)transform.position + Vector2.right; if (Input.GetKey(KeyCode.DownArrow) && valid(-Vector2.up)) dest = (Vector2)transform.position - Vector2.up; if (Input.GetKey(KeyCode.LeftArrow) && valid(-Vector2.right)) dest = (Vector2)transform.position - Vector2.right; } } // 检测移动方向是否合法 bool valid(Vector2 dir) { // 从Pacman相邻位置向自身发射射线 Vector2 pos = transform.position; RaycastHit2D hit = Physics2D.Linecast(pos + dir, pos); // 仅当射线只检测到自身Collider时,方向合法 return (hit.collider == GetComponent<Collider2D>()); } }
自动添加墙体Collider2D的脚本(疑似存在问题)
using System.Collections.Generic; using Unity.VisualScripting; using UnityEngine; using UnityEngine.Tilemaps; public class AddBoxCollidersToWalls : MonoBehaviour { public Sprite wallSprite; public float colliderSize = 1.5f; // BoxCollider2D的尺寸参数 void Start() { if (wallSprite == null) { Debug.LogError("未设置WallSprite引用!请在Inspector面板中指定墙体精灵。"); return; } AddCollidersToWallTiles(); } // 为墙体瓦片添加Collider private void AddCollidersToWallTiles() { List<List<Vector2Int>> wallTileRegions = FindWallTileRegions(); foreach (List<Vector2Int> region in wallTileRegions) { Vector3 colliderCenter = GetColliderCenter(region); Vector2 colliderSize = GetColliderSize(region); CreateColliderObject(colliderCenter, colliderSize); } } // 查找墙体瓦片区域 private List<List<Vector2Int>> FindWallTileRegions() { List<List<Vector2Int>> wallTileRegions = new List<List<Vector2Int>>(); Texture2D texture = wallSprite.texture; int width = texture.width; int height = texture.height; Color[] pixels = texture.GetPixels(); bool[,] visited = new bool[width, height]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int pixelIndex = y * width + x; // 跳过透明像素或已访问像素 if (pixels[pixelIndex].a == 0 || visited[x, y]) continue; List<Vector2Int> region = new List<Vector2Int>(); FloodFill(x, y, pixels, width, height, ref visited, ref region); wallTileRegions.Add(region); } } return wallTileRegions; } // 洪水填充算法,标记连通的墙体像素区域 private void FloodFill(int x, int y, Color[] pixels, int width, int height, ref bool[,] visited, ref List<Vector2Int> region) { if (x < 0 || x >= width || y < 0 || y >= height || visited[x, y] || pixels[y * width + x].a == 0) return; visited[x, y] = true; region.Add(new Vector2Int(x, y)); FloodFill(x + 1, y, pixels, width, height, ref visited, ref region); FloodFill(x - 1, y, pixels, width, height, ref visited, ref region); FloodFill(x, y + 1, pixels, width, height, ref visited, ref region); FloodFill(x, y - 1, pixels, width, height, ref visited, ref region); } // 计算Collider的中心位置 private Vector3 GetColliderCenter(List<Vector2Int> region) { float sumX = 0f; float sumY = 0f; foreach (Vector2Int tilePosition in region) { sumX += tilePosition.x; sumY += tilePosition.y; } float centerX = sumX / region.Count; float centerY = sumY / region.Count; return new Vector3(centerX / wallSprite.pixelsPerUnit, centerY / wallSprite.pixelsPerUnit, 0f); } // 计算Collider的尺寸 private Vector2 GetColliderSize(List<Vector2Int> region) { int minX = int.MaxValue; int minY = int.MaxValue; int maxX = int.MinValue; int maxY = int.MinValue; foreach (Vector2Int tilePosition in region) { minX = Mathf.Min(minX, tilePosition.x); minY = Mathf.Min(minY, tilePosition.y); maxX = Mathf.Max(maxX, tilePosition.x); maxY = Mathf.Max(maxY, tilePosition.y); } float tileSizeX = maxX - minX + 1; float tileSizeY = maxY - minY + 1; // 计算瓦片间的间隙并调整尺寸 float gapX = Mathf.Max(0f, (tileSizeX - 1) * (1f - colliderSize)); float gapY = Mathf.Max(0f, (tileSizeY - 1) * (1f - colliderSize)); return new Vector2((tileSizeX + gapX) / wallSprite.pixelsPerUnit, (tileSizeY + gapY) / wallSprite.pixelsPerUnit); } // 创建带有Collider的游戏对象 private void CreateColliderObject(Vector3 center, Vector2 size) { GameObject colliderObject = new GameObject("WallTileCollider"); colliderObject.transform.parent = transform; colliderObject.transform.localPosition = center; BoxCollider2D collider = colliderObject.AddComponent<BoxCollider2D>(); collider.size = size * colliderSize; } }
相关场景截图
- Is Trigger开启后向左移动的Pacman:

- Pacman对象Inspector设置:

- 带Collider的场景地图:

- 碰撞后卡死的Pacman:

- Wall Collider2D Inspector设置:

内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

