闲来无事,跟着教程做了个飞机游戏小项目。话不多说,直接上代码(备注:文章最后有图片资源)
定义一些常量
public class Constant {
public static final int GAME_FRAME_WIDTH = 900;
public static final int GAME_FRAME_HEIGHT = 900;
public static final int GAME_PLANE_WIDTH = 22;
public static final int GAME_PLANE_HEIGHT = 33;
}
工具类:GameUtil.java
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
public class GameUtil {
// 将工具类的构造器私有化
private GameUtil() {
}
public static Image getImage(String path) {
BufferedImage bImage = null;
try {
URL url = GameUtil.class.getClassLoader().getResource(path);
bImage = ImageIO.read(url);
} catch (Exception e) {
e.printStackTrace();
}
return bImage;
}
}
游戏物体的父类:GameObject.java
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
/*
* 游戏物体的父类
*/
public class GameObject {
Image img; // 图片
double x, y; // 坐标
int speed; // 速度
int width; // 宽
int height; // 高
public void dramSelf(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 getRectangle() {
return new Rectangle((int) x, (int) y, width, height);
}
}
飞机类:Plane.java
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
/*
* 飞机类
*/
public class Plane extends GameObject {
boolean left, right, up, down;
boolean live = true;
public void dramSelf(Graphics g) {
if (live) {
g.drawImage(img, (int) x, (int) y, null);
if (left) {
x -= speed;
}
if (right) {
x += speed;
}
if (up) {
y -= speed;
}
if (down) {
y += speed;
}
} else {
}
}
public Plane(Image image, double x, double y) {
this.img = image;
this.x = x;
this.y = y;
this.speed = 8;
this.width = Constant.GAME_PLANE_WIDTH;
this.height = Constant.GAME_PLANE_HEIGHT;
}
// 按下某个键位 增加方向
public void addDirection(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT: // 左 ←
left = true;
break;
case KeyEvent.VK_UP: // 上 ↑
up = true;
break;
case KeyEvent.VK_RIGHT: // 右 →
right = true;
break;
case KeyEvent.VK_DOWN: // 下 ↓
down = true;
break;
default:
break;
}
}
// 抬起按下某个键位 取消方向
public void minusDirection(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT: // 左 ←
left = false;
break;
case KeyEvent.VK_UP: // 上 ↑
up = false;
break;
case KeyEvent.VK_RIGHT: // 右 →
right = false;
break;
case KeyEvent.VK_DOWN: // 下 ↓
down = false;
break;
default:
break;
}
}
}
炮弹类:Shell.java
import java.awt.Color;
import java.awt.Graphics;
/*
* 炮弹类
*/
public class Shell extends GameObject {
double degree; // 弧度 0~2π
public Shell() {
x = 200; //初始位置
y = 300; //初始位置
width = 10;
height = 10;
speed = 6;
degree = Math.random() * Math.PI * 2;
}
public void dram(Graphics g) {
Color color = g.getColor();
g.setColor(Color.RED);
g.fillOval((int) x, (int) y, width, height);// 填充一个炮弹出来
// 任意角度飞行
x += speed * Math.cos(degree);
y += speed * Math.sin(degree);
// 边界反弹
if (x < 0 + width || x > Constant.GAME_FRAME_WIDTH - width) {
degree = Math.PI - degree;
}
if (y < 0 + 30 + height || y > Constant.GAME_FRAME_HEIGHT - height) {
degree = -degree;
}
g.setColor(color);
}
}
爆炸类:Explode.java
import java.awt.Graphics;
import java.awt.Image;
/*
* 爆炸类
*/
public class Explode {
double x, y;
static Image[] images = new Image[16];
static {
for (int i = 0; i < images.length; i++) {
images[i] = GameUtil.getImage("explode/e" + (i + 1) + ".gif");
images[i].getWidth(null);
}
}
int count;
public void draw(Graphics g) {
if (count <= 15) {
g.drawImage(images[count], (int) x, (int) y, null);
count++;
}
}
// 死亡的位置进行爆炸
public Explode(double x, double y) {
this.x = x;
this.y = y;
}
}
游戏主窗口类:MyGameFrame.java
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Date;
/**
* 主窗口
*
* @author Administrator
*
*/
public class MyGameFrame extends Frame {
private static final long serialVersionUID = 1L;
Image planImage = GameUtil.getImage("images/plane.png");
Image bgImage = GameUtil.getImage("images/bg.jpg");
Plane plane = new Plane(planImage, 450, 800);
Shell[] shells = new Shell[20];
Explode explode;
Date startTime = new Date();
Date endTime;
int period;
/*
* 初始化窗口【1】
*/
public void launchFrame() {
this.setTitle("天天打飞机(腾讯天美游戏) 作者:DoubleShift");
this.setSize(Constant.GAME_FRAME_WIDTH, Constant.GAME_FRAME_HEIGHT);
this.setLocation(600, 100);
this.setVisible(true);
// 关闭游戏窗口监听
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
// 启动重画窗口的线程【3】
new PaintThread().start();
// 给窗口增加键盘的监听【4】
addKeyListener(new KeyMonitor());
// 初始化炮弹【5】
for (int i = 0; i < shells.length; i++) {
shells[i] = new Shell();
}
}
// 窗口绘制【2】
// 该方法自动被调用,无需手动调用
@Override
public void paint(Graphics g) {
Color beginColor = g.getColor();
g.drawImage(bgImage, 0, 0, null);
plane.dramSelf(g); // 画飞机
// 画炮弹
for (int i = 0; i < shells.length; i++) {
shells[i].dram(g);
// 判断炮弹和飞机的碰撞【7】
boolean peng = shells[i].getRectangle().intersects(plane.getRectangle());
if (peng) {
System.out.println("Game Over !!!");
plane.live = false;
// 检测飞机和炮弹碰撞后产生爆炸【8】
if (explode == null) {
explode = new Explode(plane.x, plane.y);
// 计算游戏时间
endTime = new Date();
period = (int) ((endTime.getTime() - startTime.getTime()) / 1000);
}
explode.draw(g);
}
// 计算游戏时间输出到屏幕上 【9】
if (!plane.live) {
g.setColor(Color.BLUE);
g.setFont(new Font("微软雅黑", Font.BOLD, 50));
g.drawString("游戏时间:" + period + "秒", (int) plane.x, (int) plane.y);
}
}
g.setColor(beginColor);
}
// 内部类 反复重画窗口实现动态展示
class PaintThread extends Thread {
@Override
public void run() {
while (true) {
// System.out.println("窗口重画一次");
repaint(); // 重画
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 内部类 键盘监听【4】
class KeyMonitor extends KeyAdapter {
// 键盘按下
@Override
public void keyPressed(KeyEvent e) {
plane.addDirection(e);
}
// 键盘松开
@Override
public void keyReleased(KeyEvent e) {
plane.minusDirection(e);
}
}
private Image offScreenImage = null;
// 双缓冲解决闪烁问题【6】
public void update(Graphics g) {
if (offScreenImage == null) {
offScreenImage = this.createImage(Constant.GAME_FRAME_WIDTH, Constant.GAME_FRAME_HEIGHT);
}
Graphics gOff = offScreenImage.getGraphics();
paint(gOff);
g.drawImage(offScreenImage, 0, 0, null);
}
public static void main(String[] args) {
MyGameFrame gameFrame = new MyGameFrame();
gameFrame.launchFrame();
}
}
游戏效果: