我目前正在开展一个学校项目,这个项目基本上是一个涉及GDI-Winforms动画的游戏。 我选择了我的游戏,就像在越狱时试图逃离监狱,而带有轻型火把的守卫正在房间里走来走去。
所以,我有 Guard 类代表守卫并且有 A Path 来继续。此外,护罩可以旋转90度。角。 (动画到一定程度) 当我旋转防护时,我实际上旋转了通过Form_Paint事件传递的 Graphics 对象:
void Game_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
ply.Draw(e.Graphics); // Draws the player
grd.Draw(e.Graphics); // Draws the guard
e.Graphics.DrawPolygon(Pens.Red, grd.GetPath()); // Draws the guard's path
}
当我只和一名后卫打交道时,它运作得很好。顺利完成他应该做的事情。 当我试图增加1个后卫时,他们开始吓坏了。很快我发现它是因为我发送两个警卫来绘制相同的图形实例。这也意味着,它们都在旋转它。 让我们说一个旋转-90,另一个旋转,但他的角度类成员变量不会是-90,然后所有的地狱都会松动。
旋转图形方法(位于防护等级内):
public Graphics RotateGuard(Graphics g, Point pivot, float angle) // returns the rotated Graphics object
{
if (!float.IsNaN(angle))
{
using (Matrix m = new Matrix())
{
m.RotateAt(angle, pivot);
g.Transform = m;
}
}
return g;
}
我接下来要做的就是给每个人this.CreateGraphics()
。
void Game_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
ply.Draw(e.Graphics); // Draws the player
foreach (Guard grd in this.guards )
{
grd.Draw(this.CreateGraphics()); // Draws the guard
e.Graphics.DrawPolygon(Pens.Red, grd.GetPath()); // Draws the guard's path
}
}
然后一切正常。唯一的问题是,似乎GPU处理起来真的很重要。它每隔5帧就比他应该画的那样抽出一次守卫。
我用谷歌搜索但找不到任何东西,但人们说“没有必要克隆图形对象”,但是,我仍然无法想到任何更好的工作解决方案。
我怎样才能很好地解决这个问题? 谢谢你提前。
答案 0 :(得分:0)
使用旋转的Graphics
工具对象进行绘制后,只需调用e.Graphics.ResetTransform()
即可。
如果您想要返回一些设置,您可能还需要查看Graphics.Save()
和Graphics.Restore()
。它可以保存很少的状态,完成后再将它们恢复原状。非常好,至少如果你记得你在做什么。
当然,可以通过反向调用反向调用来撤消翻译/旋转,但其他方法更简单,只针对您的情况。
请注意,Graphics
并非包含任何图形,它是用于绘制到关联的Bitmap
或其中的工具对照的表面......
最后:从不<永远使用CreateGraphics
!它的结果是非持久性,你很少想要它......
答案 1 :(得分:0)
一种有效的方法是保持一个整体变换,并为你想要绘制的每个东西都有一个矩阵。在绘制之前,将当前变换与对象的变换相乘。然后在下一步绘制之前重置转换。
void Game_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
var g = e.Graphics;
g.ResetTransform();
g.MultiplyTransform (playerMatrix);
ply.Draw(e.Graphics); // Draws the player
g.ResetTransform();
foreach (Guard grd in this.guards )
{
g.MultiplyTransform (grd.Matrix);
grd.Draw(this.CreateGraphics()); // Draws the guard
e.Graphics.DrawPolygon(Pens.Red, grd.GetPath()); // Draws the guard's path
g.ResetTransform();
}
}
这些概念类似于3D图形(如Direct3D)的工作方式; XNA; OpenGL和Unity3D。
答案 2 :(得分:0)
CreateGraphics()
是一个非常糟糕的主意。您应该完成Graphics
传递的PaintEventArgs
所有绘图。所以你的初始代码就好了。但是,您需要做的是确保在Graphics
方法中接收Draw
的每个对象在完成其工作后保持不变。这可以通过使用Graphics.Save和Graphics.Restore这样来实现
class Guard
{
public void Draw(Graphics g)
{
var state = g.Save();
try
{
// The actual drawing code
}
finally
{
g.Restore(state);
}
}
}
答案 3 :(得分:0)
我弄清楚它是什么,然后我用了@Ivan做的。
void Game_Paint(object sender, PaintEventArgs e)
{
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
var saved = e.Graphics.Save();
ply.Draw(e.Graphics); // Draws the player
foreach (Guard grd in this.guards )
{
grd.Draw(e.Graphics); // Draws the guard
e.Graphics.Restore(saved);
e.Graphics.DrawPolygon(Pens.Red, grd.GetPath()); // Draws the guard's path
}
}
我所要做的就是不使用this.DoubleBuffered
我使用的SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
,起初我认为两者都是一样的,但显然它没有。
然后,我保存了当前的图形状态并重新绘制它。
非常感谢大家!