我正在尝试写一个纸牌游戏,玩家可以堆叠卡片.例如Ace,Two,Three.
我想想象一堆卡片,其中Ace卡部分被Two卡覆盖,而Two卡部分被三张卡覆盖.三张牌完全可见.
很简单,我想.我在用户控件中添加了我的卡片:Controls.Add(ace); Controls.Add被(2); 等等
然后我需要一些能够布局我的控件的东西,所以我编写了自定义的LayoutEngine(派生自LayoutEngine).我的第一次测试没有做任何事情,然后将控件移动50像素.
运行解决方案后,我注意到Z顺序是错误的.而不是三张卡在顶部,Ace卡顶部看起来像这样:
Ace卡>两张卡>三张卡:Ace卡在顶部两张卡在Ace卡下面三张卡在Two Card下面.
所以我开始寻找一种方法来改变WinForms中的Z顺序,并发现它只是"不可用".喜欢..嗯?!
替代方案(由MS提供)是可以通过为控件设置ChildIndex来更改Z顺序.Jikes,这意味着在列表中查找,改变我的应用程序的行为.去MS的路......
无论如何,我尝试了各种各样的东西,但似乎不可能编写一个可以解决问题的布局引擎.
我整天都在google-d,没有发现什么有用的东西.我不是GUI专家,所以我坚持这个蹩脚的问题.谁能帮助我?
非常感激!
巴斯
最好的办法是完全避免使用控件.他们将A)导致较差的(呃)性能和B)复杂的命中测试/绘图.
只需创建表示表状态的对象(我使用CardContainer对象)并使用Graphics.DrawImage绘制它们在paint事件中所处的所有卡片.如果还需要添加其他UI元素,则可以对整个表使用单个控件.
如果您决定添加动画,这也可以使动画卡片移动更简单.
更新
我打算扩大这个答案但被叫走了,只是发布了我的内容.以下是您可能会发现有用的一些细节.我创造了一个"纸牌游戏引擎".引擎一次承载一个单人纸牌游戏(克朗代克,蜘蛛,战略等).它跟踪每个游戏的统计数据,并允许播放和编辑各个游戏.游戏是IronPython脚本,这使得添加新游戏相对容易.
我的CardContainer是一个持有零个或多个卡片的对象.
它有一个LieDirection(无,向上,向下,向左,向右),可以确定其卡片的布局方式.
它有一个MaximumDepth,用于限制在LieDirection中绘制的卡片数量.这对于像克朗代克这样的游戏来说很方便,你只想展示废物的前三张牌.
它具有隔离卡片的属性.面朝上和面朝下的卡片有单独的间距值.它可以将卡自动打包到MaximumLength定义的区域.并且它有一个"额外的垫"值,每张卡一个 - 无论该指数是否有卡.后者在模拟鼠标悬停期间用于"揭开"指向的卡片,以便用户可以清楚地看到可能被卡片顶部遮挡的卡片.这是通过在卡片顶部设置卡片的"额外垫"来实现的.这可以通过具有"悬停卡"和"悬停间距"属性来简化,但是每张卡具有额外的填充允许奇怪类型的单人纸牌游戏,其突出具有间距的画面桩中的特定"行".
它有一个HitTest方法从给定的X,Y位置返回一张Card.
所有这一切都意味着Card对象没有关于它在桌面上绘制的概念.我有一个复杂的动画系统,所以卡的位置最终来自动画引擎.如果卡当前没有动画,则动画系统从其容器中获取其位置.
请注意,上面提到的卡的位置严格用于绘图.所有卡片都始终连接到一个CardContainer,并且只是从一个卡片移动到另一个卡片.有一个叫做Deck的"特殊"容器,最初包含每张卡片.它最初位于桌子外面.容器具有Visible属性.仅当将卡从Visible容器移动到另一个Visible容器时,动画才会播放.这允许您在必要时移动卡片而不需要动画,并且卡片可以"飞出"到桌子外面的容器.
该引擎还具有一个用于相互定位CardContainers的rudamentary布局系统.我做的一件非常方便的事情是使用卡片尺寸相对坐标系.表格的"宽度"恰好是11张卡片宽度.无论用户放大表的大小,宽度总是11卡宽.这意味着卡片尺寸(由用户查看)增长和缩小.高度是可变的,但是由固定卡大小的比率(从卡位图确定)决定.如果您给CardContainer一个X值为1.0,这意味着它将位于表格左侧的一个卡片宽度.这些值是浮点数,因此您可以指定1/2的卡宽度为0.5.这使得在脚本中定位元素非常容易,而不必担心屏幕坐标.无论用户如何改变屏幕的大小,您的游戏都将以完全相同的方式布局.
该引擎还具有无限的撤消和重做.这意味着不仅必须记录卡片移动(从一个容器到另一个容器),而且还记录所有属性更改(卡片和容器属性).如果从一开始就没有计划,撤销和重做可能很难实现.脚本可以访问Game.LogVariableChange方法,以便它们可以通过记录机制更改全局变量的值.这对于克朗代克的"三次重拍"功能来说是必要的.脚本必须存储使用的重新兑换次数,但如果用户撤销重新兑换,则该变量的值更改也必须撤消.
这对纸牌游戏很有效,但可以用于任何类型的纸牌游戏.显然,你不必第一次去实施所有这些.我提供的信息只是为了给你一些想法.