默然说话

一个异想天开的人做着异想天开的梦

牟勇ID:mouyong
61759次访问,排名1575好友4人,关注者5
我快乐,我存在
mouyong的文章
原创 108 篇
翻译 4 篇
转载 29 篇
评论 12 篇
默然的公告
如果要联系我,希望能说明来意,谢谢.

点击这里给我发消息

Google

最近评论
peigen:又~~~~为什么是又呢???
dcopperfield:顶下
gaoyunpeng:无意中进入到这个博客,很快就被里面的内容所吸引,感觉很有意思,不知道为什么会有这样的感觉,或许只是一种直觉上的吸引吧,一直在看博客里的文章,觉得很不错,天天等更新,哈哈,终于看到新的文章啦~
我会一直关注的~
mouyong:谢谢你的鼓励,我会更加努力。
了祝愿你实现自己的理想,达成自己的目标
wsspy007:牟老师,我发现你是我见过最好的老师了,为学生考虑最多,一切为学生着想,不知道牟老师还记得我么,张伟(无名小辈肯定你是忘记了),第一期跟杨大宇他们在一个班的,补考两次都没有及格,我现在不在昆明了,在胜利油田,这里一切都很好,一个月的薪金能顶得上昆明3-5个月的薪水,但是我不喜欢这份工作,钱固然多,但是从学校出来步入社会以后才发现,我还是应该走软件开发这条路,现在每天我只睡4-6个小时,工作12……
文章分类
收藏
    相册
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 Java2游戏编程读书笔记(5-2)收藏

    新一篇: 控制台版21点(BlackJack)源码(Java2游戏编程第4章练习参考答案) | 旧一篇: Java2游戏编程读书笔记(5-1)

     
    一个容器可以容纳另外一个组件——甚至是另一个容器。
    容器分为两个大类:一类是可以自由移动的(Window),另一类保持在一个固定的位置(Panel)。
                                                            Component
                                                                  
                                                            Container
                                              Window————+————Panel
                                        Dialog—+—Frame                
                                                                                     Applet
                                       FileDialog
    可以把几个Panel或者Container对象附着在一个父Container对象上,每一个附着在父Container上的对象可以拥有它自己的布局管理器,使用这个模型,可以在applet上创建一些更精致的布局。
    下面的程序PanelTest,演示了一个Panel布局。其中,创建了两个Panel对象,每一个都有一个不同的布局方式。在每一个Panel上都添加了几个Button对象,然后这两个Panel被放到了applet中,这个applet使用默认的FlowLayout布局管理器来显示这两个Panel。
    import java.awt.*;
    import java.applet.*;
     
    public class PanelTest extends Applet{
           public void init(){
                  //设置applet的布局为默认的FlowLayout
                  this.setLayout(new FlowLayout());
                 
                  //创建一个2×2的GridLayout的Panel,并添加4个按钮
                  //然后把这个Panel放到applet上
                  Panel p1=new Panel();
                  p1.setLayout(new GridLayout(2,2));
                  p1.add(new Button("B1"));
                  p1.add(new Button("B2"));
                  p1.add(new Button("B3"));
                  p1.add(new Button("B4"));
                  add(p1);
                 
                  //创建第二个Panel,布局为BorderLayout,并添加5个按钮
                  //然后把这个Panel放到applet上
                  Panel p2=new Panel();
                  p2.setLayout(new BorderLayout());
                  p2.add(new Button("North"),BorderLayout.NORTH);
                  p2.add(new Button("South"),BorderLayout.SOUTH);
                  p2.add(new Button("East"),BorderLayout.EAST);
                  p2.add(new Button("West"),BorderLayout.WEST);
                  p2.add(new Button("Center"));
                  add(p2);
           }
    }
    由于上面的程序没有保存每一个按钮的引用,所以不能捕获按钮产生的事件。当然一个实际的applet会实现ActionListener并且把按钮的引用保存为private的成员,上面的例子只是一个简单的示例。上面程序的运行结果嵌在一个150×125的窗体中。
    假设正在开发一个用户可以定制其角色的角色扮演游戏。角色扮演游戏的角色开发中的一个重要方面是技能设置,给定一个初始数目的“技能点”,用户可以把点设置到不同的技能中去。一个属性得到的技能点越多,该角色的这种技能就越强。
    下面的AttributeTest applet允许用户把10个技能点分配到4种技能中:力量,智慧,敏捷和魔法。这个applet的代码引入了两个类:AttributeButton和AttributePanel,它们通过继承基本AWT组件来增强程序的功能。AttributeButton继承Button类,添加了一种把它自己和AttributePanel联系起来并更新自己的内容的方法;AttributePanel类包含一个属性的描述以及分配给这个属性的技能点,它还包含两个分配属性点数的AttributeButton对象。用户可以反复修改各个属性所分配的点数直到满意为止。
    import java.applet.*;
    import java.awt.*;
    import java.awt.event.*;
     
    //允许改变属性
    class AttributeButton extends Button{
           //放这个按钮的Panel
           private AttributePanel parent;
          
           public AttributeButton(String label,AttributePanel ap){
                  super(label);
                  parent=ap;
           }
          
           //更新父控件的属性
           public int updatePanel(int pointsRemaining){
                  //点+号为plus按钮分配一个点值
                  if(this.getLabel().equals("+")){
                         //仅在还有点剩余时分配
                         if(pointsRemaining>0){
                                parent.allocatePoints(1);
                                return -1;
                         }
                         else{
                                return 0;
                         }
                  }else{//否则扣除一个点
                         //当点数大于零的时候才进行扣点
                         if(parent.getPointsAllocated()>0){
                                parent.allocatePoints(-1);
                                return 1;
                         }else{
                                return 0;
                         }
                  }
           }
    }
     
    //允许角色更改一个属性
    class AttributePanel extends Panel{
           //属性的文本描述
           private String attribute;
          
           //显示给这个属性所分配点值的Label
           private Label pointsAllocated;
          
           public AttributePanel(String attr,ActionListener l){
                  attribute=attr;
                 
                  pointsAllocated=new Label("0",Label.CENTER);
                 
                  //设置Panel的布局为3×1的网格
                  setLayout(new GridLayout(3,1));
                 
                  setBackground(Color.green);
                 
                  //添加描述属性的标签
                  add(new Label(attr,Label.CENTER));
                  add(pointsAllocated);
                 
                  //把+/-按钮添加到父ActionListener上
                  Button incr=new AttributeButton("+",this);
                  incr.addActionListener(l);
                  Button decr=new AttributeButton("-",this);
                  decr.addActionListener(l);
                 
                  //添加另一个有加,减按钮的Panel
                  Panel p=new Panel();
                  p.add(incr);
                  p.add(decr);
                  add(p);
           }
          
           //更新pointsAllocated label
           public void allocatePoints(int n){
                  int value=getPointsAllocated()+n;
                  pointsAllocated.setText(""+value);
           }
          
           //返回给这个属性分配的点值
           public int getPointsAllocated(){
                  return Integer.parseInt(pointsAllocated.getText());
           }
          
           public String toString(){
                  //返回这个属性的详细描述
                  return attribute+":"+getPointsAllocated();
           }
    }
     
    public class AttributeTest extends Applet implements ActionListener{
           //所有剩余的点值
           Label pointsRemaining;
          
           //这个applet的属性
           private final String ATTRS[]={"力量","智慧","敏捷","魔法"};
          
           public void init(){
                  pointsRemaining=new Label("点数剩余:10",Label.CENTER);
                 
                  this.setLayout(new FlowLayout(FlowLayout.CENTER,5,10));
                 
                  //添加组件
                  for(int i=0;i<ATTRS.length;i++){
                         add(new AttributePanel(ATTRS[i],this));
                  }
                 
                  add(pointsRemaining);
           }
          
           public void actionPerformed(ActionEvent e){
                  //得到剩余的点值
                  int n=Integer.parseInt(pointsRemaining.getText().substring(5));
                 
                  //更新按钮Panel的标签和主标签
                  n+=((AttributeButton)e.getSource()).updatePanel(n);
                  pointsRemaining.setText("点数剩余:"+n);
           }
    }
    前面的例子演示了怎么使用基本的applet组件来为一个角色扮演游戏创建一个角色轮廓,虽然它对于开始学习applet而言已经很不错了,但是还可又做些工作来进一步改善它,比如:
    q        添加更多的属性面板。如果允许用户输入名字,选择职业和性别,并且能够回顾所选属性的列表,这样就更好了。
    q        增加复杂度。如果想有多个属性菜单,可能让它们从单一的基类继承会好一些,这个基类必须包含所有属性菜单所共有的方法。这种方式可又让代码更加灵活,这样使得扩展和维护applet变得更加容易。
    CharacterBuiler applet的思路是创建一个让一系列按钮来回切换的CardLayout。布局中的每一个卡片由含有一个单一角色属性的面板组成,用户可又访问每一个卡片来选择自己的爱好,比如姓名,职业和性别;用户还可又分配给定的有限技能点,就像在前面的AttributeTest applet中所展示的一样。
    //AttributePanel.java
    import java.awt.*;
     
    public abstract class AttributePanel extends Panel{
           //属性的文本描述
           protected String attribute;
          
           public AttributePanel(String attr){
                  attribute=attr;
           }
          
           public final String getAttribute(){
                  return attribute;
           }
          
           //强制子类覆盖toString方法
           public abstract String toString();
    }
    抽象类AttributePanel提供了两个主要用途,首先,它允许几个属性和所有含有角色属性选项的面板相关联,每一个AttributePanel都定义了一个String对象来描述这个面板,并且定义了一个String对象来描述属性本身;另一个用途是可以定义一个AttributePanel对象而无须提前知道它们最后运行时的类型。
    由于AttributePanel类被声明为抽象类,不能直接实例化AttributePanel,但是这没什么问题。它被设计为功能不完善的,目的是可以根据特定的角色属性需要而被扩充。
    下面的TextFieldPanel创建了允许用户输入其姓名的一个文本域(TextField类)和标签(Label类)
    //TextFieldPanel.java
    import java.awt.*;
     
    //在Panel内放置String属性
    public class TextFieldPanel extends AttributePanel{
           //放置属性的TextField
           private TextField textField;
          
           public TextFieldPanel(String attr,String prompt,int textLength){
                  super(attr);
                 
                  this.setLayout(new FlowLayout(FlowLayout.CENTER,15,0));
                 
                  //如果提示是一个有效字符串,则添加一Label
                  if(prompt!=null){
                         add(new Label(prompt,Label.LEFT));
                  }
                 
                  //创建TextField,并把它添加到Panel上
                  textField=new TextField(textLength);
                  add(textField);
           }
          
           public String toString(){
                  //返回属性,一个"不确定"的消息
                  if(textField.getText().trim().equals("")){
                         return attribute+":未定义";
                  }
                 
                  return attribute+":"+textField.getText().trim();
           }
    }
    CheckboxPanel类允许用户在几个选项中作出唯一选择,比如选择性别和职业。下面是它的代码
    //CheckboxPanel.java
    import java.awt.*;
     
    public class CheckboxPanel extends AttributePanel{
           //容纳Checkbox的CheckboxGroup
           protected CheckboxGroup cbg;
          
           //重写Applet类的init方法
           public CheckboxPanel(String attr,String[]items,String selectedItem){
                  super(attr);
                 
                  this.setLayout(new GridLayout(items.length+1,1,5,5));
                 
                  add(new Label(attribute,Label.CENTER));
                 
                  //创建CheckboxGroup
                  cbg=new CheckboxGroup();
                 
                  for(int i=0;i<items.length;i++){
                         add(new Checkbox(items[i],cbg,items[i].equals(selectedItem)));
                  }
           }
          
           public String toString(){
                  return attribute+":"+cbg.getSelectedCheckbox().getLabel();
           }
    }
    最后是属性选项面板的清单。SkillPanel类允许用户对不同的技能分配技能点。它实现的功能和在AttributeTest applet中实现的很类似:
    //SkillPanel.java
     
    import java.awt.*;
    import java.awt.event.*;
     
    //提供了一个可以修改技能值的按钮
    class SkillButton extends Button{
           //显示给技能分配点的Label
           private Label pointsAllocated;
          
           public SkillButton(String desc,Label label){
                  super(desc);
                  pointsAllocated=label;
           }
          
           public int getPointsAllocated(){
                  return Integer.parseInt(pointsAllocated.getText());
           }
          
           private void allocatePoints(int n){
                  int value=getPointsAllocated()+n;
                  pointsAllocated.setText(""+value);
           }
          
           //更新父属性的值
           public int update(int pointsRemaining){
                  //如果是"+"则分配点数
                  if(getLabel().equals("+")){
                         //只在有点剩余时才分配
                         if(pointsRemaining>0){
                                allocatePoints(1);
                                return -1;
                         }
                  }else{
                         if(getPointsAllocated()>0){
                                allocatePoints(-1);
                                return 1;
                         }
                  }
                 
                  //分配/回收失败
                  return 0;
           }
    }
     
    //容纳不同角色的技能值
    public class SkillPanel extends AttributePanel implements ActionListener{
           //每一项技能所分配的点数
           Label[] pointsAllocated;
          
           //剩余可分配的总点数
           Label pointsRemaining;
          
           //这个applet的属性
           private String[] skills;
          
           public SkillPanel(String attr,String[] sk,int alloc){
                  super(attr);
                 
                  skills=sk;
                 
                  //创建pointsRemaining标签
                  pointsRemaining=new Label("点数剩余:"+alloc,Label.CENTER);
                 
                  //把applet的layout设为FlowLayout
                  setLayout(new FlowLayout(FlowLayout.CENTER,5,10));
                 
                  //添加组件
                  pointsAllocated=new Label[skills.length];
                  for(int i=0;i<skills.length;i++){
                         pointsAllocated[i]=new Label("0",Label.CENTER);
                         addSkill(skills[i],pointsAllocated[i]);
                  }
                 
                  add(pointsRemaining);
           }
          
           private void addSkill(String skill,Label label){
                  Panel p=new Panel();
                 
                  //设置面板布局为3×1网格
                  p.setLayout(new GridLayout(3,1));
                 
                  p.setBackground(Color.green.darker());
                 
                  //添加一个描述属性的标签
                  p.add(new Label(skill,Label.CENTER));
                  p.add(label);
                 
                  //把+/-按钮添加到父ActionListener
                  Button incr=new SkillButton("+",label);
                  incr.addActionListener(this);
                  Button decr=new SkillButton("-",label);
                  decr.addActionListener(this);
                 
                  //添加另一个有加,减按钮的Panel
                  Panel buttonPanel=new Panel();
                  buttonPanel.add(incr);
                  buttonPanel.add(decr);
                  p.add(buttonPanel);
                 
                  add(p);
           }
          
           public String toString(){
                  //返回一个包含每一种技能分配情况的String
                  String s="";
                  int points=0;
                  for(int i=0;i<skills.length;i++){
                         points=Integer.parseInt(pointsAllocated[i].getText());
                         s=s+skills[i]+"("+points+")    ";
                  }
                 
                  return s;
           }
          
           public void actionPerformed(ActionEvent e){
                  //得到可分配的点数
                  int n=Integer.parseInt(pointsRemaining.getText().substring(5));
                 
                  //更新按钮面板的主标签
                  n+=((SkillButton)e.getSource()).update(n);
                  pointsRemaining.setText("点数剩余:"+n);
           }
    }
    前面还提过一个显示用户输入概要的面板,它对主applet的每一个AttributePanel对象都有一个引用,允许它们的toString方法定义所要显示的概要文本。
    //Summarypanel.java
    import java.awt.*;
     
    //包含属性概述的Panel
    public class SummaryPanel extends Panel{
           //描述每一个属性的Label
           private Label[] summaries;
          
           //AttributePanel数组
           private AttributePanel[] panels;
           public SummaryPanel(AttributePanel[] ap){
                  super();
                  panels=ap;
                  setLayout(new GridLayout(panels.length+1,1,5,5));
                 
                  add(new Label("描述:"));
                 
                  //把Label添加到Panel
                  summaries=new Label[panels.length];
                  for(int i=0;i<panels.length;i++){
                         summaries[i]=new Label("",Label.LEFT);
                         add(summaries[i]);
                  }
           }
          
           /**
            *由于不知道到底是哪一个panel被更新,所以让每一个
            *AttributePanel更新它的标签
            */
            public void update(){
                 for(int i=0;i<panels.length;i++){
                        summaries[i].setText(panels[i].toString());
                 }
            }
    }
    现在可以把这些类组装到一起。下面的CharaterBuilder applet在一个CardLayout中定义了4个属性选择面板和一个概要面板,单击back和next按钮可以切换。
    import java.applet.*;
    import java.awt.*;
    import java.awt.event.*;
     
    //CharacterBuilder类包含几个放在一个CardLayout中的Panel,还有back和next按钮
    public class CharacterBuilder extends Applet implements ActionListener{
           //在cardPanel中选择下一个和上一个按钮
           private Button back;
           private Button next;
          
           private Panel attributePanel;
           private SummaryPanel summaryPanel;
          
           //描述不同属性选项的常数String
           private final String[] GENDERS={"男","女"};
           private final String[] SKILLS={"力量","智慧","敏捷","魔法"};
           private final String[] PROFESSIONS={"武士","吟游诗人","弓箭手","术士","铁匠","德鲁依"};
          
           public void init(){
                  //创建一个GridLayout来容纳卡片和按钮
                  setLayout(new GridLayout(2,1));
                 
                  //得到给角色分配的技能点数
                  int skillPoints;
                  try{
                         skillPoints=Integer.parseInt(getParameter("SkillPoints"));
                  }catch(NumberFormatException e){
                         skillPoints=10;
                  }
                 
                  //创建一组属性面板,其中一个是角色的姓名
                  //性别,技能和职业
                  AttributePanel[] panels=new AttributePanel[]{
                         new TextFieldPanel("姓名","键入您的姓名",20),
                         new CheckboxPanel("性别",GENDERS,GENDERS[0]),
                         new SkillPanel("技能",SKILLS,skillPoints),
                         new CheckboxPanel("职业",PROFESSIONS,PROFESSIONS[0]),
                         };
                 
                  //创建一个Panel来放置CardLayout
                  attributePanel=new Panel();
                  attributePanel.setLayout(new CardLayout());
                 
                  //把AttributePanels添加到主面板
                  for(int i=0;i<panels.length;i++){
                         attributePanel.add(panels[i],panels[i].getAttribute());
                  }
                 
                  //创建SummaryPanel,并把它加到CardLayout中
                  summaryPanel=new SummaryPanel(panels);
                  attributePanel.add(summaryPanel,"描述");
                 
                  //添加attributePanel
                  add(attributePanel);
                 
                  //创建并添加back和next按钮
                  Panel p=new Panel();
                 
                  back=new Button("上一页");
                  back.addActionListener(this);
                  p.add(back);
                 
                  next=new Button("下一页");
                  next.addActionListener(this);
                  p.add(next);
                 
                  p.setBackground(Color.BLACK);
                 
                  add(p);
           }
          
           //在单击back或者next按钮时调用
           public void actionPerformed(ActionEvent e){
                  CardLayout cardLayout=(CardLayout)attributePanel.getLayout();
                 
                  if(e.getSource()==back){
                         cardLayout.previous(attributePanel);
                  }else if(e.getSource()==next){
                         cardLayout.next(attributePanel);
                  }
                 
                  //在每一次变更后更新概要
                  summaryPanel.update();
           }
    }
    注意CharaterBuilder类的init方法中getParameter方法的使用。可以把参数传送给applet,就像可以把参数传给控制台程序一样。当希望不经过重新编译而给applet传送信息时,这是很有用的。上面的代码清单读入一个参数,该参数表示可分配的技能点。下面的代码演示了怎样在.html文档中包含参数:
    <applet height="300" width="300" code="CharacterBuilder">
           <param name="SkillPoints" value="30"/>
    </applet>
    如果要在applet中读入SkillPoints参数,只需像这样:
    skillPoints=Integer.parseInt(getParameter("SkillPoints"));
    由于点值是一个整数,这里把上述代码嵌入到一个try/catch中,只是为了处理一些聪明的玩家在网页中输入非法数据的特殊情况。applet参数是对代码作出快速改变且无须浪费时间重新编译的好方式。当希望最终用户可以快速而简单地定义参数时,使用applet参数也是很方便的。
    记住,Java applet只是嵌入到另一个应用程序中的一段程序。applet是一种把游戏发布给用户的非常方便而且非常流行的方法。
    本章没有讲解所有的AWT组件,主要是介绍组件和容器,在第6章中,我们将继续学习像Graphics等在本章被一带而过的主题。使用AWT组件是一种快捷地向用户表述交互内容的方法,像按钮,单选按钮和标签这样的组件可以用几行代码放到applet上。然而,AWT有几个限制,虽然它对设计独立于窗体方案的软件不错,本书还是建议对组件的放置做更好的控制。读者还应该结合对游戏的“感觉”来创造更且有吸引力的组件,而不是使用默认的窗体和绘制方式,但是不要完全低估原始的AWT,它们的柔性和使用上的便捷在后面是很灵便的。
    我们已经对Applet类的作用有了初步的认识,只要几行代码,就可以把按钮,文本域和标签嵌入到applet窗体上,但是,这并没有结束。在第7章,我们将学习在applet中绘制线条,图形和文本。
    5.1预计下列代码段的输出:
    public B extends Applet{
           public static void main(String[] args){
                  System.out.println(“I am a Java guru!”);
           }
    }
    5.2在使用像Button这样的组件时,为什么实现EventListener接口对Applet类来说很重要?如果不是很清楚,可以查看Button类addActionListener方法的原型。
    5.3请描述组件和容器之间的异同。
    5.4修改ButtonTest applet,使得它对color数组中的每一种颜色都有一个单独的按钮,和红色关联的按钮应该以Red为标签,都以currentColor作为索引。一个更加健壮的方法是施展Button类,在它内部变换颜色。可以在自定义Button的构造函数中给它关联一个颜色并让actionPerformed方法允许Button刷新窗体。
    5.5修改AudiochoiceTest applet,让它实现一个List对象来容纳声音文件的文件名。应该让List具备在任何时候多选的能力,所以应该仔细修改相应的声音控制代码。
    5.6描述怎样用多个Panel对象来创建更精致的布局。
    5.7什么是卸载不当引起的速度消耗?
    5.8简要描述5个按钮在给定如下几种不同的布局管理器下如何排列:FlowLayout,GridLayout,CardLayout和BoderLayout。
    5.9写一个applet用Label对象显示当前日期和时间。这个applet应该有规律地刷新自己,以便日期和时间可以看起来像是连续的。
    5.10修改CharacterBuilder类,让它能读一个描述默认角色名字的applet参数。可能需要修改TextFieldPanel的构造函数或者添加一个方法来设置这个文本域的值,还需要在.html文件中添加如下的代码来添加一个参数标签:
    <param name=”DefaultName” value=”Merlin”>
     

    发表于 @ 2007年01月01日 21:06:00|评论(loading...)|编辑

    新一篇: 控制台版21点(BlackJack)源码(Java2游戏编程第4章练习参考答案) | 旧一篇: Java2游戏编程读书笔记(5-1)

    评论

    #dcopperfield 发表于2007-09-26 11:21:58  IP: 218.196.207.*
    顶下
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © 默然