泡泡堂联机对战-Java网络编程

Java大作业要求实现游戏能够双人联机对战,在初学了网络编程后, 采用传送键值的方法,实现了游戏画面的基本同步。

那总的来说就是要写一个客户端,一个服务器端,因为要实现双人对战,所以服务器负责协调两个客户端之间信息交流。但交流的信息(数据包)的内容是一个要讨论的问题,暂时想到两种方案。

第一种:传键入的键值,另一个客户端接收键值后在本程序更新画面。

P1键入后 ,将键入信息发送给P2,P2接收后模拟在本程序键入A、W、S、D、space等按键。

P2键入后 ,将键入信息发送给P1,P1接收后模拟在本程序键入UP、DOWN、LEFT、RIGHT、Enter等按键。

第二种:服务器接收客户端键值,加载完画面后,传送给两个客户端整个画面的地图信息,实现客户端画面的同步。

由于原来写的代码对实现第二种方案的复用性不好,这里暂时用第一种方法。

1、服务器端

创建客户端线程实现P1与P2的通信

package bombman;

import javax.swing.*;
import java.awt.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class BombServer extends JFrame implements Runnable {

    private Socket s = null;
    private ServerSocket ss = null;
    private ArrayList<ChatThread> clients=new ArrayList<ChatThread>();//保存每个客户端连入的变长数组

    public BombServer()throws Exception{//初始化
        this.setTitle("泡泡堂服务器端");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setBackground(Color.yellow);
        this.setBounds(500, 250, 600, 300);
        this.setVisible(true);
        ss=new ServerSocket(9090);//服务器开辟一个端口
        new Thread(this).start();//接受客户连接的死循环开始运行
    }


    public int clientNum = 0;//给用户数量计数

    @Override
    public void run() {
        try {
            while(true)
            {
                s=ss.accept();//等待连入
                ChatThread ct=new ChatThread(s);//当有客户端连入后,为此客户端创建一个线程
                clients.add(ct);//并且将此线程加入到线程数组中
                clientNum ++;
                System.out.println("当前用户数量:"+clientNum);
                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());
        }

        //重写run,线程执行的方法
        public void run() {//把从客户那里得到的信息,传送给其他客户
            try {
                while(canRun) {
                    String str=br.readLine();//读取该Socket传来的信息,
                    System.out.println(str);
                    if(str.charAt(0) == '1'){//说明这是P2发给P1的字符串
                        sendMessage(str, 1);
                    } else if(str.charAt(0) == '2'){//说明这是P1发给P2的字符串
                        sendMessage(str, 2);
                    }

                }
            }catch (Exception ex) {
                canRun=false;
                clients.remove(this);//将此线程从客户端的数组中删除
            }
        }
    }

    //将信息发送给其他的客户端,实现客户端之间的通信
    public void sendMessage(String msg, int r) {
        /*for(ChatThread ct: clients) {
            ct.ps.println(msg);
        }*/
        if(r == 1){
            clients.get(0).ps.println(msg);//向P1发送字符串
        } else if(r == 2){
            clients.get(1).ps.println(msg);//向P2发送字符串
        }
    }

    public static void main(String[] args) throws Exception {
        BombServer server = new BombServer();
    }

}

2、客户端发送数据

在键盘监听器中发送信息,当按下一个按键时向另一个玩家发送一个字符串信息(用ps发送,ps已经连接了输出流,字符串信息包括目标玩家信息和按键信息)

字符串的第一个字代表目标玩家,”1“代表P1,”2“代表P2

字符串的第二个字代表按下按键:

玩家1:”W"、“S”、”A"、“D”、“B”,分别表示上、下、左、右、放炸弹

玩家2:”8"、“2”、”4"、“6”、“5”,分别表示上、下、左、右、放炸弹

