在C#中同时使用图形对象时出错?

在C#中同时使用图形对象时出错?,c#,windows,gdi+,system.drawing,C#,Windows,Gdi+,System.drawing,我正在创建一个游戏,在同一个形状上有两个对象,需要每隔几秒钟分别重新绘制(用于动画)。我有一个单独的线程。他们不时会产生一个错误,表示图形对象已经在使用中。由于我在同一表单上构建了两个图形对象,因此错误出现的频率较低: Graphics sprite1 = this.CreateGraphics(); Graphics sprite2 = this.CreateGraphics(); 然后我将这些对象传递给适当的方法。 我担心这可能是一种非常糟糕的做法。如能帮助解决此问题,将不胜感激 通常游戏

我正在创建一个游戏,在同一个形状上有两个对象,需要每隔几秒钟分别重新绘制(用于动画)。我有一个单独的线程。他们不时会产生一个错误,表示图形对象已经在使用中。由于我在同一表单上构建了两个图形对象,因此错误出现的频率较低:

Graphics sprite1 = this.CreateGraphics();
Graphics sprite2 = this.CreateGraphics();
然后我将这些对象传递给适当的方法。
我担心这可能是一种非常糟糕的做法。如能帮助解决此问题,将不胜感激

通常游戏不是多线程的,而是有一个游戏循环。在每次迭代中,将根据当前时间重新计算所有对象的位置。然后重新绘制

<>你可以考虑以多线程的方式进行计算;但是,所有绘图都应该出现在游戏循环内的主线程(所谓的UI线程)中



请参阅维基百科中的“游戏结构”一章。

是的,您有问题。您看到的实际错误来自GDI+中的代码,该代码确保同一图形对象不能在多个线程中使用。然而,这是一个更深层次的问题,您正在创建一个直接引用窗口的图形对象。底层Windows对象是HDC,是设备上下文的句柄。设备上下文不是线程安全的。意外事件是偶尔出现的绘制瑕疵、死锁和访问冲突

可以使由FromImage()image创建的图形对象正常工作,只要它们是从不同的位图创建的,或者确保两个线程不会同时使用同一图形对象。这在游戏编程中不会非常有用


通过创建32bppPArgb像素格式的位图,可以使精灵快速绘制。在大多数机器上,它们的绘图速度是其他格式的十倍。这是普通GDI+所能做到的,下一步是使用图形库,它使用驻留在视频内存中的位图,并使用GPU硬件。这类库常用的托管包装器是XNA、SlimDX和SharpDX。

如上所述,
这个.CreateGraphics()
实际上是在创建对同一图形对象的引用,它是整个表单本身。撇开线程问题不谈,通过确保图形不会超出预定义的绘图区域来表示不同的屏幕,您可以在代码中“理论上”处理此问题。这将涉及一点硬编码,这不是我的风格,也不是我的偏好

嗯,一个更好的方法是在内存中创建两个图像对象

    Image screen1 = new Bitmap(100, 100); // (width, height)
    Image screen2 = new Bitmap(100, 100); // (width, height)
然后你可以分别在每个图像表面上绘制,并使用一些简单的东西,比如图像查看器来保存每个“视图”


显然,这不是解决此问题的唯一方法,但应作为一个指南,激励您找到自己的解决方案。:)

你是说你把这些图形对象给了不同的线程?我敢肯定,不管你创建了多少(甚至1个)图形对象,光是零件本身是不安全的。它们被发送到不同的线程。我需要对象同时继续设置动画。一个将始终被重绘,另一个仅在用户移动时重绘。不幸的是,它同时发生。您建议我做什么?我不知道我会做什么,但我知道对.NET framework中控件的多线程访问不受支持,也不安全。
    private void DrawGame()
    {
        DrawSprite1(Graphics.FromImage(screen1));
        DrawSprite2(Graphics.FromImage(screen2));
    }
    public void DrawSprite1(Graphics g)
    {
        g.FillEllipse(Pens.Blue, screen1.GetBounds());
    }
    public void DrawSprite2(Graphics g)
    {
        g.FillRect(Brushes.Red, screen2.GetBounds());
    }