MyGameFrame类:
主要的调用类
package sc.wh.game;import javax.swing.JFrame;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import sc.wh.game.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Date;public class MyGameFrame extends Frame {// 调用工具类的getImage方法加载图片对象Image planeImg = GameUtil.getImage("images/plane.png");Image bg = GameUtil.getImage("images/bg.jpg");// 创建飞机,设置初始位置Plane plane = new Plane(planeImg,250,250);// 创建炮弹组Shell shells[] = new Shell[50];// 设置爆炸效果类的对象的引用Explode bao;// 游戏开始时间Date startTime = new Date();// 游戏结束时间Date endTime;// 游戏进行的时间int period;// 记录爆炸效果显示的图片int BaoCount = 0;// 在窗口画图方法,由repaint方法自动调用@Overridepublic void paint(Graphics g) { // 会自动被调用,g相当于一支画笔Color c = g.getColor();// 画背景g.drawImage(bg,0,0,null);// 调用飞机类的画图方法并画飞机plane.drawSelf(g);// 画炮弹组中的炮弹for (int i=0;i<shells.length;i++) {// 调用炮弹对象的draw方法shells[i].draw(g);// 获取炮弹所在矩形位置并调用intersects判断两矩形是否相交boolean peng = shells[i].getRect().intersects(plane.getRect());if(peng) {// 如果相交则设置飞机存活状态为falseplane.live = false;// 如果bao对象没有初始化过则才初始化if(bao == null) {bao = new Explode(plane.x, plane.y);endTime = new Date();period = (int)(endTime.getTime() - startTime.getTime())/1000;}if(BaoCount <= 15) {// 调用爆炸效果显示类的画图方法,每次调用只画一张图bao.draw(g);BaoCount++;}}// 如果飞机未存活则显示游戏时间if(!plane.live) {// 创建字体对象Font f = new Font("宋体",Font.BOLD,50);// 设置字体g.setFont(f);// 设置字体颜色g.setColor(Color.RED);// 显示游戏结束时间g.drawString("游戏时间:" + period + "秒", 100, 250);}}g.setColor(c);}// 继承Thread线程类class PaintThread extends Thread{// 线程开始后会自动调用run方法@Overridepublic void run() {while (true) {// 调用repaint窗口画图方法,此方法会自动调用paint方法repaint(); try {// 控制一秒25次在窗口画图的方法Thread.sleep(40);} catch (InterruptedException e) {e.printStackTrace();}}}}// 创建键盘检测内部类,并继承键盘监听类class KeyMonitor extends KeyAdapter{// 检测键盘按下事件,调用飞机类对应的方法@Overridepublic void keyPressed(KeyEvent e) {// KeyEvent键盘检测类plane.addDirection(e);}// 检测键盘释放事件,调用飞机类对应的方法@Overridepublic void keyReleased(KeyEvent e) {plane.minusDirection(e);}}// 双缓冲解决闪烁private Image offScreenImage = null;public void update(Graphics g) {if(offScreenImage == null)offScreenImage = this.createImage(Constants.WIDTH,Constants.HEIGHT);//这是游戏窗口的宽度和高度Graphics gOff = offScreenImage.getGraphics();paint(gOff);g.drawImage(offScreenImage, 0, 0, null);} public void launchFrame(){// 标题this.setTitle("game fly");// 窗口默认不可见this.setVisible(true);// 窗口大小this.setSize(Constants.WIDTH,Constants.HEIGHT);// 窗口距离左上角的坐标位置this.setLocation(300,300);//增加关闭窗口监听,这样用户点击右上角关闭图标,可以关闭游戏程序this.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e){System.exit(0);}});// 创建在窗口中画图线程并调用new PaintThread().start();// 将KeyMonitor类的对象加入键盘监控检测,对应的事件会自动调用此类对应的方法addKeyListener(new KeyMonitor());// 创建炮弹,加入炮弹数组for(int i=0;i<shells.length;i++) {shells[i] = new Shell();}}public static void main(String[] args) {MyGameFrame f = new MyGameFrame();// 调用画窗口方法f.launchFrame();}
}
工具类(用来获取图片对象):
package sc.wh.game;import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;public class GameUtil {// 工具类最好将构造器私有化。private GameUtil() {} public static Image getImage(String path) {BufferedImage bi = null;try {URL u = GameUtil.class.getClassLoader().getResource(path);bi = ImageIO.read(u);} catch (IOException e) {e.printStackTrace();}return bi;}
}
用来存储常量的类:
package sc.wh.game;public class Constants {public static int WIDTH = 500;public static int HEIGHT = 500;
}
所有游戏对象的父类:
package sc.wh.game;import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;// 游戏父类
public class GameObject {Image img; // 创建img对象double x,y; // 坐标int speed; // 速度int width,height; // 宽高// 画图方法public void drawSelf(Graphics g) {g.drawImage(img,(int)x,(int)y, null);}// 构造方法public GameObject(Image img, double x, double y, int speed, int width, int height) {super();this.img = img;this.x = x;this.y = y;this.speed = speed;this.width = width;this.height = height;}public GameObject(Image img, double x, double y) {super();this.img = img;this.x = x;this.y = y;}public GameObject() {}// 根据物体所在位置和宽度高度,返回物体所在的矩形,便与后续的碰撞检测public Rectangle getRect() {return new Rectangle((int)x,(int)y,width,height);}}
飞机类:
package sc.wh.game;import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;// 飞机类,继承自游戏类,拥有游戏类对应的方法和属性
public class Plane extends GameObject{// 当有键盘事件时,判断飞机移动的方向boolean left,right,up,down;// 飞机移动的速度int speed = 5;// 用于判断飞机是否存活boolean live = true;// 画飞机的方法,可根据键盘事件设置(left,right...)布尔值实时调整飞机位置public void drawSelf(Graphics g) {// 如果飞机存活,才调用画图方法if(live) {if(right) {x += speed;}if(left) {x -= speed;}if (up) {y -= speed;}if(down) {y += speed;}if (x<=0) {x = 0;}else if(x >= 460) {x = 460;}if(y <= 40) {y = 40;}else if(y >= 470) {y = 470;}// 根据位置画图g.drawImage(img,(int)x,(int)y, null);}}// 构造方法public Plane(Image img,double x, double y) {this.img = img;this.x = x;this.y = y;// 根据img对象的get..方法获取图片大小,用于矩形实现碰撞检测this.width = img.getWidth(null);this.height = img.getHeight(null);}// 键盘按下时,会调用此方法来设置移动的方向public void addDirection(KeyEvent e) {// getKeyCode可以获取按下键盘对应特定的值switch (e.getKeyCode()) {case KeyEvent.VK_LEFT:left = true;break;case KeyEvent.VK_RIGHT:right = true;break;case KeyEvent.VK_UP:up = true;break;case KeyEvent.VK_DOWN:down = true;break;} }// 键盘松开时,会调用此方法来设置取消移动的方向public void minusDirection(KeyEvent e) {// getKeyCode可以获取按下键盘对应特定的值switch (e.getKeyCode()) {case KeyEvent.VK_LEFT:left = false;break;case KeyEvent.VK_RIGHT:right = false;break;case KeyEvent.VK_UP:up = false;break;case KeyEvent.VK_DOWN:down = false;break;} }
}
炮弹类:
package sc.wh.game;import java.awt.Color;
import java.awt.Graphics;// 炮弹类
public class Shell extends GameObject{double degree; // 炮弹移动角度// 构造方法public Shell() {x = 200; // 设置炮弹的初始位置y = 200;width = 10; // 设置炮弹的大小height = 10;speed = 3; // 设置炮弹的速度degree = Math.random() * Math.PI * 2; // 随机设置炮弹的初始角度}// 画炮弹的方法public void draw(Graphics g) {Color c = g.getColor();g.setColor(Color.YELLOW); // 设置颜色if(x <= 0|| x >= Constants.WIDTH-width-10) {degree = Math.PI - degree; // 当碰撞水平地图边界后,反转角度}if(y<=40 || y >= Constants.HEIGHT-height) {degree = -degree; // 当碰撞垂直地图后,反转角度}// 填充一个圆作为炮弹g.fillOval((int)x, (int)y, width, height);// 根据角度设置炮弹移动的位置x += speed*Math.cos(degree);y += speed*Math.sin(degree);g.setColor(c);}}
显示爆炸效果的类:
package sc.wh.game;import java.awt.Graphics;
import java.awt.Image;public class Explode {// 记录爆炸位置double x,y;// 创建爆炸数组,static保证图片只加载一次static Image[] imgs = new Image[16];// 静态初始化块,初始化类的时候会自动调用static {for(int i=0;i<16;i++){// 挨个将爆炸图片对象获取到,并加入数组imgs[i] = GameUtil.getImage("images/explode/e"+(i+1)+".gif");imgs[i].getWidth(null);}}// 用来记录当前加载的图片int count;// 画爆炸效果public void draw(Graphics g){if(count<=15){// 轮播逐个画爆炸的图片g.drawImage(imgs[count], (int)x, (int)y, null);count++;}}// 构造方法设置爆炸位置public Explode(double x,double y){this.x = x;this.y = y;}
}
游戏效果图