1.启动页(World)思路:
(1)画窗口,继承JPanel类
(2)添加鼠标及记时器事件
英雄机坐标跟着鼠标移动,子弹跟据火力值有两种方式,坐标跟英雄机相关
在窗口上点击游戏可以实现开始暂停功能,有四种状态,开始,运行,暂停,游戏结束
游戏结束需要重新生成新的英雄机,背景,敌机,子弹
(3)画对象
敌人开始都是在窗口上面准备入场,英雄机在窗口上
活着跟死的显示图片不一样,图片全部显示完就需要被移除
(4)敌人入场,随机入场
设置随机数,根据随机数的条件返回小敌机,大敌机或者小蜜蜂
(5)飞行物移动
小敌机,大敌机向下飞,y坐标移动;小蜜蜂x,y坐标都会改变
(6)子弹入场
(7)删除越界飞行物以及已经死了需要被移除的
判断越界和需要被移除
(8)子弹打中敌机
敌机死了,子弹死了
打中小敌机,大敌机加分;打中小蜜蜂加命或者加火力值,用随机数判断
(9)英雄机碰撞敌机
敌机死了,英雄机减命并清空火力值
(10)判断游戏结束,英雄机生命值小于等于0就结束
package shoot;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public class World extends JPanel{
public static final int WIDTH = 400;
public static final int HEIGHT = 700;
private Hero hero = new Hero();
private Background background = new Background();
private List<FlyingObject> enemies = new ArrayList<FlyingObject>();
private List<Bullet> bullets = new ArrayList<Bullet>();
public static final int START=0;//启动状态
public static final int RUNNING=1;//游戏进行
public static final int PAUSE=2;//暂停
public static final int GAME_OVER=3;//结束
private int state=START;
private static BufferedImage start;
private static BufferedImage pause;
private static BufferedImage gameover;
static {
start=FlyingObject.LoadImage("start.png");
pause=FlyingObject.LoadImage("pause.png");
gameover=FlyingObject.LoadImage("gameover.png");
}
public FlyingObject nextOne() {
Random rand = new Random();
int num = rand.nextInt(20);
if(num<10) {
return new Airplane();
}else if(num<15) {
return new Bigplane();
}else {
return new Bee();
}
}
int index = 0;
public void enterAction() {
index++;
if(index%40==0) {
enemies.add(nextOne());
}
}
public void stepAction() {
background.step();
for(int i=0;i<enemies.size();i++) {
enemies.get(i).step();
}
for(int i=0;i<bullets.size();i++) {
bullets.get(i).step();
}
}
int shootIndex=0;
public void shootAction() {
shootIndex++;
if(shootIndex%30==0) {
bullets.addAll(hero.shoot());
}
}
public void outOfBoundsAction() {
for(int i=0;i<enemies.size();i++) {
FlyingObject f = enemies.get(i);
if(f.isRemove() || f.outOfBounds()) {
enemies.remove(i);
}
}
for(int i=0;i<bullets.size();i++) {
Bullet b = bullets.get(i);
if(b.isRemove() || b.outOfBounds()) {
bullets.remove(i);
}
}
}
int score = 0;
public void bulletHit() {
for(int i=0;i<bullets.size();i++) {
Bullet b = bullets.get(i);
for(int j=0;j<enemies.size();j++) {
FlyingObject f = enemies.get(j);
if(b.isLife() && f.isLife() && b.hit(f)) {
b.goDead();
f.goDead();
if(f instanceof Award) {
int type =((Award) f).getType();
switch(type) {
case Award.DOUBLE_FIRE:
hero.addDoubleFire();
break;
case Award.LIFE:
hero.addLife();
}
}
if(f instanceof Enemy) {
score +=((Enemy) f).getScore();
}
}
}
}
}
public void heroHit() {
for(int i=0;i<enemies.size();i++) {
FlyingObject f = enemies.get(i);
if(f.isLife() && hero.hit(f)) {
f.goDead();
hero.subLife();
hero.clearDoubleFire();
}
}
}
public void checkGameOverAction() {
if(hero.getLife()<=0) {
state=GAME_OVER;
}
}
public void paint(Graphics g) {
background.paint(g);
hero.paint(g);
for(int i=0;i<enemies.size();i++) {
enemies.get(i).paint(g);
}
for(int i=0;i<bullets.size();i++) {
bullets.get(i).paint(g);
}
g.drawString("SCORE:"+score,10,25);
g.drawString("LIFE:"+hero.getLife(),10,45);
switch(state) {
case START:
g.drawImage(start, 0, 0,null);
break;
case PAUSE:
g.drawImage(pause, 0, 0,null);
break;
case GAME_OVER:
g.drawImage(gameover, 0, 0,null);
break;
}
}
public void action() {
MouseAdapter l = new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
if(state==RUNNING) {
int x = e.getX();
int y = e.getY();
hero.moveTo(x,y);
}
}
public void mouseClicked(MouseEvent e) {
switch(state) {
case START:
state=RUNNING;
break;
case RUNNING:
state=PAUSE;
break;
case PAUSE:
state=RUNNING;
break;
case GAME_OVER:
hero = new Hero();
background = new Background();
enemies = new ArrayList<FlyingObject>();
bullets = new ArrayList<Bullet>();
score=0;
state=START;
break;
}
}
/*public void mouseExited(MouseEvent e) {
if(state==RUNNING) {
state=PAUSE;
}
}
public void mouseEntered(MouseEvent e) {
if(state==PAUSE) {
state=RUNNING;
}
}*/
};
this.addMouseListener(l);
this.addMouseMotionListener(l);
Timer timer = new Timer();
int interval = 10;// 时间间隔(以毫秒为单位)
timer.schedule(new TimerTask() {
public void run() {
if(state==RUNNING) {
//敌人入场
enterAction();
//飞行物移动
stepAction();
//子弹入场
shootAction();
//删除越界飞行物
outOfBoundsAction();
//子弹打中敌机
bulletHit();
//英雄机碰撞敌机
heroHit();
//判断游戏结束
checkGameOverAction();
}
//画对象
repaint();
}
}, interval, interval);
}
public static void main(String[] args) {
JFrame frame = new JFrame("飞机大战");
World world = new World();
frame.add(world);//将类画到窗口上
frame.setSize(WIDTH,HEIGHT);//设置窗口宽高
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置窗口关闭程序结束
frame.setLocationRelativeTo(null);//设置窗口居中
frame.setVisible(true);//设置窗口可见
world.action();
}
}
2.飞行物父类实现思路:
飞行物的共有属性跟行为:飞行物的状态,宽高以及x和y的坐标
移动,获取图片,碰撞和越界等行为
读取同包中的图片资源,用画笔画飞行物
package shoot;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.imageio.ImageIO;
public abstract class FlyingObject {
public static final int LIFE=0;
public static final int DEAD=1;
public static final int REMOVE=2;
protected int state=LIFE;
protected int x;
protected int y;
protected int width;
protected int height;
public abstract void step();
public abstract BufferedImage getImage();
public abstract boolean outOfBounds();
public static BufferedImage LoadImage(String fireName) {
try {
BufferedImage image = ImageIO.read(FlyingObject.class.getResource(fireName));
return image;//读取同包中的图片资源
}catch(Exception e) {//打印异常
e.printStackTrace();
throw new RuntimeException();
}
}
public void paint(Graphics g) {//画具体的对象
g.drawImage(getImage(),x,y,null);
}
public FlyingObject() {
}
public FlyingObject(int width,int height) {
this.width = width;
this.height = height;
Random rand = new Random();
x = rand.nextInt(World.WIDTH-this.width);
y = -this.height;
}
public boolean isLife() {
return state==LIFE;
}
public boolean isDead() {
return state==DEAD;
}
public boolean isRemove() {
return state==REMOVE;
}
public void goDead() {
state = DEAD;
}
public boolean hit(FlyingObject other) {
int x1=this.x-other.width;
int x2=this.x+this.width;
int y1=this.y-other.height;
int y2=this.y+this.height;
int x=other.x;
int y=other.y;
return (x>=x1 &&x<=x2) && (y>=y1 && y<=y2);
}
}
3.背景实现思路:
加载图片,重写paint方法,移动行为,不会越界(两张相同背景图向下移动)
package shoot;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
public class Background extends FlyingObject{
private int y1;
private int step;
private static BufferedImage image;
static {
image = LoadImage("background.png");
}
public BufferedImage getImage() {
return image;
}
public boolean outOfBounds() {
return false;
}
public void paint(Graphics g) {//画具体的对象
g.drawImage(getImage(),x,y,null);
g.drawImage(getImage(),x,y1,null);
}
public Background() {
width = World.WIDTH;
height = World.HEIGHT;
x = 0;
y = 0;
y1 = -this.height;
step = 1;
}
public void step(){
y += step;
y1 += step;
if(y>=this.height) {
y = -this.height;
}
if(y1>=this.height) {
y1 = -this.height;
}
}
}
4.子弹
package shoot;
import java.awt.image.BufferedImage;
public class Bullet extends FlyingObject{
private int step;
private static BufferedImage image;
static {
image = LoadImage("bullet.png");
}
public BufferedImage getImage() {
return image;
}
public Bullet(int x,int y) {
width = 8;
height = 14;
this.x=x;
this.y=y;
step = 3;
}
public void step() {
y-=step;
}
public boolean outOfBounds() {
return this.y<=-this.height;
}
}
5.英雄机实现思路:
命跟火力值以及子弹的创建相关方法需要在这里实现
接收鼠标的x,y坐标的参数移动,注意英雄机要求运行实现动态(两张图片切换)
package shoot;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
public class Hero extends FlyingObject{
private int life;//命
private int doublefire;//火力值
public Hero() {
width = 97;
height = 124;
x = 140;
y = 400;
life=3;
doublefire=0;
}
private static BufferedImage[] images;
static {
images=new BufferedImage[6];
for(int i=0;i<images.length;i++) {
images[i]=LoadImage("hero"+i+".png");
}
}
int index=0;
int deadIndex=2;
public BufferedImage getImage() {
if(isLife()) {
return images[index++%2];
}else if(isDead()) {
BufferedImage img =images[deadIndex++];
if(deadIndex==images.length) {
state=REMOVE;
}
return img;
}
return null;
}
public void step() {
}
public boolean outOfBounds() {
return false;
}
public void moveTo(int x,int y) {
this.x=x-this.width/2;
this.y=y-this.height/2;
}
public List<Bullet> shoot() {
int xStep=this.width/4;
int yStep=20;
if(doublefire>0) {
List<Bullet> bs=new ArrayList<Bullet>();
bs.add(new Bullet(this.x+1*xStep,this.y-yStep));
bs.add(new Bullet(this.x+3*xStep,this.y-yStep));
doublefire-=2;
return bs;
}else {
List<Bullet> bs=new ArrayList<Bullet>();
bs.add(new Bullet(this.x+2*xStep,this.y-yStep));
return bs;
}
}
public void subLife() {
life--;
}
public void addLife() {
life++;
}
public int getLife() {
return life;
}
public void addDoubleFire() {
doublefire+=40;
}
public void clearDoubleFire() {
doublefire=0;
}
}
6.蜜蜂的奖励接口
package shoot;
public interface Award {
int DOUBLE_FIRE = 1;
int LIFE =0;
int getType();
}
7.蜜蜂的实现思路:
返回两种奖励类型,x坐标左右移动,不会飞出横向窗口,y坐标向下移动
package shoot;
import java.awt.image.BufferedImage;
import java.util.Random;
public class Bee extends FlyingObject implements Award{
private int xStep;
private int yStep;
private int awardType;
private static BufferedImage[] images;
static {
images=new BufferedImage[5];
for(int i=0;i<images.length;i++) {
images[i]=LoadImage("bee"+i+".png");
}
}
int deadIndex = 0;
public BufferedImage getImage() {
if(isLife()) {
return images[0];
}else if(isDead()) {
BufferedImage img = images[deadIndex++];
if (deadIndex == images.length) {
state = REMOVE;
}
return img;
}
return null;
}
public Bee(){
super(60,50);
xStep = 1;
yStep = 2;
Random rand = new Random();
awardType = rand.nextInt(2);
}
public void step() {
x+=xStep;
y+=yStep;
if(x>=World.WIDTH-this.width || x<=0) {
xStep*=-1;
}
}
public boolean outOfBounds() {
return this.y>=World.HEIGHT;
}
public int getType() {
return awardType;
}
}
8.敌机奖励得分接口
package shoot;
public interface Enemy {
int getScore();
}
9.小敌机
package shoot;
import java.awt.image.BufferedImage;
public class Airplane extends FlyingObject implements Enemy{
private int step;
private static BufferedImage[] images;
static {
images=new BufferedImage[5];
for(int i=0;i<images.length;i++) {
images[i]=LoadImage("airplane"+i+".png");
}
}
int deadIndex = 0;
public BufferedImage getImage() {
if(isLife()) {
return images[0];
}else if(isDead()) {
BufferedImage img = images[deadIndex++];
if (deadIndex == images.length) {
state = REMOVE;
}
return img;
}
return null;
}
public Airplane(){
super(49,36);
step = 2;
}
public void step() {
y+=step;
}
public boolean outOfBounds() {
return this.y>=World.HEIGHT;
}
public int getScore() {
return 1;
}
}
10.大敌机
package shoot;
import java.awt.image.BufferedImage;
public class Bigplane extends FlyingObject implements Enemy{
private int step;
private static BufferedImage[] images;
static {
images=new BufferedImage[5];
for(int i=0;i<images.length;i++) {
images[i]=LoadImage("bigplane"+i+".png");
}
}
int deadIndex = 0;
public BufferedImage getImage() {
if(isLife()) {
return images[0];
}else if(isDead()) {
BufferedImage img = images[deadIndex++];
if (deadIndex == images.length) {
state = REMOVE;
}
return img;
}
return null;
}
public Bigplane() {
super(69,99);
step = 2;
}
public void step() {
y+=step;
}
public boolean outOfBounds() {
return this.y>=World.HEIGHT;
}
public int getScore() {
return 1;
}
}
需要用到的图片:
1.小敌机
2.小蜜蜂
3.大敌机
4.英雄级
5.背景图
6.子弹
7.游戏开始页面
8.游戏暂停页面
9.游戏结束页面