1、效果
2、游戏类
package com.sukla.shoot;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**游戏主界面*/
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 gameover;
public static BufferedImage pause; //暂停
public static BufferedImage airplane;
public static BufferedImage bee;
public static BufferedImage bullet;
public static BufferedImage hero0;
public static BufferedImage hero1;
public Hero hreo=new Hero(); //英雄机器
public Bullet[] bullets={}; //子弹数组
public FlyingObject[] flyings={}; //敌机和小蜜蜂
//总得分
private int score=0;
//状态
private int state; //状态
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;
static{ //加载图片资源
try {
background=ImageIO.read(ShootGame.class.getResource("background.png"));
start=ImageIO.read(ShootGame.class.getResource("start.png"));
gameover=ImageIO.read(ShootGame.class.getResource("pause.png"));
pause=ImageIO.read(ShootGame.class.getResource("pause.png"));
airplane=ImageIO.read(ShootGame.class.getResource("airplane.png"));
bee=ImageIO.read(ShootGame.class.getResource("bee.png"));
bullet=ImageIO.read(ShootGame.class.getResource("bullet.png"));
hero0=ImageIO.read(ShootGame.class.getResource("hero0.png"));
hero1=ImageIO.read(ShootGame.class.getResource("hero1.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//background成员 所在CLASS的名字ShootGame
}
//重写绘制方法
public void paint(Graphics g){//g为画笔
g.drawImage(background,0,0,null);//画图片
paintHero(g); //画英雄机
paintBullet(g); //画子弹
paintFlyingObjects(g); //画敌人
paintScore(g); //画分数画命
paintState(g); //画状态
};
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 GAME_OVER:
g.drawImage(gameover, 0, 0, null);
break;
}
}
public void paintScore(Graphics g){
g.setColor(new Color(0x22bd7a)); //设置文字颜色
g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,25)); //设置字体
g.drawString("score:"+score, 20, 35);
g.drawString("LIVE:"+hreo.getLive(), 20, 65);
}
//画英雄机
public void paintHero(Graphics g){
g.drawImage(hreo.image, hreo.x, hreo.y, null);
};
//画子弹
public void paintBullet(Graphics g){
for(int i=0;i<bullets.length;i++){
Bullet b=bullets[i];
g.drawImage(b.image, b.x, b.y, null);
};
};
//画敌人
public void paintFlyingObjects(Graphics g){
for(int i=0;i<flyings.length;i++){
FlyingObject o=flyings[i];
g.drawImage(o.image, o.x, o.y, null);
};
};
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame frame=new JFrame("飞机大战"); //画框+标题
ShootGame game=new ShootGame();
frame.add(game); //将JPanel 放到 JFrame上
frame.setSize(WIDTH, HEIGHT);
frame.setAlwaysOnTop(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //默认关闭
frame.setLocationRelativeTo(null); //初始位置
frame.setVisible(true); //显示尽快调用paint画图 绘制一次
game.action(); //启动执行操作
}
private Timer timer; //定时器
private int interval=10; //定时时间间隔ms
/**启动执行操作*/
public void action(){
//鼠标事件
//swing里面的鼠标事件适配器 MouseAdapter这个适配器用空实现实现了好几个方法 我们只需要重写想要的方法即可
MouseAdapter l=new MouseAdapter(){
/**重写鼠标移动事件*/
public void mouseMoved(MouseEvent e){//重写mouseMoved
if(state==RUNNING){
int x=e.getX(); //鼠标的x
int y=e.getY(); //鼠标的y
hreo.moveTo(x, y); //英雄机移动
}
}
/**重写鼠标点击事件*/
public void mouseClicked(MouseEvent e){
switch(state){
case START:
state=RUNNING;
break;
case GAME_OVER:
hreo=new Hero();
flyings=new FlyingObject[0];
bullets=new Bullet[0];
state=START;
break;
}
}
/**重写鼠标移出事件*/
public void mouseExited(MouseEvent e){
if(state!=GAME_OVER){
state=PAUSE;
}
}
/**重写鼠标移入事件*/
public void mouseEntered(MouseEvent e){
if(state==PAUSE){
state=RUNNING;
}
}
};
//给当前面板添加鼠标操作的监听事件
this.addMouseListener(l);
//给当前面板ipanel加一个鼠标滑动监听事件
this.addMouseMotionListener(l);
timer=new Timer();
timer.schedule(new TimerTask(){ //匿名内部类的对象
@Override
public void run() { //重写run方法
if(state==RUNNING){
//飞行物入场
enterAction();
//飞行物走步
stepAction();
//飞机发射子弹 子弹入场
shootAction();
//判断子弹是否命中敌机并处理
bangAction();
//删除越界飞行物
outOfBoundsAction();
//判断是否游戏结束
checkGameOverAction();
}
//重绘 调用paint方法
repaint();
}
}, interval,interval); //定时触发
}
/**检查游戏是否结束*/
public void checkGameOverAction(){
if(isGameOver()){//判断是否结束
state=GAME_OVER;
}
}
/**判断游戏是否结束*/
public boolean isGameOver(){
for(int i=0;i<flyings.length;i++){
int index=-1; //撞击上的飞行物的索引
FlyingObject obj=flyings[i]; //每个飞行物
if(hreo.hit(obj)){
hreo.substarctLife(); //减少,命
hreo.setDoubleFire(0); //减少火力
index=i;
}
if(index!=-1){
FlyingObject t=flyings[index]; //删除撞击的飞行物
flyings[index]=flyings[flyings.length-1];
flyings[flyings.length-1]=t;
flyings=Arrays.copyOf(flyings, flyings.length-1);
}
}
return hreo.getLive()<=0; //返回是否有命
}
/**删除越界飞行物*/
public void outOfBoundsAction(){
/**删除所有越界敌人和蜜蜂*/
int index=0; //下标
FlyingObject[] flyingLives=new FlyingObject[flyings.length]; //声明一个长度一样的数组
for(int i=0;i<flyings.length;i++){
FlyingObject f=flyings[i];
if(!f.outOfBounds()){
flyingLives[index++]=f;
}
}
flyings=Arrays.copyOf(flyingLives, index);
/**删除所有越界子弹*/
index=0;
Bullet[] bulletLives=new Bullet[bullets.length];
for(int i=0;i<bullets.length;i++){
Bullet b=bullets[i];
if(!b.outOfBounds()){
bulletLives[index++]=b;
}
}
bullets=Arrays.copyOf(bulletLives, index);
}
/**子弹是否击中敌机的处理*/
public void bangAction(){
for(int i=0;i<bullets.length;i++){ //所有子弹
Bullet b=bullets[i];
bang(b); //子弹和飞行物碰撞
}
}
/**子弹打敌人*/
public void bang(Bullet b){
int index=-1;
for(int i=0;i<flyings.length;i++){
FlyingObject obj=flyings[i];
if(obj.shootBy(b)){
index=i; //被击中的飞机的下标
break;
}
}
if(index!=-1){
FlyingObject one=flyings[index];
if(one instanceof Enemy){ //判断是不是敌机是的话就加分 多态的应用
score+=((Enemy)one).getScore(); //强转为敌机类型来使用敌机类型特有的方法
}else if(one instanceof Award){ //判断是小蜜蜂这种奖励类型
Award a=(Award)one;
int type=a.getType(); //获取奖励类型
switch(type){
case Award.DOUBLE_FIRE: //判断奖励类型
hreo.addBoubleFire(); //颁发奖励
break;
case Award.LIFE:
hreo.addLife();
break;
}
}
//获取奖励之后删除被击中的目标
//交换位置 然后缩容
FlyingObject t=flyings[index];
flyings[index]=flyings[flyings.length-1];
flyings[flyings.length-1]=t;
flyings=Arrays.copyOf(flyings, flyings.length-1);
}
}
int shootIndex=0; //控制射击频率
/**发射子弹*/
//子弹入场
public void shootAction(){
shootIndex++;
if(shootIndex%10==0){ //300ms发射一次
Bullet[] bs=hreo.shoot(); //英雄机发射子弹
bullets=Arrays.copyOf(bullets, bullets.length+bs.length); //数组的扩容
System.arraycopy(bs, 0, bullets, bullets.length-bs.length, bs.length); //数组的追加 a数组从b位置开始复制到c数组的d位置开始复制e个元素
}
}
int flyingEnterdIndex=0; //飞行物入场计数
/**飞行物入场*/
public void enterAction(){
flyingEnterdIndex++;
if(flyingEnterdIndex%40==0){
FlyingObject obj=nextone();
flyings=Arrays.copyOf(flyings, flyings.length+1); //数组扩容
flyings[flyings.length-1]=obj; //将敌人装到数组中
}
}
/**随机生成?和✈*/
//工厂方法:生产对象,一般为static的
public static FlyingObject nextone(){
Random rand =new Random();
int type=rand.nextInt(20); //[0,19)
if(type==0){
return new Bee();
}else{
return new Airplane();
}
}
/**飞行物走步*/
public void stepAction(){
//敌人(敌机和小蜜蜂)走一步
for(int i=0;i<flyings.length;i++){
flyings[i].step();
}
//子弹走一步
for(int i=0;i<bullets.length;i++){
bullets[i].step();
}
//hero
hreo.step();
}
}
package com.sukla.shoot;
/**奖励*/
public interface Award {
int DOUBLE_FIRE=0; //双倍火力
int LIFE=1; //一条命
int getType(); //获取奖励类型
}
3、可获取分数的接口
package com.sukla.shoot;
/**
* 敌机都可以得分
* 得分
* */
public interface Enemy {
int getScore();
}
4、飞行物类
package com.sukla.shoot;
import java.awt.image.BufferedImage;
/**
* 飞行物类
* created by sukla.
* 成员变量设置为私有
* 方法设置为公有
* 不建议使用默认访问修饰
*
* */
public abstract class FlyingObject {
protected int width; //宽
protected int height; //高
protected int x; //X坐标
protected int y; //Y坐标
protected BufferedImage image; //图片
public abstract void step(); //走步
/**敌人是否被子弹击中*/
public boolean shootBy(Bullet b){
int x=b.x; //子弹的x
int y=b.y; //子弹的y
return x>this.x&&x<this.x+this.width
&&
y>this.y&&y<this.y+this.height;
};
/**检测是否超出游戏面板界限*/
public abstract boolean outOfBounds();
}
5、第一类敌机、继承飞行物类、实现获取分数接口
package com.sukla.shoot;
import java.util.Random;
/**敌机:是飞行物,也是敌人*/
public class Airplane extends FlyingObject implements Enemy {
private int speed=2; //每次移动2步
/**初始化实例变量*/
public Airplane(){
image=ShootGame.airplane;
width=image.getWidth();
height=image.getHeight();
Random rand=new Random();
x=rand.nextInt(ShootGame.WIDTH-width);
y=-height;
};
public int getScore(){
return 10;
};
public void step(){
y+=speed;
};
/**重写检测是否越界*/
public boolean outOfBounds(){
return y>y+ShootGame.HEIGHT;
}
}
6、第一类奖励飞行物,继承飞行物、实现获取奖励接口
package com.sukla.shoot;
import java.util.Random;
/**小蜜蜂:飞行物+奖励*/
public class Bee extends FlyingObject implements Award{
private int xSpeed=1; //横向移动
private int ySpeed=2; //纵向移动
private int awardType;//奖励的类型
/**初始化实例变量*/
public Bee(){
image=ShootGame.bee;
width=image.getTileWidth();
height=image.getHeight();
y=-height;
Random rand=new Random();
x=rand.nextInt(ShootGame.WIDTH-width);
awardType=rand.nextInt(2);
};
/**获取奖励类型*/
public int getType(){
return awardType;
};
//走步
public void step(){
if(x<0){
xSpeed=1;
};
if(x>ShootGame.WIDTH-width){
xSpeed=-1;
}
x+=xSpeed;
y+=ySpeed;
};
/**重写检测越界*/
public boolean outOfBounds(){
return y>height+ShootGame.HEIGHT;
};
}
7、子弹类、继承飞行物类
package com.sukla.shoot;
/**子弹:飞行物*/
public class Bullet extends FlyingObject {
private int speed=30;
/**初始化成员变量*/
public Bullet(int x,int y){
image=ShootGame.bullet;
width=image.getWidth();
height=image.getHeight();
this.x=x;
this.y=y;
};
//走步
public void step(){
y-=speed;
}
/**重写检测是否越界*/
public boolean outOfBounds(){
return y<-y;
}
}
8、玩家操纵的战斗机、继承飞行物类
package com.sukla.shoot;
import java.awt.image.BufferedImage;
/**英雄机:飞行物*/
public class Hero extends FlyingObject {
private BufferedImage[] images={};
private int index; //图片交换计数
private int doubleFire; //双倍火力
private int life; //命
public Hero (){
image=ShootGame.hero0;
width=image.getWidth();
height=image.getHeight();
x=180;
y=550;
doubleFire=0;
life=3;
images=new BufferedImage[]{ShootGame.hero0,ShootGame.hero1};
}
public int getLive(){
return life;
}
//走步
public void step(){
int num=index++/10%images.length;
image=images[num];
}
//发射子弹
public Bullet[] shoot(){
int xStep=this.width/4;
int yStep=20;
if(doubleFire>0){
Bullet[] bullets=new Bullet[2];
bullets[0]=new Bullet(this.x-xStep*5,this.y-yStep);
bullets[1]=new Bullet(this.x+xStep*5,this.y-yStep);
return bullets;
}else{
Bullet[] bullets=new Bullet[1];
bullets[0]=new Bullet(this.x,this.y-yStep);
return bullets;
}
}
/**移动 x:鼠标的x y:鼠标的y*/
public void moveTo(int x,int y){
this.x=x-this.width/2;
this.y=y-this.height/2;
}
//添加双倍火力
public void addBoubleFire(){
doubleFire+=40;
}
//添加命
public void addLife(){
life++;
}
/**重写检测是否越界*/
public boolean outOfBounds(){
return false;
}
/**碰撞算法*/
public boolean hit(FlyingObject other){
return !(
(other.x+other.width<this.x)
||(other.x>this.x+this.width)
||(other.y+other.height<this.y)
||(other.y>this.y+this.height)
);
}
/**碰撞后的动作*/
public void substarctLife(){
life--;
}
/**设置火力*/
public void setDoubleFire(int doubleFire){
this.doubleFire=doubleFire;
}
}