和浙大翁恺老师学习的城堡游戏写法,加入了一些自己的内容,应该会有后续内容的添加。
代码部分
1.主程序
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
public class Game {
private Room currentRoom;
private HashMap<String,Handler>handlers=new HashMap<String,Handler>();
protected ArrayList<String>cmds=new ArrayList<String>();
public Game()
{
handlers.put("go",new HandlerGo(this));//这三句决定了handler在被调用时,不同字符串会调用不同子类对象
handlers.put("bye",new Handlerbye(this));
handlers.put("help",new HandlerHelp(this));//这个很厉害
createRooms();//构造函数直接完成房间和方向的初始化
for(String s:handlers.keySet())
{
cmds.add(s);
}
}
在Game类中定义了Room类对象和两个容器对象,然后编写构造函数,handler对象的主要目的是把输入的字符串命令和调用的类对应起来,对应的几个类会在后面解释。cmds对象的目的是把handler的关键字存入数组,目的是令后面的帮助命令可根据关键字多少输出。
public void play()
{
Scanner in = new Scanner(System.in);
while ( true ) {
String line = in.nextLine();
String[] words = line.split(" ");//以空格分割单词,放入words数组
Handler handler=handlers.get(words[0]);//这句决定调用的是handler的哪个子类
String value="";
if(words.length>1)
value=words[1];
if ( handler!=null)
{
handler.doDmc(value);//不用words1因为可能没有
}
if(handler.isbye())//此时内存中是handlerbye的对象
{
break;
}
}
System.out.println("感谢您的光临。再见!");
in.close();
}
Game类的play方法是根据用户输入的命令调用handler类的不同子类和函数,这里包含了代表结束的isbye函数和得到输入方向的doDmc函数。这里这样写的好处是如果想添加新的字符串命令,如我们要添加一个return命令,回到上一个房间,就可以在构造函数中把return和handle的对应子类(如handlerreturn)关联起来,然后在play里输入return,调用添加的handler.isreturn函数即可。这里还涉及了子类父类继承和向上造型的知识,后面再说。
private void createRooms()
{
Room outside, lobby, pub, study, bedroom;
// 制造房间
outside = new Room("城堡外");
lobby = new Room("大堂");
pub = new Room("小酒吧");
study = new Room("书房");
bedroom = new Room("卧室");//定义不同的房间名,利用toString直接输出对应房间名
// 初始化房间的出口
outside.setExit("east",lobby);
outside.setExit("south",study);
outside.setExit("west",pub);
lobby.setExit("west", outside);
pub.setExit("east", outside);
study.setExit("north",outside);
study.setExit("east",bedroom);
bedroom.setExit("west", study);//设置每个房间能走通的方向和对应的房间
lobby.setExit("up",pub);
pub.setExit("down", lobby);
currentRoom = outside; // 从城堡门外开始
//制造道具
Item gold,monster,box,exp;
gold=new Item("金币");
monster=new Item("怪物");
box=new Item("宝箱");
exp=new Item("经验");
//把房间和道具对应
outside.setItem(outside, monster);
lobby.setItem(lobby,gold);
pub.setItem(pub, box);
bedroom.setItem(bedroom, exp);
}
createRoom方法是在初始化房间和对应的方向出口,调用的是Room类中的setExit函数,可以看出来同样利用了HashMap容器把方向和出口进行关联。下面的道具类(额外写的)同理。这里的代码应该可以继续简化,等我再学学。
//欢迎函数,没必要改
private void printWelcome() {
System.out.println();
System.out.println("欢迎来到城堡!");
System.out.println("这是一个超级无聊的游戏。");
System.out.println("如果需要帮助,请输入 'help'。");
System.out.println();
showprompt();
}
// 以下为用户命令
//根据输入方向得到下次的房间名
public void goRoom(String direction)//唯一指定调用函数
{
Room nextRoom = null;
nextRoom=currentRoom.getExit(direction);
if (nextRoom == null) {
System.out.println("那里没有门!");
}
else {
currentRoom = nextRoom;//房间交替
showprompt();
Item item=null;
item=currentRoom.getItem(currentRoom);
if(item!=null)
{
System.out.println("你发现了:"+item);
}
else
{
System.out.println("什么也没有");
}
}
}
public void showprompt()
{
System.out.println("现在你在" + currentRoom);
System.out.println("出口有:");
System.out.print(currentRoom.getExitdesc());
System.out.println();
}
public static void main(String[] args) {
Game game = new Game();//Game调用Currentroom,初始化房间位置还有最初位置
game.printWelcome();
game.play();
}
}
主类中剩的方法都放在这吧,printWelcome方法就是输出各种字符串,没什么好说的,goRoom类则是根据用户输入的方向判断该方向是否有门,有的话将令当前房间为下一个房间,从而实现移动,然后利用item类对象判断当前房间是否有道具(自己额外加的),并输出结果。然后showprompt方法输出当前房间的可用出口。
2.Room类
import java.util.HashMap;
public class Room {
private String description;
private HashMap<String,Room> exist=new HashMap<String,Room>();
private HashMap<Room,Item>items=new HashMap<Room,Item>();
public Room(String description)
{
this.description = description;
}
public void setExit(String dir,Room room)
{
exist.put(dir,room);
}
//设置房间和对应事件
public void setItem(Room room,Item item)
{
items.put(room,item);
}
public String getExitdesc()
{
StringBuffer sb=new StringBuffer();
for(String s:exist.keySet())
{
sb.append(s);
sb.append(" ");
}
return sb.toString();
}
public Item getItem(Room room)
{
return items.get(room);
}
public Room getExit(String direction)
{
return exist.get(direction);//返回对应方向的房间对象
}
@Override
public String toString()
{
return description;
}
}
Room类里用的都是HashMap容器的对应,包括我后面加的Item类也是以Room类对象为关键字得到对应房间的物品,这里不解释了(懒得打字了)。
3.Item类
package castle;
public class Item {
private String description;
//构造函数
public Item(String des)
{
this.description=des;
}
//toString输出
public String toString()
{
return description;
}
}
Item类写的很简单,只包含构造函数和返回字符串的操作,保证和Room类的相同输出方法。
4.Handler类及子类
public class Handler {
protected Game game;
public Handler(Game game)
{
this.game=game;
}
public void doDmc(String string)
{
}
public boolean isbye()
{
return false;
}
}
Handler父类,主要包含的是doDme方法和isbye方法,都是留给子类重写的,先定义好放在这里。至于构造函数包含对game对象的调用,因为Game类里的Goroom方法调用了Game类的私有成员,在不改变权限的前提下,只能先用这个方法。
package castle;
public class HandlerGo extends Handler {
public HandlerGo(Game game)
{
super(game);
}
@Override
public void doDmc(String string) {
game.goRoom(string);
}
}
package castle;
public class Handlerbye extends Handler
{
public Handlerbye(Game game)
{
super(game);
}
public boolean isbye()
{
return true;
}
}
package castle;
public class HandlerHelp extends Handler{
public HandlerHelp(Game game)
{
super(game);
}
@Override
public void doDmc(String string) {
System.out.println("迷路了吗?你可以做的命令有:"+game.cmds);
System.out.println("如:\tgo east");
}
}
这里把Handler的子类都列出来,根据Game类中handlers容器对象把字符串和这几个子类对应起来。