[×××]


游戏人生Silverlight(1) - 七彩俄罗斯方块[Silverlight 2.0(c#)]


作者: webabcd


介绍
使用 Silverlight 2.0(c#) 开发一个七彩俄罗斯方块


玩法
↑ - 变形;← - 向左移动;→ - 向右移动;↓ - 向下移动


在线DEMO



思路
1、每个形状都是由4个“块”组成的,也就是“块”是俄罗斯方块的最小单位,首先要有一个“块”的用户控件。要求可以设置“块”的位置和颜色
2、经典俄罗斯方块一共7种形状,把每种形状所需要的功能抽象出来写一个抽象类,7个具体形状分别继承这个抽象类,并重写其抽象属性和抽象方法
3、核心控制部分:在容器内铺满隐藏的“块”,上/下/左/右/控制形状的变形和移动,通过控制容器内“块”的颜色来响应变化,当形状下一步移动或变形的位置处已经有颜色时则禁止移动或变形,当形状下一步移动或变形的位置在底边有颜色或处于容器的底部则判断消行并生成新的形状


关键代码
1、形状抽象类
PieceBase.cs
InBlock.gif using System;
InBlock.gif using System.Net;
InBlock.gif using System.Windows;
InBlock.gif using System.Windows.Controls;
InBlock.gif using System.Windows.Documents;
InBlock.gif using System.Windows.Ink;
InBlock.gif using System.Windows.Input;
InBlock.gif using System.Windows.Media;
InBlock.gif using System.Windows.Media.Animation;
InBlock.gif using System.Windows.Shapes;
InBlock.gif
InBlock.gif namespace YYTetris.Piece
InBlock.gif{
InBlock.gif         public abstract class PieceBase
InBlock.gif        {
InBlock.gif                 public PieceBase()
InBlock.gif                {
InBlock.gif                        InitPiece();
InBlock.gif                }
InBlock.gif
InBlock.gif                 // 形状的矩阵
InBlock.gif                 public int[,] Matrix { get; set; }
InBlock.gif
InBlock.gif                 // 形状的索引
InBlock.gif                 private int _index = 0;
InBlock.gif
InBlock.gif                 // 形状的最大索引
InBlock.gif                 public int MaxIndex { get; set; }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 初始化形状,需要设置 Matrix 和 MaxIndex
InBlock.gif                 /// </summary>
InBlock.gif                 public abstract void InitPiece();
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 变形
InBlock.gif                 /// </summary>
InBlock.gif                 /// <returns>变形后的矩阵</returns>
InBlock.gif                 public abstract int[,] GetRotate();
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 形状的颜色
InBlock.gif                 /// </summary>
InBlock.gif                 public abstract Color Color { get; }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 获取下一个形状的索引。如果超过最大索引则返回最初索引
InBlock.gif                 /// </summary>
InBlock.gif                 /// <returns></returns>
InBlock.gif                 public int GetNextIndex()
InBlock.gif                {
InBlock.gif                         int nextIndex = _index >= MaxIndex ? 0 : _index + 1;
InBlock.gif
InBlock.gif                         return nextIndex;
InBlock.gif                }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 变形。设置 Matrix 为变形后的矩阵
InBlock.gif                 /// </summary>
InBlock.gif                 public void Rotate()
InBlock.gif                {
InBlock.gif                        Matrix = GetRotate();
InBlock.gif
InBlock.gif                        _index = GetNextIndex();
InBlock.gif                }
InBlock.gif        }
InBlock.gif}
 
2、继承PieceBase类,以“L”为例。每种形状均为一个4×4矩阵,1代表有“块”,0代表空
L.cs
InBlock.gif using System;
InBlock.gif using System.Net;
InBlock.gif using System.Windows;
InBlock.gif using System.Windows.Controls;
InBlock.gif using System.Windows.Documents;
InBlock.gif using System.Windows.Ink;
InBlock.gif using System.Windows.Input;
InBlock.gif using System.Windows.Media;
InBlock.gif using System.Windows.Media.Animation;
InBlock.gif using System.Windows.Shapes;
InBlock.gif
InBlock.gif namespace YYTetris.Piece
InBlock.gif{
InBlock.gif         public class L : PieceBase
InBlock.gif        {
InBlock.gif                 public override void InitPiece()
InBlock.gif                {
InBlock.gif                        Matrix = new int[,]
InBlock.gif                        {
InBlock.gif                                {0,1,0,0},
InBlock.gif                                {0,1,0,0},
InBlock.gif                                {0,1,1,0},
InBlock.gif                                {0,0,0,0}
InBlock.gif                        };
InBlock.gif
InBlock.gif                        MaxIndex = 3;
InBlock.gif                }
InBlock.gif
InBlock.gif                 public override int[,] GetRotate()
InBlock.gif                {
InBlock.gif                         switch (GetNextIndex())
InBlock.gif                        {
InBlock.gif                                 case 0:
InBlock.gif                                         return new int[,]
InBlock.gif                                        {
InBlock.gif                                                {0,1,0,0},
InBlock.gif                                                {0,1,0,0},
InBlock.gif                                                {0,1,1,0},
InBlock.gif                                                {0,0,0,0}
InBlock.gif                                        };
InBlock.gif                                 case 1:
InBlock.gif                                         return new int[,]
InBlock.gif                                        {
InBlock.gif                                                {0,0,0,0},
InBlock.gif                                                {1,1,1,0},
InBlock.gif                                                {1,0,0,0},
InBlock.gif                                                {0,0,0,0}
InBlock.gif                                        };
InBlock.gif                                 case 2:
InBlock.gif                                         return new int[,]
InBlock.gif                                        {
InBlock.gif                                                {1,1,0,0},
InBlock.gif                                                {0,1,0,0},
InBlock.gif                                                {0,1,0,0},
InBlock.gif                                                {0,0,0,0}
InBlock.gif                                        };
InBlock.gif                                 case 3:
InBlock.gif                                         return new int[,]
InBlock.gif                                        {
InBlock.gif                                                {0,0,1,0},
InBlock.gif                                                {1,1,1,0},
InBlock.gif                                                {0,0,0,0},
InBlock.gif                                                {0,0,0,0}
InBlock.gif                                        };
InBlock.gif                                 default:
InBlock.gif                                         return Matrix;
InBlock.gif                        }
InBlock.gif                }
InBlock.gif
InBlock.gif                 public override Color Color
InBlock.gif                {
InBlock.gif                        get { return Helper.GetColor( "#339933"); }
InBlock.gif                }
InBlock.gif        }
InBlock.gif}
 
3、核心控制类
UIControl.cs
InBlock.gif using System;
InBlock.gif using System.Net;
InBlock.gif using System.Windows;
InBlock.gif using System.Windows.Controls;
InBlock.gif using System.Windows.Documents;
InBlock.gif using System.Windows.Ink;
InBlock.gif using System.Windows.Input;
InBlock.gif using System.Windows.Media;
InBlock.gif using System.Windows.Media.Animation;
InBlock.gif using System.Windows.Shapes;
InBlock.gif
InBlock.gif using YYTetris.Piece;
InBlock.gif using System.Windows.Threading;
InBlock.gif using System.Collections.Generic;
InBlock.gif using System.ComponentModel;
InBlock.gif
InBlock.gif namespace YYTetris
InBlock.gif{
InBlock.gif         public class UIControl : INotifyPropertyChanged
InBlock.gif        {
InBlock.gif                 /// <summary>
InBlock.gif                 /// 俄罗斯方块容器
InBlock.gif                 /// </summary>
InBlock.gif                 public Block[,] Container { get; set; }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 下一个形状的容器(4×4)
InBlock.gif                 /// </summary>
InBlock.gif                 public Block[,] NextContainer { get; set; }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 游戏状态(Ready, Play, Pause, Over)
InBlock.gif                 /// </summary>
InBlock.gif                 public GameStatus GameStatus { get; set; }
InBlock.gif
InBlock.gif                 private int _rows = 20; // 行数(Y 方向)
InBlock.gif                 private int _columns = 10; // 列数(X 方向)
InBlock.gif                 private int _positionX = 3; // 形状所属的 4×4 容器的 X 坐标
InBlock.gif                 private int _positionY = 0; // 形状所属的 4×4 容器的 Y 坐标
InBlock.gif
InBlock.gif                 private List<PieceBase> _pieces; // 形状集合
InBlock.gif
InBlock.gif                 private PieceBase _currentPiece; // 当前形状
InBlock.gif                 private PieceBase _nextPiece; // 下一个形状
InBlock.gif
InBlock.gif                 private int _initSpeed = 400; // 初始速率(毫秒)
InBlock.gif                 private int _levelSpeed = 50; // 每增加一个级别所需增加的速率(毫秒)
InBlock.gif
InBlock.gif                 private DispatcherTimer _timer;
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 构造函数
InBlock.gif                 /// </summary>
InBlock.gif                 public UIControl()
InBlock.gif                {
InBlock.gif                         // 初始化形状集合,共七种形状
InBlock.gif                        _pieces = new List<PieceBase>() { new I(), new L(), new L2(), new N(), new N2(), new O(), new T() };
InBlock.gif
InBlock.gif                         // 初始化方块容器(用 Block 对象填满整个容器)
InBlock.gif                        Container = new Block[_rows, _columns];
InBlock.gif                         for ( int i = 0; i < _rows; i++)
InBlock.gif                        {
InBlock.gif                                 for ( int j = 0; j < _columns; j++)
InBlock.gif                                {
InBlock.gif                                        var block = new Block();
InBlock.gif                                        block.Top = i * block.rectangle.ActualHeight;
InBlock.gif                                        block.Left = j * block.rectangle.ActualWidth;
InBlock.gif                                        block.Color = null;
InBlock.gif
InBlock.gif                                        Container[i, j] = block;
InBlock.gif                                }
InBlock.gif                        }
InBlock.gif
InBlock.gif                         // 初始化下一个形状的容器(用 Block 对象将其填满)
InBlock.gif                        NextContainer = new Block[4, 4];
InBlock.gif                         for ( int i = 0; i < 4; i++)
InBlock.gif                        {
InBlock.gif                                 for ( int j = 0; j < 4; j++)
InBlock.gif                                {
InBlock.gif                                        var block = new Block();
InBlock.gif                                        block.Top = i * block.rectangle.ActualHeight;
InBlock.gif                                        block.Left = j * block.rectangle.ActualWidth;
InBlock.gif                                        block.Color = null;
InBlock.gif
InBlock.gif                                        NextContainer[i, j] = block;
InBlock.gif                                }
InBlock.gif                        }
InBlock.gif
InBlock.gif                         // 创建一个新的形状
InBlock.gif                        CreatePiece();
InBlock.gif                         // 呈现当前创建出的形状
InBlock.gif                        AddPiece(0, 0);
InBlock.gif
InBlock.gif                         // Timer 用于定时向下移动形状
InBlock.gif                        _timer = new DispatcherTimer();
InBlock.gif                        _timer.Interval = TimeSpan.FromMilliseconds(_initSpeed);
InBlock.gif                        _timer.Tick += new EventHandler(_timer_Tick);
InBlock.gif
InBlock.gif                        GameStatus = GameStatus.Ready;
InBlock.gif                }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 开始游戏(启动计时器)
InBlock.gif                 /// </summary>
InBlock.gif                 public void Play()
InBlock.gif                {
InBlock.gif                        GameStatus = GameStatus.Play;
InBlock.gif                        _timer.Start();
InBlock.gif                }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 暂停游戏(停止计时器)
InBlock.gif                 /// </summary>
InBlock.gif                 public void Pause()
InBlock.gif                {
InBlock.gif                        GameStatus = GameStatus.Pause;
InBlock.gif                        _timer.Stop();
InBlock.gif                }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 创建一个新的形状
InBlock.gif                 /// </summary>
InBlock.gif                 private void CreatePiece()
InBlock.gif                {
InBlock.gif                         // 逻辑移到 下坠后 的逻辑内
InBlock.gif                         for ( int x = 0; x < _columns; x++)
InBlock.gif                        {
InBlock.gif                                 if (Container[0, x].Color != null)
InBlock.gif                                {
InBlock.gif                                        OnGameOver( null);
InBlock.gif                                         break;
InBlock.gif                                }
InBlock.gif                        }
InBlock.gif
InBlock.gif                         // 计算 当前形状 和 下一个形状
InBlock.gif                        Random random = new Random();
InBlock.gif                        _currentPiece = _nextPiece == null ? _pieces[random.Next(0, 7)] : _nextPiece;
InBlock.gif                        _nextPiece = _pieces[random.Next(0, 7)];
InBlock.gif
InBlock.gif                         // 形状所属的 4×4 容器的 X 坐标和 Y 坐标
InBlock.gif                        _positionX = 3;
InBlock.gif                        _positionY = 0;
InBlock.gif
InBlock.gif                         // 设置“下一个形状的容器”的 UI
InBlock.gif                        SetNextContainerUI();
InBlock.gif                }
InBlock.gif
InBlock.gif                 private void _timer_Tick( object sender, EventArgs e)
InBlock.gif                {
InBlock.gif                        MoveToDown();
InBlock.gif                }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 向左移动
InBlock.gif                 /// </summary>
InBlock.gif                 public void MoveToLeft()
InBlock.gif                {
InBlock.gif                         if (GameStatus != GameStatus.Play) return;
InBlock.gif
InBlock.gif                         if (!IsBoundary(_currentPiece.Matrix, -1, 0))
InBlock.gif                        {
InBlock.gif                                RemovePiece();
InBlock.gif                                AddPiece(-1, 0);
InBlock.gif                        }
InBlock.gif                }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 向右移动
InBlock.gif                 /// </summary>
InBlock.gif                 public void MoveToRight()
InBlock.gif                {
InBlock.gif                         if (GameStatus != GameStatus.Play) return;
InBlock.gif
InBlock.gif                         if (!IsBoundary(_currentPiece.Matrix, 1, 0))
InBlock.gif                        {
InBlock.gif                                RemovePiece();
InBlock.gif                                AddPiece(1, 0);
InBlock.gif                        }
InBlock.gif                }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 向下移动
InBlock.gif                 /// </summary>
InBlock.gif                 public void MoveToDown()
InBlock.gif                {
InBlock.gif                         if (GameStatus != GameStatus.Play) return;
InBlock.gif
InBlock.gif                         if (!IsBoundary(_currentPiece.Matrix, 0, 1))
InBlock.gif                        {
InBlock.gif                                RemovePiece();
InBlock.gif                                AddPiece(0, 1);
InBlock.gif                        }
InBlock.gif                         else
InBlock.gif                        {
InBlock.gif                                 // 如果触及底边了,则消除可消的行并且创建新的形状
InBlock.gif                                RemoveRow();
InBlock.gif                                CreatePiece();
InBlock.gif
InBlock.gif                                 // 每落下一个形状加 1 分
InBlock.gif                                Score++;
InBlock.gif                        }
InBlock.gif                }