【发布时间】:2018-03-06 20:35:11
【问题描述】:
情况
作为一个业余爱好项目,我决定冒险模拟一个令人难以置信的基本现实。我的想法是创建一个简单的宇宙,其中内部的对象将根据位置或速度等因素进行交互。一个人将能够向物体添加力以使其移动。所以为了展示这个“宇宙”,我必须学习 Window 的 Forms。因此,我对这个主题的了解是有限的。我创建了一个计时器对象,这样在每个时间段之后,我都会调用宇宙的渲染来生成一个位图并为其设置一个图片框。为了渲染宇宙,我只需将每个对象渲染到位图上,从而创建几乎一个对象拼贴。
为了测试这一点,我创建了一个 Universe,并添加了一个块。在每次更新图像时,我都会根据按键向块添加一个力。但是,我遇到的是该程序有很多视觉“滞后”。有时它会运行得非常顺利,但几秒钟后它会冻结半秒钟,然后重新开始工作。这有点明显,虽然不是非常糟糕。无论如何,这是我想要解决的问题,和/或至少知道为什么这会成为一个更好的程序员。
我已经研究过修复方法,但没有成功。我包括了诸如双缓冲和使用后处理图形和位图对象之类的东西,但这几乎没有效果。
Just the image of what the forms displays - nothing intersting
问题
是什么导致了这种“滞后”,我可以做些什么来解决它?
代码
class Block
{
...
public Tuple<float, float> Dimension { get; }
public Tuple<float, float> Position { get; set; }
...
public void Render(Bitmap bitmap)
{
using (Graphics g = Graphics.FromImage(bitmap))
{
int x = bitmap.Width / 2;
int y = bitmap.Height / 2;
//g.DrawRectangle(Pens.Black, 0, 0, 500, 500);
g.DrawRectangle(Pens.DarkCyan, Position.Item1 + x - Dimension.Item1 / 2, Position.Item2 + y - Dimension.Item2 / 2,
Dimension.Item1, Dimension.Item2);
}
}
}
class Universe
{
...
public List<IObject> Objects;
public Tuple<int, int> Dimensions;
...
public Bitmap RenderUniverse()
{
Bitmap bitmap = new Bitmap(Dimensions.Item1, Dimensions.Item2);
foreach (var obj in Objects)
{
obj.Render(bitmap);
}
return bitmap;
}
}
public partial class Form1 : Form
{
Universe Universe;
const int SPF = 50; //MILLISECONDS TILL NEXT UPDATE
public Form1()
{
Timer timer = new Timer();
timer.Tick += Update;
timer.Interval = SPF;
timer.Start();
...
InitializeComponent();
DoubleBuffered = true;
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.ClientSize = new System.Drawing.Size(Universe.Dimensions.Item1, Universe.Dimensions.Item2);
this.pictureBox1.Size = new System.Drawing.Size(Universe.Dimensions.Item1, Universe.Dimensions.Item2);
this.pictureBox1.SizeMode = PictureBoxSizeMode.Normal;
}
public void Update(object o, EventArgs args)
{
...
if (pictureBox1.Equals(null))
pictureBox1.Image.Dispose();
pictureBox1.Image = Universe.RenderUniverse();
pictureBox1.Refresh();
}
}
编辑:
我现在已经拿走了图片框并使用了 OnPaint。但是,这并没有解决问题。
【问题讨论】:
-
从代码中看不出什么。这是垃圾收集器几乎从不运行的那种程序。它使用大量非托管内存,但绘图对象太小而无法让 GC 工作。请密切注意内存使用情况并检查是否可以将 perfmon.exe 中可见的 GC 性能计数器与减速相关联。保留位图而不是重复重新创建它,使用 Graphics.Clear() 重新初始化它。