using System ;
using System . Collections . Generic;
using System . Runtime . InteropServices;
using System . Drawing . Drawing2D;
using System . Drawing . Imaging;
using System . Text;
using System . Windows . Forms;
using System . Data;
using System . Drawing;
using System . ComponentModel;
using System . Threading;
using System . Diagnostics;
using System . IO;
namespace Tetris
{
public class TetrisControl : Control
{
#region Field
private const int rowCount = 21 ; //
private const int colCount = 11 ; //
private int brickWidth = 16 ; //
private int brickHeight = 16 ; //
private ImageList imageList; //
private Bitmap backBitmap; //
private List < List < List < Point >>> brickTemplets = new List < List < List < Point >>> (); //
private byte [,] points = new byte [colCount, rowCount]; //
private byte brickIndex = 0 ; //
private byte facingIndex = 0 ; //
private Point brickPoint = new Point (); //
private byte afterBrickIndex = 0 ; //
private byte afterFacingIndex = 0 ; //
private System . Windows . Forms . Timer timer; //
private int lines; //
private Random random = new Random (); //
private int level = 0 ; //
private int score = 0 ; //
private int [] speeds = new int [] { 800 , 650 , 500 , 400 , 350 , 200 , 180 , 150 , 130 , 100 , 60 };
private int [] scoress = new int [] { 0001 , 0100 , 0300 , 0500 , 1000 , 2000 };
private bool playing = false ;
private TetrisNext tetrisNext;
private TetrisScore tetrisScore;
private int stepIndex = - 1 ;
private bool reviewing = false ;
private Thread threadReview = null ;
private int reviewSpeed = 1 ;
private List < StepInfo > StepInfos = new List < StepInfo > ();
private int lastRecordTime = 0 ; //
private bool recordMode = false ; //
private ProgressBar progressBar;
#endregion Field
/// <summary>
///
/// </summary>
public int Lines { get { return lines; } }
public int Score { get { return score; } }
public int Level { get { return level; } }
/// <summary>
///
/// </summary>
public enum BrickOperates
{
boMoveLeft = 0 , //
boMoveRight = 1 , //
boMoveDown = 2 , //
boMoveBottom = 3 , //
boTurnLeft = 4 , //
boTurnRight = 5 , //
}
/// <summary>
///
/// </summary>
public struct StepInfo
{
public byte command; //
public ushort timeTick; //
public byte param1; //
public byte param2; //
public StepInfo( int ATimeTick, byte ACommand, byte AParam1, byte AParam2)
{
timeTick = ( ushort )ATimeTick;
command = ACommand;
param1 = AParam1;
param2 = AParam2;
}
}
public TetrisControl()
{
Width = colCount * brickWidth;
Height = rowCount * brickHeight;
BackColor = Color . Black;
List < List < Point >> templets;
List < Point > bricks;
#region
//
templets = new List < List < Point >> ();
bricks = new List < Point > ();
bricks . Add( new Point ( 0 , 0 )); //[00][10][ ][ ]
bricks . Add( new Point ( 1 , 0 )); //[01][11][ ][ ]
bricks . Add( new Point ( 0 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 1 , 1 )); //[ ][ ][ ][ ]
templets . Add(bricks);
brickTemplets . Add(templets);
//
templets = new List < List < Point >> ();
bricks = new List < Point > ();
bricks . Add( new Point ( 1 , 0 )); //[ ][10][ ][ ]
bricks . Add( new Point ( 0 , 1 )); //[01][11][21][ ]
bricks . Add( new Point ( 1 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 2 , 1 )); //[ ][ ][ ][ ]
templets . Add(bricks);
bricks = new List < Point > ();
bricks . Add( new Point ( 1 , 0 )); //[ ][10][ ][ ]
bricks . Add( new Point ( 1 , 1 )); //[ ][11][21][ ]
bricks . Add( new Point ( 2 , 1 )); //[ ][12][ ][ ]
bricks . Add( new Point ( 1 , 2 )); //[ ][ ][ ][ ]
templets . Add(bricks);
bricks = new List < Point > ();
bricks . Add( new Point ( 0 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 1 , 1 )); //[01][11][21][ ]
bricks . Add( new Point ( 2 , 1 )); //[ ][12][ ][ ]
bricks . Add( new Point ( 1 , 2 )); //[ ][ ][ ][ ]
templets . Add(bricks);
bricks = new List < Point > ();
bricks . Add( new Point ( 1 , 0 )); //[ ][10][ ][ ]
bricks . Add( new Point ( 0 , 1 )); //[01][11][ ][ ]
bricks . Add( new Point ( 1 , 1 )); //[ ][12][ ][ ]
bricks . Add( new Point ( 1 , 2 )); //[ ][ ][ ][ ]
templets . Add(bricks);
brickTemplets . Add(templets);
//
templets = new List < List < Point >> ();
bricks = new List < Point > ();
bricks . Add( new Point ( 1 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 2 , 1 )); //[ ][11][21][ ]
bricks . Add( new Point ( 1 , 2 )); //[ ][12][ ][ ]
bricks . Add( new Point ( 1 , 3 )); //[ ][13][ ][ ]
templets . Add(bricks);
bricks = new List < Point > ();
bricks . Add( new Point ( 0 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 1 , 1 )); //[01][11][21][ ]
bricks . Add( new Point ( 2 , 1 )); //[ ][ ][22][ ]
bricks . Add( new Point ( 2 , 2 )); //[ ][ ][ ][ ]
templets . Add(bricks);
bricks = new List < Point > ();
bricks . Add( new Point ( 2 , 0 )); //[ ][ ][20][ ]
bricks . Add( new Point ( 2 , 1 )); //[ ][ ][21][ ]
bricks . Add( new Point ( 1 , 2 )); //[ ][12][22][ ]
bricks . Add( new Point ( 2 , 2 )); //[ ][ ][ ][ ]
templets . Add(bricks);
bricks = new List < Point > ();
bricks . Add( new Point ( 1 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 1 , 2 )); //[ ][11][ ][ ]
bricks . Add( new Point ( 2 , 2 )); //[ ][12][22][32]
bricks . Add( new Point ( 3 , 2 )); //[ ][ ][ ][ ]
templets . Add(bricks);
brickTemplets . Add(templets);
//
templets = new List < List < Point >> ();
bricks = new List < Point > ();
bricks . Add( new Point ( 1 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 2 , 1 )); //[ ][11][21][ ]
bricks . Add( new Point ( 2 , 2 )); //[ ][ ][22][ ]
bricks . Add( new Point ( 2 , 3 )); //[ ][ ][23][ ]
templets . Add(bricks);
bricks = new List < Point > ();
bricks . Add( new Point ( 2 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 0 , 2 )); //[ ][ ][21][ ]
bricks . Add( new Point ( 1 , 2 )); //[02][12][22][ ]
bricks . Add( new Point ( 2 , 2 )); //[ ][ ][ ][ ]
templets . Add(bricks);
bricks = new List < Point > ();
bricks . Add( new Point ( 1 , 0 )); //[ ][10][ ][ ]
bricks . Add( new Point ( 1 , 1 )); //[ ][11][ ][ ]
bricks . Add( new Point ( 1 , 2 )); //[ ][12][22][ ]
bricks . Add( new Point ( 2 , 2 )); //[ ][ ][ ][ ]
templets . Add(bricks);
bricks = new List < Point > ();
bricks . Add( new Point ( 1 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 2 , 1 )); //[ ][11][21][31]
bricks . Add( new Point ( 3 , 1 )); //[ ][12][ ][ ]
bricks . Add( new Point ( 1 , 2 )); //[ ][ ][ ][ ]
templets . Add(bricks);
brickTemplets . Add(templets);
//
templets = new List < List < Point >> ();
bricks = new List < Point > ();
bricks . Add( new Point ( 1 , 0 )); //[ ][10][ ][ ]
bricks . Add( new Point ( 1 , 1 )); //[ ][11][ ][ ]
bricks . Add( new Point ( 1 , 2 )); //[ ][12][ ][ ]
bricks . Add( new Point ( 1 , 3 )); //[ ][13][ ][ ]
templets . Add(bricks);
bricks = new List < Point > ();
bricks . Add( new Point ( 0 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 1 , 1 )); //[01][11][21][31]
bricks . Add( new Point ( 2 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 3 , 1 )); //[ ][ ][ ][ ]
templets . Add(bricks);
brickTemplets . Add(templets);
//
templets = new List < List < Point >> ();
bricks = new List < Point > ();
bricks . Add( new Point ( 1 , 0 )); //[ ][10][ ][ ]
bricks . Add( new Point ( 1 , 1 )); //[01][11][ ][ ]
bricks . Add( new Point ( 0 , 1 )); //[02][ ][ ][ ]
bricks . Add( new Point ( 0 , 2 )); //[ ][ ][ ][ ]
templets . Add(bricks);
bricks = new List < Point > ();
bricks . Add( new Point ( 0 , 0 )); //[00][10][ ][ ]
bricks . Add( new Point ( 1 , 0 )); //[ ][11][21][ ]
bricks . Add( new Point ( 1 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 2 , 1 )); //[ ][ ][ ][ ]
templets . Add(bricks);
brickTemplets . Add(templets);
//
templets = new List < List < Point >> ();
bricks = new List < Point > ();
bricks . Add( new Point ( 0 , 0 )); //[00][ ][ ][ ]
bricks . Add( new Point ( 0 , 1 )); //[01][11][ ][ ]
bricks . Add( new Point ( 1 , 1 )); //[ ][12][ ][ ]
bricks . Add( new Point ( 1 , 2 )); //[ ][ ][ ][ ]
templets . Add(bricks);
bricks = new List < Point > ();
bricks . Add( new Point ( 1 , 0 )); //[ ][10][20][ ]
bricks . Add( new Point ( 2 , 0 )); //[01][11][ ][ ]
bricks . Add( new Point ( 0 , 1 )); //[ ][ ][ ][ ]
bricks . Add( new Point ( 1 , 1 )); //[ ][ ][ ][ ]
templets . Add(bricks);
brickTemplets . Add(templets);
////
//templets = new List<List<Point>>();
//bricks = new List<Point>();
//bricks.Add(new Point(1, 0)); //[ ][10][ ][ ]
//bricks.Add(new Point(0, 1)); //[01][11][21][ ]
//bricks.Add(new Point(1, 1)); //[ ][12][ ][ ]
//bricks.Add(new Point(2, 1)); //[ ][ ][ ][ ]
//bricks.Add(new Point(1, 2));
//templets.Add(bricks);
//brickTemplets.Add(templets);
#endregion
base . SetStyle( ControlStyles . OptimizedDoubleBuffer, true );
base . SetStyle( ControlStyles . Selectable, true );
afterBrickIndex = ( byte )random . Next(brickTemplets . Count);
afterFacingIndex = ( byte )random . Next(brickTemplets[afterBrickIndex] . Count);
timer = new System . Windows . Forms . Timer ();
timer . Interval = 100 ;
timer . Tick += new EventHandler (timer_Tick);
DoChange();
GameOver();
}
void timer_Tick(object sender, EventArgs e)
{
BrickOperate( BrickOperates . boMoveDown);
}
public void Replay( bool ARecordMode)
{
if (threadReview != null )
{
threadReview . Abort();
threadReview = null ;
}
reviewing = false ;
playing = true ;
recordMode = ARecordMode;
Clear();
StepInfos . Clear();
afterBrickIndex = ( byte )random . Next(brickTemplets . Count);
afterFacingIndex = ( byte )random . Next(brickTemplets[afterBrickIndex] . Count);
if (recordMode && ! reviewing)
{
StepInfos . Add( new StepInfo ( 0 , 0 , afterBrickIndex, afterFacingIndex));
lastRecordTime = Environment . TickCount;
}
level = 0 ;
score = 0 ;
if (progressBar != null ) progressBar . Value = 0 ;
NextBrick();
timer . Interval = speeds[level];
timer . Enabled = true ;
if (CanFocus) Focus();
}
public void NextStep()
{
if (stepIndex < 0 ) return ;
if (stepIndex >= StepInfos . Count) return ;
switch (StepInfos[stepIndex] . command)
{
case 0 :
afterBrickIndex = StepInfos[stepIndex] . param1;
afterFacingIndex = StepInfos[stepIndex] . param2;
break ;
case 1 :
brickIndex = afterBrickIndex;
facingIndex = afterFacingIndex;
brickPoint . X = colCount / 2 - 1 ;
brickPoint . Y = 0 ;
afterBrickIndex = StepInfos[stepIndex] . param1;
afterFacingIndex = StepInfos[stepIndex] . param2;
if (tetrisNext != null && afterBrickIndex != brickIndex)
tetrisNext . Update( this );
if (tetrisScore != null )
tetrisScore . Update( this );
DrawCurrent( Graphics . FromImage(backBitmap), false );
Invalidate();
break ;
case 2 :
BrickOperate(( BrickOperates )StepInfos[stepIndex] . param1);
Invalidate();
break ;
case 3 :
GameOver();
Invalidate();
break ;
}
stepIndex ++ ;
}
public int ReviewSpeed //
{
set
{
reviewSpeed = value > 0 ? value : 1 ;
}
get
{
return reviewSpeed;
}
}
private void DoReview()
{
while (reviewing)
{
if (stepIndex < 0 || stepIndex >= StepInfos . Count)
{
reviewing = false ;
break ;
}
Thread . Sleep(( int )(( double )StepInfos[stepIndex] . timeTick / reviewSpeed));
if ( ! reviewing) break ;
Invoke( new EventHandler (DoInvoke));
}
Invoke( new EventHandler (DoInvoke));
threadReview = null ;
}
private void DoInvoke( object sender, EventArgs e)
{
if (reviewing)
{
NextStep();
if (progressBar != null )
progressBar . Value = stepIndex;
}
else if (playing)
{
timer . Enabled = true ;
if (CanFocus) Focus();
}
}
/// <summary>
///
/// </summary>
public void Review()
{
if (threadReview != null )
{
threadReview . Abort();
threadReview = null ;
}
timer . Enabled = false ;
reviewing = true ;
playing = true ;
Clear();
level = 0 ;
score = 0 ;
lines = 0 ;
stepIndex = 0 ;
NextStep();
NextStep();
if (progressBar != null )
progressBar . Maximum = StepInfos . Count;
threadReview = new Thread ( new ThreadStart (DoReview));
threadReview . Start();
}
/// <summary>
///
/// </summary>
/// <param name="ABitmap"> </param>
/// <returns> </returns>
public static bool BitmapGray( Bitmap ABitmap)
{
if (ABitmap == null ) return false ;
byte R = 0 , G = 0 , B = 0 ;
BitmapData vBitmapData = ABitmap . LockBits(
new Rectangle ( 0 , 0 , ABitmap . Width, ABitmap . Height),
ImageLockMode . ReadWrite, PixelFormat . Format32bppRgb);
int vAddress = ( int )vBitmapData . Scan0;
int vOffset = vBitmapData . Stride - ABitmap . Width * 4 ;
int h = ABitmap . Height, w = ABitmap . Width;
for ( int y = 0 ; y < h; y ++ )
{
for ( int x = 0 ; x < w; x ++ )
{
int i = Marshal . ReadInt32(( IntPtr )vAddress);
R = ( byte )(i >> 0 & 0xff );
G = ( byte )(i >> 8 & 0xff );
B = ( byte )(i >> 16 & 0xff );
R = ( byte )(( 77 * R + 151 * G + 28 * B) >> 8 );
i = ( int )(i & 0xff000000 ) | R << 0 | R << 8 | R << 16 ;
Marshal . WriteInt32(( IntPtr )vAddress, i);
vAddress += 4 ;
}
vAddress += vOffset;
}
ABitmap . UnlockBits(vBitmapData);
return true ;
}
public void GameOver()
{
BitmapGray(backBitmap);
playing = false ;
timer . Enabled = false ;
}
public void DoChange()
{
Width = brickWidth * colCount;
Height = brickHeight * rowCount;
backBitmap = new Bitmap (Width, Height);
Graphics vGraphics = Graphics . FromImage(backBitmap);
vGraphics . FillRectangle( new SolidBrush (BackColor), vGraphics . ClipBounds);
DrawPoints(vGraphics);
DrawCurrent(vGraphics, false );
Invalidate();
}
public void Clear()
{
for ( int i = 0 ; i < colCount; i ++ )
for ( int j = 0 ; j < rowCount; j ++ )
points[i, j] = 0 ;
Graphics vGraphics = Graphics . FromImage(backBitmap);
vGraphics . FillRectangle( new SolidBrush (BackColor), vGraphics . ClipBounds);
}
public void LoadFromFile( string AFileName)
{
if ( ! File . Exists(AFileName)) return ;
FileStream vFileStream = new FileStream (AFileName,
FileMode . Open, FileAccess . Read);
LoadFromStream(vFileStream);
vFileStream . Close();
}
public void LoadFromStream( Stream AStream)
{
if (AStream == null ) return ;
byte [] vBuffer = new byte[ 3 ];
if (AStream . Read(vBuffer, 0 , vBuffer . Length) != 3 ) return ;
if (vBuffer[ 0 ] != 116 || vBuffer[ 1 ] != 114 || vBuffer[ 2 ] != 102 ) return ;
if (colCount != ( byte )AStream . ReadByte()) return ;
if (rowCount != ( byte )AStream . ReadByte()) return ;
if (threadReview != null )
{
threadReview . Abort(); //
threadReview = null ;
}
timer . Enabled = false ;
playing = false ;
reviewing = false ;
brickTemplets . Clear();
int vTempletsCount = AStream . ReadByte();
for ( int i = 0 ; i < vTempletsCount; i ++ )
{
List < List < Point >> templets = new List < List < Point >> ();
int vPointsLength = AStream . ReadByte();
for ( int j = 0 ; j < vPointsLength; j ++ )
{
List < Point > bricks = new List < Point > ();
int vPointCount = AStream . ReadByte();
for ( int k = 0 ; k < vPointCount; k ++ )
{
int vData = AStream . ReadByte();
if (vData < 0 ) break;
bricks . Add( new Point (vData & 3 , vData >> 4 & 3 ));
}
templets . Add(bricks);
}
brickTemplets . Add(templets);
}
StepInfos . Clear();
vBuffer = new byte [ sizeof ( int )];
if (AStream . Read(vBuffer, 0 , vBuffer . Length) != vBuffer . Length) return ;
int vStepCount = BitConverter . ToInt32(vBuffer, 0 );
for ( int i = 0 ; i < vStepCount; i ++ )
{
StepInfo vStepInfo = new StepInfo ();
vStepInfo . param1 = ( byte )AStream . ReadByte();
vBuffer = new byte[ sizeof ( ushort )];
if (AStream . Read(vBuffer, 0 , vBuffer . Length) != vBuffer . Length) return ;
vStepInfo . timeTick = ( ushort ) BitConverter . ToInt16(vBuffer, 0 );
int vData = AStream . ReadByte();
vStepInfo . command = ( byte )(vData & 3 );
vStepInfo . param2 = ( byte )(vData >> 4 & 3 );
StepInfos . Add(vStepInfo);
}
Clear();
Invalidate();
}
public void SaveToFile( string AFileName)
{
FileStream vFileStream = new FileStream (AFileName,
FileMode . Create, FileAccess . Write);
SaveToStream(vFileStream);
vFileStream . Close();
}
public void SaveToStream( Stream AStream)
{
if (AStream == null ) return ;
byte [] vBuffer = Encoding . ASCII . GetBytes( "trf" );
AStream . Write(vBuffer, 0 , vBuffer . Length); //
AStream . WriteByte(( byte )colCount);
AStream . WriteByte(( byte )rowCount);
byte vByte = ( byte )brickTemplets . Count;
AStream . WriteByte(vByte);
foreach ( List < List < Point >> vList in brickTemplets)
{
vByte = ( byte )vList . Count;
AStream . WriteByte(vByte);
foreach ( List < Point > vPoints in vList)
{
vByte = ( byte )vPoints . Count;
AStream . WriteByte(vByte);
foreach ( Point vPoint in vPoints)
{
vByte = ( byte )(vPoint . Y << 4 | vPoint . X);
AStream . WriteByte(vByte);
}
}
}
AStream . Write( BitConverter . GetBytes(StepInfos . Count), 0 , sizeof ( int ));
foreach ( StepInfo vStepInfo in StepInfos)
{
AStream . WriteByte(vStepInfo . param1);
AStream . Write( BitConverter . GetBytes(vStepInfo . timeTick), 0 , sizeof ( ushort ));
vByte = ( byte )(vStepInfo . param2 << 4 | vStepInfo . command);
AStream . WriteByte(vByte);
}
}
/// <summary>
///
/// </summary>
/// <param name="AGraphics"> </param>
/// <param name="APoint"> </param>
/// <param name="ABrick"> </param>
public void DrawPoint( Graphics AGraphics, Point APoint, byte ABrick)
{
if (ImageList == null ) return ;
if (ImageList . Images . Count <= 0 ) return ;
if (APoint . X < 0 || APoint . X >= colCount) return ;
if (APoint . Y < 0 || APoint . Y >= rowCount) return ;
Rectangle vRectangle = new Rectangle (
APoint . X * brickWidth, APoint . Y * brickHeight,
brickWidth, brickHeight);
AGraphics . FillRectangle( new SolidBrush (BackColor), vRectangle);
if (ABrick <= 0 ) return ;
ABrick = ( byte ) Math . Min(ABrick - 1 , ImageList . Images . Count - 1 );
Image vImage = ImageList . Images[ABrick];
AGraphics . DrawImage(vImage, vRectangle . Location);
}
/// <summary>
///
/// </summary>
/// <param name="AGraphics"> </param>
public void DrawPoints( Graphics AGraphics)
{
if (ImageList == null ) return ;
if (ImageList . Images . Count <= 0 ) return ;
for ( int i = 0 ; i < colCount; i ++ )
for ( int j = 0 ; j < rowCount; j ++ )
DrawPoint(AGraphics, new Point (i, j), points[i, j]);
}
/// <summary>
///
/// </summary>
/// <param name="AGraphics"> </param>
/// <param name="AClear"> </param>
public void DrawCurrent( Graphics AGraphics, bool AClear)
{
if (ImageList == null ) return ;
if (ImageList . Images . Count <= 0 ) return ;
foreach ( Point vPoint in brickTemplets[brickIndex][facingIndex])
DrawPoint(AGraphics, new Point (vPoint . X + brickPoint . X,
vPoint . Y + brickPoint . Y),
AClear ? ( byte ) 0 : ( byte )(brickIndex + 1 ));
}
/// <summary>
///
/// </summary>
/// <param name="AGraphics"> </param>
public void DrawNext( Graphics AGraphics)
{
if (AGraphics == null ) return ;
if (ImageList == null ) return ;
if (ImageList . Images . Count <= 0 ) return ;
foreach ( Point vPoint in brickTemplets[afterBrickIndex][afterFacingIndex])
DrawPoint(AGraphics, new Point (vPoint . X, vPoint . Y),
( byte )(afterBrickIndex + 1 ));
}
public void DrawScore( Graphics AGraphics)
{
if (AGraphics == null ) return ;
RectangleF vRectangleF = new Rectangle ( 0 , 0 , brickWidth * 4 , brickHeight);
StringFormat vStringFormat = new StringFormat ();
vStringFormat . FormatFlags |= StringFormatFlags . LineLimit;
vStringFormat . Alignment = StringAlignment . Center;
AGraphics . DrawString( "Score" , new Font (Font, FontStyle . Bold),
Brushes . White, vRectangleF, vStringFormat);
vRectangleF . Offset( 0 , brickHeight);
AGraphics . DrawString(score . ToString(), Font,
Brushes . White, vRectangleF, vStringFormat);
vRectangleF . Offset( 0 , brickHeight);
AGraphics . DrawString( "Level" , new Font (Font, FontStyle . Bold),
Brushes . White, vRectangleF, vStringFormat);
vRectangleF . Offset( 0 , brickHeight);
AGraphics . DrawString(level . ToString(), Font,
Brushes . White, vRectangleF, vStringFormat);
vRectangleF . Offset( 0 , brickHeight);
AGraphics . DrawString( "Lines" , new Font (Font, FontStyle . Bold),
Brushes . White, vRectangleF, vStringFormat);
vRectangleF . Offset( 0 , brickHeight);
AGraphics . DrawString(lines . ToString(), Font,
Brushes . White, vRectangleF, vStringFormat);
}
/// <summary>
///
/// </summary>
/// <param name="ABrickIndex"> </param>
/// <param name="AFacingIndex"> </param>
/// <param name="ABrickPoint"> </param>
/// <returns> </returns>
public bool CheckBrick(byte ABrickIndex, byte AFacingIndex, Point ABrickPoint)
{
foreach ( Point vPoint in brickTemplets[ABrickIndex][AFacingIndex])
{
if (vPoint . X + ABrickPoint . X < 0 ||
vPoint . X + ABrickPoint . X >= colCount) return false ;
if (vPoint . Y + ABrickPoint . Y < 0 ||
vPoint . Y + ABrickPoint . Y >= rowCount) return false ;
if (points[vPoint . X + ABrickPoint . X,
vPoint . Y + ABrickPoint . Y] != 0 ) return false ;
}
return true ;
}
/// <summary>
///
/// </summary>
public void FreeLine()
{
int vFreeCount = 0 ;
for ( int j = rowCount - 1 ; j >= 0 ; j -- )
{
bool vExistsFull = true ; //
for ( int i = 0 ; i < colCount && vExistsFull; i ++ )
if (points[i, j] == 0 )
vExistsFull = false ;
if ( ! vExistsFull) continue ;
#region
Graphics vGraphics = Graphics . FromImage(backBitmap);
Rectangle srcRect = new Rectangle ( 0 , 0 , backBitmap . Width, j * brickHeight);
Rectangle destRect = srcRect;
destRect . Offset( 0 , brickHeight);
Bitmap vBitmap = new Bitmap (srcRect . Width, srcRect . Height);
Graphics . FromImage(vBitmap) . DrawImage(backBitmap, 0 , 0 );
vGraphics . DrawImage(vBitmap, destRect, srcRect, GraphicsUnit . Pixel);
vGraphics . FillRectangle( new SolidBrush (BackColor), 0 , 0 ,
backBitmap . Width, brickHeight);
#endregion
lines ++ ;
vFreeCount ++ ;
for ( int k = j; k >= 0 ; k -- )
{
for ( int i = 0 ; i < colCount; i ++ )
if (k == 0 )
points[i, k] = 0 ;
else points[i, k] = points[i, k - 1 ];
}
j ++ ;
}
score += scoress[vFreeCount];
if (vFreeCount > 0 )
{
level = Math . Min(lines / 30 , speeds . Length - 1 );
timer . Interval = speeds[level];
Invalidate();
}
if (tetrisScore != null ) tetrisScore . Update( this );
}
/// <summary>
///
/// </summary>
/// <param name="ABrickOperates"> </param>
/// <returns> </returns>
public bool BrickOperate( BrickOperates ABrickOperates)
{
byte vFacingIndex = facingIndex;
Point vBrickPoint = brickPoint;
switch (ABrickOperates)
{
case BrickOperates . boTurnLeft:
vFacingIndex = ( byte )((vFacingIndex + 1 ) %
brickTemplets[brickIndex] . Count);
break ;
case BrickOperates . boTurnRight:
vFacingIndex = ( byte )((brickTemplets[brickIndex] . Count +
vFacingIndex - 1 ) % brickTemplets[brickIndex] . Count);
break ;
case BrickOperates . boMoveLeft:
vBrickPoint . Offset( - 1 , 0 );
break ;
case BrickOperates . boMoveRight:
vBrickPoint . Offset( + 1 , 0 );
break ;
case BrickOperates . boMoveDown:
vBrickPoint . Offset( 0 , + 1 );
break ;
case BrickOperates . boMoveBottom:
vBrickPoint . Offset( 0 , + 1 );
while (CheckBrick(brickIndex, vFacingIndex, vBrickPoint))
vBrickPoint . Offset( 0 , + 1 );
vBrickPoint . Offset( 0 , - 1 );
break ;
}
if (CheckBrick(brickIndex, vFacingIndex, vBrickPoint))
{
if (playing && recordMode && ! reviewing)
{
StepInfos . Add(new StepInfo ( Environment . TickCount - lastRecordTime,
2 , ( byte )ABrickOperates, 0 ));
lastRecordTime = Environment . TickCount;
}
Graphics vGraphics = Graphics . FromImage(backBitmap);
DrawCurrent(vGraphics, true );
facingIndex = vFacingIndex;
brickPoint = vBrickPoint;
DrawCurrent(vGraphics, false );
if (ABrickOperates == BrickOperates . boMoveBottom)
Downfall();
else Invalidate();
}
else if (ABrickOperates == BrickOperates . boMoveDown)
{
if (playing && recordMode && ! reviewing)
{
StepInfos . Add( new StepInfo ( Environment . TickCount - lastRecordTime,
2 , ( byte )ABrickOperates, 0 ));
lastRecordTime = Environment . TickCount;
}
Downfall();
}
return true ;
}
/// <summary>
///
/// </summary>
private void NextBrick()
{
brickIndex = afterBrickIndex;
facingIndex = afterFacingIndex;
brickPoint . X = colCount / 2 - 1 ;
brickPoint . Y = 0 ;
afterBrickIndex = ( byte )random . Next(brickTemplets . Count);
afterFacingIndex = ( byte )random . Next(brickTemplets[afterBrickIndex] . Count);
if (playing && recordMode && ! reviewing)
{
StepInfos . Add(new StepInfo ( 0 , 1 , afterBrickIndex, afterFacingIndex));
lastRecordTime = Environment . TickCount;
}
if (tetrisNext != null && afterBrickIndex != brickIndex)
tetrisNext . Update( this );
DrawCurrent( Graphics . FromImage(backBitmap), false );
if ( ! CheckBrick(brickIndex, facingIndex, brickPoint))
{
if (playing && recordMode && ! reviewing)
{
StepInfos . Add( new StepInfo ( 0 , 3 , 0 , 0 ));
lastRecordTime = Environment . TickCount;
}
GameOver();
}
Invalidate();
}
/// <summary>
///
/// </summary>
private void Downfall()
{
foreach ( Point vPoint in brickTemplets[brickIndex][facingIndex])
points[vPoint . X + brickPoint . X,
vPoint . Y + brickPoint . Y] = (byte)(brickIndex + 1 );
FreeLine();
if (playing && ! reviewing) NextBrick();
}
private void ImageListRecreateHandle(object sender, EventArgs e)
{
DoChange();
}
private void DetachImageList( object sender, EventArgs e)
{
ImageList = null ;
}
public ImageList ImageList
{
get
{
return imageList;
}
set
{
if ( value != imageList)
{
EventHandler handler = new EventHandler (ImageListRecreateHandle);
EventHandler handler2 = new EventHandler (DetachImageList);
if (imageList != null )
{
imageList . RecreateHandle -= handler;
imageList . Disposed -= handler2;
}
imageList = value ;
if ( value != null )
{
brickWidth = ImageList . ImageSize . Width;
brickHeight = ImageList . ImageSize . Height;
DoChange();
if ( ! playing && ! reviewing) GameOver();
if (tetrisNext != null )
{
tetrisNext . BackColor = BackColor;
tetrisNext . SetSize(brickWidth * 4 , brickHeight * 4 );
tetrisNext . Update( this );
}
value . RecreateHandle += handler;
value . Disposed += handler2;
}
}
}
}
private void DetachTetrisNext( object sender, EventArgs e)
{
TetrisNext = null ;
}
public TetrisNext TetrisNext
{
get
{
return tetrisNext;
}
set
{
if ( value != tetrisNext)
{
EventHandler handler = new EventHandler (DetachTetrisNext);
if (tetrisNext != null ) tetrisNext . Disposed -= handler;
tetrisNext = value ;
if ( value != null )
{
value . SetSize( 4 * brickWidth, 4 * brickHeight);
value . Update( this );
value . Disposed += handler;
}
}
}
}
private void DetachTetrisScore( object sender, EventArgs e)
{
TetrisScore = null ;
}
public TetrisScore TetrisScore
{
get
{
return tetrisScore;
}
set
{
if (value != tetrisScore)
{
EventHandler handler = new EventHandler (DetachTetrisScore);
if (tetrisScore != null ) tetrisScore . Disposed -= handler;
tetrisScore = value;
if ( value != null )
{
value . SetSize( 4 * brickWidth, 6 * brickHeight);
value . Update( this );
value . Disposed += handler;
}
}
}
}
private void DetachProgressBar( object sender, EventArgs e)
{
progressBar = null ;
}
public ProgressBar ProgressBar
{
get
{
return progressBar;
}
set
{
if ( value != progressBar)
{
EventHandler handler = new EventHandler (DetachProgressBar);
if (progressBar != null ) progressBar . Disposed -= handler;
progressBar = value ;
if ( value != null )
{
progressBar . Minimum = 0 ;
progressBar . Maximum = StepInfos . Count;
progressBar . Value = stepIndex < 0 ? 0 : stepIndex;
value . Disposed += handler;
}
}
}
}
protected override void OnPaint( PaintEventArgs e)
{
base . OnPaint(e);
if (backBitmap != null ) e . Graphics . DrawImage(backBitmap, 0 , 0 );
}
protected override bool IsInputKey( Keys keydata)
{
return (keydata == Keys . Down) || (keydata == Keys . Up) ||
(keydata == Keys . Left) || (keydata == Keys . Right) ||
(keydata == Keys . Escape) || base . IsInputKey(keydata);
}
protected override void OnMouseDown( MouseEventArgs e)
{
base . OnMouseDown(e);
if (CanFocus) Focus();
}
protected override void Dispose(bool disposing)
{
if (threadReview != null ) threadReview . Abort();
base . Dispose(disposing);
}
protected override void OnKeyDown( KeyEventArgs e)
{
base . OnKeyDown(e);
if ( ! playing || reviewing) return ;
switch (e . KeyCode)
{
case Keys . A: //
case Keys . Left:
BrickOperate( BrickOperates . boMoveLeft);
break ;
case Keys . D: //
case Keys . Right:
BrickOperate( BrickOperates . boMoveRight);
break ;
case Keys . W: //
case Keys . Up:
BrickOperate( BrickOperates . boTurnLeft);
break ;
case Keys . J: //
BrickOperate( BrickOperates . boTurnRight);
break ;
case Keys . Down: //
case Keys . S:
BrickOperate( BrickOperates . boMoveDown);
break ;
case Keys . Enter: //
case Keys . Space:
case Keys . End:
BrickOperate( BrickOperates . boMoveBottom);
break ;
}
}
}
public class TetrisNext : Control
{
public TetrisNext()
{
BackColor = Color . Black;
base . SetStyle( ControlStyles . OptimizedDoubleBuffer, true );
}
private Bitmap backBitmap;
public void Clear()
{
Graphics vGraphics = Graphics . FromImage(backBitmap);
vGraphics . FillRectangle( new SolidBrush (BackColor), vGraphics . ClipBounds);
}
public void Update( TetrisControl ATetrisControl)
{
if (ATetrisControl == null ) return ;
Clear();
ATetrisControl . DrawNext( Graphics . FromImage(backBitmap));
Invalidate();
}
public void SetSize( int AWidth, int AHeight)
{
Width = AWidth;
Height = AHeight;
backBitmap = new Bitmap (AWidth, AHeight);
}
protected override void OnPaint( PaintEventArgs e)
{
base . OnPaint(e);
if (backBitmap != null ) e . Graphics . DrawImage(backBitmap, 0 , 0 );
}
}
public class TetrisScore : Control
{
private Bitmap backBitmap;
public TetrisScore()
{
BackColor = Color . Black;
base . SetStyle( ControlStyles . OptimizedDoubleBuffer, true );
}
public void Clear()
{
Graphics vGraphics = Graphics . FromImage(backBitmap);
vGraphics . FillRectangle(new SolidBrush (BackColor), vGraphics . ClipBounds);
}
public void Update( TetrisControl ATetrisControl)
{
if (ATetrisControl == null ) return ;
Clear();
ATetrisControl . DrawScore( Graphics . FromImage(backBitmap));
Invalidate();
}
public void SetSize( int AWidth, int AHeight)
{
Width = AWidth;
Height = AHeight;
backBitmap = new Bitmap (AWidth, AHeight);
}
protected override void OnPaint( PaintEventArgs e)
{
base . OnPaint(e);
if (backBitmap != null ) e . Graphics . DrawImage(backBitmap, 0 , 0 );
}
}
}