target
Develop a text game based on javaSE, which interacts with the input and output of the console. For example, you can go south by typing go south, chat with npc by typing talk, and get help by typing help. The overall game design is not complex. The more important thing is the object design. If you are a java beginner, you might as well try to write it yourself first.
Train of thought analysis
The first is the design of console interaction. If the design idea is based on process oriented, it is very simple. I just need to read the input and write some if esle statements to realize the corresponding requirements. However, if you think about it carefully, it will be very complicated. If you are currently in bedroom, enter go south on the console. In order to implement the command, first parse the command, What if (go) does and what if (help) does. After knowing the go command, you have to judge where it is and what if (bedroom) is like (lobby) well, it's very cumbersome. Moreover, if one day I want to join a command or room, the whole program will change and have poor scalability. In professional terms, this is called too strong coupling. The purpose of object-oriented design is decoupling. If inheritance and polymorphism are skillfully used, the program will become very beautiful. According to this idea, any program in the future will be very beautiful Everything should be encapsulated into objects, such as rooms, NPCs, equipment.
Implementation of design
command
thinking
To understand the coupling, we can design a command parent class with doSomething() method, which is inherited by specific command objects, such as go and help. In the Game class (that is, the class where main is located), these commands are new and stored in the map. key is the name of the command and value is the command object. When the user enters, I will find out whether there are commands entered by the user in the map. If so, I will take out the corresponding object and directly call his doSomething() method.
analysis
Is there a new feeling in this design? We no longer care about the specific commands entered. We don't need to write long strings of if else. We just need to find a suitable object to complete the relevant operations. This is the advantage of object-oriented programming. In this way, the extensibility is very good. If you want to add a command and an object, it's good.
code
public class Game { public void run() { Scanner in = new Scanner(System.in); while (true) { String line = in.nextLine(); //The default user inputs in two digits, such as go north or talk flower String[] words = line.split(" "); command handle = commands.get(words[0]); if (handle == null) { System.out.println("Wrong command"); continue; } if (handle.isBye()) { break; } String value = ""; if (words.length > 1) { value = words[1]; } if (handle != null) { handle.doSomthing(value); } } } public static void main(String[] args) { Scanner in = new Scanner(System.in); Game game = new Game(); game.printWelcome(); game.run(); System.out.println("Thank you for coming. bye!"); in.close(); } }
/** * Parent class of command */ public class command { public void doSomthing(String word) { } }
/** * The command to go to the room is inherited from command */ public class goRoom extends command{ public void doSomthing(String word) { //It doesn't matter what this method does. You just need to know that it does the relevant operations of entering the room //Remember this hero, which will be explained below if(hero.getCurrentRoom().getNearRoom().containsKey(word)){ hero.getCurrentRoom().sayBye(); hero.setCurrentRoom(hero.getCurrentRoom().getNearRoom().get(word)); hero.getCurrentRoom().sayHello(); System.out.print("There are ways to go"); for(String s:hero.getCurrentRoom().getNearRoom().keySet()){ System.out.print(" "+s+" "); } }else { System.out.println("No way"); } } }
Room
thinking
With the above example, can the room also naturally think of inheritance and write a parent class of room with map member variables nearRoom and NPCs. nearRoom is used to store the surrounding rooms, and NPCs is used to store the NPCs in the room. There is also a description of String type to introduce the room.
analysis
You may not know how to combine the room with the command until now. You can enter the corresponding room after entering the command. Don't worry, look down slowly. You can also try and think about how you will achieve it.
code
public class room{ /** * The description is set in new, and the adjacent rooms and NPCs have to be set in the game */ Map<String,room> nearRoom; Map<String, npc> npcs; //Here, I set the description as a map, which is optimized in the later stage. Just know what description is used for Map<String,String> descriptions; public room(Map<String, String> descriptions) { this.descriptions = descriptions; } public room() { } public void setDescriptions(Map<String, String> descriptions) { this.descriptions = descriptions; } public void setNearRoom(Map<String, room> nearRoom) { this.nearRoom = nearRoom; } public void setNpcs(Map<String, npc> npcs) { this.npcs = npcs; } public Map<String, room> getNearRoom() { return nearRoom; } public Map<String, npc> getNpcs() { return npcs; } }
/** * lobby */ public class lobby extends room { public lobby() { descriptions = new HashMap<String,String>(); descriptions.put("hello","This is an ordinary lobby"); descriptions.put("bye","Welcome to the lobby next time"); } public lobby(Map<String, String> descriptions) { super(descriptions); } }
Hero
thinking
The brave class is designed to combine commands and rooms. In the Game class, set a hero type global variable. The brave is the main body of the Game. The brave is required for the execution of any command. The brave class stores the current status, such as which room you are in, what equipment you have now, and how much blood you have left. Remember the hero in the command implementation, that is, the brave. When the user enters go south, he will make some operations according to the room where the brave is currently located. Because there is the nearroom variable in the room, it is easy to get which direction can go. Just do some operations according to this.
analysis
After the brave class is added, the framework of the whole game is built. In other words, it can be played. Moreover, I said the framework, which means that the program is easy to expand, such as adding npc, adding plot system, adding equipment, blood volume. As always, you can think for yourself and see what you can add.
code
public class Hero { String name; Map<String, goods> bag = new HashMap<String,goods>(); int blood = 100; room currentRoom; public room getCurrentRoom() { return currentRoom; } public Hero(String name) { this.name = name; } public String getName() { return name; } public Hero(String name, room currentRoom) { this.name = name; this.currentRoom = currentRoom; } public void setName(String name) { this.name = name; } public Map<String, goods> getBag() { return bag; } public void setCurrentRoom(room currentRoom) { this.currentRoom = currentRoom; } public int getBlood() { return blood; } }
Interactive
thinking
This interface means interactive. Yes, I translated it by Baidu. English is not very good. What is this interface used for? Remember I said that descriptions are of String type, but it was changed to map type in the code. No, this interface is to fill the hole. We can easily find that no matter the room or npc, or the equipment that will be expanded later, they will introduce themselves and interact. For example, npc can communicate, equipment can be used, and equipment in the room can be picked up. They all have the same properties and can be abstracted into interfaces.
analysis
This is designed to make the code clearer
code
package Game; public interface Interactive { public void sayHello(); public void sayBye(); //Interact with the brave public void talkHero(Hero hero); }
public class room implements Interactive { /** * The description is set in new, and the adjacent rooms and NPCs have to be set in the game * The Interactive interface is implemented */ Map<String,room> nearRoom; Map<String, npc> npcs; Map<String,String> descriptions; public room(Map<String, String> descriptions) { this.descriptions = descriptions; } public room() { } public void setDescriptions(Map<String, String> descriptions) { this.descriptions = descriptions; } public void setNearRoom(Map<String, room> nearRoom) { this.nearRoom = nearRoom; } public void setNpcs(Map<String, npc> npcs) { this.npcs = npcs; } public Map<String, room> getNearRoom() { return nearRoom; } public Map<String, npc> getNpcs() { return npcs; } @Override public void sayHello() { System.out.println(descriptions.get("hello")); } @Override public void sayBye() { System.out.println(descriptions.get("bye")); } @Override public void talkHero(Hero hero) { } }
Here, the first stage is completed and you can play.
npc
thinking
With previous experience, the design of npc is very simple. Before that, I ask a question: is npc visible to the brave. The answer is No. you may wonder how it can be invisible. If it is invisible, how can the brave interact with NPCs?
In fact, what I mean by invisible here is: from the perspective of the brave, the brave cannot directly contact the npc. He can only find the current room through the currentRoom variable, and then find the npc in the room. If you carefully observe Hero, you will find that there are no variables related to npc at all. Similarly, npc also needs to implement the Interactive interface.
Analysis
This benefit is obvious. The brave can only find NPCs in specific rooms. Think about it. If I don't design like this, when I input talk npc on the console, do I still need to judge whether the npc can be seen in the current room? In this way, the coupling becomes higher.
code
package Npc; import Game.Hero; import Game.Interactive; import java.util.HashMap; import java.util.Map; /** * npc Parent class of */ public class npc implements Interactive { Map<String,String> descriptions = new HashMap<String,String>(); @Override public void sayHello() { System.out.println(descriptions.get("hello")); } @Override public void sayBye() { System.out.println(descriptions.get("bye")); } @Override public void talkHero(Hero hero) { } }
Equipment (goods)
thinking
With previous experience, it is easy to design a good. Here is a question. We must think about whether good is designed as an ordinary parent class or an interface or an abstract class. Why should I ask this? Let's think about a specific scene. Suppose you can get the property bloodBottom in npc flower, You need to write a getGoods method in the brave class (just like the following). After writing this, if goods is an ordinary parent class, which is consistent with the npc idea above, then the object of goods type is put into the backpack, and the real bloodBottom is transformed upward. In this way, when I call the method of good, I call the method of the parent class. Therefore, it is impossible to design goods as an ordinary parent class (if you can't understand it, try it yourself, and you'll find the problem). The question that needs to be considered now is, can the parent class call the methods of its subclasses? I found an article that is very good. After reading it, you'll find that it's better to design goods as an abstract class. Here's another question to think about. What happens if goods is designed as an interface. There is no standard answer to design, mainly See what you think is appropriate. You can try it. If it is designed as an interface, you have to write sayHello and other methods repeatedly every time. It's very troublesome.
Can a parent class call a subclass method?
code
public void getGoods(String s,goods good){ bag.put(s,good); }
/** * The parent of the rig */ public abstract class goods implements Interactive { Map<String,String> descriptions = new HashMap<String,String>(); public void sayHello() { System.out.println(descriptions.get("hello")); } public void sayBye() { System.out.println(descriptions.get("bye")); }
/** * Blood bottle */ public class bloodBottle extends goods{ @Override public void talkHero(Hero hero) { hero.setBlood(hero.getBlood()+100); System.out.println("The brave adds 100 points of blood"); } }
/** * Use prop command */ public class use extends command{ public use(Hero hero) { super(hero); } public void doSomthing(String word) { if(hero.getBag().containsKey(word)){ hero.getBag().get(word).talkHero(hero); }else { System.out.println("Without this prop"); } } }
summary
Here, the project is finished. See the following website for the specific code. This game has good scalability. You can add a little plot, a little battle and a little decryption. This project is my first self-taught java project. It has been more than a year. Now I start blogging and want to write what I have done before. This game is not difficult as a whole, and there are not many design knowledge points. However, through this project, you can have a deeper understanding of object-oriented. Personally, I think it is very helpful for java beginners. If you feel that it is well written, I hope to give you a praise. Next, I will follow the new JavaSE based Cool run every day, which is also a small game suitable for beginners. Finally, I would like to thank Mr. Weng Kai of Zhejiang University. The idea of this project comes from his class.