我正在尝试构建一个国际象棋应用程序。我有后端逻辑(差不多)。但我没有在UI上工作太多。我计划使用C#,我听说WPF是可行的方法。
请您指点一下如何构建UI界面和各种硬币?我是否必须为硬币构建某种控件?另外,我应该用什么控制来开发电路板?
答案 0 :(得分:23)
我将再次尝试这个问题并实际向您展示如何使用WPF正确地完成此操作。但要注意的是,如果你之前从未做过任何WPF,那么一开始这可能有点压倒性,但希望它应该让人知道数据驱动的WPF是如何以及一旦你得到它就有多强大它的一切。
首先,您需要创建一个WPF项目并运行NuGet包管理器来添加MVVM Light包(或者如果您愿意,可以手动添加它)。接下来,您将要设置几个枚举来定义您的作品类型,并设置一个类来表示棋盘上的一个实际实例:
public enum PieceType
{
Pawn,
Rook,
Knight,
Bishop,
Queen,
King
}
public enum Player
{
White,
Black
}
public class ChessPiece : ViewModelBase
{
private Point _Pos;
public Point Pos
{
get { return this._Pos; }
set { this._Pos = value; RaisePropertyChanged(() => this.Pos); }
}
private PieceType _Type;
public PieceType Type
{
get { return this._Type; }
set { this._Type = value; RaisePropertyChanged(() => this.Type); }
}
private Player _Player;
public Player Player
{
get { return this._Player; }
set { this._Player = value; RaisePropertyChanged(() => this.Player); }
}
}
此处的其他所有内容都是在XAML中完成的。首先,您需要为电路板本身创建一个棋盘画笔,如果您愿意,这可以是位图,但我会继续创建几何图形。此代码需要放在Window.Resources部分:
<DrawingBrush x:Key="Checkerboard" Stretch="None" TileMode="Tile" Viewport="0,0,2,2" ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Tan">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,2,2" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="Brown">
<GeometryDrawing.Geometry>
<GeometryGroup>
<RectangleGeometry Rect="0,0,1,1" />
<RectangleGeometry Rect="1,1,1,1" />
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
接下来,您需要一种方法来根据您要渲染的部分选择图像。有很多方法可以做到这一点,但我在这里做的方式是声明一个Image风格,然后使用触发器根据片段类型和播放器选择合适的位图。对于这个例子,我只是热链接到wpclipart网站上的一些剪贴画。这个XAML块虽然很长,但它只对每种类型做同样的事情:
<Style x:Key="ChessPieceStyle" TargetType="{x:Type Image}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Pawn}"/>
<Condition Binding="{Binding Player}" Value="{x:Static local:Player.White}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_white_pawn_T.png" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Rook}"/>
<Condition Binding="{Binding Player}" Value="{x:Static local:Player.White}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_white_rook_T.png" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Knight}"/>
<Condition Binding="{Binding Player}" Value="{x:Static local:Player.White}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_white_knight_T.png" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Bishop}"/>
<Condition Binding="{Binding Player}" Value="{x:Static local:Player.White}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_white_bishop_T.png" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Queen}"/>
<Condition Binding="{Binding Player}" Value="{x:Static local:Player.White}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_white_queen_T.png" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.King}"/>
<Condition Binding="{Binding Player}" Value="{x:Static local:Player.White}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_white_king_T.png" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Pawn}"/>
<Condition Binding="{Binding Player}" Value="{x:Static local:Player.Black}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_black_pawn_T.png" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Rook}"/>
<Condition Binding="{Binding Player}" Value="{x:Static local:Player.Black}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_black_rook_T.png" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Knight}"/>
<Condition Binding="{Binding Player}" Value="{x:Static local:Player.Black}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_black_knight_T.png" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Bishop}"/>
<Condition Binding="{Binding Player}" Value="{x:Static local:Player.Black}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_black_bishop_T.png" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Queen}"/>
<Condition Binding="{Binding Player}" Value="{x:Static local:Player.Black}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_black_queen_T.png" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.King}"/>
<Condition Binding="{Binding Player}" Value="{x:Static local:Player.Black}"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_black_king_T.png" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
现在是董事会本身。使用上面的代码设置这个位的时间非常短,我们只是要渲染一个ItemsControl(即一个项目列表),我们将容器设置为画布,我们将设置它是我们棋盘的背景,对于每件作品我们都会根据Pos属性设置位置。显然,我们还会使用上面设置的ChessPieceStyle图像样式来选择要渲染的正确图像:
<ItemsControl Name="ChessBoard">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Width="8" Height="8" Background="{StaticResource Checkerboard}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Width="1" Height="1">
<Image Width="0.8" Height="0.8" Style="{StaticResource ChessPieceStyle}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding Pos.X}" />
<Setter Property="Canvas.Top" Value="{Binding Pos.Y}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
那就是它!我们现在拥有了渲染国际象棋棋盘所需的一切。剩下的就是创建我们的片段数组,将它放在一个ObservableCollection中(以便GUI在添加和删除片段时获取更新)并将其绑定到我们的棋盘:
this.ChessBoard.ItemsSource = new ObservableCollection<ChessPiece>
{
new ChessPiece{Pos=new Point(0, 6), Type=PieceType.Pawn, Player=Player.White},
new ChessPiece{Pos=new Point(1, 6), Type=PieceType.Pawn, Player=Player.White},
new ChessPiece{Pos=new Point(2, 6), Type=PieceType.Pawn, Player=Player.White},
new ChessPiece{Pos=new Point(3, 6), Type=PieceType.Pawn, Player=Player.White},
new ChessPiece{Pos=new Point(4, 6), Type=PieceType.Pawn, Player=Player.White},
new ChessPiece{Pos=new Point(5, 6), Type=PieceType.Pawn, Player=Player.White},
new ChessPiece{Pos=new Point(6, 6), Type=PieceType.Pawn, Player=Player.White},
new ChessPiece{Pos=new Point(7, 6), Type=PieceType.Pawn, Player=Player.White},
new ChessPiece{Pos=new Point(0, 7), Type=PieceType.Rook, Player=Player.White},
new ChessPiece{Pos=new Point(1, 7), Type=PieceType.Knight, Player=Player.White},
new ChessPiece{Pos=new Point(2, 7), Type=PieceType.Bishop, Player=Player.White},
new ChessPiece{Pos=new Point(3, 7), Type=PieceType.King, Player=Player.White},
new ChessPiece{Pos=new Point(4, 7), Type=PieceType.Queen, Player=Player.White},
new ChessPiece{Pos=new Point(5, 7), Type=PieceType.Bishop, Player=Player.White},
new ChessPiece{Pos=new Point(6, 7), Type=PieceType.Knight, Player=Player.White},
new ChessPiece{Pos=new Point(7, 7), Type=PieceType.Rook, Player=Player.White},
new ChessPiece{Pos=new Point(0, 1), Type=PieceType.Pawn, Player=Player.Black},
new ChessPiece{Pos=new Point(1, 1), Type=PieceType.Pawn, Player=Player.Black},
new ChessPiece{Pos=new Point(2, 1), Type=PieceType.Pawn, Player=Player.Black},
new ChessPiece{Pos=new Point(3, 1), Type=PieceType.Pawn, Player=Player.Black},
new ChessPiece{Pos=new Point(4, 1), Type=PieceType.Pawn, Player=Player.Black},
new ChessPiece{Pos=new Point(5, 1), Type=PieceType.Pawn, Player=Player.Black},
new ChessPiece{Pos=new Point(6, 1), Type=PieceType.Pawn, Player=Player.Black},
new ChessPiece{Pos=new Point(7, 1), Type=PieceType.Pawn, Player=Player.Black},
new ChessPiece{Pos=new Point(0, 0), Type=PieceType.Rook, Player=Player.Black},
new ChessPiece{Pos=new Point(1, 0), Type=PieceType.Knight, Player=Player.Black},
new ChessPiece{Pos=new Point(2, 0), Type=PieceType.Bishop, Player=Player.Black},
new ChessPiece{Pos=new Point(3, 0), Type=PieceType.King, Player=Player.Black},
new ChessPiece{Pos=new Point(4, 0), Type=PieceType.Queen, Player=Player.Black},
new ChessPiece{Pos=new Point(5, 0), Type=PieceType.Bishop, Player=Player.Black},
new ChessPiece{Pos=new Point(6, 0), Type=PieceType.Knight, Player=Player.Black},
new ChessPiece{Pos=new Point(7, 0), Type=PieceType.Rook, Player=Player.Black}
};
结果如下:
这似乎只是为了绘制棋盘而做的很多工作,但请记住,这现在是一个完全由数据驱动的界面....如果您添加或删除部分或更改部分中的任何字段你的棋子阵列然后那些变化将立即传播到前端。它也很容易扩展,修改和添加其他功能,如动画,3D,反射等。但也许最令人印象深刻的是,我没有必须创建任何自定义用户控件,以便按顺序要做到这一点,WPF数据绑定机制足以支持这种开箱即用的东西。
如果您需要进一步澄清和/或想要查看独立项目,请务必告诉我。
答案 1 :(得分:1)
如果它是2D,那么Canvas是显而易见的方法,你可以将图像放在它或任何你喜欢的东西上,并将它们移动到任意位置。您也可以将其包装在Viewbox中,以便它及其中的所有内容自动缩放到父窗口。
通常,您不需要进行任何用户控制。 WPF对用户控件的重视程度要低得多,一般而言,当您需要添加需要复制的现有框架未涵盖的非常具体的行为时,您只需要它们。国际象棋应用程序不太可能出现这种情况。
答案 2 :(得分:1)
ComponentOne有一个名为checkers的棋盘游戏的Silverlight演示。您可以在线查看此演示,源代码免费提供。当然,它对你开始有很大的帮助。请注意,移植到WPF会非常简单。
答案 3 :(得分:1)
1。设计画布并确定您将向棋盘提供的尺寸或得分区域或玩家名称的大小或者您希望在游戏中显示的任何其他附加信息。
2. 设计硬币的图像和纸板背景图像
3。现在设置场景,你应该有一个单独的图形类。更新它并处理它会更容易(由您自己编写它的方式)。
4. :为动画创建一个类,即图像在特定动作上的移动方式。
5. 如果您打算使用,请为声音创建一个单独的类。
6。创建另一个包含游戏逻辑的类
7. 播放器需要再增加一节课
完成它们之后,完全按照你的逻辑来处理它们。
链接为here,其位于 vb.net ,但您可以了解设计用户界面。