子弹的效率问题
1.问题的引入
子弹飞到屏幕外或者击中敌人坦克,应该怎么处理?
子弹生成后放在容器中,子弹会不会将容器撑爆?
解决方案:使用对象池来解决:提前创建好若干个子弹对象,放到一个容器中。
需要的时候从对象池中拿一个出来使用,当子弹需要被销毁时,放到原来的对象池中。
类似于线程池。
2.创建子弹对象池
在util包中创建BulletPool类。
package util;
import game.Bullet;
import java.util.ArrayList;
import java.util.List;
/**
* 子弹对象池
*/
public class BulletPool {
public static final int DEFAULT_POOL_SIZE=200;
public static final int DEFAULT_POOL_MAX_SIZE=300;
//用于保存所有子弹的容器
private static List<Bullet> pool =new ArrayList<>();
//在类加载的时候创建200个子弹对象添加到容器中
static {
for(int i=0;i<DEFAULT_POOL_SIZE;i++)
pool.add(new Bullet());
}
/**
* 从对象池中获取一个子弹对象
* @return
*/
public static Bullet get()
{
Bullet bullet=null;
//判断对象池是否为空
if(pool.size()==0){
//生成子弹对象
bullet=new Bullet();
}
else {
//拿走第一个位置上的子弹对象
bullet= pool.remove(0);
}
return bullet;
}
//归还子弹
public static void theReturn(Bullet bullet){
if(pool.size()==DEFAULT_POOL_MAX_SIZE)
return;
pool.add(bullet);
}
}
3.修改子弹生成方法
由于子弹对象池中保存不仅仅我方的坦克,还有敌人的坦克。所以原先子弹类中有参构造方法,改为默认构造方法,不确定属性。
在tank类中修改方法。
/**
*坦克发射子弹方法
*/
public void fire()
{
int bulletX=x;
int bulletY=y;
switch (dir){
case DIR_UP:
bulletY-=2*RADIUS;
break;
case DIR_DOWN:
bulletY+=2*RADIUS;
break;
case DIR_LEFT:
bulletX-=2*RADIUS;
break;
case DIR_RIGHT:
bulletX+=2*RADIUS;
break;
}
Bullet bullet = BulletPool.get();
bullet.setX(bulletX);
bullet.setY(bulletY);
bullet.setAtk(atk);
bullet.setDir(dir);
bullet.setColor(color);
//Bullet bullet=new Bullet(bulletX,bulletY,dir,atk,color);
bullets.add(bullet);
}
4.子弹归还对象池的方法
处理飞出屏幕的子弹。在子弹类新建一个变量visible。如果子弹飞出屏幕,visible为false。
private void move()
{
switch (dir){
case Tank.DIR_UP:
y-=speed;
if(y<=0)
visible=false;
break;
case Tank.DIR_DOWN:
y+=speed;
if(y>=Constant.FRAME_HEIGHT)
visible=false;
break;
case Tank.DIR_LEFT:
x-=speed;
if(x<=0)
visible=false;
break;
case Tank.DIR_RIGHT:
x+=speed;
if(y>=Constant.FRAME_WIDTH)
visible=false;
break;
}
}
如果子弹的visible为false。那么就不画这个子弹。
public void draw(Graphics g)
{
if(visible==false)return;
logic();
g.setColor(color);
g.fillOval(x-RADIUS,y-RADIUS,RADIUS<<1,RADIUS<<1);
}
归还子弹。
/**
* 绘制子弹
*/
private void drawBullet(Graphics g){
for(Bullet bullet:bullets)
bullet.draw(g);
//判断是否归还子弹
for (int i = 0; i <bullets.size(); i++) {
Bullet bullet=bullets.get(i);
if(!bullet.isVisible())
{
BulletPool.theReturn(bullets.remove(i));
}
}
}