使用GDI +在图形外部呈现图形

Lan*_*nge 2 c# gdi+ winforms

我目前正在与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();
}
Run Code Online (Sandbox Code Playgroud)

使用屏幕截图更容易解释:

游戏gfx外赢形式问题

Han*_*ant 5

Winforms中的一个设计错误是将BufferedGraphicsXxx类公开.它们是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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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