根据引导自己动手试试看
源码具体详情请点击 https://download.csdn.net/download/qq_40803710/11011232 进行下载。
1.第一个任务:做6个子类
Sky: y1;step step();
Hero: life;doubleFire move(int x,int y){}
Airplane: step step();
BigAirplane: step step();
Bee: xstep; ystep; awardType//0表示带命;1表示带分 step();
Bullet: step step();
2.第二个任务:使用构造方法,初始化数据
1)Sky:无参构造
public Sky() {
super(400,700,0,0);
y1=-700;
step = 1;
}
2) Hero:无参构造
public Hero() {
super(97,124,400/2-97/2,400);
life = 3;
doubleFire = 0;//0表示单倍火力 >0表示双倍火力
}
3)敌人对象(Airplane,BigAirplane,Bee)无参构造
public Airplane() {
super(49,36);
step = 2;
}
public BigAirplane() {
super(69,99);
step = 2;
}
public Bee() {
super(60,50);
xstep = 1;
ystep = 2;
awardType = new Random().nextInt(2); //0:火力值 1:命
}
4)Bullet
public Bullet(int x,int y) {
super(8,14,x,y);
step = 3;
state = LIFE;
}
3. 第三个任务:定义FlyingObject(实现代码重用)
1)定义FlyingObject,定义通用的变量和方法
2)设计两个构造方法:
对Airplane,Bee ,BigAirplane对象的初始化方法
//给敌人对象初始化Airplane,BigAirplane,Bee
public FlyingObject(int width,int height){
this.width = width;
this.height = height;
x = new Random().nextInt(400-this.width);
y = -height;
},在子类中调用
对Hero,Sky,Bullet对象的初始化方法
//给Sky,Hero,Bullet三个类实例化的方法
public FlyingObject(int width,int height,int x,int y){
this.width = width;
this.height = height;
this.x = x;
this.y = y;
},在子类中调用
3)调整成员变量的修饰符
父类中可以被访问的成员访问修饰符:protected
子类中的成员不被外界访问修饰符:private
4.第四个任务:画页面
1)定义World类,继承JPanel
2)定义窗口,显示窗口
import javax.swing.JPanel;
import java.awt.Graphics;
import javax.swing.JFrame;
public class world extends JPanel{
Sky sky = new Sky();
public static void main(String args[]) {
JFrame frame = new JFrame();
world world = new world();
frame.add(world);
frame.setTitle("飞机大战"); //设置窗口标题
frame.setSize(400,700); //设置窗口大小
frame.setLocationRelativeTo(null); //设置窗口居中显示
frame.setVisible(true); //设置窗口可视化
}
//实现画的功能
public void paint(Graphics g) {
sky.paintObject(g);
}
}
3)把图片拷贝到工程包下
4)加载图片
4.1)天空
//存放图片对象
private static BufferedImage image;
static{
try {
//使用ImageIO读取图片
image = ImageIO.read(Sky.class.getResource("background.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
4.2)小敌机
//加载图片到数组中
private static BufferedImage[] images = new BufferedImage[5];
static{
for(int i = 0;i<images.length;i++){
try {
images[i]=ImageIO.read(Airplane.class.getResource("airplane"+i+".png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4.3)大敌机
//加载图片到数组中
private static BufferedImage[] images = new BufferedImage[5];
static{
for(int i = 0;i<images.length;i++){
try {
images[i]=ImageIO.read(Airplane.class.getResource("bigplane"+i+".png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
5)获取图片
//类中有一个抽象方法时类不能定义为对象 要想让当前类创建对象
//要将父类抽象且方法抽象(父类中声明)才可以实现
public abstract BufferedImage getImage();
//子类中具体实现
5.1)天空@Override
public BufferedImage getImage() {
return image;
}
(1)小敌机
/*
* 1、如果当前状态为活着,加载数组的第一张图片
* 2、如果当前状态为死亡,加载数组中剩余的四张图片,把state=REMOVE
*/
int deadIndex = 1;
@Override
public BufferedImage getImage() {
if(this.isLife()) {
return images[0];
}else if(this.isDead()) {
//解决怎样加载剩余四张图片 可以多次调用返回
BufferedImage image = images[deadIndex++];
if(deadIndex==images.length) {
state = REMOVE;
}
return image;
}
return null;
}
(2)大敌机
/*
* 1、如果当前状态为活着,加载数组的第一张图片
* 2、如果当前状态为死亡,加载数组中剩余的四张图片,把state=REMOVE
*/
int deadIndex = 1;
@Override
public BufferedImage getImage() {
if(this.isLife()) {
return images[0];
}else if(this.isDead()) {
BufferedImage image = images[deadIndex++];
if(deadIndex==images.length) {
state = REMOVE;
}
return image;
}
return null;
}
(3)蜜蜂
/*
* 1、如果当前状态为活着,加载数组的第一张图片
* 2、如果当前状态为死亡,加载数组中剩余的四张图片,把state=REMOVE
*/
int deadIndex = 1;
@Override
public BufferedImage getImage() {
if(this.isLife()) {
return images[0];
}else if(this.isDead()) {
//解决怎样加载剩余四张图片 可以多次调用返回
BufferedImage image = images[deadIndex++];
if(deadIndex==images.length) {
state = REMOVE;
}
return image;
}
return null;
}
(4)子弹
public Bullet[] getBullet() {
if(doubleFire == 0) {
Bullet[] b = new Bullet[1];
int b_x = this.x + this.width/2;
int b_y = this.y - 20;
Bullet b1 = new Bullet(b_x,b_y);
b[0] = b1;
return b;
}else {
Bullet[] b = new Bullet[2];
int b_x = this.x + this.width/4;
int b_y = this.y - 20;
Bullet b1 = new Bullet(b_x,b_y);
b[0] = b1;
int b_x2 = this.x + this.width/4*3;
Bullet b2 = new Bullet(b_x2,b_y);
b[0] = b1;
b[1] = b2;
return b;
}
}
/*
* 1、如果当前状态为活着,加载数组的第一张图片
* 2、如果当前状态为死亡,把state=REMOVE
*/
@Override
public BufferedImage getImage() {
if(this.isLife()) {
return image;
}else if(this.isDead()) {
state = REMOVE;
}
return null;
}
6)画图片
public void paintObject(Graphics g) {
g.drawImage(getImage(), x, y, null);
g.drawImage(getImage(), x, y, null);
}
在World类中画图片
定义方法objectAction
FlyingObject object [] = {};
//敌人入场
public void objectAction(){
//小敌机的初始化
object = new FlyingObject[6];
object[0] = new Airplane();
object[1] = new Airplane();
object[2] = new Airplane();
object[3] = new BigAirplane();
object[4] = new BigAirplane();
object[5] = new BigAirplane();
}
//实现画的功能
public void paint(Graphics g){
sky.paintObject(g);
//画小敌机
for(int i = 0;i<object.length;i++){
object[i].paintObject(g);
}
}
5.第五个任务:让画面动起来
(1)动起来
//天空向下移动
public void step() {
y += step;
y1 += step;
if(y >= 700) {
y = -700;
}
if(y1 >= 700) {
y1 = -700;
}
}
//敌人对象动起来
public void step() {
y += step;
}
//小蜜蜂的step方法
public void step() {
x += xstep;
y += ystep;
if(x>=400-this.width) {
xstep *= -1;
}
}
//子弹动起来
public void step() {
y -= step;
}
(2)在world中定义方法
//让飞行物动起来
public void stepAction() {
//天空
sky.step();
//让敌人(小敌机、大敌机、蜜蜂)动起来
for(int i = 0;i<object.length;i++) {
object[i].step();
}
//让子弹动起来
for(int i = 0;i<bullets.length;i++) {
bullets[i].step();
}
}
在run方法中调用
public void action() {
//使用定时器
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
objectAction(); //生成敌人对象
stepAction(); //让画面动起来
bulletAction();
//run()功能:调用paint()方法
repaint();
}
}, 10, 10); //delay延迟 period
}
(3)随机产生敌人对象
3.1)//随机产生一个敌人对象
public FlyingObject nextOne() {
//20以内随机数 分成三个范围 定义其类型
int Random = new Random().nextInt(20);
if(Random<4) {
return new Bee();
}else if(Random>=4 && Random<12) {
return new BigAirplane();
}else {
return new Airplane();
}
}
//控制生成敌人数量
int flyIndex = 0;
//敌人入场
public void objectAction() {
flyIndex++;
if(flyIndex % 40 == 0) {
//敌人的初始化
FlyingObject obj = nextOne();
object = Arrays.copyOf(object, object.length+1);
object[object.length-1] = obj;
}
}
//控制生成子弹数量
int bulletIndex = 0;
public void bulletAction() {
bulletIndex++;
if(bulletIndex % 40 == 0) {
//子弹的初始化
Bullet b1[] = hero.getBullet();
//数组扩容:原来数组回收,新建数组拷贝扩容,第二参数为数组总大小
//Arrays.copyOf(original, newLength)
bullets = Arrays.copyOf(bullets, bullets.length + b1.length);
//对原数组数据拷贝第一个:从哪里开始拷;第四个:从哪里开始拷贝;第五个:拷贝多少个
System.arraycopy(b1, 0, bullets, bullets.length - b1.length, b1.length);
}
}
3.2)把随机对象放到数组中
int index = 0;
//敌人入场
public void objectAction(){
index++;
if(index%40==0){
//小敌机的初始化
FlyingObject ob = nextOne();
object = Arrays.copyOf(object,object.length+1);
object[object.length-1]=ob;
}
}
4)子弹的产生
4.1)在Hero类中定义方法
public Bullet[] getBullet(){
if(doubleFire==0){
Bullet[] b = new Bullet[1];
int b_x = this.x + this.width/2;
int b_y = this.y - 20;
Bullet bl = new Bullet(b_x,b_y);
b[0] = bl;
return b;
}else{
Bullet[] b = new Bullet[2];
int b_x = this.x + this.width/4;
int b_y = this.y - 20;
Bullet b1 = new Bullet(b_x,b_y);
int b_x2 = this.x + this.width/4*3;
Bullet b2 = new Bullet(b_x2,b_y);
b[0] = b1;
b[1] = b2;
return b;
}
}
4.2)把子弹对象放到数组中
int bulletIndex=0;
//子弹入场
public void bulletAction(){
bulletIndex++;
if(bulletIndex%30==0){
Bullet bl[] = hero.getBullet();
//数组扩容
bullets = Arrays.copyOf(bullets, bullets.length+bl.length);
//数组拷贝
System.arraycopy(bl, 0, bullets, bullets.length-bl.length, bl.length);
}
}
5)英雄机随鼠标移动(Hero类中)
5.1)//x,y表示鼠标的坐标 (Hero类中)
public void move(int x,int y){
this.x = x - this.width/2;
this.y = y - this.height/2;
}
5.2)添加事件监视器 (World类中)
//定义鼠标的移动事件处理方法(内部类:(匿名类))
MouseAdapter l = new MouseAdapter(){
public void mouseMoved(MouseEvent e){
//获取鼠标点的坐标
int x = e.getX();
int y = e.getY();
hero.move(x, y);
}
};
//给Jpanel添加事件监视器的对象
this.addMouseMotionListener(l);
6.第六个任务:删除越界的对象
- 在父类定义越界的方法,分别在子类中实现方法
public abstract boolean outOfBounds();
- 分别实现方法(敌人对象y>700,子弹y<0,天空和英雄机永不越界)
- 敌人
public boolean outOfBounds() {
return this.y>700;
}
- 子弹
public boolean outOfBounds() {
return this.y<0;
}
- 天空和英雄机
public boolean outOfBounds() {
return false;
}
- 在world类中定义方法,回收越界对象,在action方法中调用
//回收越界的对象:(敌人,子弹)
public void outOfBoundsAction() {
//装活着的敌人的对象的数组
FlyingObject[] fo = new FlyingObject[object.length];
//活着的敌人对象数目
int lifeIndex = 0;
//遍历数组
for(int i = 0;i<object.length;i++) {
//从数组中获取敌人的对象
FlyingObject f = object[i];
//找出没有越界的敌人
if(!f.outOfBounds()&&!f.isRemove()) {
fo[lifeIndex] = f;
lifeIndex++;
}
}
//数组的拷贝
object = Arrays.copyOf(fo, lifeIndex);
//子弹的越界对象的删除
//定义数组,装没有越界的子弹
Bullet[] bo = new Bullet[bullets.length];
//活着的子弹对象数目
int bulletsIndex = 0;
//遍历数组
for(int i = 0;i<bullets.length;i++) {
//从数组中获取子弹的对象
Bullet b = bullets[i];
//找出没有越界的子弹
if(!b.outOfBounds()&&!b.isRemove()) {
bo[bulletsIndex] = b;
bulletsIndex++;
}
}
//数组的拷贝
bullets = Arrays.copyOf(bo, bulletsIndex);
}
7.第七个任务:定义敌人和子弹(英雄机)发生碰撞的方法
- 定义方法,对敌人和子弹(英雄机)是否碰撞,other表示子弹(英雄机) this表示敌人对象
public boolean hit(FlyingObject other) {
/* x轴的范围:this.x-other.width(左x) this.x+this.width(右x)
y轴的范围:this.y+this.height(上y) this.y-other.height(下y)
如果子弹的x,y坐标在以上范围内,说明撞上了,返回true,否则返回false */
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;
}
(2)定义接口,定义得分的方法
public interface Enemy {
public int getScore();
}
需要大敌机和小敌机实现接口,重写方法
public int getScore() {
return 1;
}
(3)定义接口,定义福利
public interface Award {//接口中都是公有静态常量,不用写属性,只需类型名字
int DOUBLEFIRE = 0;//带火力值
int LIFE = 1;//带名
int getType();
}
需要小蜜蜂实现接口
public int getType() {
return awardType;
}
(4)定义功能方法
//让敌人去死的方法(在FlyingObject类中实现)
public void goDead() {
state = DEAD;
}
//加命(在Hero类中实现)
public void addLife(){
life++;
}
//获取命(在Hero类中实现)
public int getLife(){
return life;
}
//增加火力值(在Hero类中实现)
public void addDoubleFire(){
doubleFire+=40;
}
8.第八个任务:当子弹和敌人碰撞之后的得分和福利的设置,并在页面画分和命
//子弹和敌人发生碰撞
int score = 0;
public void bulletHitAction(){
//遍历子弹集合,
for(int i = 0;i<bullets.length;i++){
//拿到一个子弹对象
Bullet b = bullets[i];
for(int j = 0;j<object.length;j++){//遍历敌人集合
FlyingObject f = object[j];//获取一个敌人对象
if(b.isLife()&&f.isLife()&&f.hit(b)){//子弹对象和所有的敌人碰撞的匹配
f.goDead();//敌人去死
b.goDead();//子弹去死
if(f instanceof Enemy){//如果是(大敌机或者是小敌机)
score += ((Enemy) f).getScore();//得分
}
if(f instanceof Award){//如果是小蜜蜂
switch(((Award) f).getType()){
case Award.DOUBLEFIRE://带火力值得小蜜蜂
hero.addDoubleFire();//火力值增加
case Award.LIFE://带命的小蜜蜂
hero.addLife();//命增加
}
}
}
}
}
}
g.drawString("Scoure:"+score, 10, 40);
g.drawString("Life:"+hero.getLife(), 10, 60);
9.第九个任务:英雄机和敌人发生碰撞:如果碰到的是大(小)敌机,命-1;
如果碰到的是小蜜蜂:火力清0
(1)在Hero类中定义方法:subLife(); clearFire();
//减命
public void subLife(){
life--;
}
//清空火力值
public void clearFire(){
doubleFire = 0;
}
(2)heroHitAction();
//英雄机和敌人碰撞
public void heroHitAction() {
for(int i = 0;i<object.length;i++) //遍历敌人集合
{
FlyingObject f = object[i]; //获取一个敌人对象
if(f.isLife()&&f.hit(hero)) {
f.goDead(); //敌人去死
if(f instanceof Enemy) {
hero.subLife();
}
if(f instanceof Award) {
hero.clearFire();
}
}
}
}
10.第10个任务:画窗口的状态
- 在World类中定义4个常量,表示窗口的状态:开始,运行,暂停,结束
public static final int START = 0;
public static final int RUNNING = 1;
public static final int PAUSE = 2;
public static final int GAMEOVER = 3;
private int state = START;
- 设计程序结束的方法,checkGameOverAction();
public void checkGameOverAction() {
if(hero.getLife()==0&&hero.isRemove()) {
state = GAMEOVER;
}
if(hero.getLife()==0)
{
hero.goDead();
}
}
- 在World类中定义3个静态变量,加载图片(启动,暂停,结束)
//存放图片对象
private static BufferedImage startImage;
private static BufferedImage pauseImage;
private static BufferedImage gameOverImage;
static {
try {
//以读取流的方式加载图片
startImage = ImageIO.read(Sky.class.getResource("start.png"));
pauseImage = ImageIO.read(Sky.class.getResource("pause.png"));
gameOverImage = ImageIO.read(Sky.class.getResource("gameover.png"));
}
catch(IOException e) {
e.printStackTrace();
}
}
- 在World类中的paint()方法中根据不同的状态画不同的的图片
switch(state) {
case START:
g.drawImage(startImage, 0, 0, null);
break;
case PAUSE:
g.drawImage(pauseImage, 0, 0, null);
break;
case GAMEOVER:
g.drawImage(gameOverImage, 0, 0, null);
break;
}
- 在不同状态下,显示不同的运行情况
MouseAdapter l = new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
if(state == RUNNING) {
int x = e.getX();
int y = e.getY();
hero.move(x, y);
}
}
public void mouseEntered(MouseEvent e) {
if(state == PAUSE) {
state = RUNNING;
}
}
public void mouseExited(MouseEvent e) {
if(state == RUNNING) {
state = PAUSE;
}
}
public void mouseClicked(MouseEvent e) {
if(state == START) {
state = RUNNING;
}
if(state == GAMEOVER) {
//初始化操作
object = new FlyingObject[0];
bullets = new Bullet[0];
score = 0;
hero = new Hero();
state = START;
}
}
};