import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.io.IOException;
import java.util.ArrayList;
import tankImage.ImageUtil;
/**
* 抽象的坦克类,定义了坦克的相关属性
* 该坦克类具有了坦克的运动,装载子弹,发射子弹,调整运动方向的功能
* @author dell
*
*/
public abstract class Tank implements RectangleInter {
private boolean alive = true;//坦克的生命,初始值为true
private int x, y;// 坦克的横坐标和纵坐标
private int WIDTH = 30, HEIGHT = 30;//坦克的宽度和高度
private int SPEED = 5;//坦克运行的速度
Direction dir = Direction.D;//坦克运行的方向,默认向下
private Image image;//坦克图片
// 坦克炮弹夹
private ArrayList danJia = new ArrayList();
public ArrayList getDanJia() {
return danJia;
}
public void setDanJia(ArrayList danJia) {
this.danJia = danJia;
}
public boolean isAlive() {
return alive;
}
public void setAlive(boolean alive) {
this.alive = alive;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getWIDTH() {
return image.getWidth(null);
}
public int getHEIGHT() {
return image.getHeight(null);
}
public int getSPEED() {
return SPEED;
}
public Image getImage() {
return image;
}
/**
* 根据坦克的运动方向设置图片
* @param image
*/
public void setImage(Image image) {
this.image = image;
}
public Tank(String imagePath, int x, int y) {
try {
this.image = ImageUtil.getImage(imagePath);//初始化图片
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 设置x y 坐标
this.x = x;
this.y = y;
}
/**
* 该抽象类只负责绘画坦克的炮筒
*/
@Override
public void draw(Graphics g) {
}
/**
* 获得包围图片的矩形
*
* @return Rectangle 矩形
*/
public Rectangle getImageRect() {
return new Rectangle(this.getX(), this.getY(), this.getImage()
.getWidth(null), this.getImage().getHeight(null));
}
@Override
public Rectangle getRect() {
return new Rectangle(x, y, WIDTH, HEIGHT);
}
/**
* 定义坦克的运动方法及解决出界问题
* 坦克之所以会运动,本质上是应为代表坦克位置的x,y坐标的位置发生了变化,或增或者减
* 当然在运动的过程中如果坦克越界(跑出战场)的话,当然不能让它们当逃兵,所以需要把调整
* 它们的方向
*/
public void move() {
switch (dir) {
case L:
x -= SPEED;
break;
case R:
x += SPEED;
break;
case U:
y -= SPEED;
break;
case D:
y += SPEED;
break;
case STOP:
break;
}
// 解决坦克出界问题
if (x < 0)
dir = Direction.R;// 如果靠近左边界,那么就往右运动
if (y < 30)
dir = Direction.D;// 如果靠近上边界,那么就往下运动
if (x + this.getWIDTH() > WarField.WIDTH)
dir = Direction.L;// 如果靠近右边界,向左运动
if (y + this.getHEIGHT() > WarField.HEIGHT)
dir = Direction.U;// 如果靠近下边界,向上运动
}
/**
* 之所以把它们设置成为抽象类,是因为敌方坦克和我方坦克的这三个方法实现方式不一样,所以这里没有
* 提供具体的实现
*/
//装载子弹
public abstract void loadMissiles();
// 设置坦克运动的方向
public abstract void locateDirection() throws IOException;
// 坦克发射炮弹
public abstract void fire(Graphics g);
}
********************************************************************************
package imageban;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import tankImage.EnemyImage;
/**
* 敌方坦克,具有自动发炮弹,自动随机运动的工能
*
* @author dell
*
*/
public class Enemy extends Tank implements RectangleInter {
Random random = new Random();//随机数对象
int changeDirectionFrequency = random.nextInt(12) + 5;
int loadMissileFrequency = random.nextInt(5);// 装载子弹的间隔频率
EnemyImage enemyImage = new EnemyImage("images/enemy",3);//敌方坦克的图片
/**
* 注意必须调用super(x,y),否则报错这是原因之一,另一个则是,如果不调用父类的构造器 的话,导致如果该
* 子类调用getRectange(),该方法里面的参数没有得到初始化而不能获得具体你想要的值
*
* 刚开始new 出一个敌方坦克的时候,就指定(命令)它要打的我方坦克myTank(哪一个坦克),
*
* @param x
* @param y
* @param myTank
* ,敌人要打的那个坦克,即为我的坦克
*/
public Enemy(String imagePath,int x,int y){
super(imagePath,x,y);
}
/**
* 在这里没有判断坦克是否死亡,就return,没有想MyTank里一样
* 因为在子弹打击敌方坦克的时候有这一句起到了类似的作用
* enemyBase.remove(i);//敌方坦克基地删除死亡的坦克,此时坦克不画出来了
*/
@Override
public void draw(Graphics g) {
Color c = g.getColor();
g.drawImage(this.getImage(), this.getX(), this.getY(), null);// //绘画坦克
g.setColor(c);
fire(g);//开炮
move();//移动
}
/**
* 敌方坦克的运动。运动时坦克自动调整方向
*/
public void move() {
super.move();
//设置坦克的方向
locateDirection();
loadMissiles();//在运动中随机装载子弹
}
/*
* 随机取得坦克的运动方向
*/
public void locateDirection() {
if (changeDirectionFrequency == 0) {
changeDirectionFrequency = random.nextInt(12) + 5;
int step = random.nextInt(4);
Direction[] d = Direction.values();
dir = d[step];
// 为了不让敌方坦克停止,如果dir = stop则重新赋值为dir= d[--step]也就是上一步的方向
if (dir == Direction.STOP)
dir = d[--step];
}
changeDirectionFrequency--;
this.setImage(dir);
}
public void setImage(Direction dir){
switch(dir){
case L:
this.setImage(enemyImage.getImage(1));
break;
case U:
this.setImage(enemyImage.getImage(3));
break;
case R:
this.setImage(enemyImage.getImage(2));
break;
case D:
this.setImage(enemyImage.getImage(0));
break;
}
}
/**
* 装载子弹,其功能是每个一段频率让它装入一次子弹,之所以在fireMissileJiange = random.nextInt(6)
* 后面加1,是应为如果是fireMissileJiange =
* random.nextInt(6)==0的情况下,在往下执行会发现fireMissileJiange --
* 永远不会有fireMissileJiange ==0的情况出现了,也就装载不了弹药了,此为细节应该注意
*/
public void loadMissiles() {
if (this.loadMissileFrequency == 0) {
loadMissileFrequency= random.nextInt(20) + 1;//随机设定装载子弹的频率
// 向弹夹里添加子弹
this.getDanJia().add(new Missile(this.getX() + this.getWIDTH() / 2
- Missile.WIDTH / 2, this.getY() + this.getHEIGHT() / 2
- Missile.HEIGHT / 2, dir));
}
this.loadMissileFrequency--;
}
/**
* 发射炮弹,也就是让子弹画出来,Graphics 类型的参数
*
* @param g
*/
public void fire(Graphics g) {
for (int i = 0; i < this.getDanJia().size(); i++) {
this.getDanJia().get(i).draw(g);//从弹夹中拿出子弹
this.getDanJia().get(i).hitMyTank( MyTank.getMyTank(),g);
// 如果子弹打中坦克死了,就冲弹夹中删除该子弹
if (!this.getDanJia().get(i).isAlive()) {
this.getDanJia().remove(i);
}
}
}
}
**************************************************************************************
package imageban;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.io.IOException;
import music.Music;
import tankImage.ImageUtil;
import tankImage.MyImage;
/**
* 我的坦克,除了拥有父类的属性之外又定义了坦克的生命值,为100 当每次中弹的时候,生命值减去20、当生命值为
WarField.WIDTH || y > WarField.HEIGHT) {
alive = false;
}
}
/**
*子弹打击敌方坦克,子
* @param enemyBase敌方坦克的坦克基地。
*/
public void hitEnemy(EnemysBase enemyBase,Graphics g) {
enemyBase = EnemysBase.getEnemyBase();//获取一个单态实例的敌方坦克坦克基地
for(int i=0;i
