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, 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