---恢复内容开始---
线程之小球的运动
线程这个知识点我写了将近三天,而且现在还在完善阶段,写线程也暴露了我写程序时的很多缺点,下面就来看看写线程时烦的那些傻吧!
一:当我是用一个线程控制一个球的时候:(即点击一下按钮就启动一个线程)
基本思路是:
1.第一步:设置好窗体,给按钮加上监听器;
2.创建一个类实现按钮的监听;
3.创建一个线程类,实现Run()方法。
第一个越不过的坎:画小球时小球会闪动:
原因:我画小球的步骤是:改变小球颜色,改变坐标,画小球,暂停,擦除;但是线程一启动它的速度是很快的,所以先要暂停,然后擦除,改颜色和坐标,最后画小球。
//暂停 try { Thread.sleep(60);// 休眠0.01秒 } catch (InterruptedException e) { e.printStackTrace(); }//方法一:暂停时的循环休眠 // System.out.println();//空循环方法二 if (stateFlag) {// 若stateFlag为true,执行continue,进行空循环或者是循环休眠的状态,不执行下面的语句;否则,执行下面的语句 continue; } //擦除 g.drawImage(img, 0, 70, 700, 700, null); //改变坐标 x += movex; y += movey; //改颜色 g.setColor(new Color(a, b, c)); //画小球 g.fillOval(x, y, size, size);
第二个越不过的坎:小球的创建,暂停,启动,删除;
/* * 先前把小球的创建,启动和暂停想的太复杂了,其实可以把问题简单化: * 创建的时候就启动线程,暂停的话就是持续休眠,启动就是让已经创建的小球继续移动,删除就是清空画图板 * */ @Override public void actionPerformed(ActionEvent e) { String str = e.getActionCommand(); System.out.println("al" +" "+ al); if (str.equals("创建")) { System.out.println("=======================" + str); //实例化一个线程类 BallThread ball = new BallThread(rand.nextInt(700), rand.nextInt(600)+100, 40, 10, 10, bf, al); ball.start();//启动线程 al.add(ball); } else if (str.equals("启动")) { for (int i = 0; i < al.size(); i++) { BallThread ball = al.get(i);//获得已经创建的小球 ball.stateFlag = false;//让已经创建的小球继续移动 } } else if (str.equals("暂停")) { for (int i = 0; i < al.size(); i++) { BallThread ball = al.get(i); ball.stateFlag = true;//让已经创建的小球进入无限休眠的循环状态 } } else if (str.equals("删除")) { for (int i = 0; i < al.size(); i++) { ball = al.get(i); ball.flag = true; ball.stateFlag=false; ball.drawwhiterecrt(); } } }
第三个越不过的坎:小球运动的处理方法;
难点是:当两个小球碰撞时是要互相弹开时,其实是两个小球移动的方向是往回退的,机两个小球的移动方向互换
// 碰撞处理,比较圆心之间距离,遍历数组队列,找出当前球与其他球的圆心距离 for (int i = 0; i < al.size(); i++) { ball = al.get(i);//获得其他的球 if (this == ball) {//如果找出的球是和自己一样的,就继续找球,否则就继续下面的程序 continue; } int xx = Math.abs(this.x - ball.x); int yy = Math.abs(this.y - ball.y); int xy = (int) Math.sqrt(xx * xx + yy * yy);//求两个球的圆心距 int tempx = 0; int tempy = 0; //如果两个球碰撞了,两个球交换坐标(移动的方向); if (xy <= (this.size / 2 + ball.size / 2 )) { tempx = this.movex; tempy = this.movey; this.movex = ball.movex; this.movey = ball.movey; ball.movex = tempx; ball.movey = tempy; } }
第四个越不过去的坎:不要让小球把按钮擦掉了;
用随机数控制小球移动的坐标就好了:
BallThread ball = new BallThread(rand.nextInt(700),
rand.nextInt(600)+100, 40, 10, 10, bf, al);
运行的结果:
二:用一个线程控制多个小球的运动:(方法更优)
思路:
1.首先画窗体;
2.创建一个小球类,把小球的属性和方法都写上去;
属性:坐标,颜色,速度,直径
方法:画小球,移动,碰撞
3.创建一个类实现监听和Runable()和actionListener();
要注意的问题是:小球队列的存储问题,要在点击一下“创建”的时候存小球
运行的结果:
用一个线程控制多个小球的好处:
1.解决加入背景图片时小球的闪动的问题(因为背景图片带替了擦除的功能,它不停地画就会出现不断地闪动);
2.节省内存,提高程序运行的速度(时间复杂度&&空间复杂度);
因为线程没有自己独立的内存空间(运行空间),所以每次启动一个线程都需要向进程申请运行空间,多个线程就需要更多的运行空间,从而在积累到一定数量的时候,会影响到CPU的运行速度。如图所示:
三 背景图片的移动
思路:把背景图片也当作一个小球,在画小球的方法中加入背景图片的移动方法。
// 画小球的方法:暂停,擦除,换坐标,画小球 public void drawOval() { background(img); //小球的移动 move(); // 改变坐标 x += movex; y += movey; // 改颜色 g.setColor(new Color(a, b, c)); // 画小球 g.fillOval(x, y, size, size); } //背景移动的方法 public void background(Image img){ y1+=1; if(y1==0){ y1=-100; } g.drawImage(img,0,y1,700,700,null); }
线程进一步的设想:
1.在小球上再添加一个线程,发射子弹;
2.小猪冒险的游戏;
---恢复内容结束---