WPF 中的 PaddingBall 游戏





4.00/5 (7投票s)
本文展示了如何使用 WPF 开发 Padding Ball 游戏。
介绍/背景
还记得那些美好的旧时光吗,当时有一款游戏,使用一个小挡板让球在屏幕的所有角落移动,还有一款“打砖块”游戏,通过打破堆叠在窗口顶部的砖块来扫除我们所有的快乐。
本文讲述了使用 WPF 技术开发一款名为“Paddling Ball”的小游戏,这只是一个类似演示的游戏,它使用很少的用户交互,并且没有太多的图形项目。
游戏窗口
XAML 允许您以声明方式创建菜单、球和挡板对象,如下所示
<Window x:Class="PaddingBall.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Padding Ball v1.0" Height="500"
Width="700" Background="Gray"
Name="playground" ResizeMode="NoResize"
WindowStartupLocation="CenterScreen" SizeToContent="Manual">
<Canvas Width="700" Height="500">
<Menu VerticalAlignment="Top" HorizontalAlignment="Left"
Height="20" Width="700"
Background="AliceBlue" Foreground="Blue">
<MenuItem Header="File">
<MenuItem Header="Start Game"
Background="AliceBlue" Click="StartGame"></MenuItem>
<MenuItem Header="Exit" Background="AliceBlue"
Click="ExitGame"></MenuItem>
</MenuItem>
<MenuItem Header="About"
Click="ShowAboutBox"></MenuItem>
</Menu>
<Grid Height="462" Width="700">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="700*" />
<ColumnDefinition Width="0*" />
<ColumnDefinition Width="0*" />
</Grid.ColumnDefinitions>
<Rectangle Margin="114,132,0,0" Name="ball"
Stroke="Black" RadiusX="120" RadiusY="120"
Fill="Blue" Height="38" VerticalAlignment="Top"
Stretch="UniformToFill"
HorizontalAlignment="Left" Width="38">
<Rectangle.BitmapEffect>
<BevelBitmapEffect BevelWidth="11" />
</Rectangle.BitmapEffect>
<Rectangle.BitmapEffectInput>
<BitmapEffectInput />
</Rectangle.BitmapEffectInput>
</Rectangle>
<Rectangle Height="13" Margin="200,390,0,0"
Name="pad" Stroke="Black" VerticalAlignment="Bottom"
Fill="Black" HorizontalAlignment="Left" Width="100" />
</Grid>
</Canvas>
</Window>
正如您所看到的,每个菜单项都绑定到 Click
事件的相应事件处理程序。当您打开应用程序时,您会看到一个窗口,其顶部带有菜单栏。您可以通过在“文件”菜单中选择“开始游戏”命令来开始游戏。
WPF 的应用
在使用 WPF 开发这款游戏时,我发现借助 XAML 可以更轻松地绘制球、挡板和背景。另一方面,游戏的行为部分仍然有其自身的复杂性,尤其是在球和挡板的动画过程中。尽管如此,通过用户的键盘交互来控制动画的实现,为我提供了 WPF 编程的新思路。
球和挡板的大部分动画和定位都是使用 System.Windows
命名空间中的 Thickness
结构和 PresentationFramework.dll 程序集的 System.Windows.Media.Animation
命名空间中的 ThicknessAnimation
类完成的。
Thickness
结构描述了矩形周围框架的粗细,在本例中,是 Ball
和 Pad
。四个 double 值分别描述了封装 Ball
和 Pad
对象的矩形的 Left
、Top
、Right
和 Bottom
边。
ThicknessAnimation
类创建两个目标值之间的过渡。要设置其目标值,请使用窗口内 Ball
和 Pad
元素的 From
和 To
属性。
不用说,我们需要一个 StoryBoard
对象来承载整个动画。为 Ball
和 Pad
对象创建的 ThicknessAnimation
实例,以及指定的持续时间,都作为子项添加到 StoryBoard
,我们使用 Begi
n 方法来启动动画。
这是在用户按下向右和向左箭头键时为挡板设置动画的代码
void AnimatePad(double x)
{
moveThePad = new ThicknessAnimation();
moveThePad.From = PadCurrentPos;
moveThePad.To = new Thickness(pad.Margin.Left+x, pad.Margin.Top, 0, 0);
moveThePad.Duration = new Duration(TimeSpan.FromSeconds(0));
Storyboard.SetTargetName(moveThePad, "pad");
Storyboard.SetTargetProperty(moveThePad,
new PropertyPath(Rectangle.MarginProperty));
PlayPad = new Storyboard();
if (PlayPad.Children.Count > 0)
PlayPad.Children.RemoveAt(0);
PlayPad.Children.Add(moveThePad);
PlayPad.Begin(this, true);
}
值 x
指的是为挡板的目标位置(Margin
的 Left
属性)指定的增量或减量值。这可以通过在窗口的 KeyDown
事件中编写以下代码轻松完成
void playground_KeyDown(object sender, KeyEventArgs e)
{
PadCurrentPos = pad.Margin;
double xPadValue=0;
if (e.Key == Key.Left)
if (pad.Margin.Left > -100)
xPadValue = -50;
if (e.Key == Key.Right)
if (pad.Margin.Left <= (playground.Width - pad.Width))
xPadValue = 50;
AnimatePad(xPadValue);
}
为球设置动画
当球在窗口内移动时,Margin
的 Left
和 Top
属性会发生变化,并立即触发特定 WPF 元素的 LayoutUpdated
事件。在那里,我们可以编写一些代码来控制动画球的行为,例如检查它是否越过窗口的边界,或者球是否被挡板击中。
void ball_LayoutUpdated(object sender, EventArgs e)
{
BallCurrentPos = ball.Margin;
if (((ball.Margin.Top - ball.Height) >= pad.Margin.Top) &&
ball.Margin.Left >= pad.Margin.Left &&
ball.Margin.Left <= (pad.Margin.Left + 30))
{
BallNextPos.Top = 0;
BallNextPos.Left = BallCurrentPos.Left - 200;
AnimateBall(BallNextPos, BallCurrentPos);
}
else if (((ball.Margin.Top - ball.Height) >= pad.Margin.Top) &&
ball.Margin.Left >= (pad.Margin.Left + 30) &&
ball.Margin.Left <= (pad.Margin.Left + 60))
{
BallNextPos.Top = 0;
AnimateBall(BallNextPos, BallCurrentPos);
}
else if (((ball.Margin.Top - ball.Height) >= pad.Margin.Top) &&
ball.Margin.Left >= (pad.Margin.Left + 60) &&
ball.Margin.Left <= (pad.Margin.Left + 100))
{
BallNextPos.Top = 0;
BallNextPos.Left = BallCurrentPos.Left + 200;
AnimateBall(BallNextPos, BallCurrentPos);
}
else if (ball.Margin.Top <= 5)
{
BallNextPos.Top = playground.Height;
AnimateBall(BallNextPos, BallCurrentPos);
}
else if (ball.Margin.Left <= 0)
{
BallNextPos.Left = playground.Width;
AnimateBall(BallNextPos, BallCurrentPos);
}
else if (ball.Margin.Left >= playground.Width - 50)
{
BallNextPos.Left = 0;
AnimateBall(BallNextPos, BallCurrentPos);
}
}
当您在菜单栏中选择“关于”命令时,您将获得有关游戏的有用信息和说明。
摘要
回到 WPF 环境中并带回挡板和球是一次不错的体验。除了用挡板打球之外,还有很多事情要做,例如设置游戏时长、球的数量以及计算玩家获得的分数。当这些功能得到实现时,对于任何人来说,它都将是一款完美的游戏,可以充分展示 WPF 的功能。希望我能推出游戏的第 2 版。