java实战---五子棋

        学习java也有两个月了,一些简单是swing组件和事件监听机制也懂了,现在开始了我的第一个实战小程序---五子棋,说起五子棋,大家都知道,只要五个相同颜色的棋子在同一条直线或者斜线上面,就算赢,有两种颜色的棋子,黑白,标准的五子棋棋盘是15×15的,要在一个panel上利用重绘,把棋盘画好,然后加鼠标监听器,填充两种颜色的圆,每次填充的圆颜色要不一样,而且要填充到交点上,之后还要做几个按钮,例如开始按钮,点击以后开始游戏,此时添加监听器,开始游戏,还有悔棋,认输按钮,功能我就不一一赘述了。

        先写一个类继承JFrame,设置它的各种属性,顺便加了一个panel,我把它放在东边,留着加按钮的时候用,代码如下:

public class GoBong extends JFrame {
	
	
	public static void main(String[] args) throws 
	ClassNotFoundException, InstantiationException, IllegalAccessException,
	UnsupportedLookAndFeelException {
		
		//设置LookAndFeel
		UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
		GoBong gb = new GoBong();
		gb.setUI();
		
	}
	public void setUI(){
		//设置标题
		this.setTitle("五子棋");
		//设置大小
		this.setSize(new Dimension(700,600));
		//设置居中
		this.setLocationRelativeTo(null);
		//设置不可调大小
		this.setResizable(false);
		//设置背景色
		//this.getContentPane().setBackground(Color.BLUE);
		//设置关闭操作
		this.setDefaultCloseOperation(3);
		//东边面板
		setEast();
		//设置背景图片
		SetBackground();
		//设置背景透明
		ct.setOpaque(false);;
		//设置可见
		this.setVisible(true);
	}

           可能有些人会有些疑惑,因为我上面在主函数调用的时候写了一大堆异常,其实我只是想把界面作的好看,总是用java默认的swing界面,难免会觉得难看,至于上面两行代码的解释,我是从一个CSDN的博客上看到的,简单易懂,向大家推荐一下,博客地址:http://blog.csdn.net/sunyiz/article/details/7595371 ,这里面对swing界面讲解讲的很简单,很容易懂,建议大家看一下。

         接下来,我们来看一下最简单的东边panel,这个panel是留着专门添加按钮用的,先暂时只加些按钮,下一步优化正在继续,我的程序中加了三个按钮:开始游戏、悔棋、认输。这三个按钮我没有用图片,而是直接用文字代替了,这样做的好吃就是不用繁琐的设置每个按钮的“名字”(暂且这么说),而坏处就是不美观,这个panel的代码我就不拿出来了。

        写完东边的按钮panel后,就该画棋盘了,这个棋盘设置在中间面板上,用一个木纹的图片作为背景图片,然后取画布画棋盘,这个panel我新建了一个类,因为这里的代码很多,很复杂,还有重绘要写,所以用一个类继承Jpanel,直接写在重绘的方法里,因为棋盘线是固定不动的,不管怎么样,每次程序出现时都要画出来,另外在画棋子的时候,要立体感更强烈一些的话,就要对棋子用不同的颜色反复的画,来达到立体棋子的目的,而在做立体棋子的时候我发现一个问题,就是圆形棋子边缘会有锯齿,显得不美观,这里又要用到Graphics2D里面的setRenderingHint方法,小伙伴们可以用API文档查一下,至于这个方法的参数,API文档里面有说明,我把代码个小伙伴们看一下

public class SetCenter extends JPanel implements ChessIml{
	
	//重绘方法
	public void paint(Graphics g){
		//设置父类重绘方法
		super.paint(g);
		//设置画棋盘线
		Graphics2D g2 = (Graphics2D) g; 
		//消除锯齿关闭,否则棋盘线太淡
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_OFF);
		for(int i = 0;i<15;i++){
			//线条粗细
			g2.setStroke(new BasicStroke(2));
			g2.drawLine(19+i*Size, 19, 19+i*Size, 19+14*Size);
			g2.drawLine(19, 19+i*Size, 19+14*Size, 19+i*Size);
		}
}
 

 