/**
	 * !!!!!!!!!!!!!在这里发送信息,当按下按键时发送一个代表自己身份的字符串!!!!!!
	 */
	// 键盘监听器,继承键值
	class BombKeyAdapter extends KeyAdapter {
		@Override
		public void keyPressed(KeyEvent e) {
			// TODO 自动生成的方法存根
			// 根据按键来设置玩家的状态,是左 还是右?的朝向
			// 第一个 玩家 
			if(computerplayer1.ispause && !ispause){// 当电脑控制是暂停状态,并且当前游戏面板不是暂停状态,才可以操作
				if (e.getKeyCode() == KeyEvent.VK_S) {

					BombMainInterface.ps.println("2S");//代表发送给P2,按键S

					KeyTruePlayer(1,0,0);
				}
				else if (e.getKeyCode() == KeyEvent.VK_A) {

					BombMainInterface.ps.println("2A");//代表发送给P2,按键A

					KeyTruePlayer(1,1,0);
				}
				else if (e.getKeyCode() == KeyEvent.VK_D) {

					BombMainInterface.ps.println("2D");//代表发送给P2,按键D

					KeyTruePlayer(1,2, 0);
				}
				else if (e.getKeyCode() == KeyEvent.VK_W) {

					BombMainInterface.ps.println("2W");//代表发送给P2,按键W

					KeyTruePlayer(1,3, 0);
				}
				else if (e.getKeyCode() == KeyEvent.VK_SPACE) {// Enter放置炸弹

					BombMainInterface.ps.println("2B");//代表发送给P2,按键B代表放炸弹

					KeyTruePlayer(1,4, 1);
				}
			}
			
			// 第二个玩家
			if(computerplayer2.ispause && !ispause){
				if (e.getKeyCode() == KeyEvent.VK_DOWN) {

					BombMainInterface.ps.println("12");//代表发送给P1,按键VK_DOWN

					// 如果玩家与炸弹同一个位置 设置不同状态的图片
					KeyTruePlayer(2, 0, 0);
				}
				else if (e.getKeyCode() == KeyEvent.VK_LEFT) {

					BombMainInterface.ps.println("14");//代表发送给P1,按键VK_LEFT

					KeyTruePlayer(2,1, 0);
				}
				else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {

					BombMainInterface.ps.println("16");//代表发送给P1,按键VK_RIGHT

					KeyTruePlayer(2,2,0);
				}
				else if (e.getKeyCode() == KeyEvent.VK_UP) {

					BombMainInterface.ps.println("18");//代表发送给P1,按键VK_UP

					KeyTruePlayer(2,3,0);
				}
				else if (e.getKeyCode() == KeyEvent.VK_ENTER) {// 空格放置炸弹

					BombMainInterface.ps.println("15");//代表发送给P1,按键VK_ENTER

					KeyTruePlayer(2,4,1);
				}
			}
		}
	}
	// 如果按键正确就 更新地图 放置炸弹这些。state是判断单纯的走还是放炸弹,

	 //player:第几个玩家,dir:地图上玩家的朝向,state:是走动 还是放置炸弹 0走,1放炸弹

3、服务端初始化连接数据库

//连接服务器,输入输出流,启动线程
		try {
			s=new Socket("127.0.0.1",9090);  //连接服务器
			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);
		}

4、客户端接收数据并解析数据

@Override
	public void run() {
		try {
			System.out.println("等待读取字符串......");
			while(canRun) {
				String str=br.readLine();//读取到的字符串
				//int score=Integer.parseInt(str);
				System.out.println(str);

				if(str.charAt(0) == '2'){
					if(str.charAt(1) == 'S'){
						center.KeyTruePlayer(1,0,0);
					} else if(str.charAt(1) == 'A'){
						center.KeyTruePlayer(1,1,0);
					} else if(str.charAt(1) == 'D'){
						center.KeyTruePlayer(1,2,0);
					} else if(str.charAt(1) == 'W'){
						center.KeyTruePlayer(1,3,0);
					} else if(str.charAt(1) == 'B'){
						center.KeyTruePlayer(1,4,1);
					}
				} else if(str.charAt(0) == '1'){
					if(str.charAt(1) == '2'){
						center.KeyTruePlayer(2,0,0);
					} else if(str.charAt(1) == '4'){
						center.KeyTruePlayer(2,1,0);
					} else if(str.charAt(1) == '6'){
						center.KeyTruePlayer(2,2,0);
					} else if(str.charAt(1) == '8'){
						center.KeyTruePlayer(2,3,0);
					} else if(str.charAt(1) == '5'){
						center.KeyTruePlayer(2,4,1);
					}
				}

			}
		}catch(Exception ex) {
			canRun=false;
			javax.swing.JOptionPane.showMessageDialog(this, "游戏退出异常!");
			ex.printStackTrace();
			System.exit(0);
		}
	}

5、游戏运行

首先打开服务端程序,创建一个等待连接的服务器
在这里插入图片描述然后打开客户端程序,输入玩家1昵称,进入游戏画面
在这里插入图片描述
在另一台电脑打开客户端程序,输入玩家2昵称,进入游戏画面
在这里插入图片描述
连接到同一个服务器,提示连接成功!
在这里插入图片描述
弹出游戏画面,实现游戏基本同步:
在这里插入图片描述

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值