前天不知道又在哪里见到这么一句话“谁能坚持超过50秒,我请他吃饭”(可以点击玩一玩原版游戏),其实这个不就是之前在同学QQ空间里面转来转去的一个网页游戏吗?什么“据说,美国空军的飞行员被强制达到2分钟。”于是,又来了一点点兴趣再玩一下下。游戏界面如下:

其实前段时间自己也尝试用 Java 实现了这游戏,具体是按照自己对这游戏的简单理解使用 Java GUI 进行编程。电脑装了 JRE 的朋友可以下载附件直接双击 .bat 文件试玩一下哦!!!(*^__^*) 嘻嘻……

我的思路是这样子的(游戏中的方块用 JLabel 实现):

1、游戏中4个自动移动并且会慢慢加速的方块是碰到固定的“壁”就按照光的反射特性改变移动的方向,这个我们可以通过条件判断来改变方块的具体坐标 x 和 y 来实现;

2、自动移动则用 Java 线程来实现,具体是在线程类的 run() 方法中用死循环不断改变 x 和 y 坐标,然后不断地擦除、重绘即可,而碰壁之后反射的算法也是包含在这里的;

3、玩家能够通过按住鼠标左键来移动自己的方块,这个应该用 java.awt.event 包中的 MouseMotionAdapter 这个鼠标事件监听器类,Java 文档中的描述是“接收鼠标移动事件的抽象适配器类”,它包含() 和() 方法,可以监听鼠标时间按,具体的可以查阅一下该类;对于玩家控制的方块,要每时每刻都获取鼠标当前在面板上的坐标 x 、y,以此为 JLabel 方块的中心进行不断擦除、重绘,也就达到了跟着鼠标移动的效果了;

4、判断游戏是否结束,就是遍历4个自动移动的 JLabel 方块,看它们在游戏面板中的覆盖面是否与玩家控制的 JLabel 方块有一点点重合,重合则说明相碰了,游戏结束;

5、关于游戏计时,这个可以用到 Java 线程中的 java.util.TimerTask 类来实现,不过这里我的游戏中没实现,偷懒了一下;

6、至于方块的移动速度,用一定的策略对 Thead.sleep() 方法中的睡眠时间进行减少即可。

我的游戏界面:

1、游戏开始状态

2、游戏进行中

3、碰壁了,游戏结束

代码实现:

GlobalVars.java

//常量接口模式:把系统中相关的常量放在专门的常量接口中定义

publicinterfaceGlobalVars {

/**

* 4个移动方向,L、R为左、右,U、D为上、下

*/

publicstaticfinalintLD = -1;//往左下方

publicstaticfinalintRD =1;//往右下方

publicstaticfinalintRU =2;//往右上方

publicstaticfinalintLU = -2;//往左上方

/**

* 游戏窗口大小

*/

publicstaticfinalintFRAME_WIDTH =500;

publicstaticfinalintFRAME_HEIGTH =500;

/**

* 面板大小

*/

publicstaticfinalintPANEL_WIDTH =400;

publicstaticfinalintPANEL_HEIGTH =400;

/**

* 玩家JLabel的大小

*/

publicstaticfinalintPLAYER_WIDTH =50;

publicstaticfinalintPLAYER_HEIGTH =50;

}

ImpMove.java

importjavax.swing.JLabel;

/**

* 定义一个电脑方、玩家的JLabel都要实现的

* 移动策略的抽象类 ImpMove ,该接口继承自

* JLabel,所以可以获取 JLabel 类中常用 的方法

* @author haolloyin

*/

publicabstractclassImpMoveextendsJLabel{

// 移动

protectedabstractvoidmove();

// 开始

protectedabstractvoidbegin();

}

ComputerPanel.java

/**

* 电脑控制的 JLabel 方块,继承自 ImpMove

* 抽象类,必须实现其 move()和 begin()方法,

* 它可以在游戏中存在多个具体实例,由玩家

* 确定,它使用了线程因此能够自动移动

* @author haolloyin

*/

