winforms中的基本磁贴地图

时间:2014-05-21 14:32:59

标签: c# winforms grid tile sprite-sheet

我正在制作一个程序,你可以在窗体中从一个瓷砖移动到另一个瓷砖。 所以为了做到这一点,我想使用面板,每个面板都有一个标签。检测碰撞。

所以我有一张地图图片。我分成了多个瓷砖。但是现在我必须将900个瓷砖拖到面板上。

这在两个方面不是很有效。首先加载900纹理并不是一个明智的想法。这也需要很长时间。所以我想使用spritesheet或tilemap。但是我怎么能在winforms中做到这一点。我相信我看到有些人使用网格视图或其他什么。但是我不确定如何做我想做的事。

什么是最好的解决方案?

提前致谢!

1 个答案:

答案 0 :(得分:1)

对于任何严肃的游戏项目WinForms都不是最好的平台。 WPFXNAUnity能够提供高性能的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);
            }
    }

}

当我尝试它时,我有点担心性能,但是......

  • 在我的机器上加载不到1秒钟。
  • 启动程序会增加10MB的VS内存使用量。那就像什么都没有。

对于一个有趣的项目,这将做;为了获得最佳性能,可以使用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;
}