C#Graphics Object目前正在其他地方使用

时间:2016-09-11 08:30:53

标签: c# winforms exception graphics exception-handling

我创建了一个基于totorial的游戏来开始学习,我用renderScreen()渲染我的游戏,当我在屏幕上移动我的窗口时我得到了这个异常" Object目前正在其他地方使用" 。我知道错误的原因,但我无法解决它,因为我不知道该怎么做。 我能做什么 ?如果问题很愚蠢,请原谅我。

engine.cs

//MEMBERS
public static Graphics drawHandle;
private Thread renderThread;

public engine(Graphics g)
{
    drawHandle = g;
}
private object bufferLock = new object();

public void init()
{
    renderThread = new Thread(new ThreadStart(renderScreen));
    renderThread.Start();
}

public void stop()
{
    renderThread.Abort();
}

public static Bitmap frame = new Bitmap(Globals.CANVAS_WIDTH, Globals.CANVAS_HEIGHT);
Rectangle rect = new Rectangle(0, 0, frame.Width, frame.Height);

private void renderScreen()
{
    int framesRendered = 0;
    long startTime = Environment.TickCount;
    Graphics frameGraphics = Graphics.FromImage(frame);
    Unit1 unit1 = new Unit1("test1");
    Unit1 unit2 = new Unit1("test2");unit2.x = 250; unit2.y = 100;

    Globals.GameUnitsList.Add(unit1); Globals.GameUnitsList.Add(unit2);

    while (true)
    {
        //BACKGROUND
        frameGraphics.FillRectangle(new SolidBrush(Color.DarkBlue),0,0, Globals.CANVAS_WIDTH, Globals.CANVAS_HEIGHT);

        //BOXES
        Rectangle rect = new Rectangle(unit1.x, unit1.y, 50, 50);

        unit1.rectangle = rect;

        unit1.fillColor = Brushes.LightBlue;
        unit1.hitPoints = 100;
        unit1.Health = 10;

        frameGraphics.FillRectangle(unit1.fillColor, unit1.rectangle);
        frameGraphics.FillRectangle(unit1.fillColor, unit1.rectangle);

        Rectangle rect2 = new Rectangle(unit2.x, unit2.y, 50, 50);
        unit2.rectangle = rect2;
        unit2.fillColor = Brushes.LightBlue;
        unit2.hitPoints = 100;
        unit2.Health = 50;

        frameGraphics.FillRectangle(unit2.fillColor, unit2.rectangle);
        frameGraphics.FillRectangle(unit2.fillColor, unit2.rectangle);

        //HEALTH BAR
        HealthBar hb = new HealthBar();
        hb.barColor = Brushes.YellowGreen;
        hb.damageColor = Brushes.Red;
        frameGraphics.FillRectangle(hb.damageColor, hb.Draw(unit1, unit1.x, unit1.y)[1]);
        frameGraphics.FillRectangle(hb.barColor, hb.Draw(unit1, unit1.x, unit1.y)[0]);
        HealthBar hb2 = new HealthBar();
        hb2.barColor = Brushes.YellowGreen;
        hb2.damageColor = Brushes.Red;
        frameGraphics.FillRectangle(hb2.damageColor, hb2.Draw(unit2, unit2.x, unit2.y)[1]);
            frameGraphics.FillRectangle(hb2.barColor, hb2.Draw(unit2, unit2.x, unit2.y)[0]);

        //UNIT NAMES
        frameGraphics.DrawString(unit1.unitName, new Font("Arial", 24, FontStyle.Bold), Brushes.Yellow, unit1.x + 50, unit1.y + 50);
        frameGraphics.DrawString(unit2.unitName, new Font("Arial", 24, FontStyle.Bold), Brushes.Yellow, unit2.x + 50, unit2.y + 50);

        drawHandle.DrawImage(frame, 0, 0);

        //BENCHMARKING
        if (Environment.TickCount >= startTime + 750)
        {
            framesRendered++;
        }

        if (Environment.TickCount>=startTime+1000)
        {
            Console.WriteLine("Gomi-Invade Plan Game:"+framesRendered +"fps "+ Environment.TickCount);
            framesRendered = 0;
            startTime = Environment.TickCount;
        }
    }
}

gamewindow.cs

...
public static GameWindow gameW;
Game game = new Game();
...
//I have this code inside it but is this wrong ?        
private void canvas_Paint(object sender, PaintEventArgs e)
{
    Graphics g = canvas.CreateGraphics();
    game.startGraphics(g);
}
...

game.cs

private engine Gengine;

public void startGraphics(Graphics g)
{
    Gengine = new GomiEngine(g);
    Gengine.init();
}

public void stopGame()
{
    Gengine.stop();
}

1 个答案:

答案 0 :(得分:0)

你不能在你自己的线程中渲染屏幕,你需要在调用中调用invalidate,这会将windows消息排入windows消息循环,这将在主线程上处理。

private void DoWorkInThread(object sender, EventArgs e)
{
    while (true)
    {
        lock(this)
        {
                //update member properties
        }

        if (this.InvokeRequired)
            this.Invoke((MethodInvoker)delegate void ()
            {
                //this.Invalidate(); //if you don't need to render every frame, invalidate is better then refresh
                this.Refresh();  //call refresh for immediate update
            });
    }    
}

protected override void OnPaint(PaintEventArgs e) {
    base.OnPaint(e);
    lock(this)
    {
        //read your member which are modifies by the thread
    }
    //do rendering
    e.Graphics.Draw(...);

}