java基础 小游戏 飞机大战(中)

编程入门 行业动态 更新时间:2024-10-26 09:19:27

java基础 <a href=https://www.elefans.com/category/jswz/34/1769974.html style=小游戏 飞机大战(中)"/>

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基础 小游戏 飞机大战(中)

本文发布于:2024-02-25 18:20:52,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1699884.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:小游戏   大战   飞机   基础   java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!