Newer
Older
MyNWP / src / j6 / SeaGameClient.java
@Motoki Miura Motoki Miura on 22 Sep 2020 9 KB first commit for NWP exp
package j6;
// 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, ActionListener{
    // mainメソッド
    // SeaGameClientを起動します
    public static void main(String[] arg){
	new SeaGameClient();
    }
	
    // up/down/left/rightが押されたときの処理:ボタンラベルの文字列をコマンドとして送信
    public void actionPerformed(ActionEvent e){
	sendCommand(e.getActionCommand());
    }
	
    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(this);
	p.add(b, BorderLayout.NORTH);

	// leftボタンの作成
	b = new JButton("left");
	b.addActionListener(this);
	p.add(b, BorderLayout.WEST);

	// rightボタンの作成
	b = new JButton("right");
	b.addActionListener(this);
	p.add(b, BorderLayout.EAST);

	// downボタンの作成
	b = new JButton("down");
	b.addActionListener(this);
	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 "+playerName);
	    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 playerName;		// ゲーム参加者の名前

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

	    Thread.sleep(500);
	    // 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");
	} 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(playerName))	//自分の船
		    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
    //---------------------------------------------------------------------
    // サーバへコマンドを送信(up/down/left/right)
    void sendCommand(String command){
	try {
	    out.writeBytes(command+"\n");
	    out.flush();
	} catch (IOException e) {
	    e.printStackTrace();
	}
    }

} // end of class SeaGameClient