介绍
使用 Silverlight 2.0(c#) 开发个 7彩俄罗斯方块
玩法
↑ - 变形;← - 向左移动;→ - 向右移动;↓ - 向下移动
在线DEMO
点击这里查看效果
思路
1、每个形状都是由4个“块”组成也就是“块”是俄罗斯方块最小单位首先要有个“块”用户Control控件要求可以设置“块”位置和颜色
2、经典俄罗斯方块共7种形状把每种形状所需要功能抽象出来写个抽象类7个具体形状分别继承这个抽象类并重写其抽象属性和抽象思路方法
3、核心控制部分:在容器内铺满隐藏“块”上/下/左/右/控制形状变形和移动通过控制容器内“块”颜色来响应变化当形状下步移动或变形位置处已经有颜色时则禁止移动或变形当形状下步移动或变形位置在底边有颜色或处于容器底部则判断消行并生成新形状
关键代码
1、形状抽象类
PieceBase.cs
using ;
using .Net;
using .Windows;
using .Windows.Controls;
using .Windows.Documents;
using .Windows.Ink;
using .Windows.Input;
using .Windows.Media;
using .Windows.Media.Animation;
using .Windows.Shapes;
YYTetris.Piece
{
public abstract PieceBase
{
public PieceBase
{
InitPiece;
}
// 形状矩阵
public [,] Matrix { get; ; }
// 形状索引
private _index = 0;
// 形状最大索引
public MaxIndex { get; ; }
/**//// <summary>
/// 化形状需要设置 Matrix 和 MaxIndex
/// </summary>
public abstract void InitPiece;
/**//// <summary>
/// 变形
/// </summary>
/// <s>变形后矩阵</s>
public abstract [,] GetRotate;
/**//// <summary>
/// 形状颜色
/// </summary>
public abstract Color Color { get; }
/**//// <summary>
/// 获取下个形状索引如果超过最大索引则返回最初索引
/// </summary>
/// <s></s>
public GetNextIndex
{
nextIndex = _index >= MaxIndex ? 0 : _index + 1;
nextIndex;
}
/**//// <summary>
/// 变形设置 Matrix 为变形后矩阵
/// </summary>
public void Rotate
{
Matrix = GetRotate;
_index = GetNextIndex;
}
}
}
2、继承PieceBase类以“L”为例每种形状均为个4×4矩阵1代表有“块”0代表空
L.cs
using ;
using .Net;
using .Windows;
using .Windows.Controls;
using .Windows.Documents;
using .Windows.Ink;
using .Windows.Input;
using .Windows.Media;
using .Windows.Media.Animation;
using .Windows.Shapes;
YYTetris.Piece
{
public L : PieceBase
{
public override void InitPiece
{
Matrix = [,]
{
{0,1,0,0},
{0,1,0,0},
{0,1,1,0},
{0,0,0,0}
};
MaxIndex = 3;
}
public override [,] GetRotate
{
switch (GetNextIndex)
{
0:
[,]
{
{0,1,0,0},
{0,1,0,0},
{0,1,1,0},
{0,0,0,0}
};
1:
[,]
{
{0,0,0,0},
{1,1,1,0},
{1,0,0,0},
{0,0,0,0}
};
2:
[,]
{
{1,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,0,0,0}
};
3:
[,]
{
{0,0,1,0},
{1,1,1,0},
{0,0,0,0},
{0,0,0,0}
};
default:
Matrix;
}
}
public override Color Color
{
get { Helper.GetColor("#339933"); }
}
}
}
3、核心控制类
UIControl.cs
using ;
using .Net;
using .Windows;
using .Windows.Controls;
using .Windows.Documents;
using .Windows.Ink;
using .Windows.Input;
using .Windows.Media;
using .Windows.Media.Animation;
using .Windows.Shapes;
using YYTetris.Piece;
using .Windows.Threading;
using .Collections.Generic;
using .ComponentModel;
YYTetris
{
public UIControl : INotyPropertyChanged
{
/**//// <summary>
/// 俄罗斯方块容器
/// </summary>
public Block[,] Container { get; ; }
/**//// <summary>
/// 下个形状容器(4×4)
/// </summary>
public Block[,] NextContainer { get; ; }
/**//// <summary>
/// 游戏状态(Ready, Play, Pause, Over)
/// </summary>
public GameStatus GameStatus { get; ; }
private _rows = 20; // 行数(Y 方向)
private _columns = 10; // 列数(X 方向)
private _positionX = 3; // 形状所属 4×4 容器 X 坐标
private _positionY = 0; // 形状所属 4×4 容器 Y 坐标
private List<PieceBase> _pieces; // 形状集合
private PieceBase _currentPiece; // 当前形状
private PieceBase _nextPiece; // 下个形状
private _initSpeed = 400; // 速率(毫秒)
private _levelSpeed = 50; // 每增加个级别所需增加速率(毫秒)
private DispatcherTimer _timer;
/**//// <summary>
/// 构造
/// </summary>
public UIControl
{
// 化形状集合共 7种形状
_pieces = List<PieceBase> { I, L, L2, N, N2, O, T };
// 化方块容器(用 Block 对象填满整个容器)
Container = Block[_rows, _columns];
for ( i = 0; i < _rows; i)
{
for ( j = 0; j < _columns; j)
{
var block = Block;
block.Top = i * block.rectangle.ActualHeight;
block.Left = j * block.rectangle.ActualWidth;
block.Color = null;
Container[i, j] = block;
}
}
// 化下个形状容器(用 Block 对象将其填满)
NextContainer = Block[4, 4];
for ( i = 0; i < 4; i)
{
for ( j = 0; j < 4; j)
{
var block = Block;
block.Top = i * block.rectangle.ActualHeight;
block.Left = j * block.rectangle.ActualWidth;
block.Color = null;
NextContainer[i, j] = block;
}
}
// 创建个新形状
CreatePiece;
// 呈现当前创建出形状
AddPiece(0, 0);
// Timer 用于定时向下移动形状
_timer = DispatcherTimer;
_timer.Interval = TimeSpan.FromMilliseconds(_initSpeed);
_timer.Tick EventHandler(_timer_Tick);
GameStatus = GameStatus.Ready;
}
/**//// <summary>
/// 开始游戏(启动计时器)
/// </summary>
public void Play
{
GameStatus = GameStatus.Play;
_timer.Start;
}
/**//// <summary>
/// 暂停游戏(停止计时器)
/// </summary>
public void Pause
{
GameStatus = GameStatus.Pause;
_timer.Stop;
}
/**//// <summary>
/// 创建个新形状
/// </summary>
private void CreatePiece
{
// 逻辑移到 下坠后 逻辑内
for ( x = 0; x < _columns; x)
{
(Container[0, x].Color != null)
{
OnGameOver(null);
;
}
}
// 计算 当前形状 和 下个形状
Random random = Random;
_currentPiece = _nextPiece null ? _pieces[random.Next(0, 7)] : _nextPiece;
_nextPiece = _pieces[random.Next(0, 7)];
// 形状所属 4×4 容器 X 坐标和 Y 坐标
_positionX = 3;
_positionY = 0;
// 设置“下个形状容器” UI
SetNextContainerUI;
}
private void _timer_Tick(object sender, EventArgs e)
{
MoveToDown;
}
/**//// <summary>
/// 向左移动
/// </summary>
public void MoveToLeft
{
(GameStatus != GameStatus.Play) ;
(!IsBoundary(_currentPiece.Matrix, -1, 0))
{
RemovePiece;
AddPiece(-1, 0);
}
}
/**//// <summary>
/// 向右移动
/// </summary>
public void MoveToRight
{
(GameStatus != GameStatus.Play) ;
(!IsBoundary(_currentPiece.Matrix, 1, 0))
{
RemovePiece;
AddPiece(1, 0);
}
}
/**//// <summary>
/// 向下移动
/// </summary>
public void MoveToDown
{
(GameStatus != GameStatus.Play) ;
(!IsBoundary(_currentPiece.Matrix, 0, 1))
{
RemovePiece;
AddPiece(0, 1);
}
{
// 如果触及底边了则消除可消行并且创建新形状
RemoveRow;
CreatePiece;
// 每落下个形状加 1 分
Score;
}
}
/**//// <summary>
/// 变形
/// </summary>
public void Rotate
{
(GameStatus != GameStatus.Play) ;
(!IsBoundary(_currentPiece.GetRotate, 0, 0))
{
RemovePiece;
_currentPiece.Rotate;
AddPiece(0, 0);
}
}
/**//// <summary>
/// 清除俄罗斯方块容器
/// </summary>
public void Clear
{
for ( x = 0; x < _columns; x)
{
for ( y = 0; y < _rows; y)
{
Container[y, x].Color = null;
}
}
}
/**//// <summary>
/// 边界判断(是否超过边界)
/// </summary>
/// <param name="matrix">当前操作形状4×4矩阵</param>
/// <param name="offX">矩阵 X 方向偏移量</param>
/// <param name="offY">矩阵 Y 方向偏移量</param>
/// <s></s>
private bool IsBoundary([,] matrix, offX, offY)
{
RemovePiece;
for ( i = 0; i < 4; i)
{
for ( j = 0; j < 4; j)
{
(matrix[i, j] 1)
{
(j + _positionX + offX > _columns - 1 // 超过列右边界
|| i + _positionY + offY > _rows - 1 // 超过行下边界
|| j + _positionX + offX < 0 // 超过列左边界
|| Container[i + _positionY + offY, j + _positionX + offX].Color != null) // matrix 所需偏移地方已经有 Block 占着了
{
AddPiece(0, 0);
true;
}
}
}
}
AddPiece(0, 0);
false;
}
/**//// <summary>
/// 设置“下个形状容器” UI
/// </summary>
private void SetNextContainerUI
{
// 清空
foreach (Block block in NextContainer)
{
block.Color = null;
}
// 根据 _nextPiece 矩阵设置相对应 Block 对象呈现
for ( x = 0; x < 4; x)
{
for ( y = 0; y < 4; y)
{
(_nextPiece.Matrix[x, y] 1)
{
NextContainer[x, y].Color = _nextPiece.Color;
}
}
}
}
/**//// <summary>
/// 移除 _currentPiece 在界面上呈现
/// </summary>
private void RemovePiece
{
for ( i = 0; i < 4; i)
{
for ( j = 0; j < 4; j)
{
(_currentPiece.Matrix[i, j] 1)
{
Container[i + _positionY, j + _positionX].Color = null;
}
}
}
}
/**//// <summary>
/// 增加 _currentPiece 在界面上呈现
/// </summary>
/// <param name="offX">X 方向上偏移量</param>
/// <param name="offY">Y 方向上偏移量</param>
private void AddPiece( offX, offY)
{
for ( i = 0; i < 4; i)
{
for ( j = 0; j < 4; j)
{
(_currentPiece.Matrix[i, j] 1)
{
Container[i + _positionY + offY, j + _positionX + offX].Color = _currentPiece.Color;
}
}
}
_positionX offX;
_positionY offY;
}
/**//// <summary>
/// 根据游戏规则如果某行出现连续直线则将其删除该线以上部分依次向下移动
/// </summary>
private void RemoveRow
{
// 删除行数
removeRowCount = 0;
// 行遍历(Y 方向)
for ( y = 0; y < _rows; y)
{
// 该行是否是条连续直线
bool isLine = true;
// 列遍历(X 方向)
for ( x = 0; x < _columns; x)
{
(Container[y, x].Color null)
{
// 出现断行则继续遍历下行
isLine = false;
;
}
}
// 该行是条连续直线则将其删除并将该行以上部分依次向下移动
(isLine)
{
removeRowCount;
// 删除该行
for ( x = 0; x < _columns; x)
{
Container[y, x].Color = null;
}
// 将被删除行以上行依次向下移动
for ( i = y; i > 0; i--)
{
for ( x = 0; x < _columns; x)
{
Container[i, x].Color = Container[i - 1, x].Color;
}
}
}
}
// 加分计算思路方法: 2 removeRowCount 次幂 乘以 10
(removeRowCount > 0)
Score 10 * ()Math.Pow(2, removeRowCount);
// 更新总已消行数
RemoveRowCount removeRowCount;
// 根据已消行数计算级别依据丁学建议计算思路方法: 已消行数/5 平方根 取整
Level = ()Math.Sqrt(RemoveRowCount / 5);
// 根据级别计算速率计算思路方法: 速率 减 (每多个级别所需增加速率 乘以 当前级别)
_timer.Interval = TimeSpan.FromMilliseconds(_initSpeed - _levelSpeed * Level > _levelSpeed ? _initSpeed - _levelSpeed * Level : _levelSpeed);
}
private _score = 0;
/**//// <summary>
/// 得分
/// </summary>
public Score
{
get { _score; }
{
_score = value;
(PropertyChanged != null)
{
PropertyChanged(this, PropertyChangedEventArgs("Score"));
}
}
}
private _removeRowCount = 0;
/**//// <summary>
/// 总共被消除行数
/// </summary>
public RemoveRowCount
{
get { _removeRowCount; }
{
_removeRowCount = value;
(PropertyChanged != null)
{
PropertyChanged(this, PropertyChangedEventArgs("RemoveRowCount"));
}
}
}
private _level = 0;
/**//// <summary>
/// 级别(游戏难度)
/// </summary>
public Level
{
get { _level; }
{
_level = value;
(PropertyChanged != null)
{
PropertyChanged(this, PropertyChangedEventArgs("Level"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
/**//// <summary>
/// 游戏结束事件委托
/// </summary>
public event EventHandler GameOver;
/**//// <summary>
/// 游戏结束后所思路方法并触发游戏结束事件
/// </summary>
/// <param name="e"></param>
private void _disibledevent=> _timer.Interval = TimeSpan.FromMilliseconds(_initSpeed);
_timer.Stop;
EventHandler handler = GameOver;
(handler != null)
handler(this, e);
}
}
}
最新评论