Shootgame类
package com.hyxy.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.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* 游戏面板类型,需要继承Jpanel
* @author Administrator
*
*/
public class ShootGame extends JPanel{
//定义两个属性,分别是游戏面板的宽高
public static final int WIDTH=400;
public static final int HEIGHT=654;
//面板上需要有一个英雄机属性
protected Hero hero=new Hero();
protected FlyingObject[] objects={};//所有飞行物
protected Bullet[] bullets={};//所有子弹
protected int score;//面板上的总分
protected int life;//面板上的命数
protected int state;
protected static final int startgame=0;//开始状态
protected static final int running=1;//运行状态
protected static final int pausegame=2;//暂停状态
protected static final int over=3;//结束状态
//定义所有的图片属性
public static BufferedImage hero0;
public static BufferedImage hero1;
public static BufferedImage airplane;
public static BufferedImage bee;
public static BufferedImage bullet;
public static BufferedImage background;
public static BufferedImage start;
public static BufferedImage pause;
public static BufferedImage gameover;
//使用静态块给图片赋值
static{
try {
hero0=ImageIO.read(ShootGame.class.getResource("hero0.png"));
hero1=ImageIO.read(ShootGame.class.getResource("hero1.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"));
background=ImageIO.read(ShootGame.class.getResource("background.png"));
start=ImageIO.read(ShootGame.class.getResource("start.png"));
pause=ImageIO.read(ShootGame.class.getResource("pause.png"));
gameover=ImageIO.read(ShootGame.class.getResource("gameover.png"));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 重写面板绘制功能
*/
public void paint(Graphics g){
//绘制背景图片
g.drawImage(background, 0, 0, null);
paintHero(g);//绘制英雄机对象
paintBullets(g);//绘制所有的子弹
paintFlyingObject(g);//绘制敌机或蜜蜂
paintScore(g);//绘制分数和生命
paintState(g);//绘制游戏状态
}
private void paintState(Graphics g) {
switch(state){
case startgame:
g.drawImage(start, 0, 0, null);
break;
case pausegame:
g.drawImage(pause, 0, 0, null);
break;
case over:
g.drawImage(gameover, 0, 0, null);
break;
}
}
private void paintScore(Graphics g) {
int x=10;
int y=20;
g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,20));
g.setColor(new Color(0xFF0000));
g.drawString("分数:"+score, x, y);
g.drawString("生命:"+hero.getLife(), x, y+20);
}
private void paintFlyingObject(Graphics g) {
for(int i=0;i<objects.length;i++){
FlyingObject obj=objects[i];
g.drawImage(obj.image, obj.x, obj.y, null);
}
}
private void paintBullets(Graphics g) {
for(int i=0;i<bullets.length;i++){
Bullet b=bullets[i];
g.drawImage(b.image, b.x, b.y, null);
}
}
/**绘制英雄机*/
private void paintHero(Graphics g) {
//获取英雄机图片
BufferedImage image=hero.image;
g.drawImage(image, hero.x, hero.y, null);
}
Timer timer;//添加定时器属性
/**
* 程序的所有执行逻辑功能
*/
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);
}
}
/**鼠标点击即进入runnning状态*/
@Override
public void mouseClicked(MouseEvent e) {
switch (state) {
case startgame:
state=running;
break;
case over:
state=startgame;
//所有的数据都要重置
hero=new Hero();
score=0;
bullets=new Bullet[0];
objects=new FlyingObject[0];
break;
}
}
/**鼠标离开即进入pausegame状态*/
@Override
public void mouseExited(MouseEvent e) {
if(state==running){
state=pausegame;
}
}
/**鼠标进入即进入running状态*/
@Override
public void mouseEntered(MouseEvent e) {
if(state==pausegame){
state=running;
}
}
};
//将监听事件绑定到面板上
this.addMouseListener(l);
//添加监听事件的鼠标滑动效果
this.addMouseMotionListener(l);
timer=new Timer();
/**
* 设置定时器任务,
* 第一个为任务内容
* 第二个参数为多少毫秒后开始执行任务,
* 第三个是每隔多少毫秒执行任务
* */
timer.schedule(new TimerTask(){
public void run(){
if(state==running){
enterAction();//飞行物进场
stepAction();//所有飞行物开始走步
shootAction();//射击行为
boomAction();//碰撞行为
outOfBoundsAction();//处理飞行物越界情况
checkGameOver();//检查游戏是否结束
}
//重写绘制效果
repaint();
}
}, 10, 10);
}
/**处理越界行为,将没有越界的装入新的数组*/
protected void outOfBoundsAction() {
FlyingObject[] objLives={};
for(int i=0;i<objects.length;i++){
FlyingObject obj=objects[i];
if(!obj.outOfBounds()){
objLives=Arrays.copyOf(objLives, objLives.length+1);
objLives[objLives.length-1]=obj;
}
}
objects=objLives;
Bullet[] bsLives={};
for(int i=0;i<bullets.length;i++){
Bullet b=bullets[i];
if(!b.outOfBounds()){
bsLives=Arrays.copyOf(bsLives, bsLives.length+1);
bsLives[bsLives.length-1]=b;
}
}
bullets=bsLives;
}
/**检查游戏是否结束*/
protected void checkGameOver() {
if(isGameover()){
state=over;//游戏结束后,更改状态
}
}
/**判断游戏是否结束
* 条件是,生命值为0
* */
private boolean isGameover() {
int index=-1;
for(int i=0;i<objects.length;i++){
FlyingObject obj=objects[i];
if(hero.hit(obj)){
hero.substractLife();//减一条命
hero.setDoubleFire(0);//重置火力值
//让飞行物消失
index=i;//记录敌机下标
if(index!=-1){
objects[index]=objects[objects.length-1];
objects=Arrays.copyOf(objects, objects.length-1);
}
break;
}
}
return hero.getLife()<=0;
}
/**子弹与敌机或蜜蜂进行碰撞*/
protected void boomAction() {
for(int i=0;i<bullets.length;i++){
Bullet b=bullets[i];
//判断b是否与飞行物相撞
boom(b);
}
}
/**查看子弹与飞行物相撞的情况*/
private void boom(Bullet b) {
int index=-1;//用于记录被击中的飞行的下标
for(int i=0;i<objects.length;i++){
FlyingObject obj=objects[i];
//查看飞行物是否被飞行物击中
boolean f=obj.shootBy(b);
if(f){
index=i;
break;
}
}
//需要将被击中的飞行物删除
if(index!=-1){
//保存被击中的飞行物
FlyingObject obj=objects[index];
//将之从数组中删除
objects[index]=objects[objects.length-1];
//缩容一位
objects=Arrays.copyOf(objects, objects.length-1);
//查看被击中的是敌机还是蜜蜂
if(obj instanceof Bee){
//是蜜蜂
Bee bee=(Bee)obj;
int awardType=bee.getType();//获取奖励类型
switch(awardType){
case Award.DOUBLE_FIRE: //变成双倍火力
hero.addDoubleFire();
break;
case Award.LIFT: //英雄机生命+1
hero.addLife();
break;
}
}else{
//是敌机
Airplane air=(Airplane)obj;
score+=air.getScore();
}
}
}
/**英雄机发射子弹的功能*/
int shootIndex;//定义变量,计算子弹发射频率
protected void shootAction() {
shootIndex++;
/*400毫秒一发射,自定义*/
if(shootIndex%30==0){
Bullet[] bs=hero.shoot();//产生子弹
//将产生的子弹存入游戏面板的子弹数组
bullets=Arrays.copyOf(bullets, bullets.length+bs.length);
System.arraycopy(bs, 0, bullets,bullets.length-bs.length, bs.length);
}
}
/**所有飞行物开始走步*/
protected void stepAction() {
//敌机和蜜蜂开始走步
for(int i=0;i<objects.length;i++){
FlyingObject obj=objects[i];
obj.step();
}
for(int i=0;i<bullets.length;i++){
Bullet b=bullets[i];
b.step();
}
hero.step();
}
/**让所有的飞行物即敌机和蜜蜂进场*/
int objectIndex;//用来控制飞行物入场的频率
protected void enterAction() {
objectIndex++;
/**飞行物入场:每300毫秒就进入一个*/
if(objectIndex%90==0){
/**
* 随机产生一个飞行物
*/
FlyingObject obj=randomOne();
objects=Arrays.copyOf(objects, objects.length+1);
objects[objects.length-1]=obj;
}
}
/**随机一个敌机或者是蜜蜂*/
private FlyingObject randomOne() {
int num=(int)(Math.random()*20);
if(num==19){
Bee b=new Bee();
return b;
}else{
Airplane air=new Airplane();
return air;
}
}
public static void main(String[] args) {
//创建一个窗口
JFrame frame=new JFrame("雷霆战机");
//设置窗口大小
frame.setSize(WIDTH, HEIGHT);
//创建游戏面板对象
ShootGame panel=new ShootGame();
//将面板嵌入窗口
frame.add(panel);
//设置关闭即结束
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口居中
frame.setLocationRelativeTo(null);
//设置窗口在屏幕最前端
frame.setAlwaysOnTop(true);
//设置窗口可见
frame.setVisible(true);
//执行程序逻辑
panel.action();
}
}
FlyingObject:
package com.hyxy.shoot;
import java.awt.image.BufferedImage;
/**
* 定义抽象类型:飞行物
* 将面板上的所有飞行物的共有特征及其
* 功能封装到这个抽象类
* @author Administrator
*
*/
public abstract class FlyingObject {
protected BufferedImage image; //图片
protected int x;//绘制起始横坐标
protected int y;//绘制起始纵坐标
protected int width;//图片的宽
protected int height;//图片的高
//共同功能
public abstract void step();//走步行为
public abstract boolean outOfBounds();//越界行为
/**
* 查看飞行物是否被子弹击中
* @param b 子弹对象
* @return true:表示被击中
* false:表示没被击中
*/
public boolean shootBy(Bullet b) {
/**计算飞行物中心到子弹中心的距*/
//x轴的中心距离
int x1=this.x+width/2; //飞行物的中心x坐标
int y1=this.y+height/2; //飞行物的中心y坐标
int x2=b.x+b.width /2;
int y2=b.y+b.height/2;
/**满足碰撞的条件:
* 1.两个中心的x轴小于子弹与飞行物一半宽度之和的一半
* 2.两个中心的y轴小于子弹与飞行物一半高度的之和一半
* */
//x轴两个中心的距离
double xdis=Math.abs((x1-x2));
double ydis=Math.abs((y1-y2));
//y轴两个中心的距离
return xdis<(width+b.width)/2&&ydis<(height+b.height)/2;
}
}
Award类
package com.hyxy.shoot;
/**
* 定义奖励接口
* @author Administrator
*如果从蜜蜂身上获取0,就表示双倍火力
*如果从蜜蜂身上获取0,就表示生命值
*/
public interface Award {
int DOUBLE_FIRE=0;//双倍火力
int LIFT=1;//生命
/**
*获取奖励类型的方法
* @return
*/
public int getType();
}
Enemy类
package com.hyxy.shoot;
/**
* 定义敌人接口:
* 敌人被击中后,只需要提供分数
* @author Administrator
*
*/
public interface Enemy {
/**提供获取分数的方法*/
public int getScore();
}
Hero类:
package com.hyxy.shoot;
import java.awt.image.BufferedImage;
/**
* 定义定义英雄机类型继承FlyingObject
* 英雄机需要添加自己的独有属性
* @author Administrator
*
*/
public class Hero extends FlyingObject{
protected BufferedImage[] images;//图片数组
protected int double_fire;//火力值
protected int life;//生命值
/**
* 添加构造器,给属性初始化
*/
public Hero(){
image=ShootGame.hero0;//设置英雄机的初始图片
x=140;//在面板x轴上的初始位置
y=440;//在面板y轴上的初始位置
width=image.getWidth();
height=image.getHeight();
images=new BufferedImage[]{
ShootGame.hero0,ShootGame.hero1//两张图片
};
double_fire=0;//默认单倍火力
life=3;//默认3条命
}
/**
* 英雄机的走步行为即两张图片的交换
*设计 每四百毫秒交换一次
* 每十毫秒调用一次step()方法
*
* */
protected int index;//用来统计图片的交换频率
@Override
public void step() {
index++;
/**
* 每10毫秒 index都会自动加一
* */
image=images[index/10%images.length];
}
/**英雄机设置成永不越界,即返回flase*/
@Override
public boolean outOfBounds() {
// TODO Auto-generated method stub
return false;
}
/**
* 随着鼠标移动而移动
* @param x 鼠标的横坐标
* @param y 鼠标的纵坐标
*/
public void moveTo(int x,int y){
/**通过鼠标的位置计算英雄机的位置
* 鼠标位于英雄机的中心位置
* */
this.x=x-width/2;
this.y=y-height/2;
}
/**
* 英雄机的射击功能
* @return
*/
public Bullet[] shoot(){
if(double_fire==0){
Bullet[] bs=new Bullet[1];
//子弹的横坐标
int x=this.x+width/2;
//子弹的纵坐标
int y=this.y-ShootGame.bullet.getHeight();
bs[0]=new Bullet(x,y);
return bs;
}else{
//双倍火力
Bullet[] bs=new Bullet[2];
int x1=width/4;
int y1=ShootGame.bullet.getHeight();
bs[0]=new Bullet(this.x+x1,this.y-y1);
bs[1]=new Bullet(this.x+x1*3,this.y-y1);
return bs;
}
}
/**设置双倍火力,让属性double_fire大于0就行*/
public void addDoubleFire() {
double_fire+=40;
}
/**设置加命*/
public void addLife() {
life++;
}
/**设置减命*/
public void substractLife() {
life--;
}
/**设置获取英雄机的总命数*/
public int getLife(){
return life;
}
/**用来设置火力值:英雄机被撞,重置火力值*/
public void setDoubleFire(int fire){
this.double_fire=fire;
}
/**判断英雄机是否与飞行物碰撞*/
public boolean hit(FlyingObject obj) {
//飞行物的中心坐标
int x1=obj.x +obj.width/2;
int y1=obj.y+obj.height/2;
//英雄机的坐标
int x2=this.x+this.width/2;
int y2=this.y+this.height/2;
int xdis=Math.abs(x1-x2);
int ydis=Math.abs(y1-y2);
return xdis<(this.width+obj.width)/2
&&
ydis<(this.height+obj.height)/2;
}
}
Bullet类
package com.hyxy.shoot;
/**
* 定义子弹类型:Bullet
* @author Administrator
*
*/
public class Bullet extends FlyingObject{
protected int speed=3;//每次移动3像素
/**提供构造器,给属性初始化*/
public Bullet(int x,int y){
this.x=x;
this.y=y;//子弹的位置与英雄机的位置有关系
image=ShootGame.bullet;
width=image.getWidth();
height=image.getHeight();
}
@Override
public void step() {
y-=speed;
}
@Override
public boolean outOfBounds() {
//纵坐标在-height以上就是true表示越界
return this.y<-height;
}
}
Airplane类:
package com.hyxy.shoot;
/**
* 定义敌机类型:Airplane
* 继承FlyingObject,实现Enemy
* @author Administrator
*
*/
public class Airplane extends FlyingObject implements Enemy {
protected int speed=2;//每次移动2像素
/**提供构造器,给属性初始化*/
public Airplane(){
image=ShootGame.airplane;
width=image.getWidth();
height=image.getHeight();
this.x=(int)(Math.random()*(ShootGame.WIDTH-width));
this.y=-height;
}
/**每个敌机5分*/
@Override
public int getScore() {
return 5;
}
@Override
public void step() {
this.y+=speed;
}
@Override
public boolean outOfBounds() {
//敌机整个消失在面板内时才算越界
return this.y>ShootGame.HEIGHT;
}
}
Bee类:
package com.hyxy.shoot;
/**
* 定义蜜蜂类型 Bee
* 继承FlyingObject,实现Award接口
* @author Administrator
*
*/
public class Bee extends FlyingObject implements Award{
protected int xSpeed=1;//x轴上的移动像素
protected int ySpeed=2;//y轴上的移动像素
protected int awardType;//蜜蜂对象的奖励类型
/**提供构造器,给属性初始化*/
public Bee(){
image=ShootGame.bee;
width=image.getWidth();
height=image.getHeight();
this.x=(int)(Math.random()*(ShootGame.WIDTH-width));
this.y=-height;
//随机一种奖励类型
int num=(int)(Math.random()*2);
awardType=num;//奖励类型已确定
}
/**蜜蜂被击中时,需要知道是哪种奖励*/
@Override
public int getType() {
return awardType;
}
@Override
public void step() {
this.y+=ySpeed;
if(x<0){
xSpeed=-2;
}
if(x>ShootGame.WIDTH-width){
xSpeed=-2;
}
this.x+=xSpeed;
}
@Override
public boolean outOfBounds() {
return this.y>ShootGame.HEIGHT;
}
}