【Java】网络打字对战小游戏
2018-01-29 15:38
302 查看
//以下代码均出自于清华大学出版社(郭克华老师版java教材)的第二十五章练习章节
//以下为自己的对代码的理解和记录
一、网络打字小游戏
网络打字小游戏需要实现的功能:
运行服务器端,之后运行客户端,可实现多个用户随机进入和退出,进入之后出现登录界面,输入用户名,若连接成功,显示连接成功界面。之后进入游戏界面。
游戏规则为26个大写字母从上端每0.1秒向下坠落,从键盘键入此字母,若正确则自己加一分,其余在线用户减一分,若输入错误或者错过输入时间,则自己减一分。
二、分析
大致思路:建立三个.java。客户端、服务器端、游戏面板类。
服务器端:
(1).首先每个客户进入服务器的时间是不可以确定的,所以需要一个总的线程来等待每个客户的连入。
(2).同时,每个客户对服务器的输入输出也是一个线程的问题,所以还需要为每一个客户创建一个线程。为了方便操作,我们同时申请一个
变长数组来保存每个连入服务器的客户端。
(3).并且,客户端之间的通信也是通过这个变长的数组来实现的。
于是就形成了,当一个客户成功连入服务器之后,服务器在总的线程上为此用户创建一个子线程,也就是2中的线程数组。此子线程中,需要实现客户端与服务器的通信,所以将总线程接收的套接字给子线程,并实现输入输出流的连接。也就是说,当一个客户需要与另一个客户实现通信时,都需要通过主线程的套接字来实现,这样更加的方便。
游戏界面端:
此界面需要考虑的方面是游戏界面的形成(字母的下落以及键盘的键入)和生命值的修改(自己的修改以及自身行为对其他用户生命值的影响)以及判断结束的函数。
(1)游戏界面上关于字母随机的从顶上下落,于是将字符设置成Label的形式,设置下落的起始位置的函数为:
setBounds(rnd.nextInt(this.getWidth()),0, 20, 20);//此函数是起始位置是横坐标随机,纵坐标从0,组件大小为20,20。
之后利用Timer类结合ActionListener的操作函数来实现含字母的移动标签随着时间的推移下落。同时利用Key监听器来实现判断是否操作正确。
(2)在实现移动时,首先判断用户是否已经错过此字母,若错过,则自己减1。当键入时,如果匹配,则自己加2,给服务器减一(服务器将会使得所有子线程用户减1,则此用户正确是加1),否则自己减1。且为了接收服务器给的其他用户的-1,则需要创建线程,因为随时可能有-1的时候。
(3)判断游戏结束的函数是判断生命值是否为0,为0则退出。当每次生命值减少时候都需要判断是否为0。
客户端:只需要显示用户登录界面即可。
其他需要注意的就是一些exception的处理以及退出时的一些符合用户体验的解说。
ERROR:当时在通信时,只能用println,而不能用print。因为他们的套接字的读取是一行一行读取的。当时调试了很久才发现这个地方。
三、代码
四、界面的部分截图
![](https://img-blog.csdn.net/20180129153536512?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGhvdmVuX2Zpc2g=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20180129153806252?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGhvdmVuX2Zpc2g=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
//以下为自己的对代码的理解和记录
一、网络打字小游戏
网络打字小游戏需要实现的功能:
运行服务器端,之后运行客户端,可实现多个用户随机进入和退出,进入之后出现登录界面,输入用户名,若连接成功,显示连接成功界面。之后进入游戏界面。
游戏规则为26个大写字母从上端每0.1秒向下坠落,从键盘键入此字母,若正确则自己加一分,其余在线用户减一分,若输入错误或者错过输入时间,则自己减一分。
二、分析
大致思路:建立三个.java。客户端、服务器端、游戏面板类。
服务器端:
(1).首先每个客户进入服务器的时间是不可以确定的,所以需要一个总的线程来等待每个客户的连入。
(2).同时,每个客户对服务器的输入输出也是一个线程的问题,所以还需要为每一个客户创建一个线程。为了方便操作,我们同时申请一个
变长数组来保存每个连入服务器的客户端。
(3).并且,客户端之间的通信也是通过这个变长的数组来实现的。
于是就形成了,当一个客户成功连入服务器之后,服务器在总的线程上为此用户创建一个子线程,也就是2中的线程数组。此子线程中,需要实现客户端与服务器的通信,所以将总线程接收的套接字给子线程,并实现输入输出流的连接。也就是说,当一个客户需要与另一个客户实现通信时,都需要通过主线程的套接字来实现,这样更加的方便。
游戏界面端:
此界面需要考虑的方面是游戏界面的形成(字母的下落以及键盘的键入)和生命值的修改(自己的修改以及自身行为对其他用户生命值的影响)以及判断结束的函数。
(1)游戏界面上关于字母随机的从顶上下落,于是将字符设置成Label的形式,设置下落的起始位置的函数为:
setBounds(rnd.nextInt(this.getWidth()),0, 20, 20);//此函数是起始位置是横坐标随机,纵坐标从0,组件大小为20,20。
之后利用Timer类结合ActionListener的操作函数来实现含字母的移动标签随着时间的推移下落。同时利用Key监听器来实现判断是否操作正确。
(2)在实现移动时,首先判断用户是否已经错过此字母,若错过,则自己减1。当键入时,如果匹配,则自己加2,给服务器减一(服务器将会使得所有子线程用户减1,则此用户正确是加1),否则自己减1。且为了接收服务器给的其他用户的-1,则需要创建线程,因为随时可能有-1的时候。
(3)判断游戏结束的函数是判断生命值是否为0,为0则退出。当每次生命值减少时候都需要判断是否为0。
客户端:只需要显示用户登录界面即可。
其他需要注意的就是一些exception的处理以及退出时的一些符合用户体验的解说。
ERROR:当时在通信时,只能用println,而不能用print。因为他们的套接字的读取是一行一行读取的。当时调试了很久才发现这个地方。
三、代码
//服务器端 package server; import java.awt.Color; import java.io.*; import java.net.*; import java.util.*; import javax.swing.*; public class Server extends JFrame implements Runnable { private Socket s=null; private ServerSocket ss=null; private ArrayList<ChatThread> clients=new ArrayList<ChatThread>();//保存每个客户端连入的变长数组 public Server()throws Exception{ this.setTitle("服务器端"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setBackground(Color.yellow); this.setSize(200, 100); this.setVisible(true); ss=new ServerSocket(9999);//服务器开辟一个端口 new Thread(this).start();//接受客户连接的死循环开始运行 } //run函数的重写 //此线程是用来接收等待客户端不断连入时的线程 public void run() { try { while(true) { s=ss.accept();//等待连入 ChatThread ct=new ChatThread(s);//当有客户端连入后,为此客户端创建一个线程 clients.add(ct);//并且将此线程加入到线程数组中 ct.start();//启动此线程的线程,此后可以实现通信 } }catch(Exception ex) { ex.printStackTrace(); javax.swing.JOptionPane.showMessageDialog(this, "游戏异常退出!"); System.exit(0); } } //类中类的建立,此线程来接收服务器和一个客户端的通信的线程(针对于服务器) class ChatThread extends Thread{ private Socket s=null; private BufferedReader br=null; private PrintStream ps=null; private boolean canRun=true; public ChatThread(Socket s)throws Exception {//利用线程实现输入输出(通信) this.s=s; br=new BufferedReader( new InputStreamReader(s.getInputStream())); ps=new PrintStream(s.getOutputStream()); } public void run() {//把从客户那里得到的信息,穿送给其他客户 try { while(canRun) { String str=br.readLine();//读取该Socket传来的信息, System.out.println(str); sendMessage(str); } }catch (Exception ex) { canRun=false; clients.remove(this);//将此线程从客户端的数组中删除 } } } //将信息发送给其他的客户端,实现客户端之间的通信 public void sendMessage(String msg) { for(ChatThread ct: clients) { ct.ps.println(msg); } } public static void main(String[] args) throws Exception { Server server=new Server(); } }
/*游戏面板。 Timer类和Random类的使用。 */ package client; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.Socket; import java.util.Random; import javax.swing.*; public class GamePanel extends JPanel implements ActionListener,KeyListener,Runnable{ private int life=10;//生命值的初始化 private char keyChar;//按下的字母记录 private JLabel lbMoveChar=new JLabel();//掉下来的字母Label private JLabel lbLife=new JLabel();//显示当前生命值的Label private Socket s=null; private Timer timer=new Timer(100,this); private Random rnd=new Random(); private BufferedReader br=null; private PrintStream ps=null; private boolean canRun=true; public GamePanel() { /**将面板的格式置成空,由此之后将会对所有进行重新设置**/ this.setLayout(null); this.setBackground(Color.DARK_GRAY); this.setSize(240,320); /**设置显示生命值的标签的样式**/ this.add(lbLife); lbLife.setFont(new Font("黑体",Font.BOLD,20)); lbLife.setBackground(Color.YELLOW); lbLife.setForeground(Color.PINK); lbLife.setBounds(0,0,this.getWidth(),20);//设置了标签的大小 /**设置掉下来的标签**/ this.add(lbMoveChar); lbMoveChar.setFont(new Font("黑体",Font.BOLD,20)); lbMoveChar.setForeground(Color.YELLOW); this.init(); this.addKeyListener(this); try { s=new Socket("127.0.0.1",9999); JOptionPane.showMessageDialog(this, "连接成功"); InputStream is=s.getInputStream(); br=new BufferedReader(new InputStreamReader(is)); OutputStream os=s.getOutputStream(); ps=new PrintStream(os); new Thread(this).start(); }catch (Exception ex) { javax.swing.JOptionPane.showMessageDialog(this, "游戏退出异常!"); System.exit(0); } timer.start(); } //实现掉落的字母起始位置的随机 public void init() { lbLife.setText("当生命值为:"+life); String str=String.valueOf((char)('A'+rnd.nextInt(26))); lbMoveChar.setText(str); lbMoveChar.setBounds(rnd.nextInt(this.getWidth()),0, 20, 20);//起始位置是横坐标随机,纵坐标从0,组件大小为20,20 } public void run() { try { while(canRun) { String str=br.readLine(); int score=Integer.parseInt(str); life+=score; checkFail(); } }catch(Exception ex) { canRun=false; javax.swing.JOptionPane.showMessageDialog(this, "游戏退出异常!"); System.exit(0); } } //Timer来控制移动字母的下落,每100ms则执行一次此操作 public void actionPerformed(ActionEvent e) { if(lbMoveChar.getY()>=this.getHeight()) { life--; checkFail(); } lbMoveChar.setLocation(lbMoveChar.getX(),lbMoveChar.getY()+10);//实现这个字母自己下坠 } public void checkFail()//检验生命值是否小于0,如果小于0则退出游戏。 { init(); if(life<=0) { timer.stop(); javax.swing.JOptionPane.showMessageDialog(this, "生命值耗尽,游戏失败!"); System.exit(0); } } //键盘操作事件对应行为 public void keyPressed(KeyEvent e) { keyChar=e.getKeyChar();//记录键盘输入值 String keyStr=String.valueOf(keyChar).toUpperCase();//将此值转化成大写的字符 try { if(keyStr.equals(lbMoveChar.getText())) { life+=2; ps.println("-1"); }else { life--; } checkFail(); }catch(Exception ex) { ex.printStackTrace(); javax.swing.JOptionPane.showMessageDialog(this, "游戏异常退出!"); System.exit(0); } } public void keyReleased(KeyEvent arg0) {} public void keyTyped(KeyEvent arg0) {} }
//客户端 package client; import javax.swing.*; public class GameFrame extends JFrame { private GamePanel gp; public GameFrame() { this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); String nickName=JOptionPane.showInputDialog("输入昵称"); this.setTitle(nickName) 9b69 ; gp=new GamePanel(); this.add(gp); gp.setFocusable(true); this.setSize(gp.getWidth(), gp.getHeight()); this.setResizable(true); this.setVisible(true); } public static void main(String[] args) { new GameFrame(); } }
四、界面的部分截图
相关文章推荐
- 【java】英语单词对战小游戏
- 《影子跟随算法》目前试着自己写一个联网双人对战的小游戏 看到一篇网络同步的文章很受启发 这里记录一下
- Java编写网络打字游戏
- 【GOF23设计模式】_观察者模式_广播机制_消息订阅_网络游戏对战原理_自带类与接口JAVA251-252
- 使用Java测试网络连通性的几种方法
- java网络编程基础夯实01-Internet地址概述
- java关于网络编程的一些细节的复习
- Java实现基于http协议的网络文件下载
- java小游戏-坦克大战,事后总结
- Java解析网络数据流的三种特殊方法
- 自己用java做的一个打飞机的小游戏
- java网络编程基础夯实06-TCP,UDP,HTTP,Socket简介
- Java 网络文件传输
- 黑马程序员---Java基础---注册登录猜字小游戏
- 加载网络图片保存到本地java.io.IOException: open failed: EINVAL (Invalid argument)
- java IO,伪异步IO以及NIO网络编程 简单实现源码以及区别
- 小谈java与网络
- flex+java socket应用小游戏石头剪子布
- Java基础知识回顾--网络编程基础
- 基于JAVA语言的网络爬虫