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

  在经典俄罗斯方块游戏中,方块只有“I”,“L”,反“L”,“Z”,反“Z”,“T”,“正方形”这些形状,在游戏中这些方块都可以看做是由4个小方块组成,也就是上一节中提到的Rect,并且都可以旋转变形,所以在创建这些方块类之前,我们不妨先创建一个基类Block.cs。右键单击项目,选择“添加->类”,新建一个Block.cs。定义2个受保护变量,供子类继承。
        protected Point[] point;
           protected Color c;

point用来存储小方块坐标,c存储方块颜色。然后定义3个属性:

      /// <summary>
        /// 方块颜色
        /// </summary>
        public Color color
        {
            get { return c; }
        }
        /// <summary>
        /// 中心点横坐标
        /// </summary>
        public int posX { get; set; }
        /// <summary>
        /// 中心点纵坐标
        /// </summary>
        public int posY { get; set; }

中心点横坐标和中心点纵坐标是指这个方块在画板中的坐标,而point存储的是在方块内部定义的坐标,以“L”方块为例,我们这样设置:

         point[0].X = -1;
            point[0].Y = 0;
            point[1].X = -1;
            point[1].Y = -1;
            point[2].X = 0;
            point[2].Y = 0;
            point[3].X = 1;
            point[3].Y = 0;

您不妨在纸上画个坐标系,然后画出这4个点的位置,看是否够成了“L”这个形状。中心点横坐标和中心点纵坐标可以看成是原点(0,0)在画板中的坐标,这样一旦确定了posX和posY,我们就可以通过posX + this.point[index].X和 posY - this.point[index].Y来获取其他点在画板中的坐标了。于是我们再写一个索引器用来取得小方块的坐标:

        /// <summary>
        /// 小方块的坐标
        /// </summary>
        /// <param name="index">俄罗斯方块内部小方块索引</param>
        /// <returns></returns>
        public Point this[int index]
        {
            get
            {
                return new Point(posX + this.point[index].X, posY - this.point[index].Y);
            }
        }

构造函数,当方块出现在画板之前,我们要先确定它在画板中的位置,所以需要对这posX和posY属性赋值。

        /// <summary>
        /// 俄罗斯方块中心点在画板上的坐标
        /// </summary>
        /// <param name="x">横坐标</param>
        /// <param name="y">纵坐标</param>
        public Block(int x, int y)
        {
            point = new Point[4];
            this.posX = x;
            this.posY = y;
        }

方块还需要变形,我们还是以“L”方块为例,我们规定它的变形是在同样的坐标系中沿着原点(0,0)做顺时针旋转,这样一来它的每个小方块的坐标会发生什么变化呢?您可以用笔在纸上画一下,看看是不是旧坐标的Y轴变成了新坐标的X轴,旧坐标的X轴变成了新坐标的负Y轴,变形方法如下:

        public virtual void Change()
        {
            for (int z = 0; z < 4; z++)
            {
                double oldX = point[z].X;
                double oldY = point[z].Y;
                point[z].X = oldY;
                point[z].Y = -oldX;
            }
        }

这里使用的是虚方法,因为我们并不想所有的方块都以这种方式变形,一些特殊的方块我们希望能够重载,比如“正方形”方块并不需要旋转。但是还有一点需要注意,方块在某些情况是不能变形的,比如变形后超出了边界,或者变形后的新坐标上已经存在方块(即被其它方块挡住),所以在变形前我们需要先要取得方块变形后的坐标,然后判断方块能否变形。代码如下:

        public virtual Point[] GetChangedPoint()
        {
            Point[] newPoint = new Point[4];
            for (int z = 0; z < 4; z++)
            {
                double oldX = point[z].X;
                double oldY = point[z].Y;
                double newX = oldY;
                double newY = -oldX;
                newPoint[z] = new Point(posX + newX, posY - newY);
            }
            return newPoint;
        }

同样采用虚方法。最后还需要2个方法用来控制方块在画板上的显示和消失:

        public void Show(Rect[,] board)
        {
            for (int i = 0; i < 4; i++)
            {
                int x = (int)this[i].X;
                int y = (int)this[i].Y;
                board[x, y].Color = this.color;
            }
        }

        public void Hidden(Rect[,] board)
        {
            for (int i = 0; i < 4; i++)
            {
                int x = (int)this[i].X;
                int y = (int)this[i].Y;
                board[x, y].Color = null;
            }
        }

这里的参数board就是我们用Rect填充的画板,通过索引器遍历每个小方块,取得它们在画板上的坐标,然后给相应的Rect绘制方块的颜色,前面说过,当我们赋值为null的时候,相应的Rect就隐藏了,方块也就消失了,我们就是通过方块的消失和显示,来实现方块的移动和变形效果。

  俄罗斯方块的基类到此就构建完毕了,下一节中,我将介绍构建具体形状的俄罗斯方块,敬请关注。

posted @ 2011-05-20 00:49  疯狂的戴夫  阅读(946)  评论(1编辑  收藏  举报