Java2游戏编程读书笔记(4-2)

本文介绍了Java的IO操作及常用集合框架类,包括java.io包中的输入输出流概念,java.util包内的StringTokenizer、Random类使用方法,以及Vector、Stack、LinkedList和Hashtable等数据结构的特点与应用实例。
 
java.io包含许多允许发送和接收数据的统一的输入输出(I/O)操作。数据的来源或目的地事实上可以是任何事物——来自于键盘的输入输出到显示器,文件,甚至服务器/客户端架构。Java中I/O背后的魔力是通过流(streams)实现的。流只是或者从源读出,或者写入目的地的字符或字节的序列。
Java中I/O以两个叫做java.io.Reader和java.io.Writer的抽象类开始,所有其他的I/O操作都是在扩展它们功能的子类中实现的。
稍后,我们会研究处理声音,图像,文件和网络通信的流。因为GUI应用程序处理用户输入与控制台应用程序不同,所以我们不必成为写Java控制台输入程序的奇才。但是对于现在,在刚熟悉Java语言的时候来研究它则是个不错的主意,应该继续写那些控制台应用程序。
StringTokenizer类允许把String对象分解成标记(token),标记被分隔符分离。在需要分解具有一定格式的数据项目序列时,使用StringTokenizer类非常方便。
Math.random()方法产生一个在0.0到1.0之间的随机数。第一次调用这个方法时,它用当前系统时间作为种子,创建了一个新的Java.util.Random对象。接下来对Math.random()方法的调用从同一个Random对象返回下一个产生的数字。
使用Math.random()方法在大多数情况下都是好用的。但是,有时候会希望对产生的随机值多些控制,例如,当Random类用同一个值作为种子,就会产生相同的输出。这时可能想指定一个特殊的种子(一个long值),这样就能够控制并监控结果以保证每次获得的是相同的输出。有时可能还想给特定的对象以它们自己的Random对象,以保证每个对象获得它自己的随机值的惟一分配,而不是让它们都来自于同一个Random实例。
另外,使用Random类的优势还在于可以获得不同原始类型的值。
1.java.util.Vector
 
import java.util.*;
 
class VectorTest extends Object
{
       public static Vector getRandomScores(){
              //创建一个随机数产生器
              Random rand=new Random();
             
              //随机数的范围设为500-1000
              int numElements=500+Math.abs(rand.nextInt())%501;
             
              //创建一个新的Vector并随机规定一个增量
              Vector v=new Vector(numElements);
              while(numElements>0){
                     //添加一个在0-100之间的Integer
                     v.add(new Integer(Math.abs(rand.nextInt(101))));
                     numElements--;
              }
             
              return v;
       }
      
       public static void main(String[] args){
              int highestScore=0;//目前所找到的最大值
             
              //产生一些随机数
              Vector scores=getRandomScores();
             
              //遍历这些数值并找到最大值
              for(Enumeration e=scores.elements();e.hasMoreElements();){
                     Integer score=(Integer)(e.nextElement());
                    
                     if(score.intValue()>highestScore){
                            highestScore=score.intValue();
                     }
              }
             
              //打印最大值
              System.out.println(highestScore);
       }
}//VectorTest
2.java.util.Stack
堆栈是一种后进先出(LIFO)数据结构,这意味着后插入的对象会先被移出。Java中的Stack类定义了5种方法:push,pop,peek,empty,search。
方法push允许放置元素到Stack的顶部;相反地,peek方法返回顶部元素,但不把它移出;要判断Stack是否包含任何元素,使用empty方法,如果Stack中没有剩余的元素,该方法返回true值;search方法返回一个元素在Stack中放置的从1开始计数的位置,如果找到的元素在Stack的顶部,方法会返回1,如果没有这个元素,会返回-1.
 
作为一个简单例子,我们来把一组Integer对象压入堆栈,然后弹出它们并打印出值:
//创建一个新Stack对象
Stack integerStack=new Stack();
 
//把10个Integer对象压入堆栈
for(int i=0;i<10;i++){
       integerStack.push(new Integer(i));
}
 
