项目需求:实现由纯Java完成的飞机大战小游戏
可以分为三大步:
一、首先进行类的构造,将游戏所涉及的类创建好,并构造好游戏界面。
二、在游戏界面中加入所有类,并渲染使其动起来,删除越界飞行物。
三、加入碰撞判断,统计分数和生命值判断,并加入游戏状态完善程序。
具体代码如下:
飞行物父类 FlyingObject:
public abstract class FlyingObject {
protected int x;
protected int y;
protected int width;
protected int height;
protected BufferedImage image;
英雄机类 Hero:
public class Hero extends FlyingObject{
private int LIFE;
private int DOUBLE_FIRE;
private BufferedImage[] images;
private int index;
public Hero() {
this.image = ShootGame.hero0;
this.width = image.getWidth();
this.height = image.getHeight();
this.x = 150;
this.y = 400;
this.LIFE = 3;
this.DOUBLE_FIRE = 0;
images = new BufferedImage[]{ShootGame.hero0,ShootGame.hero1};
index = 0;
}
敌机类 Airplane:
public class Airplane extends FlyingObject implements Enemy {
private int speed = 2;
public Airplane() {
this.image = ShootGame.airplane;
this.width = image.getWidth();
this.height = image.getHeight();
this.y = -this.height;
Random random = new Random();
this.x = random.nextInt(ShootGame.WIDTH - this.width);
}
蜜蜂类 Bee:
public class Bee extends FlyingObject implements Award {
private int xspeed = 1;
private int yspeed = 2;
private int awardType;
public Bee() {
this.image = ShootGame.bee;
this.width = image.getWidth();
this.height = image.getHeight();
this.y = -this.height;
Random random = new Random();
this.x = random.nextInt(ShootGame.WIDTH-this.width);
this.awardType = random.nextInt(2);
}
子弹类 Bullet:
public class Bullet extends FlyingObject{
private int speed = 3;
public Bullet(int x,int y) {
this.image = ShootGame.bullet;
this.width = image.getWidth();
this.height = image.getHeight();
this.x = x;
this.y = y;
}
敌人接口 Enemy:
public interface Enemy {
int getScore();
}
奖励接口 Award:
public interface Award {
int DOUBLE_FIRE = 0;
int LIFE = 1;
int getType();
}
主程序类 ShootGame:
public class ShootGame extends JPanel{
public static final int WIDTH = 400;
public static final int HEIGHT = 654;
public static BufferedImage background;
public static BufferedImage start;
public static BufferedImage pause;
public static BufferedImage bee;
public static BufferedImage airplane;
public static BufferedImage bullet;
public static BufferedImage gameover;
public static BufferedImage hero0;
public static BufferedImage hero1;
static {
try {
background = ImageIO.read(ShootGame.class.getResource("/img/background.png"));
start = ImageIO.read(ShootGame.class.getResource("/img/start.png"));
pause = ImageIO.read(ShootGame.class.getResource("/img/pause.png"));
gameover = ImageIO.read(ShootGame.class.getResource("/img/gameover.png"));
airplane = ImageIO.read(ShootGame.class.getResource("/img/airplane.png"));
bee = ImageIO.read(ShootGame.class.getResource("/img/bee.png"));
bullet = ImageIO.read(ShootGame.class.getResource("/img/bullet.png"));
hero0 = ImageIO.read(ShootGame.class.getResource("/img/hero0.png"));
hero1 = ImageIO.read(ShootGame.class.getResource("/img/hero1.png"));
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void paint(Graphics g) {
paintBackground(g);
paintHero(g);
paintFlyingObjects(g);
paintBullet(g);
}
public void paintBackground(Graphics g) {
g.drawImage(background, 0, 0, null);
}
public void paintHero(Graphics g) {
g.drawImage(hero.image, hero.x, hero.y, null);
}
public void paintFlyingObjects(Graphics g) {
for (FlyingObject obj:flyings) {
if (obj instanceof Airplane){
g.drawImage(obj.image, obj.x, obj.y, null);
}
if (obj instanceof Bee){
g.drawImage(obj.image, obj.x, obj.y, null);
}
}
}
public void paintBullet(Graphics g) {
for (Bullet bullet: bullets) {
g.drawImage(bullet.image, bullet.x, bullet.y, null);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("fly");
ShootGame game = new ShootGame();
frame.add(game);
frame.setSize(WIDTH,HEIGHT);
frame.setAlwaysOnTop(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private Hero hero = new Hero();
private FlyingObject[] flyings = {}; //装载敌机类和蜜蜂类
private Bullet[] bullets = {};
ShootGame类:
//生成一个敌人
public FlyingObject nextOne(){
Random random = new Random();
int one = random.nextInt(20);
if(one<2){
return new Bee();
}else {
return new Airplane();
}
}
生成子弹的方法:
public Bullet[] shoot(){
if (DOUBLE_FIRE>0){
Bullet[] bs = new Bullet[2];
bs[0] = new Bullet(this.x+this.width/4, this.y-20);
bs[1] = new Bullet(this.x+this.width/4*3, this.y-20);
DOUBLE_FIRE-=2;
return bs;
}else {
Bullet[] bs = new Bullet[1];
bs[0] = new Bullet(this.x+this.width/2, this.y-20);
return bs;
}
}
定时器代码如下:
Timer timer = new Timer();
int intervel = 10;
timer.schedule(new TimerTask() {
@Override
public void run() {
//此处为定时器需要执行的内容
repaint(); //此方法确保每次改变后重新绘制游戏界面
}
}, intervel, intervel);
Hero类中的产生子弹方法:
public Bullet[] shoot(){
if (DOUBLE_FIRE>0){
Bullet[] bs = new Bullet[2];
bs[0] = new Bullet(this.x+this.width/4, this.y-20);
bs[1] = new Bullet(this.x+this.width/4*3, this.y-20);
DOUBLE_FIRE-=2;
return bs;
}else {
Bullet[] bs = new Bullet[1];
bs[0] = new Bullet(this.x+this.width/2, this.y-20);
return bs;
}
}
敌人入场具体代码:
int enemyIndex = 0;
//敌人入场
public void enterAction() {
enemyIndex++;
if (enemyIndex%20 == 0){ //控制产生敌人频率 200毫秒一次
FlyingObject one = nextOne();
flyings = Arrays.copyOf(flyings, flyings.length+1);
flyings[flyings.length-1] = one;
}
}
子弹入场具体代码:
public void shootAction() {
if (enemyIndex%20==0){
Bullet[] bs = hero.shoot();
this.bullets = Arrays.copyOf(this.bullets, this.bullets.length+bs.length);
System.arraycopy(bs, 0, this.bullets, this.bullets.length-bs.length, bs.length);
enemyIndex=0;
}
}
Airplane类的实现:
@Override
public void step() {
this.y += speed;
}
Bee类的实现:
@Override
public void step() {
this.y+=yspeed;
if (x>ShootGame.WIDTH-this.width){
this.x-=xspeed;
}
if (x<0){
this.x+=xspeed;
}
}
Bullet类的实现:
@Override
public void step() {
this.y-=speed;
}
Hero类的实现:
@Override
public void step() {
image = images[index++/10%images.length];
/**
* index++
* int a = index/10
* int b = a%2
* image = images[b]
*/
}
stepAction()方法:
//飞行物移动
public void stepAction(){
hero.step();
for (FlyingObject flyingObject:flyings) {
flyingObject.step();
}
for (Bullet bullet: bullets) {
bullet.step();
}
}
蜜蜂类和敌机类的代码相同:
@Override
public boolean outOfBounds() {
return this.y > ShootGame.HEIGHT;
}
子弹类:
@Override
public boolean outOfBounds() {
return this.y < 0;
}
//越界删除
public void outOfBoundsAction() {
int index = 0;
FlyingObject[] flys = new FlyingObject[flyings.length];
for (int i = 0; i < flyings.length; i++) {
if (!flyings[i].outOfBounds()) {
flys[index] = flyings[i];
index++;
}
}
flyings = Arrays.copyOf(flys, index);
index = 0;
Bullet[] bs = new Bullet[bullets.length];
for (Bullet bullet: bullets) {
if (!bullet.outOfBounds()){
bs[index] = bullet;
index++;
}
}
bullets = Arrays.copyOf(bs, index);
}
代码如下:
MouseAdapter l = new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
hero.x = e.getX()-hero.width/2;
hero.y = e.getY()-hero.height/2;
}
};
this.addMouseListener(l);
this.addMouseMotionListener(l);
至此,第二大部分就已完成,目前我们的程序能运行起来,也能看到子弹、敌机、蜜蜂、英雄机动态飞行,但是还不能击毁敌机以及还有游戏状态英雄机属性显示,这些将是我们最后一部分要完成的内容。
具体代码如下:
碰撞判定:
public boolean isCrash(Bullet b){
int x1 = this.x;
int y1 = this.y;
int x2 = this.x + this.width;
int y2 = this.y + this.height;
return b.x<x2 && b.x>x1 && b.y>y1 && b.y<y2;
}
ShootGame类中的碰撞方法:
int score = 0;
public void bang(Bullet b,int bindex) {
int index = -1;
for (int i = 0; i < flyings.length; i++) {
if (flyings[i].isCrash(b)) {
index = i; //记录碰撞的下标
break;
}
}
if (index!=-1) {
FlyingObject one = flyings[index];
if (one instanceof Enemy) {
Enemy enemy = (Enemy) one;
score+=enemy.getScore();
}
if(one instanceof Award){
Award award = (Award) one;
int type = award.getType();
switch (type){
case Award.LIFE:
hero.setLIFE(hero.getLIFE()+1);
break;
case Award.DOUBLE_FIRE:
hero.setDOUBLE_FIRE(hero.getDOUBLE_FIRE()+50);
break;
}
}
flyings[index] = flyings[flyings.length-1];
flyings[flyings.length-1] = one;
flyings = Arrays.copyOf(flyings, flyings.length-1);
Bullet last_bullet = bullets[bindex];
bullets[bindex] = bullets[bullets.length-1];
bullets[bullets.length-1] = last_bullet;
bullets = Arrays.copyOf(bullets,bullets.length-1);
}
定义状态常量:
private static final int START = 0;
private static final int RUNNING = 1;
private static final int PAUSE = 2;
private static final int GAMEOVER = 3;
private int state = START;
监听器中的代码:
@Override
public void mouseClicked(MouseEvent e) {
switch (state){
case START:
state = RUNNING;
break;
case GAMEOVER:
flyings = new FlyingObject[0];
bullets = new Bullet[0];
score = 0;
hero = new Hero();
state = START;
break;
}
}
@Override
public void mouseEntered(MouseEvent e) {
if (state == PAUSE) {
state = RUNNING;
}
}
@Override
public void mouseExited(MouseEvent e) {
if (state == RUNNING) {
state = PAUSE;
}
}
public void paintLifeAndScore(Graphics g){
g.setColor(new Color(0xFF0000));
g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 20));
g.drawString("LIFE:"+hero.getLIFE(), 10, 65);
g.drawString("SCORE:"+score, 10, 45);
g.drawString("DOUBLE_FIRE:"+hero.getDOUBLE_FIRE(), 10, 25);
}
public void paintState(Graphics g){
switch (state) {
case START:
g.drawImage(start, 0, 0, null);
break;
case PAUSE:
g.drawImage(pause, 0, 0, null);
break;
case GAMEOVER:
g.drawImage(gameover, 0, 0, null);
break;
}
}
Hero类中的碰撞判定方法
public boolean isCrash(FlyingObject obj){
int x1 = this.x + this.width/2;
int y1 = this.y + this.height/2;
int x2 = obj.x + obj.width/2;
int y2 = obj.y + obj.height/2;
int maxWidth = this.width/2 + obj.width/2;
int maxHeight = this.height/2 + obj.height/2;
return Math.abs(x1-x2)<maxWidth && Math.abs(y1-y2)<maxHeight;
}
public void checkGameOver() {
if(isGameOver()){
state = GAMEOVER;
}
}
public boolean isGameOver() {
for (int i = 0; i < flyings.length; i++) {
if (hero.isCrash(flyings[i])) {
hero.setLIFE(hero.getLIFE()-1);
hero.setDOUBLE_FIRE(0);
FlyingObject one = flyings[i];
flyings[i] = flyings[flyings.length-1];
flyings[flyings.length-1] = one;
flyings = Arrays.copyOf(flyings, flyings.length-1);
}
}
return hero.getLIFE()<=0;
}