1 package cn.xiaocangtian.Util; 2 3 import java.awt.Frame; 4 import java.awt.Graphics; 5 import java.awt.Image; 6 import java.awt.event.WindowAdapter; 7 import java.awt.event.WindowEvent; 8 9 10 public class MyFrame extends Frame { 11 12 //加载窗口 13 public void launchFrame() { 14 setSize(Constant.GAME_WIDTH, Constant.GAME_HEIGHT); //设置窗口大小 15 setLocation(100, 100); //设置左上角坐标,开始位置, 也就是窗口开始位置 16 setVisible(true); //设置为可见(默认为不可见) 17 18 //启动重画线程 19 new PaintThread().start(); 20 21 //匿名内部类---用来关闭窗口 22 addWindowListener(new WindowAdapter() { 23 @Override 24 public void windowClosing(WindowEvent e) { 25 System.exit(0); 26 } 27 }); 28 29 } 30 31 //双缓冲技术解决屏幕闪烁 32 private Image offScreenImage = null; //利用双缓冲技术消除闪烁 33 public void update(Graphics g) { 34 if (offScreenImage == null) 35 offScreenImage = this.createImage(Constant.GAME_WIDTH, Constant.GAME_HEIGHT); 36 37 Graphics gOff = offScreenImage.getGraphics(); 38 39 paint(gOff); 40 g.drawImage(offScreenImage, 0, 0, null); 41 } 42 43 /** 44 * 定义一个重画窗口的线程类 45 * 是一个内部类(方便访问外部类属性) 46 */ 47 class PaintThread extends Thread { 48 public void run() { 49 while (true) { 50 repaint(); //重画 51 try { 52 Thread.sleep(40); //1s = 1000ms 53 } catch (InterruptedException e) { 54 e.printStackTrace(); 55 } 56 } 57 } 58 } 59 60 }
1 package cn.xiaocangtian.Util; 2 3 import java.awt.Image; 4 import java.awt.Toolkit; 5 import java.awt.image.BufferedImage; 6 import java.io.IOException; 7 import java.net.URL; 8 9 import javax.imageio.ImageIO; 10 import javax.swing.ImageIcon; 11 12 /** 13 * 游戏开发中常用的工具类(比如:加载图片等方法) 14 * @author admin 15 * 16 */ 17 public class GameUtil { 18 19 private GameUtil () {} //工具类通常将构造方法私有 20 21 public static Image getImage(String path) { 22 // return Toolkit.getDefaultToolkit().getImage(GameUtil.class.getClassLoader().getResource(path)); 23 BufferedImage bi = null; 24 try { 25 URL u = GameUtil.class.getClassLoader().getResource(path); 26 bi = javax.imageio.ImageIO.read(u); 27 } catch (IOException e) { 28 // TODO Auto-generated catch block 29 e.printStackTrace(); 30 } 31 return bi; 32 } 33 }
1 package cn.xiaocangtian.Util; 2 3 /** 4 * 游戏项目中用到的常量 5 * 单独负责常量 6 * @author admin 7 */ 8 public class Constant { 9 10 public static final int GAME_WIDTH = 350; 11 public static final int GAME_HEIGHT = 600; 12 13 }
//以上是常用工具
//下面实现游戏功能
1 package cn.xiaocangtian.plane; 2 3 import java.awt.Image; 4 import java.awt.Rectangle; 5 6 /** 7 * 让 plane, Bullet继承之 8 * @author admin 9 * 10 */ 11 public class GameObject { 12 Image img; 13 double x, y; 14 int speed = 5; 15 16 int width, height; 17 18 //获取飞机所在矩形 19 public Rectangle getRect() { 20 return new Rectangle((int)x, (int)y, width, height); 21 } 22 23 public GameObject(Image img, double x, double y, int speed, int width, 24 int height) { 25 super(); 26 this.img = img; 27 this.x = x; 28 this.y = y; 29 this.speed = speed; 30 this.width = width; 31 this.height = height; 32 } 33 34 public GameObject() {} 35 36 }
1 package cn.xiaocangtian.plane; 2 3 import java.awt.Graphics; 4 import java.awt.Image; 5 import java.awt.Rectangle; 6 import java.awt.event.KeyEvent; 7 8 import cn.xiaocangtian.Util.GameUtil; 9 10 public class Plane extends GameObject { 11 12 private boolean left, up, right, down; 13 private boolean live = true; 14 15 public void draw(Graphics g) { 16 if (live) { 17 g.drawImage(img, (int)x, (int)y, null); 18 move(); 19 } 20 } 21 22 //根据方向来改变坐标位置 23 public void addDirection(KeyEvent e) { 24 switch (e.getKeyCode()) { 25 case KeyEvent.VK_LEFT: //左 26 left = true; break; 27 case KeyEvent.VK_UP: //上 28 up = true; break; 29 case KeyEvent.VK_RIGHT: //右 30 right = true; break; 31 case KeyEvent.VK_DOWN: //下 32 down = true; break; 33 default: break; 34 } 35 } 36 37 public void minusDirection(KeyEvent e) { 38 switch (e.getKeyCode()) { 39 case KeyEvent.VK_LEFT: //左 40 left = false; break; 41 case KeyEvent.VK_UP: //上 42 up = false; break; 43 case KeyEvent.VK_RIGHT: //右 44 right = false; break; 45 case KeyEvent.VK_DOWN: //下 46 down = false; break; 47 default: break; 48 } 49 } 50 51 52 public void move() { 53 if (left) { 54 x -= speed; 55 } 56 if (right) { 57 x += speed; 58 } 59 if (up) { 60 y -= speed; 61 } 62 if (down) { 63 y += speed; 64 } 65 } 66 67 public Plane(String imgpath, double x, double y) { 68 this.img = GameUtil.getImage(imgpath); 69 this.width = img.getWidth(null); 70 this.height = img.getHeight(null); 71 this.x = x; 72 this.y = y; 73 } 74 75 //无参构造器 76 public Plane() {} 77 78 public void setLive(boolean live) { 79 this.live = live; 80 } 81 82 public boolean isLive() { 83 return live; 84 } 85 86 87 88 89 90 91 }
1 package cn.xiaocangtian.plane; 2 3 import java.awt.Color; 4 import java.awt.Graphics; 5 import java.awt.Image; 6 import java.awt.Rectangle; 7 8 import cn.xiaocangtian.Util.Constant; 9 10 public class Bullet extends GameObject { 11 12 double degree; 13 14 public Bullet() { 15 degree = Math.random() * Math.PI * 2; 16 x = Constant.GAME_WIDTH / 2; //设置子弹发射位置 17 y = Constant.GAME_HEIGHT / 2; 18 width = 10; 19 height = 10; 20 } 21 22 //获取子弹矩形 23 public Rectangle getRect() { 24 return new Rectangle((int)x, (int)y, width, height); 25 } 26 27 public void draw(Graphics g) { 28 Color oldColor = g.getColor(); 29 //画一个子弹 30 g.setColor(Color.yellow); 31 g.fillOval((int)x, (int)y, width, height); 32 33 x += speed * Math.cos(degree); 34 y += speed * Math.sin(degree); 35 36 //使子弹遇到窗口边缘反弹 37 if (y > Constant.GAME_HEIGHT - height || y < 30) { 38 degree = -degree; 39 } 40 if (x < 0 || x > Constant.GAME_WIDTH - width) { 41 degree = Math.PI - degree; 42 } 43 44 g.setColor(oldColor); 45 46 } 47 48 }
1 package cn.xiaocangtian.plane; 2 3 import java.awt.Graphics; 4 import java.awt.Image; 5 6 import cn.xiaocangtian.Util.GameUtil; 7 8 /** 9 * 爆炸类 10 * @author admin 11 */ 12 public class Explode { 13 double x, y; 14 15 //一堆图片,直接用static,只加载一遍,所有爆炸对象共享 16 static Image[] imgs = new Image[10]; 17 int count; //imgs数量 18 19 //加载图片 20 static { //利用static方法改写static对象 21 for (int i = 0; i < 10; i++) { 22 imgs[i] = GameUtil.getImage("images/explode/e" + i + ".png"); 23 imgs[i].getWidth(null); //可真实的将image加载进来 24 } 25 } 26 27 //爆炸行为 就是 数组图片的切换 28 public void draw(Graphics g) { 29 if (count < 10) { 30 g.drawImage(imgs[count], (int)x, (int)y, null); 31 count++; 32 } 33 } 34 35 public Explode(double x, double y) { 36 this.x = x; 37 this.y = y; 38 } 39 40 }
1 package cn.xiaocangtian.plane; 2 3 import java.awt.Color; 4 import java.awt.Font; 5 import java.awt.Graphics; 6 import java.awt.Image; 7 import java.awt.event.KeyAdapter; 8 import java.awt.event.KeyEvent; 9 import java.util.ArrayList; 10 import java.util.Date; 11 12 import cn.xiaocangtian.Util.Constant; 13 import cn.xiaocangtian.Util.GameUtil; 14 import cn.xiaocangtian.Util.MyFrame; 15 16 public class PlaneGameFrame extends MyFrame { 17 Image bg = GameUtil.getImage("images/bg.png"); 18 19 Plane p = new Plane("images/plane.png", 50, 50); 20 21 //容器(泛型未学,暂时不加) 22 ArrayList bulletList = new ArrayList(); 23 24 Date startTime; 25 Date endTime; 26 27 Explode boom; 28 29 public void paint(Graphics g) { 30 g.drawImage(bg, 0, 0, null); 31 p.draw(g); 32 33 //在这里画子弹 34 for (int i = 0; i < bulletList.size(); i++) { 35 Bullet b = (Bullet)bulletList.get(i); 36 b.draw(g); 37 //检测跟飞机的碰撞 38 boolean peng = b.getRect().intersects(p.getRect()); 39 if (peng) { 40 p.setLive(false); //飞机死掉 41 if (boom == null) { //都只执行一次 42 endTime = new Date(); 43 boom = new Explode(p.x, p.y); 44 } 45 boom.draw(g); 46 47 break; 48 } 49 } 50 51 if (!p.isLive()) { 52 int period = ((int)endTime.getTime() - (int)startTime.getTime()) / 1000; //转换成秒 53 printInfo(g, "时间: " + period + "秒", 20, 115, 300, Color.white); 54 55 switch (period / 10) { 56 case 0: 57 case 1: 58 printInfo(g, "菜鸟", 40, 115, 270, Color.white); 59 break; 60 case 2: 61 printInfo(g, "入门", 40, 115, 270, Color.yellow); 62 break; 63 case 4: 64 printInfo(g, "精通", 40, 115, 270, Color.white); 65 break; 66 case 5: 67 printInfo(g, "大师", 40, 115, 270, Color.white); 68 break; 69 } 70 } 71 // printInfo(g, "分数: 100", 10, 50, 50, Color.yellow); 72 73 } 74 75 /** 76 * 在窗口 上打印信息 77 * @param g 78 * @param str 79 * @param size 80 */ 81 public void printInfo(Graphics g, String str, int size, int x, int y, Color color) { 82 Color c = g.getColor(); 83 g.setColor(color); 84 Font f = new Font("宋体", Font.BOLD, size); 85 g.setFont(f); 86 g.drawString(str, x, y); 87 g.setColor(c); 88 } 89 90 //重写父类的 launchFrame() 91 public void launchFrame() { 92 super.launchFrame(); 93 //增加键盘的监听 94 addKeyListener(new KeyMonitor()); 95 //应该在加载窗口的时候生成子弹 96 for (int i = 0; i < 10; i++) { 97 Bullet b = new Bullet(); 98 bulletList.add(b); 99 } 100 101 startTime = new Date(); //从启动窗口开始计时 102 } 103 104 //定义成内部类,可以方便使用外部类的普通属性 105 //键盘适配器 106 //定义完需要注册,然后才能用(在父类的launchFrame中注册,这里需要在 107 //子类中重写launchFrame,如上) 108 class KeyMonitor extends KeyAdapter { 109 110 @Override 111 public void keyPressed(KeyEvent e) { 112 p.addDirection(e); 113 } 114 115 @Override 116 public void keyReleased(KeyEvent e) { 117 p.minusDirection(e); 118 } 119 120 } 121 122 123 public static void main(String[] args) { 124 new PlaneGameFrame().launchFrame(); 125 } 126 }