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