C#开发密室逃脱游戏时2D Tile数组迁移到新Form后无法绘制问题求助
问题根因
你遇到的绘制失效是WinForm绘制机制的典型问题:
- 你通过
CreateGraphics()绘制的内容是临时的,只要窗体触发重绘(比如首次加载自动执行Paint逻辑、窗体被其他窗口遮挡、最小化还原、拖动改变大小),之前绘制的内容就会被默认重绘逻辑清空。 - 旧Form能正常运行只是刚好
GameSetUp调用时机在首次Paint之后,新Form的初始化顺序变化,displayRoom执行完后窗体触发了首次Paint,直接覆盖了你绘制的所有内容。
解决方案(推荐标准写法)
不要手动调用CreateGraphics绘制,将绘制逻辑放到Form的Paint事件中,每次窗体重绘会自动执行该逻辑,内容不会丢失。
修改步骤
- 将Room对象改为Form的全局成员,不要在GameSetUp中定义为局部变量:
// 放在Form类内部、方法外的位置 private Room room1;
- 调整
GameSetUp方法,删除原来的room1.displayRoom(this)调用,绑定Paint事件:
public void GameSetUp() { this.Height = 560; this.Width = 535; room1 = new Room(); room1.buildRoom(); room1.setPoints("room1"); this.Text = "Room 1"; // 绑定Paint事件,后续所有绘制由Paint事件统一处理 this.Paint += RoomPaintHandler; Character user = new Character(); StateManager.C = user; StateManager.C.addCharacter(room1, this, "room1"); }
- 新增Paint事件处理方法,实现绘制逻辑:
private void RoomPaintHandler(object sender, PaintEventArgs e) { Graphics g = e.Graphics; // 可选:开启抗锯齿提升绘制效果 g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; // using语法会自动释放Pen资源,避免GDI泄漏 using (Pen p = new Pen(Brushes.Black, 2)) { for (int x = 0; x < 10; x++) { for (int y = 0; y < 10; y++) { var tile = room1.Board[x, y]; g.DrawRectangle(p, tile.rect); if(tile.getEntry()) g.FillRectangle(Brushes.Green, tile.rect); else if (tile.getExit()) g.FillRectangle(Brushes.Red, tile.rect); else if (tile.getProblem()) g.FillRectangle(Brushes.SaddleBrown, tile.rect); else g.FillRectangle(Brushes.Bisque, tile.rect); } } } // 角色绘制逻辑也可以在这里添加 }
- 如果后续场景更新需要刷新画面,只需要调用
this.Invalidate()即可触发Paint事件重新绘制。
临时快速修复方案
如果不想改动现有结构,就调整GameSetUp的调用时机,不要在Form构造函数或Load事件中调用,改到Form的Shown事件中调用即可。这个事件是窗体首次完全显示后才触发,绘制内容不会被首次Paint覆盖。但该方案的缺陷是后续窗体被遮挡、最小化还原后,绘制内容还是会消失,仅适合临时测试使用。
其他排查点
如果修改后还是不显示,可以检查以下几点:
- 确认新Form的BackColor没有和你绘制的Tile颜色(比如Bisque)完全一致,导致视觉上看不出绘制效果
- 单步调试Paint事件,确认
room1.Board数组没有空引用,每个Tile的rect坐标都在窗体可见范围内 - 确认Form没有开启透明背景、层叠窗口等特殊属性影响绘制
内容的提问来源于stack exchange,提问作者Amy
相关产品推荐
相关产品推荐

