转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 软件开发 >> JAVA开发 >> 正文
跟我学Java Swing之游戏设计(3)         ★★★★

跟我学Java Swing之游戏设计(3)

作者:闵涛 文章来源:闵涛的学习笔记 点击数:766 更新时间:2009/4/22 23:33:17

 谁说编写程序不是一项艺术?那些命令与符号正像一幅工笔画,一笔一画产生出多少变幻莫测的结果。不过,光有骨架的工笔画恐怕也无法成为绝世佳作,那么,今天就让我们来为自己的作品添上最初的绚丽色彩吧。

  前言

  今天我们会为游戏添加动画效果,这将会涉及到图形处理,还有线程的基本概念,这可是一项非常有意思的工作哦。本期源程序下载http://www.pconline.com.cn/pcedu/empolder/gj/java/0510/acc/051025swingkyodai.zip。

  上一期我们完成了游戏界面的设计,可是游戏的功能却还十分单薄,比如说几个人同时玩一个游戏,我们怎么比较谁玩得比较好呢,就算是自己一个人在玩,也得知道自己每次的成绩啊。竞技是游戏的主要动力之一,为了提高游戏的可玩性,我们得加入计时和计分的功能才行。

  关于游戏的计时和计分功能,因为与我们Swing的主题关系不大,这部分功能的实现我就不说了,如果大家感兴趣的话可以参考一下我的源程序,里面有详细的说明,在这里我们就只讨论一下如何将显示界面做得漂亮。

  JLabel和Font

  还记得最开始的主界面是如何设计的吗?我们将界面分成了三个部分:系统菜单、游戏区、用户交互区。用户交互区的作用就是放置用户的操作及反馈信息,计时和计分功能自然就是放在这里。

  首先我们可以放置一个文本控件,然后将这个控件的背景设置为界面的背景色或透明色。那么这个控件应该是哪个呢?这个控件就是JLabel!JLabel的用法并不难,如果你能够熟练使用JButton的话,那么JLabel控件也会是小case了,让我们一起来试试吧:

JLabel score = new JLabel("307"); // 假设用户当前的分数为307分
actionPanel.add(score);
  看看程序运行的结果,感觉如何?你也许会说:字太小了,而且颜色也太暗了,看不太清楚。没关系,这很容易解决:

JLabel score = new JLabel("307");
Font font = new Font("宋体", Font.BOLD, 48);
score.setForeground(Color.yellow);
score.setFont(font);
actionPanel.add(score);
  在上面的代码中,我们首先创建了一个字体对象font,Font构造函数中3个参数的意义依次为:使用字体的名称、字体的样式(普通、粗体、斜体等)以及字体的大小等;然后,我们使用setForeground来设计JLabel的前景色;最后,我们将JLabel的字体改为我们创建的字体。现在我们再来看看程序运行的结果,是不是效果好多了(见图1)?

  在游戏的过程中,只要时间或者分数发生变化,我们就可以使用JLabel.setText(String s)来更新显示。

  细心的朋友可能会发现,在我们显示时间和分数的过程中,如果将字体设置得很大,显示内容虽然更容易看清,但视觉效果却变得很差。这是因为字体越大,字体上的锯齿就会越明显,这是Swing控件显示文字的通病,遗憾的是暂时还没有很有效的解决方法(见图2)。

 


  善用Graphics绘制图形

  在前面所有的章节中,我们都是使用现成的控件来满足自己的需要,现成的控件虽然使用方便,却不能完全满足我们的要求。这时我们就需要了解一下如何不使用控件来绘制图形。

  无论是Swing控件也好,AWT控件也好,他们都会有一个paint(Graphics g)方法,一般情况下我们不会去理它的,然而,当我们需要自己绘制图形的时候,我们就不得不对这个方法有所了解。

  为了让大家能够接受自己绘制图形的方法,我们还是从paint(Graphics g)方法讲起吧:paint(Graphics g)方法将控件看作一张空白的纸,当我们需要绘制图形的时候,就可以使用Graphics提供的一些基本方法来进行绘制。为了方便大家理解,我们新建一个Clock类来完成用户时间的显示,代码如下:

import javax.swing.*;
import java.awt.*;

public class Clock

extends JPanel {

Font font48 = new Font("serif", Font.BOLD, 48);
   this.setMinimumSize(new Dimension(156, 48));
    this.setPreferredSize(new Dimension(156, 48));
 }

public void paint(Graphics g) {
    g.setColor(new Color(111, 146, 212));
    g.clearRect(0, 0, this.getWidth(), this.getHeight());
    g.setColor(Color.yellow);
    g.setFont(font48);
    g.drawString("307", 16, 40);
  }
}
  以上内容应该在我们新建的Clock.java文件中,代码并不难读懂,大家可以自己查看文档找到相关函数的使用说明。然后,我们将原来程序中显示时间的代码部分改为:

Clock clock = new Clock();
actionPanel.add(clock);
  怎么样,运行结果是否相同?虽然此时我们仍然没有消除文字上的锯齿,不过已经对Swing中自己绘制图形有了一个大致的了解。

  随心所欲的Graphics2D

  对于追求最佳视觉效果的我们,文字上的锯齿显示是不能容忍的。那么如何解决这个问题呢?既然这是Swing控件显示字体的通病,并且就连Graphics也无能为力,看来,我们只有另辟蹊径了。

  好在Sun也意识到了这一点,因此在Java中提供了Graphics2D类来解决这种问题。下面,我们将依然使用代码来说明问题:

