Silverlight:手把手教你写俄罗斯方块(一)

  写在前面:由于之前曾写过Winform版的俄罗斯方块程序,该版本采用的是GDI+绘图技术,原理就是通过计时器,根据逻辑判断不断重新绘制画板,使得游戏以动画的方式在不断进行。在学习了silverlight之后,发现利用同样的原理,很容易将Winform版移植过来,于是就有了该教程。该教程适用于对于C#有一定基础,并且有兴趣学习silverlight的新手朋友们。在这一教程中,我会通过大量代码和示例图来演示,相信只要您跟着教程一步一步去做,就一定能创造出俄罗斯方块这个经典的游戏。本程序部分逻辑及思路参考自网络,如果有对您的权益造成侵害请及时与我联系,我会加以注明或者立即删除该文章。

  最终效果图如图所示:

您产生兴趣了吗?如果有的话就随我展开一场silverlight之旅吧。

  一.首先打开vs2010,选择“文件”、“新建”、“项目”,建立一个silverlight4程序,在弹出的对话框中,请勾选上“在新网站中承载silverlight程序”,

因为本程序设置了英雄榜的功能,后期需要与服务器通信,获得所有玩家的得分及游戏结束后的提交分数,如果您只需要做一个完全运行在客户端的东西,不需要与服务器通信,可以不选中这项。

  二.游戏需要一个画板,我们打开MainPage.xaml,在Grid里面添加一个Canvas作为画板的容器,之所以使用Canvas,是因为Canvas的SetTop和SetLeft方法很容易为其内部的元素进行定位,然后设置它的背景色为黑色,设置宽度为200、设置高度为400,最重要的是设置它的“x:Name”属性,我们设置为“playBoard”。为了美观,我们再在这个Canvas外面添加一个边框Border。为了方便画板Canvas的布局,可以在Grid的下面再添加一个Canvas作为整个页面的父容器,并且为这个容器设置一个渐变背景色,关于渐变背景色,通过Microsoft Blend4可以很轻松的完成,如果您电脑上没有装blend4也没关系,输入少量xaml亦可实现同样效果,由于本系列文章主要讲解俄罗斯方块的程序设计,所以对xaml代码不做过多解释,具体xaml代码如下:

    <Grid x:Name="LayoutRoot">
        <Canvas>
            <Canvas.Background>
                <LinearGradientBrush EndPoint="0.885999977588654,0.851999998092651" StartPoint="0.034000001847744,0.0320000015199184">
                    <GradientStop Color="Silver" Offset="0"/>
                    <GradientStop Color="#FFEBE3E3" Offset="1"/>
                </LinearGradientBrush>
            </Canvas.Background>
            <Border Width="220" Height="420" Margin="140,70,0,0" Background="#FFFAF0F0" BorderBrush="Black" BorderThickness="2" CornerRadius="10">
                <Canvas x:Name="playBoard" Height="400" Width="200" Background="Black" Canvas.Left="65" Canvas.Top="42" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </Border>
        </Canvas>
    </Grid>

Ctrl+F5运行结果,游戏画板已经产生了!

  三.接下来,右键单击项目,添加一个Silverlight用户控件,我们命名为Rect.xaml。这个控件用来干什么呢?前面说过我们的动画原理是把画板分隔成一个又一个的小矩形,然后通过改变这些矩形的颜色就来实现动画的效果,而这些矩形就相当于是画板的最小单位。例如,当方块在画板上移动了,我们就找到这个方块在画板上移动前的坐标,而这个坐标就是某个小矩形的位置,把这个矩形的颜色改成背景色黑色,然后计算出方块移动后的新坐标,把新坐标位置上的矩形设成这个方块的颜色,看上去就好像方块移动了一样。所以我们建立这样的控件用来填满整个画板。废话不多说,创建好这个控件之后,双击打开Rect.xaml,用Canvas覆盖掉自动生成的Grid代码,然后在Canvas里面添加一个Rectangle,命名为“rect”,为了美观,我们再为这个rect添加一些效果,使它的直角变得圆滑,以及渐变背景色。我们设置它的高度和宽度都为20,这样将来就可以在200*400的画板上,填充10*20个Rect控件,具体xaml代码如下:

    <Canvas>
        <Rectangle x:Name="rect" Stroke="White"  Width="20" RadiusX="2" RadiusY="2" Height="20">
            <Rectangle.Fill>
                <RadialGradientBrush RadiusX="1" RadiusY="1" GradientOrigin="0,1">
                    <RadialGradientBrush.RelativeTransform>
                        <TransformGroup>
                            <RotateTransform Angle="90" CenterX="0.5" CenterY="0.5"/>
                        </TransformGroup>
                    </RadialGradientBrush.RelativeTransform>
                    <GradientStop x:Name="fillColor" Color="#FF2266FF" Offset="1"/>
                    <GradientStop Color="White"/>
                </RadialGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
    </Canvas>

注意,因为我们需要操作这个控件的背景色,所以为这个渐变色设置了“x:Name”属性为“fillColor”。

  四.双击打开Rect.xaml.cs为这个控件添加3个自定义属性,Left,Top,Color。Left和Top是用来定义Rect在画板上的位置,假设画板被我们分隔成了10*20个小矩形,我们设置左上角第一个矩形的坐标为(0,0),向右为X轴递增,向下为Y轴递增,那么这10*20个所有矩形的坐标都可以被定义。对属性稍微做下封装,我们就可以把具体到像素的Canvas.LeftProperty和Canvas.TopProperty转变成在画板中的坐标了。这样一来我们用只关心Rect的坐标,而不用关心Rect在画板中的具体位置了。

        public double Left
        {
            get
            {
                double v = Convert.ToDouble(this.rect.GetValue(Canvas.LeftProperty));
                return v / 20;
            }
            set
            {
                this.rect.SetValue(Canvas.LeftProperty, value * 20);
            }
        }

        public double Top
        {
            get
            {
                double v = Convert.ToDouble(this.rect.GetValue(Canvas.TopProperty));
                return v / 20;
            }
            set
            {
                this.rect.SetValue(Canvas.TopProperty, value * 20);
            }
        }

颜色属性设置为可空类型,这样我们在传一个空值的时候可以直接将这个Rect隐藏掉,而如果这个Rect的Color属性返回空的时候,我们也可以判断出这个地方不存在有方块。

        public Color? Color
        {
            get
            {
                if (this.rect.Visibility == Visibility.Collapsed)
                    return null;
                else
                    return this.fillColor.Color;
            }
            set
            {
                if (value == null)
                    this.Visibility = Visibility.Collapsed;
                else
                {
                    this.Visibility = Visibility.Visible;
                    this.fillColor.Color = (Color)value;
                }
            }
        }

最后是构造函数,我们要把这个Rect定位到画板中的某个位置时,只用传坐标就好。

       public Rect(int x, int y)
        {
            // 为初始化变量所必需
          InitializeComponent();
            this.Left = x;
            this.Top = y;
            this.Color = null;
        } 
  在下一节中,我将介绍方块类的构建,敬请关注。
posted @ 2011-05-20 00:50  疯狂的戴夫  阅读(1419)  评论(1编辑  收藏  举报