 这个是画棋盘的时候所用到的,我在重绘棋子的时候试了一下打开消除锯齿,显得棋盘线会很淡,所以我在绘制棋盘的时候就把消除锯齿关掉了,上面的Size我并没有在这个类里面声明,其实它是在ChessIml这个接口里面,因为棋盘大小Size还有count和row是经常用到的,这个借口里面还有一个二维数组用来存储棋子的位置,还有一个数组队列,这个数组队列是用来做悔棋的时候用的,类型是一个ChessPiece类,这个类里面包含了两个数据成员,r,c,正好用在数组队列中,悔棋的时候根据数组队列来重绘棋盘,做悔棋的时候,这个数组队列是用来辅助二维数组画棋盘用的,为什么不直接用数组队列来画棋盘,主要是有一个黑棋白棋的问题,如果我们用数组队列,就又要用一个标志来存储黑白棋,比较麻烦,这几部分的代码如下

public interface ChessIml {
	//设置棋盘属性
	int Row =15;
	int Count = 15;
	int Size = 38;
	//创建存储棋子的数组
	int [][] SavePiece = new int [15][15];
	//创建数组队列
	ArrayList<ChessPiece> array = new ArrayList();
}
 

 

 

public class ChessPiece {
	
	private int r;
	
	private int c;
	
	public ChessPiece(int row,int count){
		this.c = count;
		this.r = row;
	}
	
	public int GetR(){
		return  r;
	}
	
	public int GetC(){
		return c;
	}
}

 

 监听器当然是少不了的,用一个类继承MouseAdapter,而我们只需要MouseAdapter其中的mousePressed就够了,要画棋子,首先要有画布,画布要从中间面板里面取到,刚开始我写了一个监听器类构造方法,想直接把中间面板在构造的时候传进来,但是后来运行 的时候抛出了一个栈内存溢出异常 ,应该是重复的调用问题,后来在构造方法直接把主GoBong类传进来,然后中间面板自然就能进来了,而且声明主类的时候不能new,那样也会抛出栈异常,这是要特别注意的。要画黑白棋,肯定要有一个标志,因为五子棋不可以连续下两个相同颜色的棋子,用一个boolean类型的flag来标志,每下一个棋子,标志位变换一次。然后比较难的就是画棋子这方面了,因为鼠标不可能每次都正好点在棋盘线的交差点上面,所以要计算每次鼠标的点击位置离哪个坐标最近,然后把位置记录下来存进数组和数组队列里面,最后画出棋子,画旗子的时候要画出立体棋子并不难,只是在fillOval这个方法里面要注意,这个方法画棋子是在鼠标点击的坐标点上以这个点为正方形画内接圆,所以循环画圆的时候要注意坐标的变化。

public class CPListener extends MouseAdapter implements ChessIml {
	//设置x,y坐标
	private int x,y;
	//下棋点坐标
	private int row,count;
	//传入GoBong用,先在此声明变量gb1
	GoBong gb1;
	private Graphics2D g1;
	//黑白棋哨兵
	Boolean flag=false;
	//构造方法,传入GoBong类对象,使得传入ct的画布
	public CPListener(GoBong gb1){
		this.gb1 = gb1;
		
	}
	
	public boolean getFlag(){
		return flag;
	}
	//鼠标按下方法
	public void mousePressed(MouseEvent e) {
		x = e.getX();
		y = e.getY();
		//将ct传入的画布转为
		g1 = (Graphics2D) gb1.ct.getGraphics();
		//消除边缘化锯齿
		g1.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
				RenderingHints.VALUE_ANTIALIAS_ON);
		//计算棋子下落点
		row=(x+(Size/2)-19)/Size;
		count=(y+(Size/2)-19)/Size;
		//System.out.print(x1+"    "+y1);
		//下黑棋
		if(flag){
			if(SavePiece[row][count]==0){
				for(int i = 0;i<10;i++){
				g1.setColor(new Color(0+i*10,0+i*10,0+i*10));
				g1.fillOval(row*Size+2*i, count*Size+2*i, 38-3*i, 38-3*i);
				//下黑棋记为1
				SavePiece[row][count]=1;
				flag = false;
				}
				
				ChessPiece cp = new ChessPiece(row,count);
				array.add(cp);
			}
		}
		//下白旗
		else{
			if(SavePiece[row][count]==0){
				for(int i = 0;i<10;i++){
				g1.setColor(new Color(205+i*5,205+i*5,205+i*5));
				g1.fillOval(row*Size+2*i, count*Size+2*i, 38-3*i, 38-3*i);
				//下白棋记为-1
				SavePiece[row][count]=-1;
				flag = true;
				}
				ChessPiece cp = new ChessPiece(row,count);
				array.add(cp);
			}
		}
	}
}

 

这一步做完了,就是最后的人人对战输赢的判断了,这个判断就是围绕最后下的那一颗棋子的四个方向来判断是否有五个棋子相连,这四个方向并不是前后左右,而是横、竖,还有两个斜着的方向,检查是否有5个棋子相连的时候是一条线一条线上的检查。

五子棋大致就是这些了,还有一部分代码没有粘贴出来,因为我是写完这个之后才写的文章,所以有点思路不是很清晰,需要小伙伴们自己想的多一些。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值