项目需求
(1)QuickHit游戏考验学员键盘输入内容的速度和准确性。
(2)根据输入速率和正确性将玩家分为不同级别,级别越高,一次显示的字符数越多,玩家正确输入一次的得分也越高。
(3)如果玩家在规定的时间内完成规定次数的输入,正确率达到规定要求,则玩家升级(为了简单起见,规定用户只要输入错误一次,则游戏结束)
(4)玩家最高级别为6级,初始级别一律为一级。
项目环境准备
完成“QuickHit”,对于开发环境的要求如下:
(1)开发工具:MyEclipse 10
(2)JDK1.7
案例覆盖的技能点
(1)面向对象程序设计的思想
(2)使用类图理解类的关系
(3)类的封装
(4)构造方法的使用
(5)this和static关键字的使用
难点分析
1、 需要用到的类
本案例功能简单,代码量较少,采用面向过程的思想可能更容易实现,
此处的关键是锻炼大家面向对象的设计能力,分析各段功能代码放到什么位置更合理一些,为大型项目的设计打好基础。
面向对象设计的过程就是抽象的过程,通过在需求中找出名次的方式确定类和属性,通过找出动词的方式确定方法;
然后对找到的词语进行筛选,剔除无关、不重要的词语;最后对词语之间的关系进行梳理,从而确定类、属性、属性值和方法。
需求中和业务相关的名词主要是游戏、输入速率、玩家、级别、一次显示的字符数、正确输入一次的得分、规定时间、规定次数、超时、玩家的积分和玩家用时等。
动词主要是输出、输入、确认和显示。
第一步:发现类。
玩游戏肯定离不开玩家与游戏,可以首先抽象出玩家、游戏两个类。一次显示的字符数、正确输入一次的得分、规定时间和规定次数都与玩家当前的级别有关。
可以再抽象出一个级别类。而积分和用时可以考虑设置为玩家属性,在此忽略。
经过分析,我们暂时从需求中抽象出如下类:
游戏(Game)
玩家(Plyer)
级别(Level)
第二步:发现类的属性。
进过分析,玩家的属性有当前级别、玩家的积分和玩家用时等,而玩家用时其实是当前时间与开始时间只差;
级别的属性有级别号、一次显示的字符数、正确输入一次的得分、规定的时间个规定次数。
进行整理并命名,得到如下结果。
玩家(Plyer)类的属性:
玩家当前级别号(levelNo)
玩家当前级别积分(currScore)
当前级别开始时间(startTime)
当前级别已用时间(elapsedTime)
级别(Level)类的属性:
各级别编号(levelNo)
各级别一次输出字符串的长度(strLength)
各级别输出字符串的次数(strTime)
各级别闯关的时间限制(timeLimit)
各级别正确输入一次的得分(perScore)
第三步:发现类的方法
经过分析,游戏类的主要方法有3个:输出字符串、确认玩家输入是否正确和输出相应结果信息。
其中,第2个方法很简单,可以和第3个方法合并。
而玩家的方法只有一个,即玩游戏(根据游戏的输出类输入相同字符串)。
级别类主要存放信息,没有具体操作。
进行整理并命名,得到如下结果。
玩家类的方法:
玩游戏play()。
游戏类的方法:
String printStr(),输出字符串,返回字符串用于和玩家的输入进行比较;
void printResult(String out,String in),比较游戏输出out和玩家输入in,根据比较结果输出相应信息。
第四步:优化设计
在游戏类的printResult(String out,String in)方法中,输出相应结果时肯定会涉及玩家类的信息,如当前级别编号、当前级别积分、当前级别已用时间等,
可以通过把Player对象作为游戏类的属性,轻松解决该问题。
级别类不包含各个级别的具体参数信息,可以增加LevelParam类,在该类中创建一个长度为6的Level数组,存放各个级别的具体参数信息,
并使用public final static修饰该数组,可以直接通过类名来访问,却无法修改其值。
2、 主要功能分析
(1)游戏输出字符串:
主要步骤是生成长度固定当内容随机的字符串,同时向控制台输出生成的字符串并返回此字符串(必须返回,用于和玩家输入比较)。
(2)确认输入并输出结果:
根据玩家输入是否正确输出不同结果。当输入正确并且未超时,要输出玩家的当前级别、当前积分和已用时间。
如何计算玩家的当前级别、当前积分和已用时间是关键。
(3)玩家玩游戏:
游戏的6个级别可以通过循环实现,而每个级别中的多次字符串输出通过内部子循环实现,该控制功能放在Player类的play()方法中。
每次玩家晋级后积分清零、计时清零。
3、 界面分析
如果玩家输入正确且未超时,则输出玩家输入的正确信息(包括级别、积分和用时),并输出玩家当前积分、当前级别和已用时间。
如果玩家输入正确但超时,则输出玩家超时信息,并退出系统。
如果玩家输入错误,则输出“输入错误,退出!”的错误信息,并退出系统。
项目实现思路
1、先编写级别类Level:
(1)定义属性:
private int levelNo; // 级别号 private int strLength; // 各级别一次输出字符串的长度 private int strTimes; // 各级别输出字符串的次数 private int timeLimit; // 各级别闯关的时间限制 private int perScore; // 各级别成功输入一次字符串后增加的分值
(2)添加包含所有参数的有参构造方法(无参构造方法后面不需要使用,可以不添加)
(3)针对封装好的属性,添加getXxx()方法,不需要添加setXxx()方法(针对级别的属性是系统规定好的,不需要用户设置)
2、编写级别参数类LevelParam:
(1)此项目会涉及到6个级别(每个级别是一个对象),所以先创建一个长度为6,类型为Level的数组,这个数组可以声明为静态常量值
(2)使用有参构造方法创建6个Level类对象,并将这6个对象存储到第一步创建的数组中,可以将这个操作生命在静态代码块中
3、创建Play玩家类:
(1)定义属性:
private int levelNo; // 级别号 private int curScore; // 当前积分 private long startTime = 0; // 各级别开始时间 private int elapsedTime; // 各级别已用时间
(2)添加无参构造方法、有参构造方法、getXxx()/setXxx()方法
(3)定义玩家玩游戏的方法play():
功能:用户由默认0级升级到1级,开始玩游戏(调用Game类里的printStr()方法和printResult())
4、创建游戏类Game:
(1)定义属性:
private Player player;// 玩家
(2)添加无参构造方法、有参构造方法
(3)定义方法printStr()
功能:根据用户级别输出指定长度的字符串(字符串的内容是随机产生的)
(4)定义方法printResult()
功能:判断用户输入的字符串与系统随机产生的字符串内容是否相同
1)如果用户输入的字符串与系统产生的字符串相同:
--》用户输入字符串的时间>对应级别需要的时间:超时,退出游戏系统
--》用户输入字符串的时间<对应级别需要的时间:
计算用户完游戏的时间
用户玩游戏积累的积分
输出当前用户所处的级别,玩游戏时间、积累的积分
计算该游戏最后一个级别的总分并判断用户是否到达第六级别以及积累的积分是否等于最高级别的积分,如果满足,输出闯关成功
2)如果用户输入的字符串与系统产生的字符串相同:
直接退出游戏系统
5、定义测试类:
在main()方法中创建Play类对象,调用play()方法,开始游戏
代码展示
1、初始属性:Level类(全部代码)
package cn.bdqn.demo09; public class Level { //定义属性 private int levelNo; // 级别号 private int strLength; // 各级别一次输出字符串的长度 private int strTimes; // 各级别输出字符串的次数 private int timeLimit; // 各级别闯关的时间限制 private int perScore; // 各级别成功输入一次字符串后增加的分值 //添加有参构造 public Level(int levelNo, int strLength, int strTimes, int timeLimit, int perScore) { super(); this.levelNo = levelNo; this.strLength = strLength; this.strTimes = strTimes; this.timeLimit = timeLimit; this.perScore = perScore; } //添加get方法 public int getLevelNo() { return levelNo; } public int getStrLength() { return strLength; } public int getStrTimes() { return strTimes; } public int getTimeLimit() { return timeLimit; } public int getPerScore() { return perScore; } }
2、初始类Level对象:LevelParam类(全部代码)
package cn.bdqn.demo09; public class LevelParam { // 定义静态常量:Level数组 public static final Level[] levels = new Level[6]; // 用静态代码块初始化Level对象 static { levels[0] = new Level(1, 2, 10, 30, 1); levels[1] = new Level(2, 3, 9, 27, 2); levels[2] = new Level(3, 4, 8, 24, 3); levels[3] = new Level(4, 5, 7, 21, 4); levels[4] = new Level(5, 6, 6, 16, 5); levels[5] = new Level(6, 7, 5, 12, 6); } }
3、系统类:Game(全部代码)
package cn.bdqn.demo09; import java.util.Random; import java.util.Scanner; public class Game { Scanner sc=new Scanner(System.in); // 定义属性 private Player player; String str=""; public Game(Player player) { super(); this.player = player; } // 定义系统输入printStr方法 public String printStr() { StringBuffer buffer = new StringBuffer(); int strLength = LevelParam.levels[player.getLevelNo()-1].getStrLength(); Random random = new Random(); // System.out.println(strLength); // 通过循环生成要输出的字符串 for (int i = 0; i < strLength; i++) { int rand = random.nextInt(strLength); // 产生随机数 // 根据随机数拼接字符串 switch (rand) { case 0: buffer.append(">"); break; case 1: buffer.append("<"); break; case 2: buffer.append("*"); break; case 3: buffer.append("#"); break; case 4: buffer.append("@"); break; case 5: buffer.append("$"); break; default: break; } } str=buffer.toString(); System.out.println(str); return str; } // 定义printResult()方法 public void printResult(String out,String in) { if(out.equals(in)){ int currentTime=(int)System.currentTimeMillis()/1000; player.setElapsedTime(currentTime); //用户输入字符串的时间<对应级别需要的时间: if(player.getElapsedTime()-player.getStartTime() < LevelParam.levels[player.getLevelNo()-1].getTimeLimit()){ //计算当前积分 player.setCurScore(player.getCurScore()+ LevelParam.levels[player.getLevelNo()-1].getPerScore()); //计算已用时间 player.setElapsedTime(currentTime-(int)player.getStartTime()); //输出当前积分、当前级别、已用时间 System.out.println("输入正确,您的级别为"+player.getLevelNo()+"级,您的积分为"+player.getCurScore() +"分,总用时为:"+player.getElapsedTime()+"秒。"); //判断用户是否已经闯过最后一关 if(player.getLevelNo()==6){ int score=LevelParam.levels[player.getLevelNo()-1].getPerScore()* LevelParam.levels[player.getLevelNo()-1].getStrTimes(); if(player.getCurScore()==score){ System.out.println("您已闯关成功,成为绝世高手,恭喜你!!!"); System.exit(0); } } }else{ System.out.println("你输入太慢了,已经超时,退出!"); System.exit(1); } }else{ System.out.println("输入错误,退出!"); System.exit(1); } } }
4、玩家类:Player类(全部代码)
package cn.bdqn.demo09; import java.util.Scanner; public class Player { //定义属性 private int levelNo; // 级别号 private int curScore; // 当前积分 private long startTime = 0; // 各级别开始时间 private int elapsedTime; // 各级别已用时间 //添加get/set方法 public int getLevelNo() { return levelNo; } public void setLevelNo(int levelNo) { this.levelNo = levelNo; } public int getCurScore() { return curScore; } public void setCurScore(int curScore) { this.curScore = curScore; } public long getStartTime() { return startTime; } public void setStartTime(long startTime) { this.startTime = startTime; } public int getElapsedTime() { return elapsedTime; } public void setElapsedTime(int elapsedTime) { this.elapsedTime = elapsedTime; } //定义玩家玩游戏的方法 public void play(){ Game game=new Game(this); Scanner sc=new Scanner(System.in); for (int i = 0; i < LevelParam.levels.length; i++) { //1、晋级 levelNo+=1; //2、晋级后计时清零,积分清零 startTime=(int)System.currentTimeMillis()/1000; curScore=0; //3、内层循环一次,完成一次字符串输出、输入、比较 for (int j = 0; j < LevelParam.levels[levelNo-1].getStrTimes(); j++) { //系统输出 String outStr=game.printStr(); //用户输入 String inStr=sc.next(); //判断用户输入是否正确,并显示相应信息 game.printResult(outStr, inStr); } } sc.close(); } }
5、测试类:GameTest类(全部代码)
package cn.bdqn.demo09; public class GameTest { public static void main(String[] args) { Player player=new Player(); player.play(); } }