C#电脑游戏(WinForms)简单快速的实时图形

我正在努力使整数数组和Bitmap协调工作,作为快速PictureBox编辑的C#winforms项目的一部分(避免慢速SetPixel命令)。

我添加了一个Button和一个PictureBox,一个关于上述Button的点击事件和一个关闭事件在Form上。

表单的代码现在是这样的:

public partial class Form1 : Form { uint[] _Pixels { get; set; } Bitmap _Bitmap { get; set; } GCHandle _Handle { get; set; } IntPtr _Addr { get; set; } public Form1() { InitializeComponent(); int imageWidth = 100; //1920; int imageHeight = 100; // 1080; PixelFormat fmt = PixelFormat.Format32bppRgb; int pixelFormatSize = Image.GetPixelFormatSize(fmt); int stride = imageWidth * pixelFormatSize; int padding = 32 - (stride % 32); if (padding < 32) { stride += padding; } _Pixels = new uint[(stride / 32) * imageHeight + 1]; _Handle = GCHandle.Alloc(_Pixels, GCHandleType.Pinned); _Addr = Marshal.UnsafeAddrOfPinnedArrayElement(_Pixels, 0); _Bitmap = new Bitmap(imageWidth, imageHeight, stride / 8, fmt, _Addr); pictureBox1.Image = _Bitmap; } private void button1_Click(object sender, EventArgs e) { for (int i = 0; i < _Pixels.Length; i++) { _Pixels[i] = ((uint)(255 | (255 << 8) | (255 << 16) | 0xff000000)); } } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { _Addr = IntPtr.Zero; if (_Handle.IsAllocated) { _Handle.Free(); } _Bitmap.Dispose(); _Bitmap = null; _Pixels = null; } } 

运行时,开头会出现预期的黑色图像。

单击按钮时图像应变为白色,但我遗漏了一些东西。

我忘了做什么?

更新_Pixels数组后添加pictureBox1.Refresh()

这种更新非常快,并且能够以高分辨率呈现流畅的video。

表单的代码现在是这样的:

 public partial class Form1 : Form { uint[] _Pixels { get; set; } Bitmap _Bitmap { get; set; } GCHandle _Handle { get; set; } IntPtr _Addr { get; set; } public Form1() { InitializeComponent(); int imageWidth = 100; //1920; int imageHeight = 100; // 1080; PixelFormat fmt = PixelFormat.Format32bppRgb; int pixelFormatSize = Image.GetPixelFormatSize(fmt); int stride = imageWidth * pixelFormatSize; int padding = 32 - (stride % 32); if (padding < 32) { stride += padding; } _Pixels = new uint[(stride / 32) * imageHeight + 1]; _Handle = GCHandle.Alloc(_Pixels, GCHandleType.Pinned); _Addr = Marshal.UnsafeAddrOfPinnedArrayElement(_Pixels, 0); _Bitmap = new Bitmap(imageWidth, imageHeight, stride / 8, fmt, _Addr); pictureBox1.Image = _Bitmap; } private void button1_Click(object sender, EventArgs e) { for (int i = 0; i < _Pixels.Length; i++) { _Pixels[i] = ((uint)(255 | (255 << 8) | (255 << 16) | 0xff000000)); } pictureBox1.Refresh(); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { _Addr = IntPtr.Zero; if (_Handle.IsAllocated) { _Handle.Free(); } _Bitmap.Dispose(); _Bitmap = null; _Pixels = null; } } 

测试

当然,我想测试这种方法的性能,看它是否足够快以呈现流畅的video。

用计时器勾选替换按钮单击

到目前为止,我的测试很简单。 我用一个timer tick event替换了button click event ,该timer tick event每毫秒触发一次,并且我用随机颜色值填充_Pixels数组。

为了确保PictureBox不会尝试刷新,直到任何当前刷新完成,我使用一个bool IsRefreshing变量。

每秒帧数计算

我还测量每次刷新之间经过的时间,通过递增单个int HzCount变量,并在每个PictureBox刷新开始时将此变量重置为零。 就在我重置HzCount *之前,我在TextBox显示该值。

Intel(R)Core(TM)i7-5600U CPU @ 2.60GHz 2.60GHz,具有16.0 GB RAM结果:

72Hz的2560×1440 @

*赫兹或Hz表示每秒经过的帧数(或多少次)。 通过扩展,这意味着MegaHertz每秒翻译数百万次,而GigaHertz翻译为每秒数千万(美国数十亿)次。

WinForms控件不会“仅仅因为”重绘自己,他们必须有理由这样做。

某些数据源能够告诉其容器已更新。 Bitmap类没有。 它无法告诉包含PictureBox(或用于显示它的任何控件)来告诉它已更新。 它可以在操作BitmapData实例后调用SetPixel()设置单个像素或UnlockBits() ,但是当使用固定数组构建位图时,无论如何操作完全不受Bitmap类的控制。

因此,Bitmap类没有事件或其他方式来通知其容器更新。

这意味着您需要告知包含控件其数据源已更新,因此控件可以重绘自身。

您可以按照如何刷新PictureBox中的说明进行操作,即使用pictureBox.Refresh() 。 这会导致PictureBox控件使自身无效,并在下一次(立即)重绘时重新读取现在更改的位图数据。

另请参阅MSDN博客:Control.Invalidate,Control.Update和Control.Refresh之间的区别是什么? 。