publicclassComputerLabelextendsImpMove{

/* 碰到壁必须反弹,这里4个常量用于

* 判断电脑方块碰到那一面壁

*/

privatestaticfinalintPL = -1;

privatestaticfinalintPR =1;

privatestaticfinalintPU =2;

privatestaticfinalintPD = -2;

privateintxx;

privateintyy;

privateintwidth;

privateintheigth;

privatePoint p;

privateRectangle r;

privateintdirection;//移动方向

privateintspeed =5;//移动速度

privateThread go;//驱动其移动的线程实例

privatebooleanisLive =true;//游戏是否结束

publicComputerLabel(intx,inty,intw,inth,intd) {

this.width = w;

this.heigth = h;

init(x, y, w, h, d);

}

privatevoidinit(intx,inty,intw,inth,intdirection) {

setBounds(x, y, w, h);

setOpaque(true);

setBackground(Color.green);

r = getBounds();

p = r.getLocation();

this.direction = direction;

}

/**

*  实现了Runnable接口的私有内部类,用于驱动move()方法

*/

privateclassMoveAbleimplementsRunnable {

publicvoidrun() {

while(isLive) {

try{

Thread.sleep(speed);

}catch(InterruptedException e) {

e.printStackTrace();

}

//              System.out.println("speed = " + speed);

move();

}

}

}

/**

* 实现ImpMove抽象类中的move()

*/

@Override

protectedvoidmove() {

isPengBi();

p.x += xx;

p.y += yy;

setLocation(p.x, p.y);

}

/**

* 测试是否碰到壁,若是则调

* 用changeDirection()改变移动方向

*/

privatevoidisPengBi() {

if(p.x <0) {

changeDirection(PL);

}elseif(p.x > GlobalVars.PANEL_WIDTH - width) {

changeDirection(PR);

}elseif(p.y <0) {

changeDirection(PU);

}elseif(p.y > GlobalVars.PANEL_HEIGTH - heigth) {

changeDirection(PD);

}

}

/**

* 碰到壁则反弹,即改变移动方向

*/

privatevoidchangeDirection(intpeng) {

if(peng == PL && direction == LD) {// ↙碰左

direction = RD;

xx =1;

yy =1;

}elseif(peng == PL && direction == LU) {// ↖碰左

direction = RU;

xx =1;

yy = -1;

}elseif(peng == PR && direction == RU) {// ↗碰右

direction = LU;

xx = -1;

yy = -1;

}elseif(peng == PR && direction == RD) {// ↘碰右

direction = LD;

xx = -1;

yy =1;

}elseif(peng == PU && direction == RU) {// ↗碰上

direction = RD;

xx =1;

yy =1;

}elseif(peng == PU && direction == LU) {// ↖碰上

direction = LD;

xx = -1;

yy =1;

}elseif(peng == PD && direction == LD) {// ↙碰下

direction = LU;

xx = -1;

yy = -1;

}elseif(peng == PD && direction == RD) {// ↘碰下

direction = RU;

xx =1;

yy = -1;

}

}

/**

* 游戏开始,启动线程

*/

@Override

protectedvoidbegin() {

go =newThread(newMoveAble());

toWhere();

go.start();

}

/**

* 确定方块的移动方向

*/

privatevoidtoWhere() {

if(direction == LD) {

xx = -1;

yy =1;

}elseif(direction == LU) {

xx = -1;

yy = -1;

}elseif(direction == RD) {

xx =1;

yy =1;

}elseif(direction == RU) {

xx =1;

yy = -1;

}

}

/**

* 游戏是否结束

*/

publicvoidisDead() {

this.isLive =false;

}

/**

* 设置移动速度

*/

publicvoidsetSpeed(intspeed) {

this.speed = speed;

}

}

PlayerPanel.java

/**

* 供玩家控制的 JLabel 方块,它在整个游戏

* 当中只会存在一个实例对象,继承自 ImpMove

* 抽象类,必须实现其 move() 和 begin() 方法

* @author haolloyin

*/

