C#-WinForms | |用于旋转的多个图形实例
我目前正在做一个学校项目,这基本上是一个游戏,涉及GDI Winforms动画。 我选择我的游戏就像《越狱》,你试图越狱,而看守拿着手电筒在房间里走来走去 因此,我有一个Guard类,它代表卫兵,并且有一条路径可以走。此外,防护罩可旋转90度。角。(在一定程度上活跃起来) 当我旋转防护罩时,我实际上旋转了通过Form_Paint事件传递的Graphics对象:C#-WinForms | |用于旋转的多个图形实例,c#,winforms,graphics,gdi+,gdi,C#,Winforms,Graphics,Gdi+,Gdi,我目前正在做一个学校项目,这基本上是一个游戏,涉及GDI Winforms动画。 我选择我的游戏就像《越狱》,你试图越狱,而看守拿着手电筒在房间里走来走去 因此,我有一个Guard类,它代表卫兵,并且有一条路径可以走。此外,防护罩可旋转90度。角。(在一定程度上活跃起来) 当我旋转防护罩时,我实际上旋转了通过Form_Paint事件传递的Graphics对象: void Game_Paint(object sender, PaintEventArgs e) { e
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
}
当我只和一名后卫打交道时,它工作得很好。顺利地完成了他应该做的事情。
当我试图再增加一名警卫时,他们开始发疯。很快我就明白了,这是因为我让两个卫兵画的是同一个图形实例。也就是说,它们都在旋转它。
假设一个旋转-90,另一个也将旋转,但是他的角度类成员变量将不会是-90,那么所有的地狱都会消失
图形方法的旋转(位于guard类中):
接下来我要做的就是给他们每人这个.CreateGraphics()
然后一切都很顺利。唯一的问题是,它似乎真的是沉重的GPU处理或什么的。它每比他预计的少5帧就吸引一次卫兵
我在谷歌上搜索了一下,但除了有人说“没有必要克隆图形对象”外,我什么也找不到,但我还是想不出更好的解决方案
我怎样才能很好地解决这个问题?
感谢您的高级支持。使用旋转的
图形绘制后
工具对象只需调用e.Graphics.ResetTransform()
此外,如果您已经进行了一些要返回的设置,您可能还需要查看Graphics.Save()
和Graphics.Restore()
。。它可以拯救少数几个州,当处理完这些州后,它们就会重新恢复。非常好,至少如果你记下你在做什么
当然,您可以通过以相反的顺序执行反向调用来撤消平移/旋转,但是其他方法更简单,并且只针对您的情况
请注意,图形
不包含任何图形,它是一个工具,用于将绘制到相关的位图
或控件表面
最后:永不,永不使用
CreateGraphics
!!!它的结果是非持久的,这是您很少需要的。一种有效的方法是维护一个整体变换,并为您希望绘制的每一个对象创建一个矩阵。绘制之前,将当前变换与对象的变换相乘。然后,在下一步绘制之前重置变换
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();
}
}
这些概念类似于Direct3D等3D图形中的操作方式;新华社;OpenGL和Unity3D。CreateGraphics()
真是个糟糕的主意。您应该对PaintEventArgs
传递的图形
执行所有绘图。所以您的初始代码很好。但是,您需要做的是确保在其Draw
方法中接收Graphics
的每个对象在完成其工作后保持不变。这可以通过使用和这样来实现
class Guard
{
public void Draw(Graphics g)
{
var state = g.Save();
try
{
// The actual drawing code
}
finally
{
g.Restore(state);
}
}
}
我弄明白了它是什么,然后我用了@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
}
}
我所要做的就是不使用这个。我使用了SetStyle(ControlStyles.OptimizedDoubleBuffer,true)的双缓冲起初我认为两者的作用是一样的,但显然不是。
然后,我保存了当前的图形状态并重新绘制
谢谢大家 你是直接在游戏中吸引守卫,还是使用管理类?@VictoriaS。你好,维多利亚,我正在发送游戏中的e.Graphics(这是我案例中的主要形式)的守卫对象,然后它在类中绘制它。我不知道“Managerclass”是什么意思。你的守卫是独立类中的独立对象吗?如果是,GuardManager.cs可以保存一份警卫列表,列出每个警卫的位置和面对的方向。你的主要阵型只需要联系警卫经理就可以知道所有的东西都在哪里,而不是做所有的工作。@VictoriaS。OP正在使用WinForms而不是XNA@Micky,我知道。这只是我分享的一个想法。嘿,伊万,它确实有效,但仍然闪烁。它将防护罩拉到应拉框架的1/4左右。(假设每180毫秒一次)。我试着调整计时器使表单失效,但它仍然在闪烁。知道为什么吗?@Cybrus您可以为绘制发生的控件设置双缓冲模式。什么类型的控件是游戏
?该控件是Windows窗体。我已经将它设置为双缓冲,它仍然闪烁,但看起来更好一些。我完全诚实地告诉你,我对“矩阵”的数学术语不太熟悉(我只有17y/o)。我发布的旋转方法是我在网上找到的东西的一个调整版本。我一点也不太懂矩阵。我确实做了一个方法,返回在RotateGuard()
方法中旋转的最后一个矩阵,但它看起来根本不起作用。(它在整个表单上都是巨大的红色X。)如果你能澄清它应该做什么,在我学习了矩阵的基础知识之后,我希望我能更好地理解你的代码。谢谢
class Guard
{
public void Draw(Graphics g)
{
var state = g.Save();
try
{
// The actual drawing code
}
finally
{
g.Restore(state);
}
}
}
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
}
}