效果图:
说明:
1.飞机初始属性:攻速低、子弹量少
2.敌机初始属性:数量少
3.飞机可以获得奖励提升攻速和子弹数量(奖励分为生命值和提升攻击属性)
4.鼠标移出界面自动暂停,鼠标进入页面继续游戏
5.记录击中的敌机数量
6.显示当前生命值
7.可自行拓展更多效果
上代码:
目录结构:
Start.java
package com.losen.plane;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
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.TimerTask;
/**
* @author losen
* @version 1.0
* @DateTime 2023/6/28 13:07
*/
public class Start extends JPanel{
public static final int WIDTH =400;
public static final int HEIGHT =654;
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 =4;
public static BufferedImage background;
public static BufferedImage start;
public static BufferedImage airplane;
public static BufferedImage bee;
public static BufferedImage bullet;
public static BufferedImage hero0;
public static BufferedImage hero1;
public static BufferedImage pause;
public static BufferedImage gameover;
private int enemyspeed = 40;
private int cartridgespeed = 30;
private PlaneObj[] flyings = {}; //敌机数组
private Cartridge [] bullets = {}; //子弹数组
private MyPlane hero = new MyPlane();//英雄鸡
private Timer timer;//定时器
private int intervel = 1000/100; //时间间隔,一毫秒
private int score = 0;//得分
public Start(){
flyings = new PlaneObj[2];
flyings[0] = new EnemyPlane();
flyings[1] = new Prize();
bullets = new Cartridge[1];
bullets[0] = new Cartridge(180,300);
}
static{//静态代码块
try {
background= ImageIO.read(Start.class.getResource("./image/background.png"));
start= ImageIO.read(Start.class.getResource("./image/start.png"));
airplane = ImageIO.read(Start.class.getResource("./image/enemyplane.png"));
bee = ImageIO.read(Start.class.getResource("./image/prize.png"));
bullet = ImageIO.read(Start.class.getResource("./image/cartridge.png"));
//bullet = ImageIO.read(Start.class.getResource("B1.png"));
//hero0= ImageIO.read(Start.class.getResource("C.png"));
hero0= ImageIO.read(Start.class.getResource("./image/plane.png"));
hero1 = ImageIO.read(Start.class.getResource("./image/plane2.png"));
pause= ImageIO.read(Start.class.getResource("./image/pause.png"));
gameover = ImageIO.read(Start.class.getResource("./image/gameover.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void paint(Graphics g) {
g.drawImage(background,0,0,null);//画背景图片
paintHero(g);
paintBullets(g);
paintFlyingObject(g);
paintScore(g);//画分数
// paintPause(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 enemyspeedaction(){
java.util.Timer timer = new java.util.Timer();
timer.schedule(new TimerTask() {
public void run() {
if(enemyspeed>1){
enemyspeed-=1;
}
repaint();//重绘,调用paint方法
}
}, 5000 ,5000);//10毫秒以后,每隔10毫秒执行一次
}
/**
* 画分数
* @param g
*/
public void paintScore(Graphics g){
Font font = new Font(Font.SANS_SERIF, Font.BOLD,4);
g.setColor(new Color(0xffff0));//设置字体
g.drawString("SCORE"+score,10,25);
g.drawString("LIFE"+hero.getLife(),10,45);
}
//画英雄鸡
public void paintHero(Graphics g){
g.drawImage(hero.getImage(),hero.getX(),hero.getY(),null);
}
//画子弹
public void paintBullets(Graphics g){
for(int i = 0;i < bullets.length; i++){
Cartridge b = bullets[i];
// 图片大小会影响子弹发射位置
g.drawImage(b.getImage(),b.getX()-22,b.getY(),null);
}
}
//画飞行物
public void paintFlyingObject(Graphics g){
for(int i = 0; i< flyings.length;i++){
PlaneObj f = flyings[i];
g.drawImage(f.getImage(),f.getX(),f.getY(),null);
}
}
// //画暂停
// public void paintPause(Graphics g){
// g.drawImage(pause,0,0,null);
// }
//随机生成飞行物
public static PlaneObj nextOne(){
//返回 飞行物对象
Random random = new Random();
int type = random.nextInt(20);//生成随机数0-19
if(type == 0){
return new Prize();
}else{
return new EnemyPlane();
}
}
int flyEnterIndex = 0;
//飞行物入场
public void enterAction () {
flyEnterIndex++;
if (flyEnterIndex % enemyspeed == 0) {//每调用40次该方法,产生飞行物速度
PlaneObj obj = nextOne();//随机生成一个飞行物
flyings = Arrays.copyOf(flyings, flyings.length + 1);//扩容
flyings[flyings.length - 1] = obj;//放在最后一位
}
}
/*
实现飞行物移动
*/
public void stepAction() {
for (int i = 0; i < flyings.length; i++){
PlaneObj f = flyings[i];
f.step();
}
for(int i = 0;i<bullets.length;i++){
/**
* 子弹走
*
*/
Cartridge b = bullets[i];
b.step();
// bullets[i].step();
}
hero.step();
}
int shootIndex = 0;
//射击
public void shootAction() {
shootIndex++;
if (shootIndex % cartridgespeed == 0) {//每调用30次该方法,子弹速度
Cartridge [] bs = hero.shoot();//己方飞机发射子弹
bullets = Arrays.copyOf(bullets, bullets.length + bs.length);
System.arraycopy(bs,0,bullets,bullets.length - bs.length,bs.length);
}
}
public void bangAction() {
for (int i = 0; i< bullets.length; i++){
Cartridge b = bullets[i];
bang(b);
}
}
private void bang(Cartridge bullet) {
int index = -1;
for (int i = 0; i <flyings.length;i++){
PlaneObj obj = flyings[i];
if(obj.shootBy(bullet)){
index = i;
break;
}
}
if(index != -1) {
//击中
PlaneObj one = flyings[index];//记录被击中的飞行物
PlaneObj temp = flyings[index];//被击中的飞行物与最后一个飞行物交换
flyings[index] = flyings[flyings.length - 1];
flyings[flyings.length - 1] = temp;
//删除最后一个飞行物(被击中的飞行物)
flyings = Arrays.copyOf(flyings, flyings.length - 1);
// // 子弹碰撞消失
bullets = Arrays.copyOf(bullets, bullets.length-1);
//检测one的类型,若果是敌人就加分
if (one instanceof Enemy) {
Enemy e = (Enemy) one;
score += e.getScore();
}
if (one instanceof PrizeContent) {
PrizeContent a = (PrizeContent) one;
int type = a.getType();
switch (type) {
case PrizeContent.DOUBLE_FIRE:
hero.addDoubleFire(); // 获得加强火力奖励
if(cartridgespeed>=5){ // 同时射速提升
cartridgespeed-=4;
}
break;
case PrizeContent.LIFE:
hero.addLife();
break;
}
}
}
}
/**
* 删除屏幕外的飞行物
*/
public void outOfBoundsAction() {
int index = 0;
PlaneObj[] flyingLives = new PlaneObj[flyings.length];//没有碰撞的飞行物
for (int i = 0; i < flyings.length; i++) {
PlaneObj f = flyings[i];
if (!f.outOfBounds()) {
flyingLives[index++] = f;//没有越界的存储到或者的数组
}
}
flyings = Arrays.copyOf(flyingLives, index);//没有越界的都留着
index = 0;
Cartridge[] bulletLives = new Cartridge[bullets.length];//存储没有发生碰撞的子弹
for (int i = 0; i < bullets.length; i++) {
Cartridge b = bullets[i];
if (!b.outOfBounds()) {//如果没有越界
bulletLives[index++] = b;
}
}
bullets = Arrays.copyOf(bulletLives,index);
}
/**
* 判断游戏结束
*/
public boolean isGameOver() {
for (int i = 0; i < flyings.length; i++) {//遍历所有飞行物
int index = -1;//没有发生碰撞
PlaneObj obj = flyings[i];
if(hero.hit(obj)){//检查己方飞机与飞行物是否碰撞
hero.subtractLife();//生命减一
hero.setDoubleFire(0);//重置火力
index = i;//将碰撞飞行物的下标给到index
}
if(index!=-1){
PlaneObj t = flyings[index];
flyings[index] = flyings[flyings.length - 1];
flyings[flyings.length - 1] = t;//发生碰撞的元素和最后一个元素交换
flyings = Arrays.copyOf(flyings,flyings.length-1);
}
}
return hero.getLife() <= 0;
}
/**
* 检查游戏是否结束
*/
public void checkGameOverAction() {
if(isGameOver()){//如果已经结束
state = GAME_OVER;//改变状态为结束
}
}
public void action(){
//鼠标监听事件
MouseAdapter i = new MouseAdapter(){
public void mouseMoved(MouseEvent e) {//鼠标移动
if(state == RUNNING) {
int x = e.getX();
int y = e.getY();
hero.moveTo(x, y);
}
}
public void mouseEntered(MouseEvent e){//鼠标进入
if(state == PAUSE){
state = RUNNING;
}
}
@Override
public void mouseExited(MouseEvent e) {//鼠标退出
if(state!=GAME_OVER&&state!=START){
state = PAUSE;//游戏装态不是GAMEOVER ,鼠标离开窗口 ,设置暂停
}
}
@Override
public void mouseClicked(MouseEvent mouseEvent) {
//鼠标点击事件
switch(state){
case START:
state = RUNNING;
break;
case GAME_OVER://当状态是结束的时候,点击鼠标,会重新初始化各个对象,状态变为开始
flyings = new PlaneObj[0];
bullets = new Cartridge[0];
hero = new MyPlane();
score = 0;
state = START;
}
}
};
this.addMouseListener(i);//处理鼠标点击事件
this.addMouseMotionListener(i);//处理鼠标滑动操作
//启动执行代码
java.util.Timer timer = new java.util.Timer();
timer.schedule(new TimerTask() {
public void run() {
if(state == RUNNING){
enterAction();//飞行物入场
stepAction();//飞行物走一步
shootAction();
bangAction();
isGameOver();
checkGameOverAction();//检查游戏结束
outOfBoundsAction();
}
repaint();//重绘,调用paint方法
}
}, intervel ,intervel);//10毫秒以后,每隔10毫秒执行一次
}
public static void main(String[] args){
JFrame frame = new JFrame("雷霆战机");//画框
Start game = new Start();
game.enemyspeedaction();
frame.add(game);
frame.setSize(WIDTH, HEIGHT);//窗口的大小
frame.setAlwaysOnTop(true);//窗口在最上边
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//点x关闭
frame.setLocationRelativeTo(null);//设置窗体的初始记录
frame.setVisible(true);//尽快调用paint方法
game.action();
}
}
PlaneObj.java(飞行父类)
package com.losen.plane;
import java.awt.image.BufferedImage;
/**
* 飞行抽象
* @author losen
* @version 1.0
* @DateTime 2023/6/28 13:11
*/
public abstract class PlaneObj {
protected int x;//x坐标
protected int y;//y坐标
protected int width;//宽
protected int height;//高
protected BufferedImage image;//图片
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public BufferedImage getImage() {
return image;
}
public void setImage(BufferedImage image) {
this.image = image;
}
public abstract void step();
public boolean shootBy(Cartridge bullet){
int x= bullet.x;
int y = bullet.y;
return this.x<x&&x<this.x+width&&this.y<y && y<this.y+height;
}
/**
* 检查是否出界
* @return
*/
public abstract boolean outOfBounds();//
/**
* 检测是否碰墙
*/
public abstract boolean hitColumn();
}
Cartridge.java(子弹)
package com.losen.plane;
/**
* 飞行子类:子弹
* @author losen
* @version 1.0
* @DateTime 2023/6/28 13:15
*/
public class Cartridge extends PlaneObj{
private int speed = 10;//移动速度
public Cartridge(int x,int y){
this.x = x;
this.y = y;
this.image = Start.bullet;
}
@Override
public void step() {
y -= speed;
}
@Override
public boolean outOfBounds() {
return y<-height;
}
@Override
public boolean hitColumn() {
return y<-height;
}
}
Enemy.java(敌人接口)
package com.losen.plane;
/**
* 敌人接口
* @author losen
* @version 1.0
* @DateTime 2023/6/28 13:25
*/
public interface Enemy {
int getScore();
}
EnemyPlane.java(敌方接口实现)
package com.losen.plane;
/**
* @author losen
* @version 1.0
* @DateTime 2023/6/28 13:25
*/
public class EnemyPlane extends PlaneObj implements Enemy{
private int speed = 2;//敌人飞机移动速度2
public EnemyPlane(){
this.image = Start.airplane;
width = image.getWidth();
height = image.getHeight();
y= -height;
x = (int)(Math.random()*(Start.WIDTH - width));
// x = 300;
// y = 190;
}
@Override
public int getScore() {
return 1;
}
@Override
public void step() {
y+=speed;
}
@Override
public boolean outOfBounds() {
return y>Start.HEIGHT;
}
@Override
public boolean hitColumn() {
return y>Start.HEIGHT;
}
}
MyPlane.java(己方飞机)
package com.losen.plane;
import java.awt.image.BufferedImage;
/**
* 己方飞机实体
* @author losen
* @version 1.0
* @DateTime 2023/6/28 13:09
*/
public class MyPlane extends PlaneObj{
BufferedImage[] images = {};
int index = 0;
private int doubleFire;//双倍火力的子弹数量
private int life;//命的数量
public MyPlane() {
life = 3;
doubleFire = 0;
this.image = Start.hero0;
images = new BufferedImage[]{Start.hero0, Start.hero1};
width = image.getWidth();
height = image.getHeight();
x = 150;
y = 400;
}
@Override
public void step() {
if (images.length > 0) {
image = images[index++ / 10%images.length];
}
}
@Override
public boolean outOfBounds() {
return false;
}
@Override//重写
public boolean hitColumn() {
return false;
}
//发射子弹
public Cartridge[] shoot() {
int xStep = width / 4;
int yStep = 10;
if (doubleFire > 0) {//双倍火力
Cartridge[] bullets = new Cartridge[3];//2
// bullets[0] = new Cartridge(x + 5* xStep, y + -8 * yStep);
bullets[0] = new Cartridge(x + 5 *xStep, y + -7 * yStep);
// bullets[2] = new Cartridge(x + 2 *xStep, y + -8 * yStep);
bullets[1] = new Cartridge(x + 2 *xStep, y + -7 * yStep);
// bullets[4] = new Cartridge(x + -1*xStep, y + -8 * yStep);
bullets[2] = new Cartridge(x + -1*xStep, y + -7 * yStep);
// doubleFire -= 2;
return bullets;
} else {
Cartridge[] bullets = new Cartridge[1];
bullets[0] = new Cartridge(x + 2 * xStep, y - yStep);
return bullets;
}
}
/**
*
* @param x:鼠标x坐标位置
* @param y;鼠标y坐标位置
*/
public void moveTo(int x, int y) {
this.x = x- width/2;//hero.x+width/2;
this.y = y - height/2;
}
public void addDoubleFire(){
doubleFire += 4; // 加强的子弹发数
}
public void addLife(){
life++;
}
//获取英雄鸡命数
public int getLife(){
return life;
}
// public boolean outOfBounds(){
// return false;
// }
//减命
public void subtractLife(){
life--;
}
//重新设计双倍火力值
public void setDoubleFire(int doubleFire){
this.doubleFire = doubleFire;
}
//碰撞的算法
public boolean hit(PlaneObj other){
int x1 = other.x - this.width/2 ;
int x2 = other.x + this.width/2 + this.width;
int y1 = other.y - this.height/2 ;
int y2 = other.y + other.height + other.height/2;
return this.x + this.width/2>x1
&&this.x+this.width/2<x2
&&this.y+this.height/2>y1
&&this.y+this.height/2<y2;
}
}
PrizeContent.java(奖励接口)
package com.losen.plane;
/**
* 奖励内容
* @author losen
* @version 1.0
* @DateTime 2023/6/28 13:26
*/
public interface PrizeContent {
int DOUBLE_FIRE = 0;//双倍火力
int LIFE = 1;//一条命
/**
* 获得奖励的类型为上面的0或者1
* @return
*/
int getType();
}
Prize.java(奖励接口实现)
package com.losen.plane;
import java.util.Random;
/**
* 奖励实体
* @author losen
* @version 1.0
* @DateTime 2023/6/28 13:17
*/
public class Prize extends PlaneObj implements PrizeContent{
private int xSpeed = 1;//x坐标的移动速度
private int ySpeed = 2;//y坐标的移动速度
private int awardType;//奖励类型
public Prize(){
this.image = Start.bee;
width = image.getWidth();
height = image.getHeight();
y = - height;
//y = 200;
x= (int)Math.random()*(Start.WIDTH - width);
Random r =new Random();
//int x = r.nextInt(Start.WIDTH - width);
//x = 100;
awardType = r.nextInt(2);
}
@Override
public int getType() {//奖励类型
return awardType;
}
@Override
public void step() {
x+= xSpeed;
y+= ySpeed;
if(x>Start.WIDTH - width){
xSpeed = -1;
}
if(x<0){
xSpeed = 1;
}
}
@Override
public boolean outOfBounds() {
return y>Start.HEIGHT;
}
@Override
public boolean hitColumn() {
return false;
}
}
ps:图片素材可以去阿里巴巴矢量图标库自行搜索获取,搜索词(子弹:下拉、飞机:飞机、奖励:收藏、开始、暂停、游戏结束)