四、 其它源代码一览
本文为节省篇幅起见,只保留了最关键的几个类,而且删掉了许多界面处理代码,包括菜单,窗口定位,帮助文件等;删掉了判断落子是否合法的代码,譬如不能吃自家的子,不能超越走棋的规则等;删掉了生成加载棋谱文件,演示以前棋局的代码等。读者可以自行完善,有兴趣者也可与作者联系。
/* chessArray类 抽象类 用来在不同的线程间传递数据*/
import java.awt.*;import java.io.*;class chessArray{ …………此处加入代码一………….
public static int chArray[][]=new int[10][9]; public static Image imgBak[]=new Image[8]; public static Image img; public static Image imgRed;
public static Image imgBlue;
public static String information;
public static Dimension offsize;//屏幕尺寸
public static boolean repaint=false;//允许棋盘重画为true,否则为false
public static boolean repaintWarn=false;//允许警告重画为true,否则为false
public static boolean repaintStart=false;
public static boolean fileChange=false;
public static boolean repaintEnd=false;
public static boolean readyIn=false; //允许接受数据为true,否则为false
public static boolean readyOut=false;//允许发送数据为true,否则为false
public static boolean change=false;//允许走棋为true,否则为false
public static boolean netChange=false;//从网络接受数据后值为true,将接受//的数据进行处理后为false
public static int changeCount1=-1;//changeCount=XXYYYXX,此值标记走棋过程,
//走前的数据
public static int changeCount2=-1;//changeCount=XXYYY,此值标记走棋过程,
//走棋后的数据
//X表示横坐标,Y表示纵坐标
private chessArray()
{ };
public static void chA(int aBak[][])//获取开局数据
{
for(int i=0;i<10;i++)
for(int j=0;j<9;j++)
chArray[i][j]=aBak[i][j];
}
public static void information(String s1)
{
information=s1;
repaintWarn=true;
}
}
/* chessPcName类 用来获得输入庄家电脑名称*/import java.awt.*;import chessArray;import java .awt.event .* ;public class chessPcName extends Dialog implements ActionListener
{
TextField td=new TextField ("",30);
Label lb=new Label ("请输入庄家电脑名称:");
Button bt=new Button ("确定");
public chessPcName(Frame frbak)
{
super(frbak,"获取庄家名称",true);
setBackground(Color.cyan);
int width=200;
int height=200;
this.add("North",lb);
this.add("Center",td);
bt.addActionListener (this);
this.add("South",bt);
setFont(new Font("chequer",Font.BOLD,16));
setBounds(chessArray.offsize.width/2-width/2,chessArray.offsize.height/2-height/2,width,height);
show();
}
public void actionPerformed(ActionEvent e)
{
chessClient chCe= new chessClient (td.getText ());
chessArray.information("您是挑战者,不能先走棋");
chessArray.readyIn=true;//挑战者只能先接受数据
chessArray.change =false;//挑战者不允许先走棋
chCe.start ();
this.dispose ();
}
}
/* chessBoard 实现棋盘的绘制,布局,以及棋子的移动*/
import java.awt.*;import chessArray;public class chessBoard extends Panel implements Runnable
{
public int width,height;
Dimension thisSize;
Thread thread;
int waitCount;//纪录加载图像的程度
String chString[][]={
{"将","車","炮","馬","象","士","卒"}, //*将一 車二 炮三 馬四 相五 士六 兵七 卒八
{"帅","車","炮","馬","相","士","兵"}
};
String chCount[]={"一","二","三","四","五","六","七","八","九","十"};
Color chColor[]={Color.blue,Color.red}; //棋子的前景颜色
Color backColor=Color.black ; //棋子的背景颜色
chessMan chequer[]=new chessMan[32];
boolean chooseCh=false;//判断是选棋子还是选棋子欲走的地方
//false 表示尚未选定棋子,true 表示已选定棋子
boolean First=true;
public static boolean Bcount=true;//次变量用来标记一个棋子,从而避免每次都得重画所有棋子
public chessBoard()
{//根据框架的大小绘制棋盘
thread=new Thread(this);
thread.start ();
}
public void chB()
{
thisSize=getSize();
/*getSize()方法可以获取框架的尺寸,之所以将它放在paint() 方法中,是因为当框架
尺寸发生变化时,便自动调用paint()重画框架,这样程序便可以同时获取框架的尺寸
*/
width=thisSize.width;
height=thisSize.height;
LcornerX=width/11; LcornerY=height/12;
lengthX=(width-width/10-LcornerX)/8;
lengthY=(height-height/11-LcornerY)/9;
lengthMin=lengthX<lengthY?lengthX:lengthY;//取x,y方向宽度中的最小值做为棋子的直径
}
public void addMan()
{
chessArray.img=Toolkit.getDefaultToolkit().getImage ("棋盘图案\\"+"雨后初晴.jpg");
chessArray.imgRed=Toolkit.getDefaultToolkit().getImage ("棋子图案\\"+"red1.jpg");
chessArray.imgBlue=Toolkit.getDefaultToolkit().getImage ("棋子图案\\"+"blue1.jpg");
int num=0;
for(int i=0;i<10;i++)
for(int j=0;j<9;j++)
{
if(chessArray.chArray[i][j]!=0)
{
chequer[num]=new chessMan(this.getGraphics (),this);
chequer[num].Num=chessArray.chArray[i][j];
chequer[num].Count =num;
chequer[num].X =j;
chequer[num].Y =i;
num++;
}
}
}
public void drawCh()
{
if(!this.Bcount )
{
this.Bcount =true;
return;
}
int num=0;
for(int i=0;i<10;i++)
for(int j=0;j<9;j++)
{
int ch;
if(chessArray.chArray[i][j]!=0)
{
ch=chessArray.chArray[i][j];
chequer[num].Num=chessArray.chArray[i][j];
chequer[num].chM(LcornerX+lengthX*j-this.lengthMin/2,LcornerY+lengthY*i-this.lengthMin/2,lengthMin-1,
chString[ch/200][ch%100/10-1],chColor[ch/200],backColor);
chequer[num].setVisible (true);
chequer[num].paint ();
num++;
}
}
}
………..此处加入代码二 …………….
public synchronized void run()
{
while(true)
{
waitCount++;
if(waitCount==10)
{//检查图像是否以加载完
mt.checkID (0,true);
}
try{
thread.sleep(1);
}catch(InterruptedException e)
{ };
if(chessArray.netChange)
{
numyBak=9-chessArray.changeCount1/10;//进行网络转换,让玩家//始//终面对下方棋子
numxBak=8-chessArray.changeCount1%10;
numy=9-chessArray.changeCount2/10;
numx=8-chessArray.changeCount2%10;
walkCh(true);//走棋
chessArray.netChange=false;
chessArray.change=true;
chessArray.information("对家已走完,该您走了");
//网络改动已结束,
}
if(chessArray.repaint ){//重画棋盘
repaint ();
chessArray.repaint =false;
}
}
………此处加入代码四………..
}
/* chessFrame 用来生成主界面,包括菜单,加载棋盘类*/
import java.awt.*;
import chessArray;
import chessBoard;
public class chessFrame extends Frame implements Runnable
{
public int width,height;
Dimension thisSize;
TextField South=new TextField ("正在加载图象",30);
chessServer chSv=null;
chessPcName chP=null;
Thread thread=new Thread (this);
chessBoard chB=new chessBoard();//定义棋盘
public chessFrame()
{
setTitle("让我们一起来下棋");
chM.CreateMenu(chessArray.mb ,chessArray.menu1 );
chessArray.offsize=Toolkit.getDefaultToolkit().getScreenSize();
width=chessArray.offsize.width;
height=chessArray.offsize.height;
setBounds(width/2-320,height/2-240,640,480);
//将框架置于屏幕中间
chessArray.chA(chessArray.arrayBak);//将棋子的位置数据化
/*将面板加入到框架中,之所以没有将此语句放在
构造函数中,是因为那时还没有获得框架的尺寸
*/
South.setBackground (Color.white);
South.setForeground (Color.red );
South.setEditable (false);
add("South",South);
this.setVisible (true);
add("Center",chB);
chB.addMan();//添加棋子
}
public void chessMenu()
{ /*此处加入菜单,代码从略*/ } public void run()
{
while(true)
{
if(chessArray.repaintWarn )
{
this.South .setText (chessArray.information );
chessArray.repaintWarn =false;
}
try{
thread.sleep(1000*3);
}catch(InterruptedException e){ };
}
}
public boolean handleEvent(Event evt)
{
switch (evt.id)
{
case Event.WINDOW_DESTROY:
System.exit(0);
case Event.ACTION_EVENT:
if(evt.arg.equals("重下(New)"))
{
if(chSv!=null||chP!=null){
if(chessArray.readyIn)
{
chessArray.information("等待对家走棋,不能选择重下");
return false;
}else
{
chessArray.information("正在告诉对家,您已选择重下");
chessArray.changeCount1=-1;
chessArray.chA(chessArray.arrayBak);
chessArray.repaint=true;
chessArray.change =false;//此时不允许走棋
chessArray.readyOut =true;
chessArray.changeCount1 =254;//告诉对家已选择重下
}
return true;
}
}
if(evt.arg.equals("庄家"))
{
chSv= new chessServer (new Frame());
chSv.start ();
return true;
}
if(evt.arg.equals("挑战者"))
{
chP=new chessPcName (new Frame ());
return true;
}
default: return false;
}
}
public void start()
{ thread.start(); }
//main() 函数,代码从略
}
五、总结与启示
本文较为详细的介绍了网络象棋的原理,以此为启示,只需对图片及棋盘棋子数据做些须改动,便可轻松实现网络围棋跳棋国际象棋以及各种扑克游戏,甚至别的复杂游戏。
另外其中的无背景色显示图片技术不仅可用来做棋子,可以做不规则按钮。这正好弥补了Java的一个不足。
本文所有源代码均在JDK1.1版本,Windows98环境下调试通过。
|