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

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

eb9f48d00dec808b19978dd93a4a087c.png

其实前段时间自己也尝试用 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、游戏开始状态

dbb1b265dbddd4ab39c826b6f11f0bf7.png

2、游戏进行中

2d8cf0ac08f26088f7982fe9e02dbbd2.png

3、碰壁了,游戏结束

9b7a625f4519ace94a97901b1ee2cc38.png

代码实现:

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值