//弹出堆栈中所有的值并打印
while(!integerStack.empty()){
       System.out.println(integerStack.pop());
}
堆栈最好的应用之一是处理自定义菜单对象,在第3篇中我们会实际看到如何写一个自定义菜单处理器。
3.java.util.LinkedList
与堆栈不同,链表是先进先出结构。LinkedList类的Java实现包括允许在链表任一端插入和取回的方法,这样的链表通常被称为双向链表,或双端队列。
链表也提供插入,移出以及在集合中查询数据的操作,并且不用写额外的代码。
当有一个需要有规律的查询或更新的数据集合时,应该考虑使用LinkedList类。像往常那样,在使用之前应该多思考问题,在想清楚是使用数组还是链表之后再动手。
4.java.util.Hashtable
Java的Hashtable类的妙处在于它可以用非常少的代码建立一个简单的数据库。
添加到Hashtable的元素由两部分组成:元素的Object值以及与它相关的Object关键字值。添加到表的值在以后可以由它的相关关键字重新获得。虽然关键字值可以是任何类型,但是它们必须能够实现hashCode和equals方法。
假设要为一个overhead-view游戏实现tile引擎。这里想把所有的tiles放到一个容器中,并且通过含有每个tile的图像数据的文件名来访问它们。Hashtable可能是实现这种方案的理想选择。Tiles的图像会作为数据元素被添加进来,它们相关的String表示将作为关键字值。
现在已对如何存储图像有了清晰的认识,下面写一个程序来试验一下。
import java.applet.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.util.*;
 
public class HashTest extends Applet implements ItemListener{
       //用来添加平铺图片的Hashtable
       private Hashtable imageTable;
      
       //选择不同平铺图像的
       private Choice selections;
      
       //假设图片块的宽与高相等,这个值既代表宽又代表高
       private int imageSize;
      
       //图片的文件名
       private final String[] filenames={"cement.gif","dirt.gif","grass.gif",
                                                               "pebbles.gif","stone.gif","water.gif"};
       //初始化Applet
       public void init(){
              int n=filenames.length;
             
              //创建一个有n个成员的Hashtable
              imageTable=new Hashtable(n);
             
              //创建Choice
              selections=new Choice();
             
              //创建一个Panel来在窗体的底部容纳选择框
              Panel p=new Panel();
              p.add(selections,BorderLayout.SOUTH);
              p.setBackground(Color.RED);
             
              //把Choice添加到applet中并注册ItemListener
              setLayout(new BorderLayout());
              add(p,BorderLayout.SOUTH);
              selections.addItemListener(this);
             
              //为图像分配内存
              for(int i=0;i<n;i++){
                     Image img=getImage(getCodeBase(),filenames[i]);
                     while(img.getWidth(this)<0);//这句代码不知道有什么用 ,看不明白
                    
                     //把图像添加到Hashtable和Choice中
                     imageTable.put(filenames[i],img);
                     selections.add(filenames[i]);
                    
                     //设置imageSize属性
                     if(i==0){
                            imageSize=img.getWidth(this);
                     }
              }
       }//init
      
       //在Applet内平铺当前所选择的图像
       public void paint(Graphics g){
              //把传入的Graphics容器转化为可用的Graphics2D对象
              Graphics2D g2d=(Graphics2D)g;
             
              //把Applet的宽和高存下来
              int width=getSize().width;
              int height=getSize().height;
             
              //为放置平铺图像创建一个AffineTransform
              AffineTransform at=new AffineTransform();
             
              //得到当前所选择的图像
              Image currImage=(Image)imageTable.get(selections.getSelectedItem());
             
              //在Applet内部铺满图像
              int y=0;
              while(y<height){
                     int x=0;
                     while(x<width){
                            at.setToTranslation(x,y);
                            //绘制图像
                            g2d.drawImage(currImage,at,this);
                            x+=imageSize;
                     }
                     y+=imageSize;
              }
       }//paint
      
