Newer
Older
NWP / src / j7 / SeaGameClient.java
@Motoki Miura Motoki Miura on 22 Aug 2020 9 KB run7-2 client
package j7;
// File: SeaGameClient.java
// 海ゲームのクライアントプログラム
// Usage: java SeaGameClient
// 起動してloginボタンを押すと,接続先サーバの名前や利用者の名前を問い合わせてくる
// サーバ名と利用者名を入力する
// 続いてOK ボタンを押すと,ポート番号10000 番でサーバと接続
//
// プログラムを停止するにはlogout ボタンを押す

// グラフィックス
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
// イベント関連
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
// ネットワーク関連
import java.net.Socket;
import java.util.StringTokenizer;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class SeaGameClient implements Runnable {
	JFrame f;// クライアント情報表示用ウィンドウ
	JPanel p;// 上下左右の移動ボタンと海の状態を表示するパネル
	Canvas c;// 海の状態を表示するキャンバス

	//---------------------------------------------------------------------
	// GUI 画面の初期配置
	public SeaGameClient () {
		JButton b;
		f = new JFrame();//クライアント情報ウィンドウ全体の表示
		p = new JPanel();//海表示部分と操作ボタンの表示
		p.setLayout(new BorderLayout());

		// upボタンの作成
		b = new JButton("up");
		b.addActionListener(new ActionListener(){
			// upボタンが押されたらupコマンドを送信
			public void actionPerformed(ActionEvent e){
				sendCommand("up");
			}
		});
		p.add(b, BorderLayout.NORTH);

		// leftボタンの作成
		b = new JButton("left");
		b.addActionListener(new ActionListener(){
			// leftボタンが押されたらleftコマンドを送信
			public void actionPerformed(ActionEvent e){
				sendCommand("left");
			}
		});
		p.add(b, BorderLayout.WEST);

		// rightボタンの作成
		b = new JButton("right");
		b.addActionListener(new ActionListener(){
			// rightボタンが押されたらrightコマンドを送信
			public void actionPerformed(ActionEvent e){
				sendCommand("right");
			}
		});
		p.add(b, BorderLayout.EAST);

		// downボタンの作成
		b = new JButton("down");
		b.addActionListener(new ActionListener(){
			// downボタンが押されたらdownコマンドを送信
			public void actionPerformed(ActionEvent e){
				sendCommand("down");
			}
		});
		p.add(b, BorderLayout.SOUTH);

		// 海上の様子を表示するCanvasを作成
		c = new Canvas();
		c.setSize(256,256);// 大きさの設定
		// フレームに必要な部品の取り付け
		p.add(c);
		f.add(p);

		// フレームfにloginボタンの取り付け
		b = new JButton("login");
		b.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				// loginボタンが押された場合の処理
				// サーバがセットされていなければlogin処理
				if(server == null) login();
			}
		});
		f.add(b,BorderLayout.NORTH);

		// フレームfにlogoutボタンの取り付け
		b = new JButton("logout");
		b.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				logout();
			}
		});
		f.add(b,BorderLayout.SOUTH);

		// フレームfを表示します
		f.setSize(335,345);
		f.setVisible(true);
	} // end of SeaGameClient
	//--------------------------------------------------------------------
	// runメソッド/ 500ミリ秒ごとに画面を更新
	Thread thread = null;
	public void run(){
		while (thread != null){
			System.out.println("client "+name);
			try {
				Thread.sleep(500);
			}catch(Exception e){
			}
			// repaintメソッドを用いて,サーバ上の情報を画面に出力します
			repaint();
		}
	} // end of run
	//---------------------------------------------------------------------
	// login処理関連のオブジェクト
	int sx = 100;
	int sy = 100;
	JTextField host, tf_name;
	JDialog d;

	//---------------------------------------------------------------------
	// loginウィンドウを表示し,必要な情報を得る
	// 実際のlogin処理は,realLoginメソッド
	void login(){
		// ウィンドウの表示とデータの入力
		d = new JDialog(f, true);
		host = new JTextField("127.0.0.1",10) ;
		tf_name = new JTextField("user",10) ;
		d.setLayout(new GridLayout(3,2));
		d.add(new JLabel("host:"));
		d.add(host);
		d.add(new JLabel("name:"));
		d.add(tf_name);
		JButton b = new JButton("OK");
		b.addActionListener(new ActionListener(){
			// 入力が完了したら,readlLoginメソッドを使ってサーバにloginします
			public void actionPerformed(ActionEvent e){
				realLogin(host.getText(), tf_name.getText());
				d.dispose();
			}
		});
		d.add(b);
		d.setResizable(true);
		d.setSize(200, 150);
		d.setVisible(true);
		thread = new Thread(this);
		thread.start();
	} // end of login
	//---------------------------------------------------------------------
	// realLogin関連のオブジェクト
	Socket server;// ゲームサーバとの接続ソケット
	int port = 9999;	// 接続ポート
	BufferedReader in;	// 入力ストリーム
	DataOutputStream out;	// 出力ストリーム
	String name;		// ゲーム参加者の名前

	//---------------------------------------------------------------------
	// サーバへのログイン処理
	void realLogin(String host, String name){
		System.out.println("realLogin "+host+" "+name);
		try {
			// サーバとの接続
			this.name = name;
			server = new Socket(host, port);
			in = new BufferedReader(new InputStreamReader(server.getInputStream()));
			out = new DataOutputStream(server.getOutputStream());

			Thread.sleep(1000);
			// loginコマンドの送付
			out.writeBytes("login " + name+"\n");
			System.out.println("sent login name "+name);
			repaint();
		} catch(Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
	} // end of realLogin
	//---------------------------------------------------------------------
	// サーバからのログアウト
	void logout(){
		try {
			// logoutコマンドの送付
			out.writeBytes("logout\n");
			out.flush();
			server.close();
		}catch (Exception e){
			;
		}
		System.exit(0);
	} // end of logout
	//---------------------------------------------------------------------
	// サーバからゲームの情報を得て,クライアントの画面再描画
	void repaint(){
		// サーバにstatコマンドを送付し,盤面の様子などの情報を取得
		try {
			out.writeBytes("stat\n");
			out.flush();
		} catch (IOException e1) {
			e1.printStackTrace();
		}

		try {
			String line = in.readLine();// サーバからの入力の読み込み
			Graphics g = c.getGraphics();// Canvas cに海の様子を表示

			// 海の描画 (青い四角形)
			g.setColor(Color.blue);
			g.fillRect(0, 0, 256, 256);

			//ship_infoから始まる船の情報の先頭行を探す
			while (!"ship_info".equalsIgnoreCase(line))
				line = in.readLine();

			// 船の情報ship_infoの表示
			// ship_infoはピリオドのみの行で終了
			line = in.readLine();
			while (!".".equals(line)){
				StringTokenizer st = new StringTokenizer(line);
				String obj_name = st.nextToken().trim(); // 名前を読み取ります


				// 自分の船は赤(red)でし,他人の船は緑(green)で表示
				if (obj_name.equals(name))	//自分の船
					g.setColor(Color.red);
				else // 他人の船
					g.setColor(Color.green);

				// 船の位置座標を読み取る
				int x = Integer.parseInt(st.nextToken()) ;
				int y = Integer.parseInt(st.nextToken()) ;


				g.fillOval(x - 10, 256 - y - 10, 20, 20);	// 船を表示
				g.drawString(st.nextToken(),x+10,256-y+10) ;	// 得点を船の右下に表示
				g.drawString(obj_name,x+10,256-y-10) ;		// 名前を船の右上に表示

				line = in.readLine();
			} // end while (!".".equals(line))

			// energy_infoから始まる,燃料タンクの情報の待ち受け
			while (!"energy_info".equalsIgnoreCase(line))
				line = in.readLine();

			// 燃料タンクの情報energy_infoの表示
			line = in.readLine();
			while (!".".equals(line)){ // ピリオドのみの行でない間,繰り返す
				StringTokenizer st = new StringTokenizer(line);

				// 燃料タンクの位置座標を読み取る
				int x = Integer.parseInt(st.nextToken()) ;
				int y = Integer.parseInt(st.nextToken()) ;

				// 燃料タンクを白抜きの赤丸で示す
				g.setColor(Color.red);
				g.fillOval(x - 5, 256 - y - 5, 10, 10);
				g.setColor(Color.white);
				g.fillOval(x - 3, 256 - y - 3, 6, 6);

				line = in.readLine();
			} // end while (!".".equals(line))
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
	} // end of repaint
	//---------------------------------------------------------------------
	// サーバへコマンドを送信
	void sendCommand(String s){
		System.out.println(s);
		try {
			if ("up".equals(s)){
				out.writeBytes("up\n");
			}else if ("down".equals(s)){
				out.writeBytes("down\n");
			}else if ("left".equals(s)){
				out.writeBytes("left\n");
			}else if ("right".equals(s)){
				out.writeBytes("right\n");
			}
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// mainメソッド
	// SeaGameClientを起動します
	public static void main(String[] arg){
		new SeaGameClient();
	}
} // end of class SeaGameClient