publicclassPlayerLabelextendsImpMove{

privateRectangle r;//方块的大小、位置

privatePoint now;//方块的坐标x、y

privateintx;//原来的坐标 x

privateinty;//原来的坐标 y

privateintmax_x = PANEL_WIDTH - PLAYER_WIDTH;

privateintmax_y = PANEL_HEIGTH - PLAYER_HEIGTH;

publicPlayerLabel() {

begin();

}

/**

* 重写begin()方法,玩家鼠标一单击中间的

* JLabel 方块,则游戏开始

*/

@Override

protectedvoidbegin() {

setText("点击吧");

setForeground(Color.black);

setSize(PLAYER_WIDTH, PLAYER_HEIGTH);

setLocation(150,150);

setOpaque(true);

setBackground(Color.green);

r =this.getBounds();

now =newPoint();

/**

* 为当前JLabel对象添加接收鼠标移动事件的抽象适配器类,

* 用于当按下鼠标时获取当前坐标并开始游戏

*/

addMouseMotionListener(newMouseMotionAdapter() {

publicvoidmouseDragged(MouseEvent e) {

x = e.getX();

y = e.getY();

move();

}

});

/**

* 添加可以变换鼠标指针样式的事件监听器

*/

addMouseListener(newMouseAdapter() {

publicvoidmouseEntered(MouseEvent e) {

// 变成手型鼠标

setBackground(Color.yellow);

setCursor(newCursor(Cursor.HAND_CURSOR));

}

publicvoidmouseExited(MouseEvent e) {

// 变成默认鼠标

setBackground(Color.green);

setCursor(newCursor(Cursor.DEFAULT_CURSOR));

}

});

}

/**

* 游戏的主要算法:实现ImpMove抽象类中的move()

*/

@Override

protectedvoidmove() {

now = MouseInfo.getPointerInfo().getLocation();

if(now.x %10>4)

now.x = now.x /10+1;

else

now.x /=10;

if(now.y %10>4)

now.y = now.y /10+1;

else

now.y /=10;

r.x += (x - now.x);

r.y += (y - now.y);

/*

* 如果玩家JLabel方块碰壁了,则保证其

* 始终紧靠着壁,而不是结束游戏

*/

if(r.x <=0)

r.x =0;

if(r.y <=0)

r.y =0;

if(r.x > max_x)

r.x = max_x;

if(r.y > max_y)

r.y = max_y;

now.x = x;

now.y = y;

setBackground(Color.cyan);

setLocation(r.x, r.y);

}

/**

* 测试

*/

publicstaticvoidmain(String[] args) {

JFrame jf =newJFrame();

PlayerLabel p1 =newPlayerLabel();

jf.setLayout(null);//布局设置为null

jf.add(p1);

jf.setLocation(400,50);

jf.setSize(500,500);

jf.setVisible(true);

jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

}

}

GamePanel.java

/**

*  游戏的面板,所有JLabel对象都被添加

*  到该面板,由其来具体控制游戏的运行,

*  类似于中介者模式中的 Mediator

* @author haolloyin

*/

