我正在尝试构建一个多线程游戏,我在表单上有一个单独的线程,而不是主线程。这给我们带来了线程安全技术,我已经阅读了很多关于它的内容,但我不确定我是否正确使用它。
我的问题是我有一个结构,每个数据对象都在表单上自绘它,所以我没有弄清楚如何实现它。
这是我工作的单线程代码的片段:
public partial class Form1 : Form
{
GameEngine Engine;
public Form1()
{
InitializeComponent();
Engine = new GameEngine();
}
protected override void OnPaint(PaintEventArgs e)
{
Engine.Draw(e.Graphics);
}
}
class GameEngine
{
Maze Map;
List<Player> Players;
public void Draw(Graphics graphics)
{
Map.Draw(graphics);
foreach (var p in Players)
{
p.Draw(graphics);
}
}
}
所以,任何人都可以给我一个提示或链接到好文章,帮助我学习如何在另一个线程上分离绘图吗?
[编辑]
我设法实现了我打算做的事情 这就是我编码的方式
protected override void OnPaint(PaintEventArgs e)
{
formGraphics = e.Graphics;
DisplayThread = new Thread(new ThreadStart(Draw));
DisplayThread.Start();
}
private void Draw()
{
if (this.InvokeRequired)
{
this.Invoke(new DrawDelegate(this.Draw));
}
else
{
Engine.Draw(formGraphics);
}
}
但我收到了ArgumentException:参数无效
请指出该代码中的错误
答案 0 :(得分:7)
我认为你需要绘制一个Bitmap,然后在OnPaint方法中,将该位图绘制到窗口。我马上就会证明。
汉斯指出,在OnPaint方法中你正在设置
formGraphics = e.Graphics;
但是在方法结束时e.Graphics被处理掉了,所以你不能再使用它,如果你的代码到了
Engine.Draw(formGraphics);
你会得到一个例外。
所以基本上你需要有一个全局
Bitmap buffer = new Bitmap(this.Width, this.Height)
在你的asynced线程中,你可以调用你的绘图到你可以使用的位图
Graphics g=Graphics.FromBitmap(buffer);//
获取图形对象,但记住你必须
g.Dispose()
或将其包装在
中using (Graphics g=Graphics.FromBitmap(buffer))
{
//do something here
}
我打算玩一会儿,看看我能不能给你一份工作样本
编辑这是您的工作样本。 我开始一个新的表格并在上面扔了一个按钮。我将mainform backgroundimagelayout更改为none。
我认为您需要使用.net 4.0或更高版本,如果不使用此功能,请告诉我我可以更改它以匹配您的版本...我认为。
//you need this line to use the tasks
using System.Threading.Tasks;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void Draw()
{
Bitmap buffer;
buffer = new Bitmap(this.Width, this.Height);
//start an async task
Task.Factory.StartNew( () =>
{
using (Graphics g =Graphics.FromImage(buffer))
{
g.DrawRectangle(Pens.Red, 0, 0, 200, 400);
//do your drawing routines here
}
//invoke an action against the main thread to draw the buffer to the background image of the main form.
this.Invoke( new Action(() =>
{
this.BackgroundImage = buffer;
}));
});
}
private void button1_Click(object sender, EventArgs e)
{
//clicking this button starts the async draw method
Draw();
}
}
}