Java程序设计实验报告2(弹球游戏).docx
Java 语言程序设计课程设计实习报告题目:班级: 学号: 姓名:同组人员:指导教师:张彬一、试验目的1、把握 Swing 图形用户界面编程以及大事处理等,把握 java 绘图技术。2、把握多线程编程的根本原理,能使用 Runnable、ExecutorService 等接口进展线程的创立、启动等工作。3、培育独立查找资料,并解决问题的力气。二、试验任务1、设计并编程实现弹球玩耍:用户能通过 GUI 组件指定生成小球的数量,每个小球将从随机的位置消灭, 并具有随机颜色,随机速度以及随机的运动方向,小球沿初始方向匀速运动,当遇到窗口边缘时,小球将依据受力原理转变运动方向可简化考虑,受力只转变小球的运动方向,小球仍依据初始速度匀速运动,且不考虑小球之间的碰撞。鼠标在界面中显示为方块状,玩家需按住鼠标来回移动以避开运动的小球及屏幕四周,假设鼠标遇到任一小球或者窗口四周,则玩耍完毕。程序需供给计时功能,并最终显示玩家能坚持多少秒。2、程序要求:(1) 具备相应界面,并通过大事编程,实现相应的 GUI 组件功能。(2) 使用多线程技术,在程序窗口区域绘制小球,并以线程把握小球的移动, 实现动画效果。(3) 实现鼠标与屏幕四周,以及与小球的碰撞检测。三、开发工具与平台1. 开发工具:Eclipse 默认是一个和 Jbuilder 类似的Java 开发工具,但它不仅仅只是 Java 开发工具,只要装上相应的插件,eclipse 也可作为其它语言的开发工具。如 C/C+插件(CDT)。2. 开发平台:JDK1.5四、设计思路1. 界面设计(1) 制作一个简洁的面板 JFrame,文件保存为 bollFrame.java 其中为一 public 的类 bollFrame,其构造方法为: bollFrame(int n)setTitle“(我的弹球小玩耍“);super;setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);Dimension dimension = Toolkit.getDefaultToolkit.getScreenSize;/得到电脑屏幕大小setSize(450,450);setLocation(dimension.width-game.getWidth)/2-250, (dimension.height-game.getHeight)/2-250);/设置面板显示基中;this.n = n;myBollPanel = new bollPanel(n);/构造一个画板; add(myBollPanel);/将画板放入 JFramecreateMenu;/创立菜单; setJMenuBar(bar);(2) 构造画板类,文件保存为 bollPanel.java其构造函数如下:bollPanel(int n)this.n = n;/ executorThread = Executors.newCachedThreadPool;/创立线程池; mouse = new mouseThread(mxNow,myNow,groupThread,this);/启动鼠标线程;this.setIsOver(false);/玩耍开头线程条件的推断; for(int i =0 ;i<n;+i)myBollThread =new bollThread(this); groupThread.add(myBollThread);/executorThread.execute(myBollThread);/小球线程参与线程池;addMouseListener(this); addMouseMotionListener(this);Paint方法如下构造:publicvoid paint(Graphics g)if(!this.getIsOver)/假设玩耍还没完毕;super.paint(g);/去除原先的图像g.setColor(Color.RED);g.setFont(new Font(“宋体“,Font.BOLD+Font.ITALIC,15); g.drawString(“你已坚持:“+getT+“S“, 15, 15);/计时器的显示;for(int i = 0;i<n;+i)/画出每个线程球int xNow =groupThread.get(i).getxNow; int yNow = groupThread.get(i).getyNow;g.setColor(groupThread.get(i).getColor); g.fillOval(xNow,yNow,30,30);if(xNow>(getWidth-23)|xNow<0)/遇到左右边界; groupThread.get(i).dx = -groupThread.get(i).dx;if(yNow>(getHeight-23)|yNow<0)/遇到上下边界; groupThread.get(i).dy = -groupThread.get(i).dy;groupThread.get(i).setxNow(xNow+groupThread.get(i).getdx);/设置下一个位置;groupThread.get(i).setyNow(yNow+groupThread.get(i).getdy);if(isMouse)g.drawImage(newImageIcon(“boll.gif“).getImage,mxNow,myNow, 40,40, this);/鼠标的图像;/end paint;总体界面如下:2. 规律设计(1).首先,我们考虑到多个小球的运动,实质上是多线程的使用,n 个小球我们就同时启动 n 个线程去把握每个小球的运动。因此我构造出一个类作为一个小球的线程,保存文件为 bollThread.java,顾名思义,小球线程类。相关构造方法如下:public bollThread(bollPanel my)this.myPanel = my;xStart = data.nextInt(200);/随机产生开头位置; yStart = data.nextInt(200);setxNow(xStart);/设置现在的位置; setyNow(yStart);setdx;/设置随机方向使用;留意:假设不设置为随机,则全部小球将一样一个方向运动;setdy;(2) 再次,小球的消灭需要有载体,这就是画板,前面界面设置中已提到过,通过让多个小球共享一个画板,以及通过线程把握小球的重绘,最终通过画板显示给用户。(3) 在第2点中提到的画板上我们需要实现鼠标的监听,以下给出几个重要的鼠标大事监听:public void mousePressed(MouseEvent e) /单击启动鼠标大事; if(e.getButton=MouseEvent.BUTTON1)copy.schedule(new task, 0,1000);/启动定时器; for(int i =0 ;i<n;+i)Thread my = new Thread(groupThread.get(i); my.start;/启动玩耍,启动小球线程;mxNow = e.getX; myNow = e.getY; isMouse = true; if(!mouse.isAlive)mouse.start;/启动鼠标线程;/end if(e.getButton=MouseEvent.BUTTON1);/留意按下鼠标开头玩耍;publicvoid mouseDragged(MouseEvent e) /玩耍过程中通过按住鼠标左键把握“眼睛”的移动来躲避小球;mxNow = e.getX;/ TODO Auto-generated method stub myNow = e.getY;if(mxNow>(this.getWidth-30)|mxNow<=0|myNow>(this.getHeight-30)|myNow<=0)/鼠标是否遇到边界;/ executorThread.shutdown; this.setIsOver(true); copy.cancel;JOptionPane.showMessageDialog(null, “你撞墙了,下次小心点。玩耍完毕“,“提示“ ,JOptionPane.OK_OPTION);this.removeMouseListener(this); this.removeMouseMotionListener(this);for(int i =0 ;i<n;+i)int xNow =groupThread.get(i).getxNow; int yNow = groupThread.get(i).getyNow;if(isPeng(xNow,yNow,mxNow,myNow)/ executorThread.shutdown; this.setIsOver(true); copy.cancel;JOptionPane.showMessageDialog(null,“if(你 撞 球了)“+“n“+“挑战失败,玩耍完毕.“,“提示“ ,JOptionPane.OK_OPTION);/System.exit(0); this.removeMouseListener(this); this.removeMouseMotionListener(this); /鼠标的上下左右边和 球碰撞的状况,(4) 假设玩耍开头后我们突然松开鼠标,让我们把握的小球或 “眼睛“停留在最终松开的点上,那么小球遇到它还会推断是否相撞吗?答案是可以的,我们可以通过编写一个鼠标线程类来实现,保存文件为 mouseThread.java;让此线程在我们按下鼠标开头玩耍时同时启动,在我们松开鼠标时启动推断相撞大事。相关的构造方法如下:mouseThread(int mxNow,int myNow,List<bollThread>group,bollPanel bollpane) this.mxNow = mxNow;/传入鼠标现在位置;this.myNow = myNow;this.groupThread = group;/传入小球线程组; this.bollpane = bollpane;/传入画板对象;3. 程序测试在程序测试中,先后测试出了,以下几个留意点:A.在推断小球与鼠标把握的小球“眼睛”相撞时,条件中用到两点之间的距离问题,觉察条件不能是两点距离刚好等于两相撞物体半径和,此条件太苛刻,可能引起推断的失误概率蛮高的呵呵,而应当是小于半径和。B.在小球碰撞或把握的小球”眼睛“遇到边界玩耍完毕时,已经停顿了线程,小球竟然还能动,而且是缓慢移动,但是推断是否碰撞及边界问题都能正常执行,与我所意料的完全相反,到现在也不知道是怎么回事,只能在 paint 里进展条件推断,只让 bollPanel 留下最终一次的个小球及“眼睛”位置。C.这是最终才调试出来的,也是这个玩耍中较难留意到的。就是一些 boolean 变量的设置:privateboolean isTime;/定时器是否启动;private boolean isGroupThread;/全部小球线程组是否启动; private boolean isMouseThread;/鼠标线程是否启动; private boolean isMouse;/鼠标大事是否启动;private boolean isOver;/玩耍是否完毕;刚开头时并没有留意到这些,假设我点击鼠标左键开头玩耍时,启动了小球线程,这时要设置变量 isGroupThread = true 标志小球线程组已启动,释放鼠标启动鼠标线程时,isMouseThread = true让鼠标线程来把握与小球相撞的推断,定时器也在这时响应启动 isTime =true 开头计时,假设不设置这些的话,将发生以下本质上的共同错误::等我释放鼠标后想再次把握小球,就必需在一次启动鼠标大事,这时将重启动一次计时器,重启动一次小球线程组,重启动鼠标线程;这样的结果是导致玩耍的结果不确定性,没遇到小球实际上已碰撞它就检测碰撞完毕玩耍。以及计时器的计时紊乱等。具体调试后的相关代码实现见附录.。五、试验总结通过这次的程序设计,我更加明白了学以致用的道理,对线程的应用使得我更好更快的把握了线程的本质,同时,在此次的程序设计中,经过不断地调试, 是我明白了一个程序或工程要做到“精巧”,是是需要花多大的精力和急躁,总之,学以致用,会将学到的学问应用到实际中才是学之根本。此次试验也更了解到了线程的学问,比方:一个线程stop 后,不能再用start 启动,而应当重实例化,在start。也就是说线程的状态转换过程建-就绪-运行-堵塞-死忙是不行逆的,这是个人理解,至少从本试验中可以得到验证。最终,感谢教师的指导和同学们对我的帮助。六、附录以下是调试后的相关算法实现:A:public boolean isPeng(int xNow,int yNow,int mxNow,int myNow)/ 利用两点之间的距离算法,推断是否撞球int x1 = xNow+15,y1 = yNow+15;int x2 = mxNow+20,y2 = myNow+20; int mulx = x1-x2,muly = y2 -y1;double sum = Math.pow(muly, 2)+Math.pow(mulx, 2); if(sum<Math.pow(35, 2)/留意是小于!return true; else return false;B:publicvoid paint(Graphics g)if(!this.getIsOver)/在此推断玩耍是否完毕;super.paint(g);/去除原先的图像g.setColor(Color.RED);g.setFont(new Font(“宋体“,Font.BOLD+Font.ITALIC,15); g.drawString(“你已坚持:“+getT+“S“, 15, 15);for(int i = 0;i<n;+i)/画出每个线程球int xNow =groupThread.get(i).getxNow; int yNow = groupThread.get(i).getyNow;g.setColor(groupThread.get(i).getColor); g.fillOval(xNow,yNow,30,30);if(xNow>(getWidth-23)|xNow<0)/遇到左右边界; groupThread.get(i).dx = -groupThread.get(i).dx;if(yNow>(getHeight-23)|yNow<0)/遇到上下边界; groupThread.get(i).dy = -groupThread.get(i).dy;groupThread.get(i).setxNow(xNow+groupThread.get(i).getdx); groupThread.get(i).setyNow(yNow+groupThread.get(i).getdy);if(isMouse)myNow, 40,40, this);/end paint;g.drawImage(newImageIcon(“boll.gif“).getImage,mxNow,C :(1) public void mousePressed(MouseEvent e) /单击启动鼠标大事; if(e.getButton=MouseEvent.BUTTON1)if(isMouseThread)/鼠标线程是否活着; mouse.stop;isMouseThread = false;if(!isTime)copy.schedule(new task, 0,1000);/启动定时器; isTime = true;if(!isGroupThread)for(int i =0 ;i<n;+i)Thread my = new Thread(groupThread.get(i); my.start;/启动玩耍,启动小球线程;isGroupThread = true;mxNow = e.getX; myNow = e.getY; isMouse = true;/end if(e.getButton=MouseEvent.BUTTON1);(2) public void mouseReleased(MouseEvent e) /mouse.setmxNow(e.getX);/ mouse.setmyNow(e.getY);/设置松开点的鼠标位置; mxNow = e.getX;myNow = e.getY; if(!isMouseThread)mouse = new mouseThread(mxNow,myNow,groupThread,this);/建鼠标线程;/启动鼠标线程;.mouse.start; isMouseThread = true;(3) publicvoid mouseDragged(MouseEvent e) mxNow = e.getX;/ TODO Auto-generated method stub myNow = e.getY;if(mxNow>(this.getWidth-30)|mxNow<=0|myNow>(this.getHeight-30)|myNow<=0)/鼠标是否遇到边界;/ executorThread.shutdown; this.setIsOver(true); copy.cancel;JOptionPane.showMessageDialog(null, “ 你撞墙了,下次留神点。玩耍完毕“,“提示“ ,JOptionPane.OK_OPTION);this.removeMouseListener(this); this.removeMouseMotionListener(this);for(int i =0 ;i<n;+i)int xNow =groupThread.get(i).getxNow; int yNow = groupThread.get(i).getyNow;if(isPeng(xNow,yNow,mxNow,myNow)/ executorThread.shutdown; this.setIsOver(true); copy.cancel;JOptionPane.showMessageDialog(null, “if( 你 撞 球了)“+“n“+“挑战失败,玩耍完毕.“,“提示“ ,JOptionPane.OK_OPTION);/System.exit(0); this.removeMouseListener(this); this.removeMouseMotionListener(this); /鼠标的上下左右边和 球碰撞的状况,