【java】英语单词对战小游戏

//此游戏是在之前的打字对战小游戏的基础上修改而成。分析游戏功能之后可以知道只需要修改GamePanel类的内容即可。

一、题目分析
     根据我的分析之后,明确了三个需要更改的地方。(1)界面的问题,单词实现随机的读取以及四个选项标签的设置。(2)选择正确时候的监听器如何处理才能使得加减分正确。(3)退出游戏后将正确错误未判断单词的一个存储问题。


二、解决问题
  (1)对于第一个问题,首先需要了解的是如何随机读取单词。我采用的方法是将单词从文件中读取存储到变长数组ArrayList里面,然后通过随机数的选定来选定此时判断的单词是哪一个。对于四个选项来说,首先一定需要正确的选项在其中,且正确选项在ABCD中是随机存放的。由此为了找到这个正确的选项,我选择将单词的存储方式写成为:单词一行,下一行是其对应的中文。所以在选择随机数和数组对应时需要小小的计算一下对应关系。
代码如下:

   int lenth=0;
  while(lenth<3) lenth=(int)(Math.random()*al.size()/2-1);//为了下面的选项的选择,增加了3个空的单词内容
  String str=(String) al.get((int)(2*lenth));//此时的str就是选择出来的单词。

对于选项的随机方式如下:
//将选择正确单词周围的单词意思(如果当前单词是第一个的话会使得其越界,由此上面增加了3个空内容单词),将四个意思存放在数组内,然后随机产生r值来显示在不同的选项标签上。
all.add((String) al.get((int)(2*lenth+1)));
  all.add((String) al.get((int)(2*lenth-3)));
all.add((String) al.get((int)(2*lenth-1)));
  all.add((String) al.get((int)(2*lenth-5)));
System.out.println(all);
r=rnd.nextInt(4);

(2)对于此问题就是KeyListener来解决。我们把上面的r作为判断的标志,我们现在知道,当r=0时,正确答案在A...所以把r设置在函数外面,方便我们的处理函数使用。当我们按压下的键盘值-65,所得值是==r的话,那么选择正确。
(3)对于第三个问题比较简单。就是先设置三个文件,在判断的地方加上写入函数即可。(下面代码没有这一部分,解决的思想是将length放在前面,这样可以访问数组中正确单词与意思)

三、代码
一下代码还含有调试代码。

/*题目要求:
 Q:线程的理解。
  大致思路:建立三个类。客户端、服务器端、游戏面板类。
  
  对于客户端,主要是为了实现可以使多个客户通过网络连接到一个服务器上,实现数据的交互。
        由此,对于服务器来说:
  1.首先每个客户进入服务器的时间是不可以确定的,所以需要一个总的线程来等待每个客户的连入。
  2.同时,每个客户对服务器的输入输出也是一个线程的问题,所以还需要为每一个客户创建一个线程。为了方便操作,我们同时申请一个
  变长数组来保存每个连入服务器的客户端。
  3.并且,客户端之间的通信也是通过这个变长的数组来实现的。
*/

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类的使用。
  
  1.5个标签的形成。4个选项外加一个下落的单词。
  2.正确的答案的匹配。
