C#-WinForms | |用于旋转的多个图形实例

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

我目前正在做一个学校项目,这基本上是一个游戏,涉及GDI Winforms动画。 我选择我的游戏就像《越狱》,你试图越狱,而看守拿着手电筒在房间里走来走去

因此,我有一个Guard类,它代表卫兵,并且有一条路径可以走。此外,防护罩可旋转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

    }
当我只和一名后卫打交道时,它工作得很好。顺利地完成了他应该做的事情。 当我试图再增加一名警卫时,他们开始发疯。很快我就明白了,这是因为我让两个卫兵画的是同一个图形实例。也就是说,它们都在旋转它。 假设一个旋转-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
        }



    }