Java小游戏之打飞机(二)
2015-08-11 23:11
423 查看
Java小游戏之打飞机(二)
这篇文章本应昨天写的,可是真打算写的时候,CSDN博客维护,导致拖到了今天:
在上篇文章Java小游戏之打飞机(一)中已经详细介绍了该游戏的基本架构和需求分析,今天就详细写一写具体每个类的实现:
1)PlaneGameFrame类 ----游戏的主界面以及一些具体的飞机动作方法、碰撞检测等
代码:
2)MyFrame类 ----PlaneGameFrame类的父类,主要是一些有关界面的基本属性及方法的封装,便于游戏的扩充
代码:
3)Constant类 ----常量类,主要封装了项目中用到的常量
代码:
4)GameUtil类 ----游戏的工具类,用于封装游戏中常用的工具方法,由于项目比较小,这里只是封装了一个加载图片的方法,后续可以封装更多的方法
代码:
5)GameObject类 ----游戏物体类,封装了游戏物体基本的属性和方法,如图片,坐标,图片宽度高度等属性,还有一个比较重要的方法public Rectangle getRect()这个方法用于后来的碰撞检测
代码:
6)Plane类 ----继承至GameObject类,封装了飞机移动的方法(键盘事件)
代码:
7)Bullet类 ----子弹类,继承至GameObject类,封装了子弹的基本属性与方法,有个重要的关于子弹碰到墙壁反弹的实现
代码:
8)Explode类 ----爆炸类,主要用于子弹击中飞机时的爆炸效果的实现,即一系列爆炸的图片的加载与画在面板上
代码:
----------------------------------------------------------------------------------
自此,项目中所有的类的源码及大致解释已经结束,下面将详细说说其中的重要方法以及我遇到的困难:
1.碰撞检测-----子弹与飞机碰撞
游戏中的碰撞检测一般都是检测两个物体所在的矩形是否相交?如果相交则碰撞否则没有
首先介绍一个创建矩形的方法:
public Rectangle getRect(){
Rectangle r = new Rectangle((int)x, (int)y, width, height);
return r;
}
这个方法主要用来返回一个矩形,根据坐标和长宽创建一个矩形对象
然后介绍一个检测矩形相交的方法:
boolean java.awt.Rectangle.intersects(Rectangle r)
如果两矩形相交,则返回true,否则返回false
2.如何让子弹碰到墙壁反弹回来:
if(y>Constant.GAME_HEIGHT-height-40||y<0){
degree = -degree;
}
if(x<0||x>Constant.GAME_WIDTH-width-width){
degree = Math.PI-degree;
}
degree表示子弹运行的角度,x、y表示子弹的坐标,Constant.GAME_HEIGHT表示游戏面板高度、Constant.GAME_WIDTH表示游戏面板宽度,height表示子弹的高度、width子弹的宽度
3.关于键盘事件不响应的原因:
Panel中的键盘事件会默认获得焦点,而JPanel中获得焦点默认是false,需手动设为true,否则不响应键盘事件
在newJFrame时手动加上setFocusable(true);这句就ok
自此,整个游戏结束,欢迎共同学习与指正!!!
这篇文章本应昨天写的,可是真打算写的时候,CSDN博客维护,导致拖到了今天:
在上篇文章Java小游戏之打飞机(一)中已经详细介绍了该游戏的基本架构和需求分析,今天就详细写一写具体每个类的实现:
1)PlaneGameFrame类 ----游戏的主界面以及一些具体的飞机动作方法、碰撞检测等
代码:
package plane; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Image; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Date; import util.GameUtil; import util.MyFrame; /** * 飞机游戏主页面 * 继承至util包下的MyFrame类 * @author long * */ public class PlaneGameFrame extends MyFrame { Image bg=GameUtil.getImage("images/bg.jpg"); Plane p=new Plane("images/plane.png",50,50); int bulletNum = 10; ArrayList list = new ArrayList<Bullet>(); Explode e = null; //Explode e = new Explode(30, 30); Date startTime; Date endTime; @Override public void paint(Graphics g) { g.drawImage(bg, 0, 0, null); if(p.isLive){ p.draw(g); drawBullet(g); endTime=new Date(); printTime(g); }else{ e.draw(g); printInfo(lever(),180,200,50,Color.YELLOW,g); printInfo("总用时:"+getTime()+"s",180,240,20,Color.YELLOW,g); } } public void printTime(Graphics g){ double t = getTime(); if(t>0){ printInfo("Time:"+t+"s",390,50,15,Color.YELLOW,g); } } public double getTime(){ double time; int t=(int)(endTime.getTime()-startTime.getTime())/100; System.out.println("time:"+t); time = t/10.0; if(t<0.2) return 0; return time; } public String lever(){ String msg=""; int lever = (int)getTime()/10; switch (lever) { case 0: msg = "菜鸟"; break; case 1: msg = "小鸟"; break; case 2: msg = "大鸟"; break; case 3: msg = "鸟王子"; break; default: msg = "鸟神"; break; } return msg; } public void drawBullet(Graphics g){ for(int i=0;i<bulletNum;i++){ Bullet b=(Bullet) list.get(i); b.draw(g); boolean peng = b.getRect().intersects(p.getRect()); if(peng){ p.isLive = false; if(e==null){ e=new Explode(p.x, p.y); } //e.draw(g); //printInfo("GAME OVER",150,300,50,Color.YELLOW,g); break; } } } public void printInfo(String str,int x,int y,int size,Color color,Graphics g){ Color c = g.getColor(); g.setColor(color); Font f = new Font("楷体",Font.BOLD,size); g.setFont(f); g.drawString(str, x, y); g.setColor(c); } public void launchFrame(){ super.launchFrame(); this.addKeyListener(new KeyMonitor()); for(int i=0;i<bulletNum;i++){ Bullet b=new Bullet(); list.add(b); } startTime = new Date(); } class KeyMonitor extends KeyAdapter{ @Override public void keyPressed(KeyEvent e) { //System.out.println("##########"); //System.out.println(e.getKeyCode()); p.addMove(e); } @Override public void keyReleased(KeyEvent e) { p.reliseMove(e); } } public static void main(String[] args) { new PlaneGameFrame().launchFrame(); } }
2)MyFrame类 ----PlaneGameFrame类的父类,主要是一些有关界面的基本属性及方法的封装,便于游戏的扩充
代码:
package util; import javax.swing.JFrame; import javax.swing.JPanel; /** * 游戏面板的父类 * @author long * */ public class MyFrame extends JPanel{ /** * 加载Frame的方法 */ public void launchFrame(){ JFrame frame = new JFrame("MyGame"); frame.add(this); frame.setSize(Constant.GAME_WIDTH,Constant.GAME_HEIGHT); frame.setAlwaysOnTop(true); // 设置其总在最上 frame.setLocationRelativeTo(null); // 设置窗体初始位置 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); setFocusable(true); new PaintThread().start(); } /** * 定义一个重画窗口的线程类,是一个内部类 * @author dell * */ class PaintThread extends Thread { public void run(){ while(true){ repaint(); try { Thread.sleep(40); //1s = 1000ms } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { new MyFrame().launchFrame(); } }
3)Constant类 ----常量类,主要封装了项目中用到的常量
代码:
package util; public class Constant { public static final int GAME_WIDTH = 500; public static final int GAME_HEIGHT = 500; }
4)GameUtil类 ----游戏的工具类,用于封装游戏中常用的工具方法,由于项目比较小,这里只是封装了一个加载图片的方法,后续可以封装更多的方法
代码:
package util; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URL; import javax.imageio.ImageIO; /** * 工具类(加载图片) * @author long * */ public class GameUtil { private GameUtil(){ } //工具类通常将构造方法私有 public static Image getImage(String path){ URL u = GameUtil.class.getClassLoader().getResource(path); BufferedImage img = null; try { img = ImageIO.read(u); } catch (IOException e) { e.printStackTrace(); } return img; } }
5)GameObject类 ----游戏物体类,封装了游戏物体基本的属性和方法,如图片,坐标,图片宽度高度等属性,还有一个比较重要的方法public Rectangle getRect()这个方法用于后来的碰撞检测
代码:
package plane; import java.awt.Image; import java.awt.Rectangle; /** * 游戏物体类 * @author long * */ public class GameObject { Image img; //图片 double x,y; //坐标 int speed; //速度 int width; //宽度 int height; //高度 public GameObject(){ } 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 Rectangle getRect(){ Rectangle r = new Rectangle((int)x, (int)y, width, height); return r; } }
6)Plane类 ----继承至GameObject类,封装了飞机移动的方法(键盘事件)
代码:
package plane; import java.awt.Graphics; import java.awt.Image; import java.awt.event.KeyEvent; import util.Constant; import util.GameUtil; /** * 飞机类 * * @author long * */ public class Plane extends GameObject { boolean left, right, up, down; // 移动方向的状态 boolean isLive = true; public void draw(Graphics g) { g.drawImage(img, (int) x, (int) y, null); move(); } /** * 按下键盘时移动状态 * * @param e */ public void addMove(KeyEvent e) { 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; default: break; } } /** * 松开键盘时的移动状态改变情况 * * @param e */ public void reliseMove(KeyEvent e) { 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; default: break; } } public void move() { if (left) { x -= speed; if (x < 0) { x = 0; } } if (right) { x += speed; if (x > Constant.GAME_WIDTH-width) { x = Constant.GAME_WIDTH-width; } } if (up) { y -= speed; if (y < 0) { y = 0; } } if (down) { y += speed; if (y > Constant.GAME_HEIGHT-height-30) { y = Constant.GAME_HEIGHT-height-30; } } } public Plane() { } public Plane(Image img, double x, double y) { this.speed = 10; this.img = img; this.x = x; this.y = y; this.width = img.getWidth(null)-10; this.height = img.getHeight(null)-10; } public Plane(String imgPath, double x, double y) { this(GameUtil.getImage(imgPath), x, y); } }
7)Bullet类 ----子弹类,继承至GameObject类,封装了子弹的基本属性与方法,有个重要的关于子弹碰到墙壁反弹的实现
代码:
package plane; import java.awt.Color; import java.awt.Graphics; import java.awt.Image; import util.Constant; /** * 子弹类 * 随机生成移动角度 * 碰到墙壁会反弹回来 * @author long * */ public class Bullet extends GameObject { double degree; //角度 public void draw(Graphics g) { Color c = g.getColor(); g.setColor(Color.YELLOW); g.fillOval((int)x, (int)y, width, height); g.setColor(c); x += speed*Math.cos(degree); y += speed*Math.sin(degree); if(y>Constant.GAME_HEIGHT-height-40||y<0){ degree = -degree; } if(x<0||x>Constant.GAME_WIDTH-width-width){ degree = Math.PI-degree; } } public Bullet(){ this.x = Constant.GAME_WIDTH/2; this.y = Constant.GAME_HEIGHT/2; this.width = 10; this.height = 10; this.speed = 5; //子弹移动速度 degree = Math.random()*Math.PI*2; //随机生成 } }
8)Explode类 ----爆炸类,主要用于子弹击中飞机时的爆炸效果的实现,即一系列爆炸的图片的加载与画在面板上
代码:
package plane; import java.awt.Graphics; import java.awt.Image; import util.GameUtil; public class Explode { double x,y; static Image[] imgs=new Image[16]; static { for(int i=0;i<imgs.length;i++){ Image img=GameUtil.getImage("images/explode/e"+(i+1)+".gif"); //System.out.println("images/explode/e"+(i+1)+".gif"); imgs[i]=img; 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; } public static void main(String[] args) { //new Explode(10, 10); } }
----------------------------------------------------------------------------------
自此,项目中所有的类的源码及大致解释已经结束,下面将详细说说其中的重要方法以及我遇到的困难:
1.碰撞检测-----子弹与飞机碰撞
游戏中的碰撞检测一般都是检测两个物体所在的矩形是否相交?如果相交则碰撞否则没有
首先介绍一个创建矩形的方法:
public Rectangle getRect(){
Rectangle r = new Rectangle((int)x, (int)y, width, height);
return r;
}
这个方法主要用来返回一个矩形,根据坐标和长宽创建一个矩形对象
然后介绍一个检测矩形相交的方法:
boolean java.awt.Rectangle.intersects(Rectangle r)
如果两矩形相交,则返回true,否则返回false
2.如何让子弹碰到墙壁反弹回来:
if(y>Constant.GAME_HEIGHT-height-40||y<0){
degree = -degree;
}
if(x<0||x>Constant.GAME_WIDTH-width-width){
degree = Math.PI-degree;
}
degree表示子弹运行的角度,x、y表示子弹的坐标,Constant.GAME_HEIGHT表示游戏面板高度、Constant.GAME_WIDTH表示游戏面板宽度,height表示子弹的高度、width子弹的宽度
3.关于键盘事件不响应的原因:
Panel中的键盘事件会默认获得焦点,而JPanel中获得焦点默认是false,需手动设为true,否则不响应键盘事件
在newJFrame时手动加上setFocusable(true);这句就ok
自此,整个游戏结束,欢迎共同学习与指正!!!
相关文章推荐
- 《Java实战开发经典》第四章4.3
- 《Java实战开发经典》第四章4.2
- 《Java实战开发经典》第四章4.1
- java类初始化,使用构造方法
- 深入理解Java虚拟机(1)虚拟机内存区域划分 与内存溢出异常
- java写文件时,输出不完整的原因以及解决方法close()或flush()
- 对spring默认的单列模式的理解
- java编码 100匹马 100块瓦
- Java Dynamic proxy
- 安装myeclipse-10.7.1及注册解码
- springmvc学习第三天
- (转)java二维数组的深度学习(静态与动态)
- Java基础-反射
- JAVA多线程实现的三种方式
- 大一新生第一次写java程序,用System.currentTimeMillis() 获取当前时间
- java二维数组学习(转)
- JAVA ReentrantLock的使用
- java一维数组学习
- 【leetcode】Remove Element【java】
- 2012华为机试第三题引发的关于“java传值,传引用”思考