结对实践项目——“五子棋”小游戏
之前与小组同学合作过一起写代码,那时老师分工明确,写两部分代码,一人负责一部分,剩下一个人做测试代码,在老师详尽的分工下,我们顺利的完成了那次任务。
这次从无范围自主选题,到熟练运用GUI,实现了人人对战。
【功能分析】
(1)程序在设计初就定义黑棋先行,白棋随后。一个玩家通过w,a,s,d键控制落子位置,按Space落子,另一个玩家通过控制方向键up,down,left,right控制位置,按Enter落子,从第一个棋子开始开始相互顺 序落子。
(2)通过坐标索引算出最先在棋盘的横向、竖向、斜向形成连续的相同色五棋子的一方为胜利。
(3)初始界面洁净无子设为游戏固定界面。
(4)在游戏过程中单击重新开局按钮或下完时可选择重新开始。
(5)游戏结束,会出现赢家对话框提示。
(6)游戏实现了基本的人人对战。
【分工情况】
芦畅:GUI设计及代码规范
苏正生:棋子胜负判断
【代码链接】
队友苏正生的报告:http://www.cnblogs.com/suzhengsheng/p/4549516.html
源代码链接:http://git.shiyanlou.com/szs20135333/shiyanlou_cs212
【总体设计】
主要包括的类有四个:GameFrame、GamePanel、ChessMan、Player
1、 GamePanel类
GamePanel类是java版五子棋的主框架,程序的启动类。
其中包括游戏界面的创建、按钮的设置、相关的事件监听器设置、游戏的启动
2、GameFrame类
GameFrame类主要实现的是棋盘的绘制、创建数组存放棋子的坐标、设置只能在棋盘内可以落子、实现判断黑白棋的输赢、实现重新游戏。
3、ChessMan类
Point类主要就是实现棋子的功能
4、Player类
Player类主要实验玩家的功能
【过程分析】
这次实验,我主要负责
这次我主要负责的是GUI设计以及代码规范,我来大概说下GUI。
GUI编程规范总结:
1、首先就是建立菜单栏。在GUI控件使用时所有的控件都是层层嵌套的,就是控件依托,最终整合到面板上,进而再添加事件监听器,已响应事件的发生;
①首先要建立主框架:GamePanel Gpanel=new GamePanel();
②取得框架的内容窗格
③在制作复杂的用户界面时,常常需要使用多个JPanel将复杂的界面分解为先对建大的子界面,然后再对每个JPanel进行布局:
package WuZiGame; import java.awt.*; import javax.swing.*; import java.awt.event.*; class GameFrame extends JFrame { private static final int Width=570; private static final int Height=470; GameFrame(){ setTitle("五子棋游戏"); CenteredFrame(); setSize(Width,Height); GamePanel Gpanel=new GamePanel(); add(Gpanel); } void CenteredFrame(){ Toolkit kit=Toolkit.getDefaultToolkit(); Dimension screenSize=kit.getScreenSize(); int screenHeight=screenSize.height; int screenWidth=screenSize.width; int Xposition=(screenWidth-Width)/2; int Yposition=(screenHeight-Height)/2; setLocation(Xposition,Yposition); } }
⑤处理控件的依赖关系,及消息的定义,各种细节的设计
⑥控件的逐级加入
⑦将面板加入到框架的内容窗格中
package WuZiGame; import javax.swing.*; public class Game { public static void main(String[] args) { GameFrame GFrame=new GameFrame(); GFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); GFrame.setVisible(true); } }
package WuZiGame; import java.awt.*; import java.awt.event.*; import javax.swing.*; class GamePanel extends JPanel { private Point cursor=new Point(40,60); //棋盘坐标 private int[][] ChessState=new int[18][18];//棋盘状态 private int i=0;//横坐标 private int j=0;//纵坐标 private final static int testnum=5;//五子棋的规定棋子数 private Player Black=new Player(1,Color.BLACK,"黑方");//黑方棋子 private Player White=new Player(2,Color.WHITE,"白方");//白方棋子 private Player Cplayer=null;//当前用户的引用 private JTextField textBlack=new JTextField("",5);//黑方文本提示框对象和文本长度设置 private JTextField textWhite=new JTextField("",5);//白方文本提示框对象和文本长度设置 private String Nothing=""; private String textblack="请黑方下子";//黑方提示文本 private String textwhite="请白方下子";//白方提示文本 GamePanel(){ setLayout(null); Initialization(); setFocusable(true); JButton Rutton=new JButton("重新开局"); Rutton.setBounds(20,14,100,26); RestartListener restart=new RestartListener(); Rutton.addActionListener(restart); add(Rutton); textBlack.setHorizontalAlignment(JTextField.CENTER); textBlack.setBounds(150,14,110,26); textBlack.setEditable(false); add(textBlack); textWhite.setHorizontalAlignment(JTextField.CENTER); textWhite.setBounds(290,14,110,26); textWhite.setEditable(false); add(textWhite); JTextArea gInstruction=new JTextArea(); gInstruction.setSelectedTextColor(new Color(238,238,238)); String gSInstruction= "Play1(黑方) Key \nup--------W \ndown----S \nleft--------A \nright------D \n\n"+ "Play2(白方) Key \nup--------up \ndown----down \nleft--------left \nright------right \n\n"+ "Exit game: \nPress Esc"; gInstruction.setText(gSInstruction); gInstruction.setEditable(false); gInstruction.setBounds(440,60,100,340); add(gInstruction); ChessManPerformListener Perform=new ChessManPerformListener(); addKeyListener(Perform); } // 设置第一个JTextField输出"请黑方下棋",坐标为(40,60) void Initialization(){ for(int i=0,j;i<18;i++) for(j=0;j<18;j++){ ChessState[i][j]=0; } cursor.setLocation(40,60); Cplayer=Black; textBlack.setText(textblack); textWhite.setText(Nothing); } //画棋盘和初始化棋局状态 protected void paintComponent(Graphics g){ super.paintComponent(g); Graphics2D g2=(Graphics2D) g; for(int i=60;i<=400;i+=20){ g2.drawLine(40,i,380,i); } for(int j=40;j<=380;j+=20){ g2.drawLine(j,60,j,400); } g2.drawString("_",cursor.x-6,cursor.y); g2.drawString("_",cursor.x,cursor.y); for(i=0;i<18;i++) for(j=0;j<18;j++){ if(ChessState[i][j]!=0){ if(ChessState[i][j]==1){ g2.setPaint(Black.getplayerChessManColor()); } if(ChessState[i][j]==2){ g2.setPaint(White.getplayerChessManColor()); } g2.fillOval(j*20+40-10, i*20+60-10, ChessMan.getChessManSize(), ChessMan.getChessManSize()); } } } //判断棋盘的当前位置是否已有棋子 boolean isChessState(){ this.j=(cursor.x-40)/20; this.i=(cursor.y-60)/20; if(ChessState[this.i][this.j]!=0) return true; else return false; } //记录落子后棋盘的当前位置的状态 void RecordChessState(){ this.j=(cursor.x-40)/20; this.i=(cursor.y-60)/20; ChessState[this.i][this.j]=Cplayer.getCurrentIdentify(); } //判断当前玩家落子后是否赢了 void JudgeWin(){ for(int i=0;i<4;i++) if(JudgeWinLine(i)){ //提示当前玩家已经获得胜利 try{ String Ginformation="GameInformation"; String Message="恭喜玩家"+Cplayer.getsIdentify()+"获胜!"+"\n"+"继续游戏还是退出游戏?"; String[] options = {"继续","退出"}; int selection=JOptionPane.showOptionDialog(null,Message,Ginformation, JOptionPane.YES_NO_OPTION,JOptionPane.INFORMATION_MESSAGE ,null,options,options[0]);//throws HeadlessException if(selection==JOptionPane.OK_OPTION){ Initialization(); repaint(); return; } if(selection==JOptionPane.NO_OPTION){ System.exit(0);//退出程序 } }catch(HeadlessException e){ e.printStackTrace(); } } //如果当前方没有赢棋则双方轮换 ChangeCurrentPlayer(); } //在当前方向上是否有连续的五只棋子 boolean JudgeWinLine(int direction){ int i,j,di,dj,count; i=j=di=dj=count=0; switch(direction){ case 0: j=this.j-(testnum-1); i=this.i; dj=1; di=0; break; case 1: j=this.j; i=this.i-(testnum-1); dj=0; di=1; break; case 2: j=this.j-(testnum-1); i=this.i+(testnum-1); dj=1; di=-1; break; case 3: j=this.j-(testnum-1); i=this.i-(testnum-1); dj=1; di=1; break; } for(int k=0;k<testnum*2+1;k++){ if(j>=0&&j<18&&i>=0&&i<18){ if(ChessState[i][j]==Cplayer.getCurrentIdentify()){ count++; if(count>=testnum) return true; } else count=0; } j+=dj; i+=di; } return false; } //更换当前玩家 void ChangeCurrentPlayer(){ if(Cplayer==Black){ Cplayer=White; textBlack.setText(Nothing); textWhite.setText(textwhite); } else{ Cplayer=Black; textBlack.setText(textblack); textWhite.setText(Nothing); } } //重新开局监听器 private class RestartListener implements ActionListener{ public void actionPerformed(ActionEvent arg0) { Initialization(); repaint(); requestFocus(); } } //棋盘、棋局状态监听器 private class ChessManPerformListener implements KeyListener{ //玩家2的按键 public void keyPressed(KeyEvent event) { int keyCode=event.getKeyCode(); if(keyCode==KeyEvent.VK_ESCAPE) System.exit(0); if(Cplayer.getCurrentIdentify()==2){//判别当前玩家 if(keyCode==KeyEvent.VK_LEFT){ if(cursor.x>40) cursor.x-=20; } else if(keyCode==KeyEvent.VK_RIGHT){ if(cursor.x<380) cursor.x+=20; } else if(keyCode==KeyEvent.VK_UP){ if(cursor.y>60) cursor.y-=20; } else if(keyCode==KeyEvent.VK_DOWN){ if(cursor.y<400) cursor.y+=20; } else if(keyCode==KeyEvent.VK_ENTER){ if(!isChessState()){ Cplayer.PerformChessMan(); RecordChessState(); repaint(); JudgeWin();//判定当前落子后是否赢棋 } } repaint(); } } public void keyReleased(KeyEvent event) {} //玩家1的按键 public void keyTyped(KeyEvent event) { char keyChar=event.getKeyChar(); if(Cplayer.getCurrentIdentify()==1){//判别当前玩家 if(keyChar=='a'){ if(cursor.x>40)//对移动光标超界现象做判别 cursor.x-=20; } else if(keyChar=='d'){ if(cursor.x<380) cursor.x+=20; } else if(keyChar=='w'){ if(cursor.y>60) cursor.y-=20; } else if(keyChar=='s'){ if(cursor.y<400) cursor.y+=20; } else if(keyChar==' '){ if(!isChessState()){ //落子前先判断当前位置上是否已有棋子 Cplayer.PerformChessMan();//落子 RecordChessState();//记录当前落子后棋盘状态 repaint(); JudgeWin();//判定当前落子后是否赢棋 } } } repaint(); } } }
package WuZiGame; import java.awt.Color; class ChessMan { private static final int ChessManSize=20; private Color ChessManColor; ChessMan(Color c){ ChessManColor=c; } static int getChessManSize(){ return ChessManSize; } Color getChessManColor(){ return ChessManColor; } }
package WuZiGame; import java.awt.Color; class Player { private int identify; private ChessMan pChessMan; private String PlayerStringIdentify; Player(int identify,Color c,String sIdentify){ this.identify=identify; pChessMan=new ChessMan(c); this.PlayerStringIdentify=sIdentify; } int getCurrentIdentify(){ return identify; } String getsIdentify(){ return PlayerStringIdentify; } void PerformChessMan(){} Color getplayerChessManColor(){ return pChessMan.getChessManColor(); } }
【设计结果】
初始界面
下棋中
结束界面
【统计时间】
步骤 |
耗时 |
百分比 |
需求分析 |
1.5h |
13.6% |
设计 |
2h | 18.2% |
代码实现 |
3h | 27.3% |
测试 |
2h | 18.2% |
分析总结 |
2.5h | 22.7% |
【实验心得】
通过这次对Java的学习,让我渐渐体会到了Java的博大精深。以及怎么学习Java,怎么学习计算机语言,怎样对问题进行解决和运用Java GUI,查找的使用都用了更进一步的理解。而且这次两人团队工作,也让我体会到合作的重要意义,两个人的想法经过商讨,研究总会比一个人的好很多,两个人事先做好分工工作再汇总整合也大大提高了效率。刚开始学习Java时我并不是非常的理解,知道就如何做能实现相应的功能,并没有很深刻的去理解它为什么要这么做。这次实验使我明白,真正的用Java去做一个东西不理解它是不行的,而且这个游戏涉及到了Java 中许多的知识点,如Java图形用户界面设计、Java的异常处理机制、Java中的多线程程序设计、Java输入输出流,要应用这些东西更要求我去好好理解Java的这些规则。这次实验,我还是收获良多。虽然界面也不是很美观,有点功能间的连接做的也不是特别的好,但是我能认识到自己的不足,并且在跟队友的交流中也学到了一些的设计思路,也知道今后要加强哪些方面的知识。