*/
package client;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.Socket;
import java.util.Random;
import java.util.ArrayList;
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(500,this);
	private Random rnd=new Random();
	private BufferedReader br=null;
	private PrintStream ps=null;
	private boolean canRun=true;
	private int r=0;
	//选项的四个标签
	private JLabel ca=new JLabel();
	private JLabel cb=new JLabel();
	private JLabel cc=new JLabel();
	private JLabel cd=new JLabel();
	private File file=new File("D:\\ENG.txt");
	private BufferedReader fbr=null;
	private ArrayList al=new ArrayList();
	private ArrayList all=new ArrayList();
	
	public GamePanel() throws Exception{
		//存储单词到数组里面。
		String str=null;
		fbr=new BufferedReader(new FileReader(file));
		while(true) {
			str=fbr.readLine();
			al.add(str);
			if(str==null)
			break;
		}
		/**将面板的格式置成空,由此之后将会对所有进行重新设置**/
		this.setLayout(null);
		this.setBackground(Color.DARK_GRAY);
		this.setSize(600,400);
		
		/**设置显示生命值的标签的样式**/
		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,16));
		lbMoveChar.setForeground(Color.YELLOW);
		
		
		
		/***设置选择的标签***/
		this.add(ca);
		ca.setFont(new Font("黑体",Font.BOLD,10));
		ca.setBounds(0,360,200,20);
		ca.setForeground(Color.white);
		this.add(cb);
		cb.setBounds(150,360,200,20);
		cb.setFont(new Font("黑体",Font.BOLD,10));
		cb.setForeground(Color.white);
		this.add(cc);
		cc.setBounds(300,360,200,20);
		cc.setFont(new Font("黑体",Font.BOLD,10));
		cc.setForeground(Color.white);
		this.add(cd);
		cd.setBounds(450,360,200,20);
		cd.setFont(new Font("黑体",Font.BOLD,10));
		cd.setForeground(Color.white);
		this.init();
		
		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);
		}
		
		this.addKeyListener(this);
		timer.start();
	}
	
	
	//实现掉落的字母起始位置的随机
	public void init() {
		lbLife.setText("当生命值为:"+life);
		int lenth=0;
		while(lenth<3)	lenth=(int)(Math.random()*al.size()/2-1);//范围
		System.out.println(lenth);
		String str=(String) al.get((int)(2*lenth));//
		System.out.println(str);
		lbMoveChar.setText(str);
		lbMoveChar.setBounds(rnd.nextInt(this.getWidth()-200),0, 200, 18);//起始位置是横坐标随机,纵坐标从0,组件大小为20,20
        //选项的设置		
		all.add((String) al.get((int)(2*lenth+1)));
		all.add((String) al.get((int)(2*lenth-3)));
		all.add((String) al.get((int)(2*lenth-1)));
		all.add((String) al.get((int)(2*lenth-5)));
		System.out.println(all);
	   r=rnd.nextInt(4);
	   System.out.println("r为:"+r);
			if(r==0) 
			{
				ca.setText("A:"+all.get(0));
				cb.setText("B:"+all.get(1));
				cc.setText("C:"+all.get(2));
				cd.setText("D:"+all.get(3));
			}
			if(r==1) 
			{
				cb.setText("B:"+ all.get(0));
				ca.setText("A:"+all.get(1));
				cc.setText("C:"+ all.get(2));
				cd.setText("D:"+ all.get(3));
			}
			if(r==2) 
			{
				cc.setText("C:"+ all.get(0));
				cb.setText("B:"+ all.get(1));
				ca.setText("A:"+ all.get(2));
				cd.setText("D:"+  all.get(3));
			}
			if(r==3) 
			{
				cd.setText("D:"+all.get(0));
				cb.setText("B:"+all.get(1));
				cc.setText("C:"+ all.get(2));
				ca.setText("A:"+all.get(3));
			}
			
			all.clear();
		
	}
	
	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, "1游戏退出异常!");
			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 keyPressed(KeyEvent e) {
		try {
			if(e.getKeyCode()-65==r) {
				life+=2;
				ps.println("-1");
			}else {
				life--;
			}
			checkFail();
		}catch(Exception ex) {
			ex.printStackTrace();
			javax.swing.JOptionPane.showMessageDialog(this, "2游戏异常退出!");
			System.exit(0);
		}	
		
	}


	public void keyReleased(KeyEvent arg0) {}

	public void keyTyped(KeyEvent arg0) {}
	
	
	public void checkFail()//检验生命值是否小于0,如果小于0则退出游戏。
	{
		init();
		if(life<=0) {
		timer.stop();
			javax.swing.JOptionPane.showMessageDialog(this, "生命值耗尽,游戏失败!");
			System.exit(0);
		}
	}
	
public static void main(String[] args){

	}

}
//客户端
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);
		try{gp=new GamePanel();}catch(Exception e) {}
		this.add(gp);
		gp.setFocusable(true);
		this.setSize(gp.getWidth(), gp.getHeight());
		this.setLocation(650, 300);
		this.setResizable(true);
		this.setVisible(true);
	}
	
	public static void main(String[] args) {
		new GameFrame();
	}

}

遇到的几个问题:1.由于标签的大小不够导致显示只有小点点。2.由于设置标签没有设置前景色,使得选项和背景颜色一样,看不出来。3.没有连接监听器。4.尚未解决的是会有重复单词的出现。

四、运行效果。

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值