首先呢,想编写这个程序的同学一定是要下过象棋的(国际的,中国的都可以),就算没下过,也应该看别人下过吧。 好吧..你也没见别人下过,那你至少应该知道象棋长什么样子吧...
首先选择自己的武器,如果你觉得自己够牛的话,那我建议你选择C语言,编译环境为turboC. 然后拥有超强的记忆力记下一大堆的API函数..然后开始动工.. 最后在花上远远多过编写代码所用时间的时间来调试自己的程序(你也就不用再看这篇日志了)
或者说,你觉得自己一般牛B,选择MFC来编写这个程序,虽然说武器是先进了一些,但是依然无法从根本上解决API函数的复杂性。
如果你想用VB6来编写类似于这样的一个Windows程序,可以是可以。但是你永远无法学习到OOP的真正价值所在。VB6不允许程序员在类与类之间建立“is a”的关系. 对于象棋这样的小型程序尚罢..
废话不说了.. 这次的例子我选择了基于.net framew 2.0以上的平台,C#语言来编写这样一个程序。 现在开始动工吧!
首先,你应该明确这是一个Windows Form程序, 而不是一个Console程序..(这一点应该都清楚吧) 所以在这个程序中会使用许多的资源,例如棋盘,棋子图形等等..所以第一步,你需要打开你的Photoshop, 开始绘制这些图片。
棋子的图片如下:
棋盘图片如下
大家可以根据自己的不同爱好来制作自己的图片,本人一向没有什么审美能力,所以能有这样的图片已经是很尽力了..
准备工作做完后,现在开始编码:
首先打开VS2008 ,新建一个Windows Form Project, 在Projrect中添加第一个类ChessPiece。IDE会自动帮你生成一个ChessPiece.cs文件 和一个Form1.cs文件
现在删除IDE自动在ChessPiece.cs这个文件中的代码,开始自己编写代码:
using System; using System.Drawing; // 创建一个棋子类 class ChessPiece { public enum Types //这是一个枚举类新,表示所有的棋子种类 { KING,//国王 QUEEN,//王后 BISHOP,//象 KNIGHT,//马 ROOK,//车 PAWN//卒 } private int currentType; // 当前类型,用于后台控制当前应该绘制的图像 private Bitmap pieceImage; // 用来储存当前图像当前图像 // 初始化一个矩形区域,这个矩形区域就是以后棋盘的边缘,用于放置整个棋盘和棋盘上的棋子 private Rectangle targetRectangle = new Rectangle( 0, 0, 75, 75 ); // 构造函数 public ChessPiece( int type, int xLocation, int yLocation, Bitmap sourceImage ) { currentType = type; // 设置棋子类型 targetRectangle.X = xLocation; // 设置X坐标 targetRectangle.Y = yLocation; // 设置Y坐标 // 将棋子的子图从大图资源中切割下来 pieceImage = sourceImage.Clone( new Rectangle( type * 75, 0, 75, 75 ), System.Drawing.Imaging.PixelFormat.DontCare ); } // 绘制棋子 public void Draw( Graphics graphicsObject ) { graphicsObject.DrawImage( pieceImage, targetRectangle ); } // 获得当前棋子坐标 public Rectangle GetBounds() { return targetRectangle; } // 设置当前棋子坐标 public void SetLocation( int xLocation, int yLocation ) { targetRectangle.X = xLocation; targetRectangle.Y = yLocation; } } 好了,这个棋子类已经写完。那应该如何让这些“死”代码活灵活现的呈现在大家面前呢? 我们还需要一个前台呈现类,也就是我们常说的UI类,或者叫Interface。 现在,将刚才在PS中绘制好的图片放置在bin/Release/images目录下 将之前IDE自动生成的Form1.cs改名为ChessGame.cs (不改也可以) 删除IDE自动生成的代码,然后自己编码: // ChessGame.cs //该文件实现棋盘和棋子的初始化,部署,和在窗口和面板上的绘制,移动,刷新等工作 using System; using System.Collections; using System.Drawing; using System.Windows.Forms; public partial class ChessGame : Form { private ArrayList chessTile = new ArrayList(); // 创建一个动态数组储存棋盘的图片 private ArrayList chessPieces = new ArrayList(); // 创建一个动态数组储存棋子的图片 private int selectedIndex = -1; // 所选图片的索引 private int[ , ] board = new int[ 8, 8 ]; // 将棋盘用一个 8 * 8 的数组来表示 private const int TILESIZE = 75; // 将每个图片快定义为 75 像素 // 初始化构造函数 public ChessGame() { // 对主窗口进行生成 InitializeComponent(); } // 将棋盘的4种图片快存入动态数组chessTile中并对棋子进行部署 private void ChessGame_Load( object sender, EventArgs e ) { chessTile.Add( Bitmap.FromFile( @"images\lightTile1.png" ) ); chessTile.Add( Bitmap.FromFile( @"images\lightTile2.png" ) ); chessTile.Add( Bitmap.FromFile( @"images\darkTile1.png" ) ); chessTile.Add( Bitmap.FromFile( @"images\darkTile2.png" ) ); ResetBoard(); //对棋盘上棋子进行部署 Invalidate(); // 刷新主窗口 } // 具体实现对棋盘的部署 private void ResetBoard() { int current = -1; ChessPiece piece; Random random = new Random(); bool light = false; int type; chessPieces.Clear(); // 确保此时棋子的动态数组为空 // 将白方棋子大图放入临时变量whitePieces中 Bitmap whitePieces = ( Bitmap ) Image.FromFile( @"images\whitePieces.png" ); // 将黑方棋子大图放入临时变量blackPieces中 Bitmap blackPieces = ( Bitmap ) Image.FromFile( @"images\blackPieces.png" ); // 从上到下先部署白色棋子 Bitmap selected = whitePieces; // 遍历棋盘的行 for ( int row = 0; row <= board.GetUpperBound( 0 ); row++ ) { // 当到达第 6 行时开始部署黑色棋子 if ( row > 5 ) selected = blackPieces; // 第二层遍历 遍历棋盘的列 for ( int column = 0; column <= board.GetUpperBound( 1 ); column++ ) { // 部署第一行和最后一行上的棋子 if ( row == 0 || row == 7 ) { switch ( column ) { case 0: case 7: // 部署车 current = ( int ) ChessPiece.Types.ROOK; break; case 1: case 6: // 部署马 current = ( int ) ChessPiece.Types.KNIGHT; break; case 2: case 5: // 部署象 current = ( int ) ChessPiece.Types.BISHOP; break; case 3: // 部署国王 current = ( int ) ChessPiece.Types.KING; break; case 4: // 部署王后 current = ( int ) ChessPiece.Types.QUEEN; break; } // 确定当前棋子的信息 piece = new ChessPiece( current, column * TILESIZE, row * TILESIZE, selected ); chessPieces.Add( piece ); // 将子图存入动态数组中 } // end if // 当遍历到第二行和倒数第二行 if ( row == 1 || row == 6 ) { piece = new ChessPiece( ( int ) ChessPiece.Types.PAWN, column * TILESIZE, row * TILESIZE, selected ); chessPieces.Add( piece ); // 将卒的子图存入动态数组 } type = random.Next( 0, 2 ); // 随即决定棋盘的格式 if ( light ) // 设置亮棋盘 { board[ row, column ] = type; light = false; } else // 设置暗棋盘 { board[ row, column ] = type + 2; light = true; } } light = !light; // 让亮色和暗色棋盘交替出现 } } // 在主窗口中绘制棋盘 private void ChessGame_Paint( object sender, PaintEventArgs e ) { Graphics graphicsObject = e.Graphics; // 实例化一个图形对象 graphicsObject.TranslateTransform( 0, 28 ); // 将棋盘整体下沿一定的距离,防止菜单栏挡住棋盘 for ( int row = 0; row <= board.GetUpperBound( 0 ); row++ ) { for ( int column = 0; column <= board.GetUpperBound( 1 ); column++) { // 绘制棋盘 graphicsObject.DrawImage( ( Image ) chessTile[ board[ row, column ] ], new Point( TILESIZE * column, ( TILESIZE * row ) ) ); } } } // 绘制棋盘上的棋子 private void pieceBox_Paint( object sender, System.Windows.Forms.PaintEventArgs e ) { // 便利整个动态数组 for ( int i = 0; i < chessPieces.Count; i++ ) GetPiece( i ).Draw( e.Graphics ); } //检测鼠标点击区域是否有棋子 private int CheckBounds( Point point, int exclude ) { Rectangle rectangle; // current bounding rectangle for ( int i = 0; i < chessPieces.Count; i++ ) { // 获得鼠标区域坐标信息 rectangle = GetPiece( i ).GetBounds(); if ( rectangle.Contains( point ) && i != exclude ) return i; } return -1; } // 鼠标点击左键产生事件 private void pieceBox_MouseDown( object sender, System.Windows.Forms.MouseEventArgs e ) { // 获得点击棋子的索引号 selectedIndex = CheckBounds( new Point( e.X, e.Y ), -1 ); } // 如果选中棋子,移动产生事件 private void pieceBox_MouseMove( object sender, System.Windows.Forms.MouseEventArgs e ) { if ( selectedIndex > -1 ) { Rectangle region = new Rectangle( e.X - TILESIZE * 2, e.Y - TILESIZE * 2, TILESIZE * 4, TILESIZE * 4 ); // 将图片中心设置为鼠标所在区域 GetPiece( selectedIndex ).SetLocation( e.X - TILESIZE / 2, e.Y - TILESIZE / 2 ); pieceBox.Invalidate( region ); // 局部刷新棋子移动后的棋盘 } } // 将棋子放下时产生的事件 private void pieceBox_MouseUp( object sender, MouseEventArgs e ) { int remove = -1; // 如果棋子被选中 if ( selectedIndex > -1 ) { Point current = new Point( e.X, e.Y ); //调整棋子放下时的位置 Point newPoint = new Point( current.X - ( current.X % TILESIZE ), current.Y - ( current.Y % TILESIZE ) ); // 检查该位置是否具有其他棋子 remove = CheckBounds( current, selectedIndex ); // 将新棋子放在新位置上 GetPiece( selectedIndex ).SetLocation( newPoint.X, newPoint.Y ); selectedIndex = -1; // 将棋子索引还原为-1,为下一次移动做准备 //如果有棋子,将其移除并换上新棋子 if ( remove > -1 ) chessPieces.RemoveAt( remove ); } pieceBox.Invalidate(); // 刷新棋盘 } //获得棋子 private ChessPiece GetPiece( int i ) { return ( ChessPiece ) chessPieces[ i ]; } //点击New Game重新开始游戏 private void newGameItem_Click( object sender, System.EventArgs e ) { ResetBoard(); // 重新部署棋盘 Invalidate(); // 刷新主窗口 } }
如果有兴趣,你还可以为自己的象棋添加AI,让电脑自动下棋。 不过这就不属于这个例子的范围之类了。
总之,对于那些刚刚从控制台程序转向Windwos程序的同学来说,初次这个程序可能稍微
有些困难,不过只要你能硬着头皮看下去,认真对待每一行代码,相信对你的编程能力会有提高的。