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

如何在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组件替代按键一次性移动:

  1. 在窗体中添加一个Timer控件,设置Interval为16左右(约60帧/秒)。
  2. 记录玩家的移动方向,在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 05:55:47