       //在所选图像改变时调用
       public void itemStateChanged(ItemEvent e){
              //下拉列表框已经改变,重新绘制画面
              repaint();
       }
}//HashTest
虽然已经在第1章看到如何编译和运行applet,但因为这是我们研究的第一个applet,所以还要再复习一遍。编译源代码总是如下所示:
javac HashTest.java
一旦编译成功,运行HashTest applet就简单了:
appletviewer HashTest.html
Hashtable applet的代码清单看起来比较复杂,在第2篇中将会讲解每个构成部分。就目前而言,应把注意力集中于如何使用插入和从表中取值时调用的方法上。
第3篇中讨论创建自定义字体类时,我们将研究另外一个Hashtable例子。如果理解了这个例子以及本章练习中出现的表练习,那么就可以认为自己已经掌握了Hashtable。
请不要把本章看作关于Java功能的一个完整的可用的论述,在API的标准版本中有数百个Java类。这里只是想使读者熟悉Java提供的很多常用特性中的一些。在自己的Java学习中,一定要在构思编写工具之前查询Java API——可能已经存在提供读者所期望的功能的类,或者至少有一个可以依赖的基类。
总而言之,Java提供了许多类,接口和工具,比如线程,使用它可以更快,更简单地开发更强大的应用程序,并且比其他大多数语言优美。本书希望在理解了Java语言背后的所有细节和扩展能力之后,读者会欣赏到它帮助程序员摆脱基本操作,而专注于解决问题的好处和能力。
试着做下面的练习,并设想用其他的语言如C++解决它可能有的难度。希望读者会认同Java所提供的类是构建起程序并更快有效地运行的最好方法。
4.1写出保存一个链表顺序的代码。(提示:Java LinkedList是FIFO结构——哪些类具有LIFO结构?)
4.2练习4.1的代码会不会与保存一个StringBuffer对象的内容有很大的不同?
4.3写一个工具类,封装BufferedReader类,并从键盘读入不同类型的信息,如float值,int值,boolean值等。可以写如readInt,ReadFloat等的方法,确保每个组件只接收有效的输入,并且在输入值不正确时提示用户重新输入数据。
4.4写一个程序(使用BufferedReader类),从名为file.txt的文件读入Strings。Reader应该连续地读遍全文件。文件输入应该立即改变到标准输出。文件不存在或打不开时输出一个错误消息。(提示:使用java.io包中的FileReader类)
4.5重写Fibonacci程序,使用Java.util包提供的Timer和TimerTask类。建议保持Fibonacci类框架,但是用一个匿名内部类来做定时。
4.6创建一个映射假期和它们的日历日期的Hashtable。使用java.util.GregorianCalendar对象作为表值,String对象作为关键字。例如,要添加最喜欢的假期到表,可能会这样写:
Hashtable ht=new Hashtable();
Calendar c=new GregorianCalendar();
c.set(Calendar.MONTH,Calendar.NOVEMBER);
c.set(Calendar.DAY_OF_MONTH,3);
ht.put(“Tom’s birthday”,c);
System.out.println(ht.get(“Tom’s birthday”));
试着添加一些你最喜爱的假期,并确保可以从表中重新得到它们。
4.7这道题更多是关于工程风格的问题,所以请仔细思考。我们还没有研究过如何创建和绘制图形,但是仍然可以写一个使用面向对象概念,简单地使用命令行的游戏。写一个玩扑克牌的二十一点的单人游戏,会需要(至少)5个类:Card类,Deck类,Hand类,Player类和Blackjack类。在第1篇中我们已经见到过Card和Deck类。Blackjack类将完成主程序所要处理的大部分工作。Card只包括一个声明是52张纸牌中某一个的整数型变量。更多关于这个类的信息可以参照第3章。Deck包括52个Card对象,并且应该在每个游戏之前调用它的shuffle方法。一个Deck对象也必须能够把这副纸牌中的下一张纸牌处理到某一玩家。为了灵活起见,Hand类应该能够包含任何数量的Card对象;实际上可以为任何纸牌游戏重用Hand类。Player类应该含有玩游戏者的数量,以及游戏胜利的数量。它还会包含一个Hand变量来表示玩家的纸牌。但是,确保Blackjack类做全部游戏的大部分处理。
记住下面的细节:
q        幺点可以表示1或11,这依赖于哪一个更合适。例如AA25可能总共有19点;AAAQ可能总共有13点;AK则可能是21点。
q        可能需要询问用户是否愿意在游戏开始之前浏览二十一点的规则。
q        如果玩家能够拿到5张牌而没超过21,则获胜。
如果需要这个工程的帮助,可以浏览配书光盘中的源代码。希望读者能做出干净的界面和令人上瘾的游戏局。
对于一个Java新手来说,这个程序最难的地方可能是使每一部分在一起工作。建议在写任何代码之前把所想列到纸上。并且可以使用你觉得有必要而这里没有指出的方法。记住保持数据成员private(或protected),并且使用正确的访问方法访问它们。可以同样使用Card,Deck和Hand类,把Blackjack程序扩展成单人5张牌游戏。
现在的位置和目标
第2篇看起来好像一次需要掌握的东西很多——尤其对于Java或面向对象程序设计的新手来说。把整个Java语言的细节浓缩成几章是很难的,一个关于整个语言的彻底的研究可能会需要差不多1000页的篇幅才能完成。因此,如果现在你对我们所讲述的内容感觉不满意的话,可能就需要再复习一遍。在继续前进之前,努力做好每章后面的练习,或者自己写一些基本的程序。开始编写游戏时,并不需要必须是Java专家,但是要对相关的Java基础有比较牢固的理解,这会帮助你更容易地消化本书余下的部分。Java中充满着奇妙的地方,但是它并不像火箭技术那样高深(除非你用它来设计火箭)
如果你真想深入到Java语言工作机理的核心,可以查阅Java语言详述(Java Language Specification),可以在Java 2文档或在线 http://java.sun.com/docs/books/jls/second_edition/html/j.title.doc.html查看。
讲到这里,大多数读者差不多已准备好开始编写一些游戏了,接下来我们会关注创建图形化用户界面,以及如何使用输入设备来真正地告诉应用程序谁是“老板”。
 
