我正在制作一个程序,你可以在窗体中从一个瓷砖移动到另一个瓷砖。 所以为了做到这一点,我想使用面板,每个面板都有一个标签。检测碰撞。
所以我有一张地图图片。我分成了多个瓷砖。但是现在我必须将900个瓷砖拖到面板上。
这在两个方面不是很有效。首先加载900纹理并不是一个明智的想法。这也需要很长时间。所以我想使用spritesheet或tilemap。但是我怎么能在winforms中做到这一点。我相信我看到有些人使用网格视图或其他什么。但是我不确定如何做我想做的事。
什么是最好的解决方案?
提前致谢!
答案 0 :(得分:1)
对于任何严肃的游戏项目WinForms
都不是最好的平台。 WPF
或XNA
或Unity
能够提供高性能的DirectX使用。
但是既然你想在Winforms
中这样做,这是一种方法。
它创建了一个高达900 PictureBoxes
的数量,并且每个都加载了一小部分源图像:
private void Form1_Load(object sender, EventArgs e)
{
int tileWidth = 30;
int tileHeight = 30;
int tileRows = 30;
int tileCols = 30;
using (Bitmap sourceBmp = new Bitmap("D:\\900x900.jpg"))
{
Size s = new Size(tileWidth, tileHeight);
Rectangle destRect = new Rectangle(Point.Empty, s);
for (int row = 0; row < tileRows; row++)
for (int col = 0; col < tileCols; col++)
{
PictureBox p = new PictureBox();
p.Size = s;
Point loc = new Point(tileWidth * col, tileHeight * row);
Rectangle srcRect = new Rectangle(loc, s);
Bitmap tile = new Bitmap(tileWidth, tileHeight);
Graphics G = Graphics.FromImage(tile);
G.DrawImage(sourceBmp, destRect, srcRect, GraphicsUnit.Pixel);
p.Image = tile;
p.Location = loc;
p.Tag = loc;
p.Name = String.Format("Col={0:00}-Row={1:00}", col, row);
// p.MouseDown += p_MouseDown;
// p.MouseUp += p_MouseUp;
// p.MouseMove += p_MouseMove;
this.Controls.Add(p);
}
}
}
当我尝试它时,我有点担心性能,但是......
对于一个有趣的项目,这将做;为了获得最佳性能,可以使用Panels
,但这些必须在Paint
事件中填充和重新填充。这个解决方案可以节省您的麻烦,因为您不会一直改变平铺图片,这种方法效果不错。
请注意:我已经为每个PictureBox添加了一个名称和一个标签,以便您以后可以参考它。这些都包含有关Picturebox原始位置的信息。名称如下所示:Col=23-Row=02
,标签是原始的位置对象。
另外:动态添加的控件会占用一些额外的脚本,因为您无法在设计器中创建方法体。而是像上面一样添加它们。这样做Intellisense和Tab键是你最好的朋友..
我为一些鼠标事件添加了三个事件处理程序。当您取消注释它们时,您将不得不添加方法,例如这样:
void p_MouseMove(object sender, MouseEventArgs e)
{
throw new NotImplementedException();
}
但也许你想使用其他事件来玩Drag&amp; Drop或键盘事件..
有两种方法可以引用这些图块。也许你想尝试和/或使用它们:你可以用
循环表单的控件 foreach (Control ctl in this.Controls)
{ if (ctl is PictureBox ) this.Text = ((PictureBox)ctl).Name ; }
它测试正确的类型,然后转换为PictureBox。作为示例,它在窗口标题中显示图块的名称。
或者你可以拥有一个变量并在MouseDown事件中设置它:
PictureBox currentTile;
void p_MouseDown(object sender, MouseEventArgs e)
{
currentTile = (PictureBox ) sender;
}