《Java小游戏实现》:坦克大战

前面写了一个简单的聊天小程序,今天开始就写一个坦克大战的游戏,算是对Java相关小知识点的一个应用。

这个游戏的完成,我们也是分步完成,逐步累加,一个一个小功能的添加,最后直至完成整个游戏的开发。

第一步:写一个界面

    public class TankClient extends JFrame{public static void main(String[] args) {new TankClient().launchFrame();}public void launchFrame(){this.setTitle("坦克大战");this.setLocation(300, 400);this.setSize(300, 400);//this.setBackground(Color.RED);this.getContentPane().setBackground(Color.RED);//为关闭窗口添加响应this.addWindowListener(new WindowAdapter(){@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});//设置是否允许用户改变窗口的大小,这里限制下,不允许this.setResizable(false);this.setVisible(true);}}

以上就是为坦克大战写了一个界面,这是我们的第一步,算是完成了。

在完成这个界面时,遇到了一点小小的问题,这里有必要说明下,本来我想将这个界面设置一个背景颜色,但是使用
this.setBackground(Color.RED);就是不能成功,于是百度了下,这是由于我这里继承的是JFrame,而不是Frame,如果是继承的是Frame,则就可以通过this.setBackground(Color.RED)来设置颜色。如果我们选择的是继承JFrame,则需要使用this.getContentPane().setBackground(Color.RED)来设置背景颜色。

出现上面的原因如下:Frame和JFrame的窗口层次结构不同,JFrame的窗口包括:JFrame、Root Pane、Layered pane、Content Pane、Glass Pane;而Frmae窗口包括:Frame、Content Pane。

其次,窗口背景颜色是指直接调用JFrame或者Frame的setBackground(Color color)方法设置后显示出来的颜色。其实,JFrame在你直接调用这个方法后,你的确设置了背景颜色,而你看到的却不是直接的JFrame或者Frame,而是JFrame.getContentPane().而JFrame上的contentPane默认是Color.WHITE的,所以,无论你对JFrame或者Frame怎么设置背景颜色,你看到的都只是contentPane.因此,

    this.setBackground(Color.RED);his.getContentPane().setVisible(false);//得到contentPane容器,设置为不可见

也可以解决JFram设置的背景颜色的问题。

第二步:在界面上显示一个坦克图标

有界面,没有坦克在上面,肯定不是我们想要的,是吧,因此,我们就先完成这个功能。

在这里我们用一个圆来代表一个坦克。绘图代码如下:

    @Overridepublic void paint(Graphics g) {Color c = g.getColor();g.setColor(Color.RED);g.fillOval(50, 50, 30, 30);g.setColor(c);}

完整的代码如下:

    public class TankClient extends Frame{public static void main(String[] args) {new TankClient().launchFrame();}@Overridepublic void paint(Graphics g) {Color c = g.getColor();g.setColor(Color.RED);g.fillOval(50, 50, 30, 30);g.setColor(c);}public void launchFrame(){this.setTitle("坦克大战");this.setLocation(300, 400);this.setSize(600, 400);//this.getContentPane().setBackground(Color.GRAY);this.setBackground(Color.GRAY);//为关闭窗口添加响应this.addWindowListener(new WindowAdapter(){@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});//设置是否允许用户改变窗口的大小,这里限制下,不允许this.setResizable(false);this.setVisible(true);}}

细心的朋友可能会发现,第一个版本窗口是继承的是JFrame,而我这个版本是继承的是Frame,是出现了这样一个问题,在我重写了paint方法之后,继承JFrame实现的窗口使用this.getContentPane().setBackground(Color.GRAY);来设置颜色又不是我们所期望的。

下面左边的图是使用继承Frame+this.setBackground(Color.GRAY);

右边的图是使用继承JFrame+this.getContentPane().setBackground(Color.GRAY);结果居然是白色。

所以说Frame和JFrame还是有一定的差别的,这里不再仔细研究,而是直接使用Frame来完成。

第三步:控制坦克移动

经过第二步的处理,可以在界面上显示一个坦克了,那么应该如何来控制坦克移动了。下面我们来研究并完成。

我们再实现通过键盘的方向键来控制坦克移动之前,我们实现这样一个功能,什么功能呢??就是:坦克在某一个方向上移动。

坦克移动,简单来说,就是坦克所在的位置。即每次改变坦克的位置之后重画调用paint函数。因此,我们将坦克的位置用x/y表示。然后写一个线程专门用于重画。

实现代码如下:

    public class TankClient extends Frame{public static void main(String[] args) {new TankClient().launchFrame();}//坦克所在的位置的坐标private int x=50;private int y=50;@Overridepublic void paint(Graphics g) {Color c = g.getColor();g.setColor(Color.RED);g.fillOval(x, y, 30, 30);g.setColor(c);y+=5;//该表坦克的位置}public void launchFrame(){this.setTitle("坦克大战");this.setLocation(300, 400);this.setSize(600, 400);this.setBackground(Color.GRAY);//为关闭窗口添加响应this.addWindowListener(new WindowAdapter(){@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});//设置是否允许用户改变窗口的大小,这里限制下,不允许this.setResizable(false);this.setVisible(true);new Thread(new MyRepaint()).start();}private class MyRepaint implements Runnable{@Overridepublic void run() {while(true){//每50ms重画一次repaint();try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}}}

通过开启一个线程以及在paint函数中改变坦克的位置(y+=5),这样,坦克就会一直往下面移动。

实现了坦克一直往下移动之后,我们就可以实现通过键盘来控制坦克的移动了。

通过键盘来实现坦克的移动,我们只需要添加一个键盘按键的监听事件即可,根据键盘按键的不同,做相应的一个处理。

1、首先先写一个键盘按键监听类,键盘按键监听类,有两种实现方式,一种是继承KeyAdapter(重写我们需要的方法,比较方便);另一种是实现KeyListener接口(需要实现3个抽象方法)。

2、然后使用组件的 addKeyListener 方法将从该类所创建的侦听器对象向该组件注册。按下、释放或键入键时生成键盘事件。

    private class KeyMonitor extends KeyAdapter{@Overridepublic void keyPressed(KeyEvent e) {int key=e.getKeyCode();switch(key){case KeyEvent.VK_LEFT:x -= 5;break;case KeyEvent.VK_UP:y -= 5;break;case KeyEvent.VK_RIGHT:x += 5;break;case KeyEvent.VK_DOWN:y += 5;break;}}}

完整代码如下:

    public class TankClient extends Frame{public static void main(String[] args) {new TankClient().launchFrame();}//坦克所在的位置的坐标private int x=50;private int y=50;@Overridepublic void paint(Graphics g) {Color c = g.getColor();g.setColor(Color.RED);g.fillOval(x, y, 30, 30);g.setColor(c);}public void launchFrame(){this.setTitle("坦克大战");this.setLocation(300, 400);this.setSize(600, 400);this.setBackground(Color.GRAY);//为关闭窗口添加响应this.addWindowListener(new WindowAdapter(){@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});//设置是否允许用户改变窗口的大小,这里限制下,不允许this.setResizable(false);this.setVisible(true);new Thread(new MyRepaint()).start();this.addKeyListener(new KeyMonitor());}private class MyRepaint implements Runnable{@Overridepublic void run() {while(true){//每50ms重画一次repaint();try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}}private class KeyMonitor extends KeyAdapter{@Overridepublic void keyPressed(KeyEvent e) {int key=e.getKeyCode();switch(key){case KeyEvent.VK_LEFT:x -= 5;break;case KeyEvent.VK_UP:y -= 5;break;case KeyEvent.VK_RIGHT:x += 5;break;case KeyEvent.VK_DOWN:y += 5;break;}}}}

以上就通过键盘的上下左右键来移动界面上的坦克了。

第四步:面向对象的思想构造坦克类

对于面向对象编程的思想,我们首先要考虑的事情就是有哪些类和对象,每个类中有哪些属性和方法。

上面的版本都还没有利用面向对象的思想。这一小节,我们就来构造坦克类,这样便于面向对象编程。

首先,我们构造一个Tank类,Tank类中有两个属性,分别为坦克位置x和y。包含的方法应该有:draw方法和keyMonitor方法。即自己画图的方法和自己对键盘的响应的方法。

Tank类的代码如下:

    public class Tank {//坦克所在的位置坐标private int x;private int y;public Tank(int x, int y) {super();this.x = x;this.y = y;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}//绘图public void draw(Graphics g){Color c = g.getColor();g.setColor(Color.RED);g.fillOval(x, y, 30, 30);g.setColor(c);}//响应键盘按键的方法public void keyMonitor(KeyEvent e){int key=e.getKeyCode();switch(key){case KeyEvent.VK_LEFT:x -= 5;break;case KeyEvent.VK_UP:y -= 5;break;case KeyEvent.VK_RIGHT:x += 5;break;case KeyEvent.VK_DOWN:y += 5;break;}}}

TankClient类的方法重构后的代码如下:

    public class TankClient extends Frame{private Tank tk=new Tank(50,50);public static void main(String[] args) {new TankClient().launchFrame();}@Overridepublic void paint(Graphics g) {//直接调用坦克至圣的draw方法tk.draw(g);     }public void launchFrame(){this.setTitle("坦克大战");this.setLocation(300, 400);this.setSize(600, 400);this.setBackground(Color.GRAY);//为关闭窗口添加响应this.addWindowListener(new WindowAdapter(){@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});//设置是否允许用户改变窗口的大小,这里限制下,不允许this.setResizable(false);this.setVisible(true);new Thread(new MyRepaint()).start();this.addKeyListener(new KeyMonitor());}private class MyRepaint implements Runnable{@Overridepublic void run() {while(true){//每50ms重画一次repaint();try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}}private class KeyMonitor extends KeyAdapter{@Overridepublic void keyPressed(KeyEvent e) {tk.keyMonitor(e);}       }}

解决闪烁现象

什么是闪烁现象呢??可以理解为丢帧。即在视觉上少了一些中间过程的变化。

当使用graphics对象在窗体中绘制多种图像时,每次窗体改变都要调用repaint()函数,相当于把所有图像按顺序重新绘制一次,所以就出现了闪烁现象。 这一点在棋类游戏更加明显(想象一下每次落子都需要重新绘制棋盘上的几十上百个棋子是什么概念)

解决的方法是使用双缓冲技术。也就是说,先将所有图像都绘制在一个缓冲区中,形成一张图片,这样每次调用repaint()只需要将该缓冲图片画到窗体上就可以了。

在本例中,只需要引入一个画布,并重写update方法

    private Image offScreenImage =  null;@Overridepublic void update(Graphics g) {if (offScreenImage == null) {offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);}Graphics goffScreen = offScreenImage.getGraphics();// 重新定义一个画虚拟桌布的画笔//Color c = goffScreen.getColor();goffScreen.setColor(Color.GRAY);goffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);goffScreen.setColor(c);//调用paint方法paint(goffScreen);//最后,将虚拟画布作为整体直接画上去,避免闪烁的发生g.drawImage(offScreenImage, 0, 0, null);}@Overridepublic void paint(Graphics g) {//直接调用坦克至圣的draw方法tk.draw(g);     }

未完,待续

《Java小游戏实现》:坦克大战相关推荐

  1. 微信小游戏制作坦克大战(四)添加敌方坦克,敌方坦克可以随机移动

    微信小游戏制作坦克大战(四)添加敌方坦克,敌方坦克可以随机移动 首先导入敌方坦克素材 重命名为敌方坦克1 敌方坦克也移动到屏幕外面,后面使用克隆体来显示. 我们给敌方坦克添加事件 好的,现在敌方坦克已 ...

  2. 微信小游戏制作坦克大战(六)碰撞检测,主角坦克碰到敌方坦克、炮弹爆炸

    微信小游戏制作坦克大战(六)碰撞检测,主角坦克碰到敌方坦克.炮弹爆炸 导入坦克爆炸效果的图片和声音素材 给主角坦克添加事件 给爆炸动画添加事件 当主角坦克碰到敌方坦克或者炮弹时显示爆炸效果 下一篇文章 ...

  3. java小游戏:五子棋人机大战

    一.java小游戏:五子棋人机大战 1.绘制窗口 package wuziqi;import javax.swing.*; import java.awt.event.MouseAdapter; im ...

  4. 微信小游戏制作坦克大战(五)敌方坦克可以发射炮弹

    微信小游戏制作坦克大战(五)敌方坦克可以发射炮弹 在资源管理器中复制炮弹,重命名为敌人坦克的炮弹. 修改敌方坦克的积木 给敌方坦克炮弹添加事件 现在,敌方坦克已经可以自动发射炮弹啦. 下一篇文章:微信 ...

  5. 使用jquery—Canvas实现html5小游戏——《坦克大战》

    目录 1.项目背景 2.项目展示 3.设计思路 3.1.坦克移动 3.2.坦克开火 3.3.击中坦克 4.实现代码 5.总结 1.项目背景 2021年春节期间在家无聊,正好又学过一些前端的知识,因此就 ...

  6. 微信小游戏制作坦克大战(九)切换场景,游戏重新开始

    微信小游戏制作坦克大战(九)切换场景,游戏重新开始 新建一个游戏结束场景 主角坦克爆炸后切换到游戏结束场景 添加背景音乐 好了,至此坦克大战小游戏基本做好,小伙伴们可以继续完善哈. 体验地址:

  7. 微信小游戏制作坦克大战(八)统计得分

    微信小游戏制作坦克大战(八)统计得分 导入数字图片素材 新建得分变量 给数字添加事件 敌方坦克发生爆炸时,数字增加1 实现效果 下一篇文章:微信小游戏制作坦克大战(九)切换场景,游戏重新开始

  8. 微信小游戏制作坦克大战(七)碰撞检测,敌方坦克碰到主角坦克炮弹爆炸

    微信小游戏制作坦克大战(七)碰撞检测,敌方坦克碰到主角坦克炮弹爆炸 导入发生炮弹的音效素材 主角坦克发射炮弹或者敌方坦克发射炮弹时播放音效 修改敌方坦克积木 4.效果: 敌方坦克碰到主角坦克炮弹爆炸 ...

  9. python小游戏经典坦克大战-实验设计

    一. 游戏流程概述 游戏基本规则: 按上下左右键移动我方坦克,按空格键进行发射子弹,击中坦克,坦克爆炸消失.若我方坦克被子弹击中或撞上,我方坦克死亡按ESC键可以重生. 敌方坦克功能:白色敌方坦克为一 ...

  10. JAVA小游戏之飞机大战(超详细)

    前言:在一定的java基础上就可以进行飞机大战小游戏的编写了.整个小游戏主要涉及到的基础知识为:类与对象,鼠标事件监听,线程.重绘等. 整体思路框架 设计一个初始界面,在开始后出现自己的战机和敌机且自 ...

最新文章

  1. CVPR 2019收录论文ID公开,你上榜了吗?
  2. varnish缓存的配置优化(redhat5.4)
  3. 骑芯供应链(T 面试)
  4. 方法练习2_求出1到100的累加和
  5. SAP CRM CRM_PARTNER_READ_MULTI_OB
  6. API – MultiByteToWideChar的用法
  7. 删除顽固文件夹cygwin的方法,挺折腾的
  8. bootstraptable 数字不换行_不知道这些数据录入技巧,你就凹凸了!|Excel093
  9. 软件无线电实验 matlab,基于MATLAB和ModelSim的软件无线电课程实验设计
  10. 软件生命周期及工作分解结构
  11. 全网最详细的排列组合系列算法题整理
  12. 启发式搜索(heuristic search)———A*算法
  13. 实现一个打点计时器,要求 1、从 start 到 eThd(包含 start 和 eThd),每隔 100 毫秒 coThsole.log 一个数字,每次数字增幅为 1 2、返回的对象中需要包含一个
  14. 【hadoop】进阶篇一:MapReduce之Job的提交
  15. AD软件绘制stm32最小系统电路原理图与PCB图
  16. 初学者学习插画原画以后就业方向有哪些?和大家聊聊插画原画师就业、薪资等
  17. # C#调用已经使用Python训练好的神经网络做图片检测
  18. QPainter绘制自定义大小的图片
  19. git改变用户名和邮箱
  20. 穿过任意防火墙NAT的远程控制软件TeamViewer

热门文章

  1. HTML期末学生大作业-节日网页作业html+css+javascript
  2. 注册公司的步骤及费用
  3. 使用python修复文件乱码
  4. ReThought (二): 如何照顾团队中的新人
  5. Pytnon画一个小猪佩奇
  6. mysql 1032错误_如何快速解决MySQL 1032 主从错误
  7. J2ME 2D小游戏入门之旅(五) 实现爆炸效果、并加入道具导弹(转)
  8. DS12C887实时时钟
  9. 一些常用的英文写作网站
  10. 人生苦短,我用Python,那么问题来了,普通人要学python吗?