中文名: Java2游戏编程 原名: Java 2 Game Programming 作者: Thomas Petchel译者: 晏利斌 孙淑敏 邵荣 资源格式: PDF 版本: 扫描版 出版社: 清华大学出版社书号: 7302112932发行时间: 2005年08月 地区: 大陆 语言: 简体中文 简介: 内容介绍:   你经常看到有人在玩手机游戏吧,那些手机游戏基本上是用Java编写的。Java已经成熟了,它现在是一种开发能够多种平台上运行的中小型游戏的很好方式。本书将向读者展示用Java语言和它的类库创建2D游戏,所涉及的主题包括高速性能、双缓冲图像、动画、声音、媒体控制、I/O和网络支持等。将带领大家一步一步学习编写Java游戏,最终打造属于自己的Java游戏。 目录: 第1篇 步入Java丛林:从Java2 API开始 第1章 Java2软件开发工具包 1.1 Java简史 1.2 为什么在游戏中使用Java 1.3 为Java准备系统 1.3.1 安装Java SDK 1.3.2 编译和运行Java程序 1.3.3 使用命令行 1.3.4 使用集成开发环境(IDE) 1.3.5 关于Java2文档的说明 1.4 总结 第2章 预备:学习Java2 API 2.1 Game Over! 程序 2.1.1 import语句 2.1.2Java代码加注释 2.1.3 Java类声明 2.1.4 Java方法声明 2.1.5 Java中的代码块 2.1.6 Java程序组成部分的关键点回顾 2.2 比特和字节:原始的Java类型 2.2.1 基本的整数类型 2.2.2 浮点类型 2.2.3 Char类型 2.2.4 布尔型 2.2.5 String类型 2.2.6 强制转换变量类型 2.2.7 Java数据类型、数组和标识符需要记忆的要点 2.3 Java中的运算符 2.3.1 赋值运算符 2.3.2 比较运算符 2.3.3 算术运算符 2.3.4 自增和自减运算符 2.3.5 更多的整数运算符 2.3.6 使用点运算符 2.3.7 instanceof运算符 2.3.8 优先级顺序 2.3.9 关于运算符的记忆要点 2.4 条件语句 2.4.1 switch语句 2.4.2 Java中的循环语句 2.4.3 用break、continue和return提前退出循环 2.5 处理运行时异常 2.5.1 使用try和catch块 2.5.2 使用throws子句 2.5.3 关于流程控制语句的记忆要点 2.6 总结 2.7 练习 第3章 带有类的语言:Java面向对象程序设计 3.1 设计一个Java类 3.2 方法的魔法 3.3 关于方法的更多话题 3.3.1 构造函数方法 3.3.2 访问方法 3.3.3 类方法 3.3.4 “其他”方法 3.4 继承 3.5 抽象类 3.6 类修饰符 3.7 接口 3.8 快捷地创建类 3.9 包 3.10 总结 3.11 练习 第4Java API为你服务:常用Java4.1 java.lang包 4.1.1 java.lang.Object 4.1.2 java.lang.String 4.1.3 java.lang.StringBuffer 4.1.4 封装类 4.1.5 java.lang.Math 4.1.6 java.lang.System 4.1.7 java.lang.Cloneable 4.1.8 java.lang.Thread 4.2 java.io包 4.3 java.util包 4.3.1 java.util.StringTokenizer 4.3.2 java.util.Random 4.3.3 Java2集合框架 4.4 总结 4.5 练习 第2Java 2-D图像开发和抽象Window工具包 第5章 Applet基础 5.1 什么是Java applet 5.2 Applet和Application的比较 5.3 Applet的组成和生命周期 5.4 一个Applet例子 5.5 运行Java Applets 5.6 通用AWT组件 5.6.1 按钮 5.6.2 单选按钮(Radio Button) 5.6.3 作出重要选择 5.6.4 循环播放声音文件 5.6.5 文本域 5.6.6 标签 5.7 布局管理 5.7.1 FlowLayout类 5.7.2 GridLayout类 5.7.3 BorderLayout类 5.7.4 CardLayout类 5.8 容器(Container) 5.9 创建自定义组件 5.10 一个完整的例子 5.11 总结 5.12 练习 第6章 监听用户 6.1 EventLi
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

默然说话

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值