如何在C#迷宫程序中阻止玩家穿过墙体?
迷宫玩家移动穿墙问题修复
迷宫元素说明
- 红色方块:玩家(PlayerPictureBox)
- 蓝色方块:终点
- 黑色方块:墙体
问题描述
我通过PictureBox创建了一个迷宫,玩家是固定尺寸的PictureBox对象,期望实现玩家在迷宫中平滑移动且被墙体阻挡无法穿过,但目前出现了玩家穿墙的问题。
当前代码
public partial class Form1 : Form { private int XTILES = 25; private int YTILES = 25; private int TILESIZE = 10; private PictureBox[,] mazeTiles; } public void CreateNewMaze() { mazeTiles = new PictureBox[XTILES, YTILES]; for (int i = 0; i < XTILES; i++) { for (int j = 0; j < YTILES; j++) { mazeTiles[i, j] = new PictureBox(); int xPosition = (i * TILESIZE) + 25; int yPosition = (j * TILESIZE) + 10; mazeTiles[i, j].SetBounds(xPosition, yPosition, TILESIZE, TILESIZE); this.Controls.Add(mazeTiles[i, j]); } } } protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { bool isRoad = mazeTiles[(PlayerPictureBox.Left - 25) / TILESIZE, (PlayerPictureBox.Top - 10) / TILESIZE].BackColor != Color.Black; switch (keyData) { case Keys.Left: if (isRoad) PlayerPictureBox.Left -= 10; return true; case Keys.Right: if (isRoad) PlayerPictureBox.Left += 10; return true; case Keys.Up: if (isRoad) PlayerPictureBox.Top -= 10; return true; case Keys.Down: if (isRoad) PlayerPictureBox.Top += 10; return true; } return base.ProcessCmdKey(ref msg, keyData); }
问题原因
当前代码中isRoad判断的是玩家当前所在格子是否为可通行区域,而非移动后将要进入的格子。这导致只要玩家当前在道路上,按下方向键就会直接移动,哪怕下一格是墙体,从而出现穿墙现象。
修复方案
修改碰撞检测逻辑,针对每个方向,先计算移动后玩家将要进入的格子坐标,判断该格子是否为墙体,仅当目标格子可通行时才允许移动:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { // 获取玩家当前所在格子的坐标 int currentX = (PlayerPictureBox.Left - 25) / TILESIZE; int currentY = (PlayerPictureBox.Top - 10) / TILESIZE; bool canMove = false; switch (keyData) { case Keys.Left: // 计算左移后的目标格子X坐标 int targetXLeft = currentX - 1; // 确保目标格子在迷宫范围内,且不是墙体 if (targetXLeft >= 0 && mazeTiles[targetXLeft, currentY].BackColor != Color.Black) { PlayerPictureBox.Left -= TILESIZE; canMove = true; } break; case Keys.Right: int targetXRight = currentX + 1; if (targetXRight < XTILES && mazeTiles[targetXRight, currentY].BackColor != Color.Black) { PlayerPictureBox.Left += TILESIZE; canMove = true; } break; case Keys.Up: int targetYUp = currentY - 1; if (targetYUp >= 0 && mazeTiles[currentX, targetYUp].BackColor != Color.Black) { PlayerPictureBox.Top -= TILESIZE; canMove = true; } break; case Keys.Down: int targetYDown = currentY + 1; if (targetYDown < YTILES && mazeTiles[currentX, targetYDown].BackColor != Color.Black) { PlayerPictureBox.Top += TILESIZE; canMove = true; } break; } return canMove || base.ProcessCmdKey(ref msg, keyData); }
进阶优化(平滑移动)
如果需要更平滑的逐像素移动效果,可以使用Timer组件替代按键一次性移动:
- 在窗体中添加一个Timer控件,设置
Interval为16左右(约60帧/秒)。 - 记录玩家的移动方向,在Timer的
Tick事件中逐像素移动,每次移动前检测碰撞。
示例代码片段:
private Keys currentDirection = Keys.None; private void timer1_Tick(object sender, EventArgs e) { int moveStep = 1; int currentX = (PlayerPictureBox.Left - 25) / TILESIZE; int currentY = (PlayerPictureBox.Top - 10) / TILESIZE; switch (currentDirection) { case Keys.Left: int targetLeft = PlayerPictureBox.Left - moveStep; int targetXLeft = (targetLeft - 25) / TILESIZE; if (targetXLeft >= 0 && mazeTiles[targetXLeft, currentY].BackColor != Color.Black) { PlayerPictureBox.Left = targetLeft; } else { // 对齐到格子边界 PlayerPictureBox.Left = currentX * TILESIZE + 25; currentDirection = Keys.None; } break; // 其他方向逻辑类似,此处省略 } } protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { if (keyData is Keys.Left or Keys.Right or Keys.Up or Keys.Down) { currentDirection = keyData; return true; } return base.ProcessCmdKey(ref msg, keyData); }
内容的提问来源于stack exchange,提问作者toe ko
相关产品推荐
相关产品推荐

