c# - 使用 GDI+ 在窗体外渲染图形

标签 c# winforms gdi+

我目前正在使用 GDI+ 制作游戏,我知道这不是开发游戏的最佳解决方案,但由于这是一个学校项目,我别无选择。

大约每十次我运行我的游戏时,图形就会在屏幕左上角的窗体外渲染。

如果这有助于缩小问题范围,我正在使用双缓冲。

渲染代码如下所示:

while (true)
{       
    // Create buffer if it don't exist already
    if (context == null)
    {
        context = BufferedGraphicsManager.Current;
        this.buffer = context.Allocate(CreateGraphics(), this.DisplayRectangle);
    }

    // Clear the screen with the forms back color
    this.buffer.Graphics.Clear(this.BackColor);

    // Stuff is written to the buffer here, example of drawing a game object:
    this.buffer.Graphics.DrawImage(
        image: SpriteSheet,
        destRect: new Rectangle(
            this.Position.X
            this.Position.Y
            this.SpriteSheetSource.Width,
            this.SpriteSheetSource.Height),
        srcX: this.SpriteSheetSource.X,
        srcY: this.SpriteSheetSource.Y,
        srcWidth: this.SpriteSheetSource.Width,
        srcHeight: this.SpriteSheetSource.Height,
        srcUnit: GraphicsUnit.Pixel);

    // Transfer buffer to display - aka back/front buffer swapping 
    this.buffer.Render();
}

用截图解释更容易:

Game gfx outside win form problem

最佳答案

将 BufferedGraphicsXxx 类公开是 Winforms 中的一个设计错误。它们是 Winforms 中双缓冲支持的实现细节,并且它们对错误使用它们的弹性不是很大。

您肯定错误地使用了从 Allocate() 返回的 BufferedGraphics。您在游戏循环内以高速率创建缓冲区。但是您忘记处理在循环结束时使用的缓冲区。这将以高速率消耗设备上下文 (HDC)。这不会永远持续下去,如果您的程序没有以其他方式让垃圾收集器运行,那么 Windows 将关闭插头并且不会让您创建新的设备上下文。内部 CreateCompatibleDC() 调用将失败并返回 NULL。 BufferedGraphicsContext 类否则会错过检查此错误的代码,并继续使用 NULL 句柄。并开始绘制到桌面窗口而不是表单。

解决方法是将 Allocate() 调用移到循环之外,这样您只需执行一次。但是现在当用户更改窗口大小时您将遇到一个新问题,缓冲区不再是正确的大小。

更好的捕鼠器是不使用 BufferedGraphics 类,而是让 Winforms 来处理它。有几种方法可以在 Winforms 中获得游戏循环,但最简单的方法是只使用 OnPaint() 方法来渲染场景并立即请求另一种绘制,这样它就会被一遍又一遍地调用。类似这样:

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
        this.DoubleBuffered = true;
        this.ResizeRedraw = true;
    }
    protected override void OnPaint(PaintEventArgs e) {
        RenderScene(e.Graphics);
        this.Invalidate();
    }
}

RenderScene() 应该使用传递的 Graphics 实例绘制游戏对象。请注意,您不再需要使用 Clear(),这已经完成了。

关于c# - 使用 GDI+ 在窗体外渲染图形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14087051/

相关文章:

c# - 如何设计炫酷的半透明闪屏?

vb.net - 禁用图片框上的图像混合

c# - 是否可以在不使用路由器的情况下添加 Blazor WebAssembly 并将其放入现有的 ASP.NET Core 网站中?

C# 和 SQL Server 查询在大表上返回空列

c# - 调试 Windows 窗体应用程序

c# - GDI+、JPEG Image to MemoryStream 中出现一般性错误

c# - 透明重叠圆形进度条(自定义控件)

c# - 为什么 Entity Framework 不生成代理?

c# - 在windows服务中传递参数

c# - 可访问性不一致