小游戏 飞机大战(中)"/>
java基础 小游戏 飞机大战(中)
文章目录
- 7 键盘控制原理
- 8 面向对象重构飞机类的键盘控制
- 9 炮弹类基本设计
- 10 使用数组产生多发炮弹
- 11 双缓冲解决闪烁
- 12 矩形检测原理
- 13 炮弹和飞机的碰撞检测
7 键盘控制原理
键盘和程序交互时,每次按下键,松开键都会触发相应的键盘事件,事件的信息被封装到了KeyEvent对象中
为了识别按下的是哪个键,系统对所有按键都做了编号,每个按键都对应相应的数字,如回车对应10,空格对应32等,这些编号都可以通过KeyEvent对象来查询
//定义键盘监听的内部类class KeyMonitor extends KeyAdapter{@Overridepublic void keyPressed(KeyEvent e) {System.out.println("按下" + e.getKeyCode());}@Overridepublic void keyReleased(KeyEvent e) {System.out.println("松开" + e.getKeyCode());}}//初始化窗口public void launchFrame() {this.setTitle("coisini"); //设置窗口名字 this.setSize(500, 500); //设置窗口大小this.setLocation(300,300); //设置窗口显示位置this.setVisible(true); //窗口可视化//实际关闭窗口this.addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e) {System.exit(0);} });new PaintThread().start(); //启动重画窗口的线程addKeyListener(new KeyMonitor()); //给窗口增加键盘的监听}public static void main(String[] args) { //主方法创建窗口入口MyGameFrame f = new MyGameFrame(); //由MyGameFrame类新建对象f.launchFrame(); //调用lanuchFrame()方法}}
分别按下上下左右,记录按下键位和松下键位的编号数字
8 面向对象重构飞机类的键盘控制
理解了键盘的控制原理,增加了键盘监听后,在Plane类中增添两种控制方法,按下键位时和松开键位时对plane的移动控制
package cn.coisini.game;import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;public class Plane extends GameObject {int speed = 3;boolean left,right,up,down;//按下键位时重画位置public void drawSelf(Graphics g) { g.drawImage(img, (int)x, (int)y, null);if(left) {x -= speed;}if(right) {x += speed;}if(up) {y -= speed;}if(down) {y += speed;}}public Plane(Image img, double x, double y) {this.img = img;this.x = x;this.y = y;}//按下某个键增加相应的方向public void addDirection(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;}}//更改键位后,取消原来的方向public void minusDirection(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;} }}
9 炮弹类基本设计
炮弹类用黄色实心椭圆实现,不用再加载新的图片,我们的逻辑是在窗口固定位置(200,200)处生成炮弹,炮弹的方向是随机的,并且遇到边界会反弹
由于窗口界面大小是确定的,为了避免更改后产生的问题,创建一个常量类Constant来存储不变的数值:
package cn.coisini.game;public class Constant {public static final int GAME_WIDTH = 500;public static final int GAME_HEIGHT = 500;}
炮弹类:
package cn.coisini.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;//角度设置为0-360之间的随机数degree = Math.random()*Math.PI*2;}public void draw(Graphics g) {Color c = g.getColor();g.setColor(Color.YELLOW);g.fillOval((int)x, (int)y, width, height);//炮弹沿着任意角度去飞x += speed*Math.cos(degree);y += speed*Math.sin(degree);//设置炮弹反弹if(x<0 || x>Constant.GAME_WIDTH - width) {degree = Math.PI - degree; //碰到左右边界,则做纵坐标反转}if(y<30 || y>Constant.GAME_HEIGHT - height) {degree = -degree; //碰到右边界,则做横坐标反转}g.setColor(c);}}
完成这些后,在MyGameFrame中new一个shell,并调用Shell的draw方法
10 使用数组产生多发炮弹
完成Shell类后,现在开始产生多发炮弹,使用数组的知识,一开始先创建一个shells的数组,再对这50个元素初始化(即创建50个对象存入),再使用draw方法循环画出这50个炮弹
/*** @author coisini1999* @飞机游戏的主窗口*/package cn.coisini.game;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.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;import javax.swing.JFrame; //导入JFrame包public class MyGameFrame extends JFrame {Image bg = GameUtil.getImage("images/bg.jpg"); //加载图片对象,指定路径Image planeImg = GameUtil.getImage("images/plane.png"); //加载图片对象,指定路径Plane plane = new Plane(planeImg, 250 ,250); //创建飞机对象Shell[] shells = new Shell[50]; //创建炮弹数组public void paint(Graphics g) { //自动被调用,g 相当于一支笔g.drawImage(bg, 0, 0, null);plane.drawSelf(g); //画飞机//画50个炮弹for(int i=0; i < shells.length; i++) {shells[i].draw(g);}}//帮助我们反复重画方法class PaintThread extends Thread { //内部类,使用此类的所有属性和方法 Thread是线程@Overridepublic void run() {while(true) {//System.out.println("窗口重画了一次");repaint(); //重画try {Thread.sleep(40); //40ms} catch (InterruptedException e) {e.printStackTrace();}}}}//定义键盘监听的内部类class KeyMonitor extends KeyAdapter{@Overridepublic void keyPressed(KeyEvent e) {plane.addDirection(e);}@Overridepublic void keyReleased(KeyEvent e) {plane.minusDirection(e);}}//初始化窗口public void launchFrame() {this.setTitle("coisini"); //设置窗口名字 this.setSize(Constant.GAME_WIDTH, Constant.GAME_HEIGHT); //设置窗口大小this.setLocation(300,300); //设置窗口显示位置this.setVisible(true); //窗口可视化//实际关闭窗口this.addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e) {System.exit(0);} });new PaintThread().start(); //启动重画窗口的线程addKeyListener(new KeyMonitor()); //给窗口增加键盘的监听//初始化50个炮弹for(int i=0; i < shells.length; i++) {shells[i] = new Shell();}}public static void main(String[] args) { //主方法创建窗口入口MyGameFrame f = new MyGameFrame(); //由MyGameFrame类新建对象f.launchFrame(); //调用lanuchFrame()方法}}
11 双缓冲解决闪烁
再完成上面工作后,使用JFrame包,屏幕有略微的闪烁,使用普通的Frame包,闪烁的更为严重,影响用户体验,为了解决闪烁问题,采用Frame加双缓冲来解决优于JFrame
双缓冲机制原理如下:
1,在内存中创建与画布一样的缓冲区
2,在缓冲区画图
3,将缓冲区位图拷贝到当前画布上
4,释放内存缓冲区
双缓冲即在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象拷贝到屏幕上,能大大加快绘图的速度
//双缓冲机制private Image offScreenImage = null;public void update(Graphics g) {if(offScreenImage == null) {offScreenImage = this.createImage(Constant.GAME_WIDTH, Constant.GAME_HEIGHT); }Graphics gOFF = offScreenImage.getGraphics();paint(gOFF);g.drawImage(offScreenImage, 0, 0, null);}
12 矩形检测原理
在窗口中的所有物体(飞机,炮弹等)其实都是矩形,我们需要检测游戏中,飞机是否碰撞到了炮弹,即矩形间有没有相交,相交就可以认为游戏失败
java的API中,提供了Rectangle类来表示矩形相关信息,并且提供了intersects()方法,直接判断矩形是否相交
在GameObject类中,之前定义过一个方法:
//返回物体所在的矩形,便于后续的碰撞检测public Rectangle getRect() {return new Rectangle((int)x, (int)y, width, height);}
通过返回物体所在的矩形,来判断是否发生碰撞
13 炮弹和飞机的碰撞检测
对飞机类增加新的属性来判断飞机是否死亡,以及在MyGameFrame中进行飞机的碰撞检测和反馈
Plane类新增属性及新的画飞机方法:
int speed = 3;boolean left,right,up,down;boolean live = true; //创建飞机是否死亡的属性public void drawSelf(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;}}}
在MyGameFrame中每次画一个炮弹后进行矩形相交检测,反馈飞机是否死亡,从而决定画不画飞机:
public void paint(Graphics g) { //自动被调用,g 相当于一支笔g.drawImage(bg, 0, 0, null);plane.drawSelf(g); //画飞机//画50个炮弹for(int i=0; i < shells.length; i++) {shells[i].draw(g);//每画出一个炮弹进行炮弹和飞机的矩形相交检测boolean peng = shells[i].getRect().intersects(plane.getRect());//碰撞后令飞机死亡if(peng) {plane.live = false;}}}
更多推荐
java基础 小游戏 飞机大战(中)
发布评论