(一)设计思路:
游戏效果如下图所示:
游戏描述:
-
游戏采用Java设计,采用了面向对象思想,游戏使用Swing实现面板;采用哈希表Hashtable建立客户端和服务器端之间输入输出流的通信,使用户之间可以进行通信,多线程并发处理任务;随时对游戏中的情况进行判断;
-
玩法描述:玩家首先打开服务器端,进入等待状态,之后进行打开客户端使其与服务器端建立连接;等待其它玩家的加入,选择玩家进行对战即可;
游戏框架如下:
总共有四个大的类:
服务端,客户端,用户类,以及游戏主题类
具体的类如下:
- 1.服务器端:
如下图:
服务器端中有三个类:
分别是主题类ServerRunner,和两个类ServerThread,ServerMsgPanel;分别实现消息的发送,服务端的运行,以及服务端的多线程运行
-
2.客户端
客户端类中也有两个类:
分别是主题类ClientChess和ClientThread,分别实现客户端对于棋盘的连接和对于服务器端连接实现相互交流 -
3.玩家端
玩家中有玩家列表,玩家之间的信息交流,对玩家的消息输入,以及玩家对游戏控制 -
4.棋局端
棋局类中分别由黑棋类,白棋类,以及棋盘的主题类,和棋盘线程类;
Java中Jpanel与panel有何区别:
panel是包java.awt当中的类,Jpanel是包javax.swing当中的类,属于前者的升级。二者在本质上并没有太大的区别。
相对awt图形用户界面而言,Swing图形用户界面不仅增强了功能,而且减弱了平台相关性,即Swing图形用户界面比AWT图形用户界面可以克服更多的由于操作系统不同所带来的在图形用户界面或交互方式上的差别,因此建议使用swing当中的JPanel
游戏中的难点
- 1.基于TCP/IP协议,使用socket创建客户端和服务器端
Socket clientSocket;
有关Socket编程可参考;Socket简介及客户端服务端代码实现
- 2.其中客户端和服服务器端采用Hashtable建立通信,反应速度更快,不适用HashMap是因为HashMap不能保证线程安全,但Hash大部分函数都有Synchronized关键字,可以保证线程安全,下面为服务器端所用到的Hashtable变量;
Hashtable clientDataHash = new Hashtable(50); // 将客户端套接口和输出流绑定 Hashtable clientNameHash = new Hashtable(50); //将客户端套接口和客户名绑定Hashtable chessPeerHash = new Hashtable(50); //将游戏创建者和游戏加入者绑定
关于Hashtable和HashMap的区别可参考:Hashtable和HashMap的区别
- 3.多线程并发问题:
此游戏中有客户端线程类,服务端线程类,以及棋局线程类;涉及了多线程并发问题 - 4.java.IO流输入输出问题:
主要使用了字节流inputStream,Outputstream ,
涉及到的其它知识:
-
Canvas类:
Canvas 组件表示屏幕上一个空白矩形区域,应用程序可以在该区域内绘图,或者可以从该区域捕获用户的输入事件。
应用程序必须为 Canvas 类创建子类,以获得有用的功能(如创建自定义组件)。必须重写paint 方法,以便在 canvas 上显示; -
JTextField和JTextArea
JTextField称为文本框,它只能接收单行文本的输入
JTextField() 创建一个空的文本框,初始字符串为null
JTextFiled(int columns) 创建一个具有指定列数的文本框,初始字符串为null
JTextField(String text) 创建一个显示指定初始字符串的文本框
JTextField(String text,int column) 创建一个具有指定列数、并显示指定初始字符串的文本框
JTextArea称为文本域,它能接收多行文本的输入,使用JTextArea构造方法创建对象时可以设定区域的行数、列数
JTextArea() 构造方法,创建一个空的文本域
JTextArea(String text) 构造方法,创建显示指定初始字符串的文本域
JTextArea(int rows,int columns) 构造方法,创建具有指定行和列的空的文本域
JTextArea(String text,int rows,int columns) 构造方法,创建显示指定初始文本并指定了行列的文本域
- WindowListener :
用于接收窗口事件的侦听器接口。旨在处理窗口事件的类要么实现此接口(及其包含的所有方法),要么扩展抽象类 WindowAdapter(仅重写所需的方法)。然后使用窗口的 addWindowListener 方法将从该类所创建的侦听器对象向该 Window 注册。当通过打开、关闭、激活或停用、图标化或取消图标化而改变了窗口状态时,将调用该侦听器对象中的相关方法,并将 WindowEvent 传递给该方法。
(二)客户端和服务器端的实现:
服务器端实现:
服务器端的信息的输出:
public class ServerMsgPanel extends Panel {public TextArea msgTextArea = new TextArea("", 30, 71, TextArea.SCROLLBARS_VERTICAL_ONLY);public JLabel statusLabel = new JLabel(" ", Label.LEFT ); //显示用户数public Panel msgPanel = new Panel();public Panel statusPanel = new Panel();public ServerMsgPanel() { //构造函数初始化}
}
服务器端的线程运行,处理信息
public class ServerThread extends Thread{// 保存客户端套接口信息Socket clientSocket;// 保存客户端端口与输出流对应的HashHashtable clientDataHash;// 保存客户端套接口和客户名对应的HashHashtable clientNameHash;//保存游戏创建者和游戏加入者对应的Hash Hashtable chessPeerHash;// 判断客户端是否关闭boolean isClientClosed = false;ServerMsgPanel serverMsgPanel;public ServerThread(Socket clientSocket, Hashtable clientDataHash, Hashtable clientNameHash,Hashtable chessPeerHash, ServerMsgPanel server) {this.clientSocket = clientSocket;this.clientDataHash = clientDataHash;this.clientNameHash = clientNameHash;this.chessPeerHash = chessPeerHash;this.serverMsgPanel = server;}//处理信息public void dealWithMsg(String msgReceived) {}// 发送公开信息 public void sendPublicMsg(String publicMsg) {synchronized (clientDataHash) {}}// 发送信息给指定的游戏中的用户 public boolean sendGamePeerMsg(String gamePeerTarget, String gamePeerMsg) {}return true;}//发送反馈信息给连接到主机的人public void Feedback(String feedBackMsg) {synchronized (clientDataHash) {DataOutputStream outputData = (DataOutputStream) clientDataHash.get(clientSocket);try {outputData.writeUTF(feedBackMsg);} catch (Exception eb) {eb.printStackTrace();}}}// 取得用户列表public String getUserList() {String userList = "/userlist";for (Enumeration enu = clientNameHash.elements(); enu.hasMoreElements();) {userList = userList + " " + enu.nextElement();}return userList;}//根据value值从Hashtable中取得相应的keypublic Object getHashKey(Hashtable targetHash, Object hashValue) {Object hashKey;for (Enumeration enu = targetHash.keys(); enu.hasMoreElements();) {hashKey = (Object) enu.nextElement();if (hashValue.equals((Object) targetHash.get(hashKey))) {return hashKey;}}return null;}// 刚连接到主机时执行的方法 public void sendInitMsg() {}//关闭服务器public void closeClient() {}@Overridepublic void run() {DataInputStream inputData;synchronized (clientDataHash) {serverMsgPanel.statusLabel.setText("当前连接数:" + clientDataHash.size());}// 等待连接到主机的信息 }
}
服务的主体类:
public class ServerRunner extends Frame implements ActionListener {//设置按钮JButton clearMsgButton = new JButton("清空");JButton serverStatusButton = new JButton("状态");JButton closeServerButton = new JButton("关闭");Panel buttonPanel = new Panel();ServerMsgPanel serverMsgPanel = new ServerMsgPanel();ServerSocket serverSocket;int clientAccessNumber = 1;//将客户端套接口和输出流绑定 Hashtable clientDataHash = new Hashtable(50);//将客户端套接口和客户名绑定Hashtable clientNameHash = new Hashtable(50);//将游戏创建者和游戏加入者绑定Hashtable chessPeerHash = new Hashtable(50);public ServerRunner() { //初始化}//用指定端口和面板创建服务器public void createServer(int port, ServerMsgPanel serverMsgPanel) throws IOException {}//对动作进行监听public void actionPerformed(ActionEvent e) {}public static void main(String[] args) {new ServerRunner();}}
通过该项目,对于Hashtable,socket编程,java.IO流以及多线程开发等有了深入认识