public void paint(Graphics g) {
  Graphics2D g2 = (Graphics2D) g;
  Dimension d = getSize();
  g2.setBackground(new Color(111, 146, 212));
  g2.clearRect(0, 0, d.width, d.height);
  g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
  RenderingHints.VALUE_ANTIALIAS_ON);
  g2.setColor(Color.yellow);
  g2.setFont(font48);
  g2.drawString("123", 16, 40);
}
  在上述的代码中,我们将Graphics对象转换成Graphics2D对象后,只需使用简单的一句setRenderingHint()就完成了抗锯齿的功能。现在再来看看程序运行的效果,你还满意吗(见图3)?

  让文字活起来

  渴望无限,创造无限。如果能把计分和计时功能做成动画,一定会更加生动。最简单的做法就是让数字依次变化,比如说时间,我们可以每隔1秒钟就显示一次数值,比如说上面的代码,我们可以简单改为:

for (int i = 1000; i < 2000; i++) {
  g2.setBackground(new Color(111, 146, 212));
  g2.clearRect(0, 0, d.width, d.height); // 清除当前绘图区域
  g2.setColor(Color.yellow);
  g2.drawString("" + i, 16, 40);
  try {
    Thread.sleep(1000); // 延时 1 秒钟
  } catch (InterruptedException ex) {
  }
}
  当你执行以上代码以后便会知道,上面的代码实际上有问题!我们使用了Thread.sleep(1000)来让程序进行延时,每当执行Thread.sleep()的时候,程序会进入休眠状态,不响应其他任何操作,就连显示也不会更新,所以也就无从显示动画效果了。

  线程(Thread)是惟一的解决方法,它可以让程序在同一个时刻完成两件或者两件以上的事情。想让你的程序支持线程,你可以选择以下两种方法的任意一种:

①public class Clock extends Thread
②public class Clock implements Runnable

  第一种方法要求你的程序继承Thread类,可是,如果继承Thread类之后,我们就没有办法再继承JPanel了,因为Java不支持多重继承,如果不能继承JPanel,那么paint(Graphics g)也没有用武之地了。而第二种方法只要求你实现Runnable接口,而Java允许一个类实现多个接口,所以我们应该选择第二种方法。

  首先需要把Clock的声明改成public class Clock extends JPanel implements Runnable,然后添加public void run() {  }

  上面是实现Runnable接口的最基本的构架。有的时候,为了让线程能够具备开始和停止的功能,我们还得再扩充一下。首先是线程的开始:

public void start() {
  startTime = System.currentTimeMillis();
  thread = new Thread(this);
  thread.start();
}
  这里我们使用了System.currentTimeMillis()来获得开始时的系统时间,以便于以后计算用户的游戏时间。

  然后是运行的过程:

public void run() {
  Thread currentThread = Thread.currentThread();
  while (thread == currentThread) {
    long time = System.currentTimeMillis();
    usedTime = time - startTime;
    try {
      repaint();
      thread.sleep(100);
    }
    catch (InterruptedException ex) {
    }
  }
}
  第一句话Thread currentThread = Thread.currentThread();获得系统当前的线程,然后在循环中进行判断是否为当前线程,这在在线程比较多而且线程之间的依赖性比较强的情况下非常有必要。repaint() 是AWT/Swing控件的方法,它会自动调用paint(Graphics g)方法以便重新绘制显示区域。最后,我们使用了thread.sleep(100)来让程序每隔0.1秒运行一次。由于thread.sleep()方法会抛出异常,所以我们还需要捕获异常。

  由于paint(Graphics g)每次显示的内容都会不同,因此,我们需要使用一个全局全量usedTime来记录当前的时间,在输出的时候,我们应写成:

  g2.drawString("TimE:" + getTime(), 16, 40);
  其实getTime()方法是我们自己写的,其作用是获得用户当前使用的时间,并将时间格式化后传出。最后,别忘记了在我们的主程序中调用start()方法,如:

Clock clock = new Clock();
clock.start();
actionPanel.add(clock);
  小方糖

  Thread的前世今生

  最早的Thread提供了Thread.start() 、Thread.pause()/Thread.resume() 、Thread.stop() 这三个方法来完成线程的开始、暂停和结束功能,然而,在后来的JDK中,Sun却不推荐使用pause()/resume()和stop()方法,理由是pause()和stop()方法在某些场合会让程序进入死锁状态,因此,在你的程序中,假如你使用了Thread的以上几种方法,编译的时候编译器会告诉你

"xxx.java": stop() in java.lang.Thread has been deprecated at line xx, column xx
  这时候你就要注意了!

  小结

  今天我们学习了使用Graphics/Graphics2D来满足自己特殊的需要,再也不需要看控件的脸色了。同时,我们也知道了如何使用线程来让程序同时进行多个操作,并且结合了以上两点来实现计时功能。但是我没有在这里完成计分功能,就把这当作留给大家的小小作业吧!

 
作者:张剑    


[JAVA开发]详述:JAVA也能克隆!  [JAVA开发]跟我学Java Swing之游戏设计(1)
[JAVA开发]跟我学Java Swing之游戏设计(2)  [JAVA开发]Java学习指南
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · C语言系列  · VB.NET程序
    · JAVA开发  · Delphi程序
    · 脚本语言
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台