- 浏览: 163909 次
- 性别:
- 来自: 长沙
最新评论
-
baiqiuhanzb:
我试验了多次fitCenter跟centerInside没看出 ...
【android】scaleType属性与ImagView中图片的显示的关系 -
work_asdf:
不错,学习了
【android】scaleType属性与ImagView中图片的显示的关系 -
faithmy509:
非常不错,thx
【android】scaleType属性与ImagView中图片的显示的关系 -
284772894:
学习了,不错
【android】scaleType属性与ImagView中图片的显示的关系 -
doctorkkkk:
谢谢 受教了
【android】scaleType属性与ImagView中图片的显示的关系
专门学习java已经有一个月了,舍友说:“对女生来说,学技术是条不归路啊!”做画图板时不这么觉得,但做五子棋时就感受深刻了,不是因为难学,是因为坎坷,很容易放弃……尤其是在做P2C(人机对战)的时候,纠结于算法好久,单单是用最笨的权值法,我就在分类、赋值的时候,从不同的角度考虑了各种方法。之前写了一个版本,我称之为智商为负。后来,考虑了很久,这样的赋值方法很欠缺考虑,以后P2C完成时的总结时会,共享给大家见笑见笑。总之,P2C的算法,我还没有纠结出来,所以,先对P2P对战总结一下。
五子棋的开发,之前自己在做,基本实现了可以相互交换放棋子,和判断输赢。但代码结构十分的混乱,排错也比较困难,需要重头梳理一遍思路。龙哥后来给我们梳理了一下各个类之间的关系,令我茅塞顿开啊。原来,每一个项目的不能着急开始,都需要整体的规划。
混乱版的就不拿出来献丑了,就总结一下整理后的版本。
一、面板的制作。
用三块面板将窗体分为控制区、游戏区、菜单栏。
代码如下:
1、面板类
public void init(javax.swing.JFrame fccp) {
// 设置窗体相关信息
this.setTitle("Ailse五子棋");
this.setSize(750, 633);
this.setResizable(false);
this.setDefaultCloseOperation(3);
//creat layut-fl(flowlayout)
java.awt.BorderLayout fl=new java.awt.BorderLayout();
this.setLayout(fl);
// 创建并定义一个菜单栏
javax.swing.JMenuBar menubar= new FCChessmenubar();
this.add(menubar);
//creat a jpanel-playfield
FCChessplayfield playfield=new FCChessplayfield();
this.add(playfield);
//creat a jpanel-playcontrl
JPanel playcontrl=new FCChesscontrlfield(playfield,fccp);
this.add(playcontrl);
2、控制面板
public FCChesscontrlfield(FCChessplayfield playfield,JFrame fccp){ this.setSize( 150, 600);//(150,600); this.setBackground(Color.GRAY); this.setLayout(null); //creat some button to playcontrl javax.swing.JButton undo=new javax.swing.JButton("悔棋"); undo.setBounds(650, 200, 60, 25); this.add(undo); undo.setActionCommand("undo"); javax.swing.JButton giveup=new javax.swing.JButton("认输"); giveup.setBounds(650, 300, 60, 25); this.add(giveup); giveup.setActionCommand("giveup"); javax.swing.JButton rebegin=new javax.swing.JButton("重玩"); rebegin.setBounds(650, 400, 60, 25); this.add(rebegin); rebegin.setActionCommand("rebegin"); //创建一个鼠标监听器,监听控制面板 FCChesscontrlfieldListener rbml=new FCChesscontrlfieldListener(playfield,fccp,p); giveup.addMouseListener(rbml); undo.addMouseListener(rbml); rebegin.addMouseListener(rbml); } }
3、游戏面板
public class FCChessplayfield extends JPanel implements FCCconfig{ public FCChessplayfield(){ this.setBounds(0, 25, 600, 600); this.setBackground(Color.LIGHT_GRAY); this.setLayout(null);} // 屏幕重绘 public void paint(Graphics g) { super.paint(g); System.out.println("jpanel重绘了"); // 在屏幕重绘时重绘棋盘网格 drawchess(g); // 在屏幕重绘时,重绘棋子 redrawp(g); } // 绘制棋盘 public void drawchess(Graphics g) { System.out.println("网格重绘了"); g.setColor(Color.black); for (int i = 0; i < 11; i++) { g.drawLine(FCCconfig.x0, FCCconfig.gsize * (i + 1), FCCconfig.xe, FCCconfig.gsize * (i + 1)); } for (int j = 0; j < 11; j++) { g.drawLine(FCCconfig.gsize * (j + 1), FCCconfig.y0, FCCconfig.gsize * (j + 1), FCCconfig.ye); } } // 遍历二维数组,为棋盘所有点标记为0 public void remark() { System.out.println("标记恢复为0了"); for (int i = 0; i < FCCconfig.row; i++) { for (int j = 0; j < FCCconfig.rank; j++) { CCmark[i][j] = 0; } } } // 棋子的重绘 public void redrawp(Graphics g) { System.out.println("棋子重绘了!"); for (int i = 0; i < FCCconfig.row; i++) { for (int j = 0; j < FCCconfig.rank; j++) { System.out.print(CCmark[i][j] + "\t"); if (CCmark[i][j] != 0) { if (CCmark[i][j] == 1) { g.setColor(Color.BLACK); } else if (CCmark[i][j] == -1) { g.setColor(Color.BLUE); } g.fillOval((i + 1) * FCCconfig.gsize - FCCconfig.CCPsize / 2, (j + 1) * FCCconfig.gsize - FCCconfig.CCPsize / 2, 40, 40); } } System.out.println(); } } }
4、菜单面板
public FCChessmenubar(){ this.setBounds(0, 0, 750, 25); //为菜单栏加布局 java.awt.FlowLayout menubarfl=new java.awt.FlowLayout(0); this.setLayout(menubarfl); // add menu to menubar javax.swing.JMenu File = new javax.swing.JMenu("File"); File.setPreferredSize(new Dimension(100, 25)); this.add(File); // add menuitem to menu-File javax.swing.JMenuItem open = new javax.swing.JMenuItem("open"); open.setSize(100, 25); javax.swing.JMenuItem save = new javax.swing.JMenuItem("save"); save.setSize(100, 25); javax.swing.JMenuItem exit = new javax.swing.JMenuItem("exit"); exit.setSize(100, 25); File.add(open); File.add(save); File.add(exit); //System.out.println("FILE按钮添加了"); javax.swing.JMenu about = new javax.swing.JMenu("about"); about.setPreferredSize(new Dimension(100, 25)); this.add(about); //add menuitem to menu-about javax.swing.JMenuItem aboutgame = new javax.swing.JMenuItem("aboutgame"); aboutgame.setSize(100, 25); javax.swing.JMenuItem abouteditor= new javax.swing.JMenuItem("abouteditor"); abouteditor.setSize(100, 25); about.add(aboutgame); about.add(abouteditor); //创建动作监听器,监听按钮aboutgame ActionListener alis = new ActionListener(){ public void actionPerformed(ActionEvent e){ javax.swing.JFrame aboutgame=new javax.swing.JFrame("about game"); aboutgame.setSize(300, 300); aboutgame.setBackground(Color.blue); javax.swing.JLabel jlab1=new javax.swing.JLabel("made by Ailse"); jlab1.setBounds(25, 25, 200,200 ); aboutgame.add(jlab1); aboutgame.setVisible(true); } }; aboutgame.addActionListener(alis); } }
效果图:
二、监听
监听时相应的,分为三个部分,和三块面板对应。如上图示。
但是游戏面板的监听却放在了窗体类里了。
// 创建并鼠标监听器,通过鼠标监听棋盘面板 FCChessplayfieldListener pillms = new FCChessplayfieldListener(g, fccp,CCmark); playfield.addMouseListener(pillms);
这是因为,鼠标监听器需要画布,但画布的定义要在窗体可见后,而游戏面板却要在窗体定义时就要定义。所以只能放在窗体类中定义监听器。同样的问题出现在了窗体重绘时,这时调用了超父类的paint()方法-----super.paint();
1、控制面板监听
public void mousePressed(MouseEvent e) { JButton btn = (JButton)e.getSource(); String command=btn.getActionCommand(); if(command=="rebegin"){ cp.remark(); cp.repaint(); } if(command=="giveup"){ javax.swing.JOptionPane.showMessageDialog(jf2, "你太厉害了,甘拜下风啊!"); } if(command=="undo"){ javax.swing.JOptionPane.showMessageDialog(jf2, "呵呵呵!下错位置了,我要悔棋!"); int x=0, y=0; if(list.size()-1<1){ javax.swing.JOptionPane.showMessageDialog(jf2, "请按重玩按钮!!"); // System.out.println(x+","+y+","+CCmark[x][y]); //System.out.println("棋子数目:"+list.size()); // System.out.println("重新标记棋盘了"); }else{ p=list.get(list.size()-1); x=p.getx(); y=p.gety(); CCmark[x][y]=0; list.delect(list.size()-1); p=list.get(list.size()-1); x=p.getx(); y=p.gety(); CCmark[x][y]=0; list.delect(list.size()-1); } cp.repaint(); } }
对于重玩的实现,还是比较费力的。要想悔棋,就要让我们的计算机记得下棋的顺序和下的棋子的颜色。我用了一个棋子类将每放的一颗棋子的坐标和棋子颜色记录,然后用队列(大小可变数组)顺序存放这些棋子类的棋子对象。
public class pill { private int x; private int y; private int color; //标记 public pill(int x, int y, int color){ this.color=color; this.x=x; this.y=y; } public int getx(){ return x; } public int gety(){ return y; }
2、游戏面板监听
public void mouseReleased(MouseEvent e) { // 定义一个变量用于控制放置黑棋和白棋交替放置 // count为奇数时,黑棋下;count为偶数时,蓝棋下 x1 = e.getX(); y1 = e.getY(); // 通过count,判断黑棋行还是白棋行 if (count % 2 == 1) { g.setColor(Color.BLACK); t = 1; } else if (count % 2 == 0) { g.setColor(Color.blue); t = -1; } // 判断点击位置是否在棋盘上 if ((x1 > 50 && x1 < 550) && (y1 > 50 && y1 < 550)) { // 判断点击位置,并在离的最近的交叉点放置棋子 // FCCconfig.gsize:格宽;FCCconfig.CCPsize/2:棋半径;FCCconfig.gsize/2:格中间的位置 // x1,y1为鼠标按下处点的坐标 // x2,y2为离按下处最近的交叉点的坐标 if ((x1 % FCCconfig.gsize) < FCCconfig.gsize / 2) { x2 = x1 - (x1 % FCCconfig.gsize) - FCCconfig.CCPsize / 2; } else if ((x1 % FCCconfig.gsize) >= FCCconfig.gsize / 2) { x2 = x1 + (FCCconfig.gsize - (x1 % FCCconfig.gsize)) - FCCconfig.CCPsize / 2; } if ((y1 % FCCconfig.gsize) < FCCconfig.gsize / 2) { y2 = y1 - (y1 % FCCconfig.gsize) - FCCconfig.CCPsize / 2; } else if ((y1 % FCCconfig.gsize) >= FCCconfig.gsize / 2) { y2 = y1 + (FCCconfig.gsize - (y1 % FCCconfig.gsize)) - FCCconfig.CCPsize / 2; } i = x2 / FCCconfig.gsize; j = y2 / FCCconfig.gsize; if (CCmark[i][j] == 0) { // 绘制棋子 g.fillOval(x2, y2, FCCconfig.CCPsize, FCCconfig.CCPsize); count++; CCmark[i][j] = t; pill pill = new pill(i,j,t); list.add(pill);
棋子是通过在对应点画圆实现的。但是画圆时需要的参数是(x1,y1,height,wide),且x1,y1是圆外切矩形的左上顶点。而鼠标监听只能获得按下的点,且我们不是总能恰好按到那个点。于是我们就要得到棋盘上纵横线的交点。我选取了比较笨的方法,就是用小学数学加减乘除法,将点击时获取的点换算到我们需要的离其最近的交叉点。
3、菜单栏监听
操作较少,暂不赘述。
三、判断输赢
判断输赢放在了游戏面板监听器中。
// 判断是否获胜 successcheck check=new successcheck( i, j, CCmark); if (check.checkrow() >= 5 || check.checkrank() >=5 || check.checkl() >= 5 || check.checkr() >= 5) { if(CCmark[i][j]==1){ javax.swing.JOptionPane.showMessageDialog(jf, "黑方获胜了!!"); }else if(CCmark[i][j]==-1){ javax.swing.JOptionPane.showMessageDialog(jf, "蓝方获胜了!!"); }
而判断方法则单另写了一个类,方便超找排错。而且分为了横、竖、左斜和右斜四个方法。以方便调用。
/** * 用于检验行 * @return */ public int checkrow() { int pcount = 1;// 定义一个棋子个数计数器 for (int i = x + 1; i <= CCmark.length; i++) {// 向右 if (i < 11 && CCmark[i][y] == CCmark[x][y]) { pcount++; } else break; } for (int i = x - 1; i >= 0; i--) {// 向左 if (i < 11 && CCmark[i][y] == CCmark[x][y]) { pcount++; } else break; } return pcount; } /** * 用于检验列 */ public int checkrank() { int pcount = 1;// 定义一个棋子个数计数器 for (int i = y + 1; i <= CCmark.length; i++) {// 向下 if (i < 11 && CCmark[x][i] == CCmark[x][y]) { pcount++; } else break; } for (int i = y - 1; i >= 0; i--) {// 向上 if (i < 11 && CCmark[x][i] == CCmark[x][y]) { pcount++; } else break; } return pcount; } /** * 用于检验左斜线方向 */ public int checkl() { int pcount = 1;// 定义一个棋子个数计数器 for (int i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--) {// 向左上 if (CCmark[i][j] == CCmark[x][y]) { pcount++; } else { break; } } // System.out.println(pcount); for (int i = x + 1, j = y + 1; i < 11 && i < CCmark.length && j < 11 && j < CCmark.length; i++, j++) {// 向右下 if (CCmark[i][j] == CCmark[x][y]) { pcount++; } else { break; } } // System.out.println(pcount); return pcount; } /** * 用于检验右斜线方向 */ public int checkr() { int pcount = 1;// 定义一个棋子个数计数器 for (int i = x + 1, j = y - 1; i < 11 && i < CCmark.length && j >= 0; i++, j--) {// 向右上 if (CCmark[i][j] == CCmark[x][y]) { pcount++; } else { break; } } // System.out.println(pcount); for (int i = x - 1, j = y + 1; i >= 0 && j < 11 && j < CCmark.length; i--, j++) {// 向左下 if (CCmark[i][j] == CCmark[x][y]) { pcount++; } else { break; } } // System.out.println(pcount); return pcount; }
想要判断输赢,就要计算机可以记得棋盘上棋子的位置和颜色。所以,我选择了用二维数组存储这些信息,刚好下标可以存交叉点坐标,而数组的值也可以存棋子颜色,个人认为利用率比较高,比起用队列存,应该要方便些。
四、配置类。
经常玩游戏,知道可以设置许多的配置,原来,这就算配置类的图形化。这样在人性化和可移植性都比较好,所以也学来:
public interface FCCconfig { public final static int row = 11;// 棋盘的行 public final static int rank = 11;// 棋盘的列 public final static int CCPsize = 40;// 棋子直径 public final static int gsize = 50;// 格间距 public final static int x0 = 50;// 棋盘左边缘x坐标 public final static int y0 = 50;// 棋盘上边缘y坐标 public final static int ye = 550;// 棋盘下边缘y坐标 public final static int xe = 550;// 棋盘右边缘x坐标 // 定义一个二维数组用来标记下过棋的位置 public final static int[][] CCmark = new int[FCCconfig.row][FCCconfig.rank]; //定义一个队列用来记录棋子的情况 ListImp<pill> list=new ListImp<pill>();
定义为接口确实调用也方便,修改也方便。
我的收获:
1、果然,好的框架结构,会为后面的开发提供莫大的方便。
2、要充分理解各个类之间的结构,这样可以避免混乱和代码的重复。
3、学会利用接口,和很有实际意义的Config类。
4、数据结构这门课真是大有用处啊!好的结构不仅可以省下不少代码,还可以提高运行效率。
5、罗马不是一天建成的。浮躁是我的弊病,只有一步一步的走才能爬上山,不要期望自己可以瞬间漂移到山顶,这只会是神话。空想主义者并不会比实干家过的好多少!
发表评论
-
简单账号管理系统的实现(b/s、servlet、html、mysql)
2012-05-20 16:07 2802漫漫学习路,无处是尽头。“技术是学不完的,只能学会 ... -
由hash结构,看数据结构优化“宗法”
2012-03-14 23:10 2610俗话说:“万 ... -
【Exception】报错也光荣(待更新)
2012-03-12 20:18 1404从初学java至今,不可避免的会遇到各式各样的报错 ... -
TCP通信与UDP通信
2012-03-10 02:10 2630TCP是面向连接 ... -
在学习“通信”过程中的小感悟和理解
2012-01-14 02:55 1501在学习“通信”过程中的小感悟 连续学习“通信”了几天, ... -
画图板实现和优化总结
2011-10-22 16:40 2176画图板实现和优化总结 来蓝杰参加培训的第一个完 ...
相关推荐
标题提到的"五子棋对战"是利用P2P技术实现的一个典型应用,使得用户可以直接与其他用户进行游戏对战,无需通过中央服务器作为中介。这样的设计具有许多优点,包括减少服务器负载、提高系统鲁棒性以及节省带宽资源。 ...
【P2P五子棋游戏Java编写】是一个基于Java实现的简单P2P(Peer-to-Peer)网络应用,主要用于让玩家之间通过网络进行实时的五子棋对战。在这个项目中,每个参与者既是服务器也是客户端,即P2P网络中的每一个节点都能...
【P2P版五子棋源码】是一个基于P2P技术实现的在线五子棋游戏,使用Visual Studio 2005或2008作为开发环境。五子棋是一种双人对弈的策略棋类游戏,目标是在棋盘上连成五颗棋子以获得胜利。P2P(Peer-to-Peer)技术在...
【标题】"javaP2P五子棋沙滩版"是一个基于Java编程语言的五子棋游戏,特别设计用于课程设计项目。此版本被称为“沙滩版”,可能是因为其界面或主题设计融入了沙滩元素,旨在为玩家提供一种休闲的对弈体验。 【描述...
QQ五子棋是一款在线对战的游戏,而这款基于MFC的五子棋则强调“不需要服务器”,这意味着它采用了点对点(P2P)的通信方式,用户之间可以直接连接进行游戏,减少了对中央服务器的依赖。此外,“能自动搜索在线用户”...
斗地主游戏,基本功能都已经实现,支持单机没有开发网络对战,AI还比较简单, C#计算器 仿照Windows系统计算器制作,处理简单计算任务, C#扫雷 经典的扫雷游戏,可以自己定义,搭配数据库保存过关成绩 C#贪食...
【在线五子棋VC源代码】是一个以Visual C++(简称VC)为开发工具,采用P2P(Peer-to-Peer)技术实现的网络对战游戏项目。此项目旨在提供一个平台,让玩家能通过互联网实时对弈五子棋,享受竞技的乐趣。以下是关于这...
【Java点对点五子棋游戏】是一款基于Java编程语言开发的在线多人对战游戏,主要功能是允许两位玩家通过网络进行实时的五子棋对决。这个游戏是Java课程的一个期中作业项目,旨在让学生们实践网络编程和图形用户界面...
【标题】"一个简易的网络点对点的五子棋"揭示了这是一个基于网络的、双人对战的五子棋游戏项目。在点对点(P2P)架构下,意味着游戏是直接由两个玩家的设备之间进行通信,而非通过中央服务器。这通常涉及到网络编程...
在这些网络高级程序设计课设题目中,学生们将面临一系列挑战,涵盖网络通信、游戏开发、数据传输和网络协议应用等多个方面。以下是各个题目涉及的知识点的详细说明: 1. FTP 客户端: - FTP(File Transfer ...
3. 游戏集成:如文中提到的五子棋游戏,可以实现多人在线对战,所有游戏逻辑和状态更新都在P2P网络中完成。 【创新与挑战】 创新之处在于,无固定服务器的设计降低了运营成本,增强了系统的健壮性,因为没有单一...
首先,"manan19-jong"这个名字可能源于传统的韩国棋类游戏"Go-Moku"或"五子棋",暗示这是一个简单的策略游戏。源代码将揭示游戏的逻辑、用户界面以及可能的网络对战功能。 在iOS开发中,通常使用Swift作为主要编程...
用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...
Java目录监视器源程序 9个目标文件 内容索引:JAVA源码,综合应用,目录监视 用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。...
Java目录监视器源程序 9个目标文件 内容索引:JAVA源码,综合应用,目录监视 用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。...
用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历...
用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历...
用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历...