publicclassGamePanelextendsJPanel{

// 保存自动移动的JLabel对象,即电脑控制的方块

privateLinkedList labels;

// 游戏是否结束

privatebooleanisLive =true;

// 玩家JLabel

privatePlayerLabel player;

//游戏进行中判断是否相碰的线程

privateThread go;

publicGamePanel() {

setBounds(50,30, PANEL_WIDTH, PANEL_HEIGTH);

setBackground(Color.yellow);

setLayout(null);

init();

}

privatevoidinit() {

labels =newLinkedList();

player =newPlayerLabel();

this.add(player);

player.addMouseListener(newMouseAdapter() {

publicvoidmousePressed(MouseEvent me) {

player.setText("我闪...");

startGame();

}

});

}

privatevoidstartGame() {

intnum = labels.size();

for(inti =0; i

labels.get(i).begin();

}

if(this.go ==null) {

go =newThread(newCheckGameIsOver());

go.start();

}

}

privatevoidisOver() {

Rectangle r_player = player.getBounds();

intnum = labels.size();

for(inti =0; i

if(labels.get(i).getBounds().intersects(r_player)) {

System.out.println("Game Over ...");

System.out.println("你碰到第--> "+ i +"

gameOver();

try{

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

System.exit(0);

}

}

}

privatevoidgameOver() {

intnum = labels.size();

for(inti =0; i

ComputerLabel l = (ComputerLabel)labels.get(i);

l.isDead();

}

}

privateclassCheckGameIsOverimplementsRunnable {

publicvoidrun() {

while(isLive) {

isOver();

}

}

}

publicvoidaddLabel(ImpMove label) {

this.labels.add(label);

this.add(label);

}

}

Game.java

/**

* 最终游戏测试类,其实就是初始化所有

* JLabel 对象并启动游戏

* @author haolloyin

*/

publicclassGameextendsJFrame {

publicGame() {

setTitle("躲避 游戏");

setLayout(null);

setBounds(300,100, FRAME_WIDTH, FRAME_HEIGTH);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

}

/*

* 测试

*/

publicstaticvoidmain(String[] args) {

GamePanel gamePanel =newGamePanel();

ComputerLabel p1 =newComputerLabel(340,320,35,59, RU);

ComputerLabel p2 =newComputerLabel(13,30,40,20, LU);

ComputerLabel p3 =newComputerLabel(20,200,60,40, RD);

ComputerLabel p4 =newComputerLabel(350,60,70,60, LD);

ComputerLabel p5 =newComputerLabel(200,20,10,15, LD);

p1.setBackground(Color.black);

p2.setBackground(Color.DARK_GRAY);

p3.setBackground(Color.magenta);

p4.setBackground(Color.red);

p5.setBackground(Color.red);

p1.setSpeed(4);

p2.setSpeed(5);

p3.setSpeed(6);

p4.setSpeed(3);

p5.setSpeed(2);

gamePanel.addLabel(p1);

gamePanel.addLabel(p2);

gamePanel.addLabel(p3);

gamePanel.addLabel(p4);

gamePanel.addLabel(p5);

Game game =newGame();

game.add(gamePanel);

}

}

小结:

1、各个类的设计、结构感觉很乱;

2、上面的一点还体现在关于游戏实体(即 JLabel 方块)所选取的数据结构很乱;

3、重要方法如 move() 的代码过多且杂,本来这是整个游戏的重点算法实现,却这样子糟糕,+_+;

4、代码中没有注释,所以刚才在理解自己的代码时花了点时间,%>_<%…嗯,以后这要注意了。

java51游戏_简单实现美空军也得玩的游戏-谁能坚持超过50秒?(Java)相关推荐

  1. 用swing设计一个打地鼠小游戏_这7个风靡欧美的英语小游戏,学会胜过刷100道题!...

    精彩导读 小编为大家搜罗了一些在国外家喻户晓的语言类小游戏.好的方法胜过刷上100道题,真正让孩子觉得好玩,教学才会事半功倍! 01 Would You Rather... 最近牛津大学的面试考题惊天 ...

  2. 教ai玩游戏_简单解释:DeepMind如何教AI玩视频游戏

    教ai玩游戏 by Aman Agarwal 通过阿曼·阿加瓦尔(Aman Agarwal) 简单解释:DeepMind如何教AI玩视频游戏 (Explained Simply: How DeepMi ...

  3. 用深度强化学习玩atari游戏_(一)深度强化学习·入门从游戏开始

    1.在开始正式进入学习之前,有几个概念需要澄清,这样有利于我们对后续的学习有一个大致的框架感 监督型学习与无监督型学习 深度强化学习的范畴 监督型学习是基于已有的带有分类标签的数据集合,来拟合神经网络 ...

  4. linux可以玩什么游戏_为什么我们要在Linux上玩游戏,与Icculus聊天等等

    linux可以玩什么游戏 开源游戏综述 2014年8月31日至9月6日,一周 在本周的开源游戏新闻综述中,我们看了一些用旧游戏组件制成的令人惊叹的灯,Linux Action Show与Ryan&qu ...

  5. unity 音乐节奏游戏_使用您当地音乐收藏的最佳节奏游戏

    unity 音乐节奏游戏 You can't have video games without music. Well, you can-the earliest games didn't have ...

  6. 3ds java游戏_比耐力比持久 3DS耐玩游戏大盘点

    监督:巴士速攻-丢丢 排版:巴士速攻-灵刻 作者:巴士速攻(内详) 来源:BBS.TGBUS.COM 前言: 各位不大♂不小的撸友玩家们,你们好,我是鲁肃,喜欢我的朋友们都叫我撸大湿,今天很荣幸被邀请 ...

  7. 手机改小视窗什么意思_简单几步教你如何将手机投屏到电视,1秒小屏变大屏!...

    原标题:简单几步教你如何将手机投屏到电视,1秒小屏变大屏! Hi,大家好,我是小雨!最近有人在后台咨询小雨,怎样将手机画面投屏到电视上,让手机的小屏变大屏.今天小雨就来和大家一起聊一聊这个问题,简单几 ...

  8. tc溜溜865手机投屏卡_溜溜tcgames老版本(电脑玩手机游戏)-溜溜TC Games32位/64位旧版本PC下载V2.0.0官网安卓真机投屏-西西软件下载...

    溜溜TC Games32位/64位旧版本PC是一款非常好用的手机游戏投屏工具,有了这款软件我们就可以将手机上的游戏画面投入到电脑上,大屏幕玩游戏,这样肯定会跟畅快,该软件是由成都杰华科技有限公司基于P ...

  9. 想作为程序员工作 需要什么_您不想作为程序员玩的游戏

    想作为程序员工作 需要什么 by Amy M Haddad 通过艾米·M·哈达德(Amy M Haddad) 您不想作为程序员玩的游戏 (The game you don't want to play ...

最新文章

  1. 在看不见的地方,AI正在7×24为你在线服务
  2. R语言笔记5:控制结构
  3. 北区首届科技文化潮流节启幕!诚邀科技企业参展,共同打造海淀北部最大科技“party”...
  4. python语言实战-Python实战-从菜鸟到大牛的进阶之路 pdf完整版
  5. MyEclipse 2017软件安装教程
  6. 统计次数c语言,C 语言统计关键字出现次数
  7. echarts定时加载动画数据
  8. 有的时候不评价别人其实挺难的
  9. DDD理论学习系列(9)-- 领域事件
  10. mysql+误操作怎么恢复_MySQL 误操作后如何快速恢复数据
  11. Java Byte类的compareTo()方法和示例
  12. eclipse导出doc,文件夹为空
  13. 【IT】Asp.Net MVC
  14. GJB150A湿热试验-高低温交变湿热试验标准检测报告
  15. 常见笔顺错误的字_容易出错的汉字|汉字中哪些字笔顺容易错
  16. 测度论与概率论笔记6:符号测度
  17. c语言编译运行的几步
  18. Git使用:拉取最新代码、提交本地代码到远程仓库冲突
  19. LORA无线模块使用
  20. Merge用法:Oracle 10g中对Merge语句的增强

热门文章

  1. 如何用纯 CSS 创作一个摇摇晃晃的 loader
  2. Java反斜线(\)路径与转义字符的小坑
  3. 深入Oracle的left join中on和where的区别详解
  4. js之字面量、对象字面量的访问、关键字in的用法
  5. MySQL常用简单小命令
  6. 联络中心的发展方向是SOA
  7. PHP正则表达式快速学习方法
  8. c语言指向常量的指针和常量指针
  9. postgresql中自定义函数脚本的备份及恢复
  10. Fedora20下安装VLC