本次專題問題重點:
- socket server 處理流程
- 美工
- JApplet 加載圖片不完整
1. socket server 處理流程
在 ServerThread.class 中,會等待新的顧客(Client) 開啟網路連線,
當沒有新的使用者時,則會停留在 Socket socket = serverSocket.accept();,
並且持續等待,等到接受到一個新的網路連線時,判斷後決定是否保留,
若要保留則會丟進 ClientThread.class 去負責個別的顧客傳送過來的值,
而這個顧客就不會再次在 ServerThread.class 中被處理到。
2. 美工
後來除了上圖的範例圖,又再次進行了修改(但並不在下方的程式碼中),增加了一些小道具,由於為了使圖片重疊時不要太突兀,因此採用有透明效果的 .png 檔,在 drawImage() method 中不用擔心,是支援這個功能的。
3. JApplet 加載圖片不完整
一般在 Eclipse 中進行 debug 動作時,並不會發生這種加載不完全的情況,而當檔案壓縮成 .jar 時,就很容易發生這種問題。因此,用的方法是
public void loadImages() {
tracker = new MediaTracker(this);
try {
for (int i = 0; i < imgNames.length; i++) {
img[i] = getImage(getDocumentBase(), imgNames[i]);
tracker.addImage(img[i], i);
}
} catch (Exception e) {
System.err.println("Error loading image");
}
try {
tracker.waitForAll();
} catch (Exception e) {
System.err.println("Unknown error while loading images");
}
}
當圖片檔案大一點時,由於其他讀圖的方法可能是額外的線程,因此可能會被突如其來的指令中斷,進而發生了加載不完整的情況。使用 getImage() 去做,而 getDocumentBase() 則是 JApplet 裡頭的 method,得到當前的路徑,並且在路徑中去找圖片的檔名。則用 tracker 監聽有沒有發生圖片讀入錯誤。
而在 MServer.class 的地方也是會在壓成 .jar 發生這個問題,這裡(JFrame)由於沒有 getDocumentBase() method, 因此我們用
img[i] = java.awt.Toolkit.getDefaultToolkit().getImage( imgNames[i]);代替之。所以基本上圖片都要放在 .class 同一個資料夾下,但在 Eclipse 中 debug,默認路徑則是在 Project 的資料夾(也就是與 bin, src, .settings 同一個資料夾)中。壓成 .jar 時,記得要將圖片一起壓入(這一點我還不確定。),壓縮有封包的類似語法如下:
jar cvfm MServer.jar manifest.mf Server\*.class Server\*.png Server\*.jpg
4. 圖檔製作
網路上抓取的圖片不一定都是 .png 檔,更別說是透明處理,因此我這裡使用 PhotoImpact 12,很陽春簡單的初階使用者可以學的,開啟新檔案-選擇透明背景-將要的圖片複製貼上-點選右鍵-內容-透明度、透明色彩、RGB 容許誤差,這樣調一調就可以上場了。
最好把檔案用小的一點,畢竟真正看得到的部分還只有一小塊,用小一點跑得就比較快。
5. 遊戲構思
"火"轟炸當前方向前十個消失
"水"加速其自身速度
"冰"放慢其自身速度,
"陽光"轟炸當前為中心的 5*5 正方形。
package Server;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.io.BufferedInputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;
import java.lang.Thread;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentListener;
import java.awt.event.AdjustmentEvent;
public class MServer {
// <UI>
private JFrame frame; // main windows
private JTextArea contentArea; // chat message post
private JTextField txtMsg; // user post message
private JTextField txtPort; // server open [port number]
private JTextField txtMax; // max login users limited
private JButton btnStart; // open server
private JButton btnStop; // close server
private JButton btnSend; // send [txtMsg]
private JPanel northPanel;
private JPanel southPanel;
private JPanel chatPanel;
private GPanel gamePanel;
private JScrollPane leftPane;
private JScrollPane rightPane;
private JSplitPane centerSplit; // page windows
private JList userList;
private DefaultListModel listModel;
// </UI>
// <Socket&Server>
boolean serverRunning = false;
private ServerSocket serverSocket;
private ServerThread serverThread;
ArrayList<ClientThread> clientList;
// </Socket&Server>
// <Game>
Timer timer;
private boolean gameRunning = false;
private int RTeamX, RTeamY, RTeamD, RTeamDinv;// U, D, L, R
private int GTeamX, GTeamY, GTeamD, GTeamDinv;
// </Game>
public MServer() {
frame = new JFrame("MServer - Phi");
contentArea = new JTextArea("");
txtMsg = new JTextField();
txtMax = new JTextField("10"); // default users limited = 10
txtPort = new JTextField("2047"); // default port number = 2047
btnStart = new JButton("On"); // open server
btnStop = new JButton("Off"); // close server
btnSend = new JButton("↵ ");
northPanel = new JPanel();
southPanel = new JPanel(new BorderLayout());
chatPanel = new JPanel();
gamePanel = new GPanel();
listModel = new DefaultListModel();
userList = new JList(listModel);
leftPane = new JScrollPane(userList);
rightPane = new JScrollPane(contentArea);
contentArea.setEditable(false);
contentArea.setBackground(Color.BLACK);
contentArea.setForeground(Color.GREEN);
//contentArea.setFont(new Font("Calibri", Font.ITALIC, 20));
contentArea.setFont(new Font("微軟正黑體", Font.ITALIC, 20));
btnStop.setEnabled(false);
userList.setBackground(Color.BLACK);
userList.setForeground(Color.GREEN);
//userList.setFont(new Font("Calibri", Font.ITALIC, 20));
userList.setFont(new Font("微軟正黑體", Font.ITALIC, 20));
northPanel.setLayout(new GridLayout(1, 6));
northPanel.setBorder(new TitledBorder("Setting"));
northPanel.add(new JLabel("User Limit"));
northPanel.add(txtMax);
northPanel.add(new JLabel("Port Number"));
northPanel.add(txtPort);
northPanel.add(btnStart);
northPanel.add(btnStop);
southPanel.setLayout(new BorderLayout());
southPanel.setBorder(new TitledBorder("Input"));
southPanel.add(txtMsg, BorderLayout.CENTER);
southPanel.add(btnSend, BorderLayout.EAST);
leftPane.setBorder(new TitledBorder("User List"));
rightPane.setBorder(new TitledBorder("Room Message"));
centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPane,
rightPane);
centerSplit.setDividerLocation(100);
chatPanel.setLayout(new BorderLayout());
chatPanel.add(northPanel, BorderLayout.NORTH);
chatPanel.add(centerSplit, BorderLayout.CENTER);
chatPanel.add(southPanel, BorderLayout.SOUTH);
frame.setLayout(new GridLayout(2, 1));
frame.add(gamePanel);
frame.add(chatPanel);
frame.setSize(800, 650);
frame.setResizable(false);
// <setting listener>
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
rightPane.getVerticalScrollBar().addAdjustmentListener(
new AdjustmentListener() {
JScrollBar sb = rightPane.getVerticalScrollBar();
public void adjustmentValueChanged(AdjustmentEvent e) {
sb.setValue(sb.getMaximum());
}
});
txtMsg.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send();// when touch [Enter] key
}
});
btnSend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send();
}
});
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (serverRunning) {
JOptionPane.showMessageDialog(frame, "Server opened.",
"Error", JOptionPane.ERROR_MESSAGE);
return;
}
try {
int maxUser, portNumber;
maxUser = Integer.parseInt(txtMax.getText());
portNumber = Integer.parseInt(txtPort.getText());
if (maxUser < 0)
throw new Exception("maxUser < 0");
if (portNumber < 0)
throw new Exception("portNumber < 0");
openServer(maxUser, portNumber);
} catch (Exception err) {
JOptionPane.showMessageDialog(frame, "Setting error.",
"Error", JOptionPane.ERROR_MESSAGE);
}
}
});
btnStop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
closeServer();
}
});
// </setting listener>
frame.setVisible(true);
}
public void openServer(int maxUser, int portNumber)
throws java.net.BindException {
try {
serverSocket = new ServerSocket(portNumber);
serverThread = new ServerThread(serverSocket, maxUser);
serverThread.start();
clientList = new ArrayList<ClientThread>();
serverRunning = true;
contentArea.append("System> Server open.\r\n");
btnStart.setEnabled(false);
btnStop.setEnabled(true);
txtMax.setEditable(false);
txtPort.setEditable(false);
timer = new Timer();
timer.schedule(new GameHeart(), 1000, 20000);
} catch (java.net.BindException e) {
throw new java.net.BindException("Change port number.");
} catch (Exception ee) {
throw new java.net.BindException(ee.getMessage());
}
}
public void closeServer() {
try {
if (serverThread != null)
serverThread.stop();
sendServerMessage("CLOSE@");
for (int i = 0; i < clientList.size(); i++) {
ClientThread cl = clientList.get(i);
cl.reader.close();
cl.writer.close();
cl.socket.close();
}
clientList.clear();
listModel.removeAllElements();
if (serverSocket != null)
serverSocket.close();
serverRunning = false;
contentArea.append("System> Server close.\r\n");
btnStart.setEnabled(true);
btnStop.setEnabled(false);
txtMax.setEditable(true);
txtPort.setEditable(true);
timer.cancel();
} catch (Exception e) {
e.printStackTrace();
}
}
public void send() {// admin type message
if (!serverRunning || clientList.size() == 0) {
contentArea.append("Error> Send message missed." + txtMsg.getText() + "\r\n");
txtMsg.setText(null);
return;
}
String msg = txtMsg.getText();
if (msg == null || msg.equals("")) {
contentArea.append("Error> Empty message.\r\n");
return;
}
msg = "System> " + msg + "\r\n";
sendServerMessage("SYSTEM@" + msg); // tell all clients
contentArea.append(msg);
txtMsg.setText(null);
if (contentArea.getText().length() > 262144)
contentArea.setText(contentArea.getText().substring(131072));
}
public void sendServerMessage(String msg) { // tell all clients
for (int i = clientList.size() - 1; i >= 0; i--) {
clientList.get(i).getWriter().println(msg);
clientList.get(i).getWriter().flush();
}
}
class ServerThread extends Thread {// get clients
private ServerSocket serverSocket;
private int maxUser;
public ServerThread(ServerSocket serverSocket, int maxUser) {
this.serverSocket = serverSocket;
this.maxUser = maxUser;
}
public void run() {
while (true) {
try {
System.out.println("X");
Socket socket = serverSocket.accept();
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(
socket.getOutputStream());
String msg = reader.readLine();
if (msg == null || msg.equals(""))
continue;
System.out.println(msg);
StringTokenizer st = new StringTokenizer(msg, "@");
User user = new User(st.nextToken(), st.nextToken());
// <check server loading>
if (clientList.size() == maxUser) {
writer.println("E@Server too busy.\r\n");
writer.flush();
reader.close();
socket.close();
continue;
}
// </check server loading>
// <check same user>
boolean sameFlag = false;
for (int i = 0; i < clientList.size() && !sameFlag; i++) {
if (clientList.get(i).user.getName().equals(
user.getName()))
sameFlag = true;
}
if (sameFlag) {
writer.println("E@Change username.\r\n");
writer.flush();
reader.close();
socket.close();
continue;
}
// </check same user>
String teamID = st.nextToken();
msg = "System> " + user.getName()
+ " has entered the room.";
if (teamID.equals("1"))
msg += "(R Team)\r\n";
else
msg += "(G Team)\r\n";
listModel.addElement(user.getName());
ClientThread client = new ClientThread(socket, user);
client.start();
clientList.add(client);
contentArea.append(msg);
sendServerMessage("ADD@" + user.getName());
sendServerMessage("SYSTEM@" + msg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class ClientThread extends Thread {// send message to client
private Socket socket;
private User user;
private BufferedReader reader;
private PrintWriter writer;
private boolean alive = true;
private boolean closeFlag = false;
private Timer timer;
public ClientThread(Socket socket, User user) {
try {
this.socket = socket;
this.user = user;
this.reader = new BufferedReader(new InputStreamReader(
socket.getInputStream(), "UTF-8"));
this.writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(),"UTF-8"));
// <build user list>
for (int i = clientList.size() - 1; i >= 0; i--)
writer.println("ADD@" + clientList.get(i).user.getName());
} catch (Exception e) {
e.printStackTrace();
}
timer = new Timer();
timer.schedule(new AliveHeart(), 1000, 10000);
}
class AliveHeart extends TimerTask {
public void run() {
System.out.println("check alive");
if (alive == false) {// client disconnected
closeConnection();
}
alive = false;
}
}
public void closeConnection() {
try {
String msg;
msg = "System> " + user.getName() + " has left the room.\r\n";
contentArea.append(msg);
sendServerMessage("SYSTEM@" + msg);
sendServerMessage("DELETE@" + user.getName());
reader.close();
writer.close();
socket.close();
// UI list remove
listModel.removeElement(user.getName());
for (int i = 0; i < clientList.size(); i++) {
if (clientList.get(i).user.getName().equals(user.getName())) {
clientList.remove(i);
break;
}
}
closeFlag = true;
timer.cancel();
} catch (Exception e) {
e.printStackTrace();
}
}
public void run() {
String msg;
while (!closeFlag) {
try {
msg = reader.readLine();
dispatcherMessage(msg);
} catch (Exception e) {
//e.printStackTrace();
}
}
}
public void dispatcherMessage(String msg) {
if (msg == null || msg.equals(""))
return;
StringTokenizer st = new StringTokenizer(msg, "@");// CMD@MSG....,
String cmd = st.nextToken();
System.out.println(msg);
if (cmd.equals("CLOSE")) {
closeConnection();
return;
}
if (cmd.equals("A")) {
alive = true;
return;
}
// CMD@GAME@TEAM@DIR
if (cmd.equals("T")) {
msg = st.nextToken();
while (st.hasMoreTokens())
msg += "@" + st.nextToken();
msg = user.getName() + "> " + msg + "\r\n";
contentArea.append(msg);
sendServerMessage("MSG@" + msg);
return;
}
if (cmd.equals("GAME")) {
System.out.println(msg);
cmd = st.nextToken();
int DIR = Integer.parseInt(st.nextToken());
if (cmd.equals("1")) {
if (DIR != RTeamDinv)
RTeamD = DIR;
} else {
if (DIR != GTeamDinv)
GTeamD = DIR;
}
System.out.println(GTeamD);
}
}
public BufferedReader getReader() {
return reader;
}
public PrintWriter getWriter() {
return writer;
}
}
class GameHeart extends TimerTask {
public void run() {
if (gameRunning == true)
return;
gameRunning = true;
gamePanel.newGame();
sendServerMessage("GAME@NEWGAME");
RTeamX = 30;
RTeamY = 7;
RTeamD = 2;// U, D, L, R
RTeamDinv = 3;
sendServerMessage("GAME@MOVE@" + 1 + "@" + RTeamX + "@" + RTeamY);
gamePanel.doing(RTeamX, RTeamY, 1);
GTeamX = 7;
GTeamY = 7;
GTeamD = 3;
GTeamDinv = 2;
sendServerMessage("GAME@MOVE@" + 2 + "@" + GTeamX + "@" + GTeamY);
gamePanel.doing(GTeamX, GTeamY, 2);
Timer timer = new Timer();
timer.schedule(new GameProcess(), 1000, 200);
}
}
class GameProcess extends TimerTask {
int dx[] = { 0, 0, -1, 1 };
int dy[] = { -1, 1, 0, 0 };
int Dinv[] = { 1, 0, 3, 2 };
public void run() {
if (RTeamX + dx[RTeamD] < 0
|| RTeamX + dx[RTeamD] >= 40
|| RTeamY + dy[RTeamD] < 0
|| RTeamY + dy[RTeamD] >= 15
|| gamePanel.board[RTeamX + dx[RTeamD]][RTeamY + dy[RTeamD]] != 0) {
for (int i = 0; i < 4; i++) {
if (RTeamX + dx[i] < 0 || RTeamX + dx[i] >= 40)
continue;
if (RTeamY + dy[i] < 0 || RTeamY + dy[i] >= 15)
continue;
if (gamePanel.board[RTeamX + dx[i]][RTeamY + dy[i]] == 0) {
RTeamD = i;
if (Math.random() * 2 > 1)
break;
}
}
}
RTeamX += dx[RTeamD];
RTeamY += dy[RTeamD];
RTeamDinv = Dinv[RTeamD];
if (GTeamX + dx[GTeamD] < 0
|| GTeamX + dx[GTeamD] >= 40
|| GTeamY + dy[GTeamD] < 0
|| GTeamY + dy[GTeamD] >= 15
|| gamePanel.board[GTeamX + dx[GTeamD]][GTeamY + dy[GTeamD]] != 0) {
for (int i = 0; i < 4; i++) {
if (GTeamX + dx[i] < 0 || GTeamX + dx[i] >= 40)
continue;
if (GTeamY + dy[i] < 0 || GTeamY + dy[i] >= 15)
continue;
if (gamePanel.board[GTeamX + dx[i]][GTeamY + dy[i]] == 0) {
GTeamD = i;
if (Math.random() * 2 > 1)
break;
}
}
}
GTeamX += dx[GTeamD];
GTeamY += dy[GTeamD];
GTeamDinv = Dinv[GTeamD];
int RFlag = gamePanel.doing(RTeamX, RTeamY, 1);
sendServerMessage("GAME@MOVE@" + 1 + "@" + RTeamX + "@" + RTeamY);
int GFlag = gamePanel.doing(GTeamX, GTeamY, 2);
sendServerMessage("GAME@MOVE@" + 2 + "@" + GTeamX + "@" + GTeamY);
if (Math.random() > 0.93) {
for (int i = 0; i < 5; i++) {
String cmd = gamePanel.eraseRandom();
if (!cmd.equals("")) {
sendServerMessage("GAME@ERASE@" + cmd);
}
}
}
if (RFlag == 0 || GFlag == 0) {
if (RFlag == 0 && GFlag == 0) {
txtMsg.setText("Deuce");
} else if (RFlag == 0) {
txtMsg.setText("Green Team Win.");
} else {
txtMsg.setText("Red Team Win.");
}
System.out.println(txtMsg.getText());
send();
this.cancel();
gameRunning = false;
}
}
}
public static void main(String[] args) {
new MServer();
}
}
package Server;
import javax.swing.JPanel;
import java.awt.Image;
import javax.swing.ImageIcon;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.MediaTracker;
import java.io.InputStream;
public class GPanel extends JPanel {
byte[][] board = new byte[800 / 20][300 / 20];
int GX, GY, RX, RY;
boolean startFlag = false;
boolean endFlag = true;
int ptX, ptY, ptC;
Image image, body, ghead, rhead;
Image img[] = new Image[4];
private String imgNames[] = { "background.jpg", "body.png", "ghead.png",
"rhead.png" };
private MediaTracker tracker = null;
public void loadImages() {
tracker = new MediaTracker(this);
try {
for (int i = 0; i < imgNames.length; i++) {
img[i] = java.awt.Toolkit.getDefaultToolkit().getImage(imgNames[i]);
tracker.addImage(img[i], i);
}
} catch (Exception e) {
System.err.println("Error loading image");
}
try {
tracker.waitForAll();
} catch (Exception e) {
System.err.println("Unknown error while loading images");
}
}
public void newGame() {
startFlag = true;
endFlag = false;
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
board[i][j] = 0;
}
}
/*image = readImg("background.jpg");
body = readImg("body.png");
ghead = readImg("ghead.png");
rhead = readImg("rhead.png");*/
loadImages();
GX = -1;
GY = -1;
RX = -1;
RY = -1;
repaint();
}
public int doing(int x, int y, int c) {
if (x < 0 || y < 0 || x >= 800 / 20 || y >= 300 / 20) {
startFlag = false;
endFlag = true;
return 0; // color c lose.
}
if (board[x][y] != 0) {
startFlag = false;
endFlag = true;
return 0; // color c lose.
}
ptX = x;
ptY = y;
ptC = c;
board[x][y] = (byte) c;
if (c == 1) {
RX = x;
RY = y;
}
if (c == 2) {
GX = x;
GY = y;
}
repaint();
return 1;
}
public String eraseRandom() {
int x = (int) (Math.random() * board.length);
int y = (int) (Math.random() * board[0].length);
int count = 0;
while (board[x][y] == 0 && count++ < 50) {
x = (int) (Math.random() * board.length);
y = (int) (Math.random() * board[0].length);
}
if (board[x][y] == 0)
return "";
board[x][y] = 0;
return x + "@" + y;
}
@Override
public void paintComponent(Graphics g) {
// super.paintComponent(g);
g.setColor(Color.black);
if (image == null) {
for (int i = 0; i < this.getHeight(); i++)
g.drawLine(0, i, 800, i);
image = img[0];
} else {
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
for (int i = 0; i < 800 / 20; i++) {
for (int j = 0; j < 300 / 20; j++) {
if (board[i][j] == 0)
continue;
if (board[i][j] == 1)
g.setColor(Color.red);
else
g.setColor(Color.green);
if (body != null) {
g.drawImage(body, i * 20, j * 20, 20, 20, null);
continue;
}
body = img[1];
int xpoints[] = { i * 10 + 7, i * 10 + 14, i * 10 + 7, i * 10 };
int ypoints[] = { j * 10, j * 10 + 7, j * 10 + 14, j * 10 + 7 };
int npoints = 4;
g.fillPolygon(xpoints, ypoints, npoints);
// g.fillOval(i * 10, j * 10, 11, 11);
// g.fillRect(i * 10, j * 10, 8, 8);
}
}
if (GX >= 0 && ghead != null) {
g.drawImage(ghead, GX * 20 - 15, GY * 20 - 15, 50, 50, null);
}
if (RX >= 0 && rhead != null) {
g.drawImage(rhead, RX * 20 - 15, RY * 20 - 15, 50, 50, null);
}
ghead = img[2];
rhead = img[3];
}
}
package Server;
public class User {
private String name;
private String ip;
public User(String name, String ip) {
this.name = name;
this.ip = ip;
}
public String getName() {
return name;
}
public String getIp() {
return ip;
}
public void setName(String name) {
this.name = name;
}
public void setIp(String ip) {
this.ip = ip;
}
}
package Client;
import java.net.Socket;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.Map;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.lang.Thread;
public class NetClient extends JApplet {
MClient p;
private MediaTracker tracker = null;
Image img[] = new Image[4];
private String imgNames[] = { "background.jpg", "body.png", "ghead.png",
"rhead.png" };
public void init() {
MClient p = new MClient(this);
this.getContentPane().add(p.frame);
loadImages();
}
public void loadImages() {
tracker = new MediaTracker(this);
try {
for (int i = 0; i < imgNames.length; i++) {
img[i] = getImage(getDocumentBase(), imgNames[i]);
tracker.addImage(img[i], i);
}
} catch (Exception e) {
System.err.println("Error loading image");
}
try {
tracker.waitForAll();
} catch (Exception e) {
System.err.println("Unknown error while loading images");
}
}
}
class MClient {
// <UI>
public JPanel frame; // main windows
JTextArea contentArea; // chat message post
JTextField txtMsg; // user post message
private JTextField txtPort; // server open [port number]
private JTextField txtHost; // server open [host ip address]
private JTextField txtName; // user name
private JButton btnStart; // open server
private JButton btnStop; // close server
private JButton btnSend; // send [txtMsg]
private JButton btnCH; // game choose item
private JPanel northPanel;
private JPanel southPanel;
private JPanel chatPanel;
private GPanel gamePanel;
private JScrollPane leftPane;
private JScrollPane rightPane;
private JSplitPane centerSplit; // page windows
private JList userList;
private DefaultListModel listModel;
// </UI>
int teamID, teamDir;
boolean clientRunning = false;
// <Socket&Client>
private Socket socket;
private PrintWriter writer;
private BufferedReader reader;
private ClientThread clientThread;
Timer timer;
NetClient parent;
public MClient(NetClient parent) {
this.parent = parent;
frame = new JPanel();
contentArea = new JTextArea("");
txtMsg = new JTextField();
txtName = new JTextField("guest"); // default users limited = 10
txtPort = new JTextField("2047"); // default port number = 2047
txtHost = new JTextField("127.0.0.1"); // default ip address
btnStart = new JButton("LogIn"); // log in server
btnStop = new JButton("LogOut"); // log out server
btnSend = new JButton("↵ ");
btnCH = new JButton("Green");
northPanel = new JPanel();
southPanel = new JPanel(new BorderLayout());
chatPanel = new JPanel();
gamePanel = new GPanel(this, this.parent);
listModel = new DefaultListModel();
userList = new JList(listModel);
leftPane = new JScrollPane(userList);
rightPane = new JScrollPane(contentArea);
contentArea.setEditable(false);
contentArea.setBackground(Color.BLACK);
contentArea.setForeground(Color.GREEN);
//contentArea.setFont(new Font("Calibri", Font.ITALIC, 20));
contentArea.setFont(new Font("微軟正黑體", Font.ITALIC, 20));
btnStop.setEnabled(false);
userList.setBackground(Color.BLACK);
userList.setForeground(Color.GREEN);
//userList.setFont(new Font("Calibri", Font.ITALIC, 20));
userList.setFont(new Font("微軟正黑體", Font.ITALIC, 20));
northPanel.setLayout(new GridLayout(1, 8));
northPanel.setBorder(new TitledBorder("Setting"));
northPanel.add(new JLabel("Port"));
northPanel.add(txtPort);
northPanel.add(new JLabel("Host"));
northPanel.add(txtHost);
northPanel.add(new JLabel("Username"));
northPanel.add(txtName);
northPanel.add(btnStart);
northPanel.add(btnStop);
northPanel.add(btnCH);
southPanel.setLayout(new BorderLayout());
southPanel.setBorder(new TitledBorder("Input"));
southPanel.add(txtMsg, BorderLayout.CENTER);
southPanel.add(btnSend, BorderLayout.EAST);
leftPane.setBorder(new TitledBorder("User List"));
rightPane.setBorder(new TitledBorder("Room Message"));
centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPane,
rightPane);
centerSplit.setDividerLocation(100);
chatPanel.setLayout(new BorderLayout());
chatPanel.add(northPanel, BorderLayout.NORTH);
chatPanel.add(centerSplit, BorderLayout.CENTER);
chatPanel.add(southPanel, BorderLayout.SOUTH);
frame.setLayout(new GridLayout(2, 1));
frame.add(gamePanel);
frame.add(chatPanel);
frame.setSize(800, 650);
// <setting listener>
rightPane.getVerticalScrollBar().addAdjustmentListener(
new AdjustmentListener() {
JScrollBar sb = rightPane.getVerticalScrollBar();
public void adjustmentValueChanged(AdjustmentEvent e) {
sb.setValue(sb.getMaximum());
}
});
txtMsg.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send();// when touch [Enter] key
}
});
btnSend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send();
}
});
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
int portNumber;
portNumber = Integer.parseInt(txtPort.getText());
if (portNumber < 0)
throw new Exception("portNumber < 0");
if (txtName.getText().equals(""))
throw new Exception("Change username.");
openConnection(portNumber, txtHost.getText(),
txtName.getText());
} catch (Exception err) {
JOptionPane.showMessageDialog(frame, "Setting error.",
"Error", JOptionPane.ERROR_MESSAGE);
}
}
});
btnStop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
closeConnection();
}
});
btnCH.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (btnCH.getText().equals("Green")) {
btnCH.setText("Red");
teamID = 1;
sendMessage("T@" + txtName.getText() + " become RED Team.");
} else {
btnCH.setText("Green");
teamID = 2;
sendMessage("T@" + txtName.getText()
+ " become GREEN Team.");
}
}
});
// </setting listener>
timer = new Timer();
timer.schedule(new AliveHeart(), 1000, 2000);
}
public void openConnection(int portNumber, String host, String name) {
try {
socket = new Socket(host, portNumber);
writer = new PrintWriter(new OutputStreamWriter(
socket.getOutputStream(), "UTF-8"));
reader = new BufferedReader(new InputStreamReader(
socket.getInputStream(), "UTF-8"));
sendMessage(name + "@" + socket.getLocalAddress().toString() + "@"
+ teamID);
clientThread = new ClientThread();
clientThread.start();
clientRunning = true;
txtPort.setEditable(false);
txtName.setEditable(false);
txtHost.setEditable(false);
btnStart.setEnabled(false);
btnStop.setEnabled(true);
} catch (Exception err) {
contentArea.append("Error> Connection fails.\r\n");
}
}
public void closeConnection() {
try {
sendMessage("CLOSE@");
clientRunning = false;
listModel.clear();
txtPort.setEditable(true);
txtName.setEditable(true);
txtHost.setEditable(true);
btnStart.setEnabled(true);
btnStop.setEnabled(false);
} catch (Exception e) {
clientRunning = false;
e.printStackTrace();
}
}
public void send() { // admin type message
if (!clientRunning) {
contentArea.append("Error> Send message missed.\r\n");
txtMsg.setText(null);
return;
}
String msg = txtMsg.getText();
if (msg == null || msg.equals("")) {
contentArea.append("Error> Empty message.\r\n");
return;
}
msg = msg + "\r\n";
sendMessage("T@" + msg); // tell all clients
txtMsg.setText(null);
if (contentArea.getText().length() > 262144)
contentArea.setText(contentArea.getText().substring(131072));
}
public void sendMessage(String msg) {
if (writer != null) {
writer.println(msg);
writer.flush();
}
}
public void sendGame() {
if (!clientRunning) {
contentArea.append("Error> Disconnect\r\n");
return;
}
sendMessage("GAME@" + teamID + "@" + teamDir);
}
class ClientThread extends Thread { // listen server command
public ClientThread() {
}
public void run() {
String msg;
while (clientRunning) {
try {
msg = reader.readLine();
if (msg == null || msg.equals(""))
continue;
StringTokenizer st = new StringTokenizer(msg, "@");
String cmd = st.nextToken();
if (cmd.equals("CLOSE")) {
contentArea.append("System> Server close!\r\n");
closeConnection();
} else if (cmd.equals("ADD")) { // ADD@username
String name = st.nextToken();
listModel.addElement(name);
} else if (cmd.equals("DELETE")) { // DELETE@username
String name = st.nextToken();
if (name.equals(txtName.getText()))
closeConnection();
listModel.removeElement(name);
} else if (cmd.equals("MSG")) { // from other people message
msg = st.nextToken();
while (st.hasMoreTokens())
msg += "@" + st.nextToken();
contentArea.append(msg + "\r\n");
} else if (cmd.equals("SYSTEM")) { // system
contentArea.append(st.nextToken() + "\r\n");
} else if (cmd.equals("E")) {
contentArea.append("Error> " + st.nextToken() + "\r\n");
closeConnection();
} else if (cmd.equals("GAME")) {
cmd = st.nextToken();
if (cmd.equals("NEWGAME")) {
gamePanel.newGame();
} else if (cmd.equals("MOVE")) {
int TEAM, X, Y;
TEAM = Integer.parseInt(st.nextToken());
X = Integer.parseInt(st.nextToken());
Y = Integer.parseInt(st.nextToken());
gamePanel.doing(X, Y, TEAM);
} else if (cmd.equals("ERASE")) {
int X, Y;
X = Integer.parseInt(st.nextToken());
Y = Integer.parseInt(st.nextToken());
gamePanel.erase(X, Y);
System.out.println("erase");
}
} else {
System.out.println(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class AliveHeart extends TimerTask {
public void run() {
sendMessage("A@");
}
}
}
package Client;
import java.io.InputStream;
import javax.swing.JPanel;
import javax.swing.JApplet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.MediaTracker;
import java.awt.event.KeyEvent;
public class GPanel extends JPanel implements KeyEventDispatcher {
byte[][] board = new byte[800 / 20][300 / 20];
int GX, GY, RX, RY;
boolean startFlag = false;
boolean endFlag = true;
int ptX, ptY, ptC;
MClient parent;
NetClient gparent;
Image image = null, body = null, ghead = null, rhead = null;
Image readImg(String fileName) {
Image icon = null;
try {
InputStream in = this.getClass().getResourceAsStream(fileName);
if (in == null) {
System.err.println("Image not found");
}
byte[] buffer = new byte[in.available()];
in.read(buffer);
icon = java.awt.Toolkit.getDefaultToolkit().createImage(buffer);
} catch (java.io.IOException e) {
System.err.println("Unable to read image");
}
return icon;
}
public GPanel(MClient parent, NetClient gparent) {
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventDispatcher(this);
this.parent = parent;
this.gparent = gparent;
/*image = readImg("background.jpg");
body = readImg("body.png");
ghead = readImg("ghead.png");
rhead = readImg("rhead.png");*/
image = gparent.img[0];
body = gparent.img[1];
ghead = gparent.img[2];
rhead = gparent.img[3];
System.out.println(image == null);
GX = -1;
GY = -1;
RX = -1;
RY = -1;
}
public void newGame() {
startFlag = true;
endFlag = false;
for (int i = 0; i < board.length; i++)
for (int j = 0; j < board[0].length; j++)
board[i][j] = 0;
GX = -1;
GY = -1;
RX = -1;
RY = -1;
repaint();
}
public void erase(int x, int y) {
board[x][y] = 0;
}
public int doing(int x, int y, int c) {
if (x < 0 || y < 0 || x >= 800 / 20 || y >= 300 / 20) {
startFlag = false;
endFlag = true;
return 0; // color c lose.
}
if (board[x][y] != 0) {
startFlag = false;
endFlag = true;
return 0; // color c lose.
}
ptX = x;
ptY = y;
ptC = c;
board[x][y] = (byte) c;
if (c == 1) {
RX = x;
RY = y;
}
if (c == 2) {
GX = x;
GY = y;
}
repaint();
return 1;
}
@Override
public void paintComponent(Graphics g) {
// super.paintComponent(g);
g.setColor(Color.black);
if (image == null) {
for (int i = 0; i < this.getHeight(); i++)
g.drawLine(0, i, 800, i);
image = gparent.img[0];
} else {
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
for (int i = 0; i < 800 / 20; i++) {
for (int j = 0; j < 300 / 20; j++) {
if (board[i][j] == 0)
continue;
if (board[i][j] == 1)
g.setColor(Color.red);
else
g.setColor(Color.green);
if (body != null) {
g.drawImage(body, i * 20, j * 20, 20, 20, null);
continue;
}
body = gparent.img[1];
int xpoints[] = { i * 10 + 7, i * 10 + 14, i * 10 + 7, i * 10 };
int ypoints[] = { j * 10, j * 10 + 7, j * 10 + 14, j * 10 + 7 };
int npoints = 4;
g.fillPolygon(xpoints, ypoints, npoints);
// g.fillOval(i * 10, j * 10, 11, 11);
// g.fillRect(i * 10, j * 10, 8, 8);
}
}
if (GX >= 0 && ghead != null) {
g.drawImage(ghead, GX * 20 - 15, GY * 20 - 15, 50, 50, null);
}
if (RX >= 0 && rhead != null) {
g.drawImage(rhead, RX * 20 - 15, RY * 20 - 15, 50, 50, null);
}
ghead = gparent.img[2];
rhead = gparent.img[3];
}
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_RELEASED)
return false;
switch (e.getKeyCode()) {
case KeyEvent.VK_DOWN:
parent.teamDir = 1;
break;
case KeyEvent.VK_UP:
parent.teamDir = 0;
break;
case KeyEvent.VK_RIGHT:
parent.teamDir = 3;
break;
case KeyEvent.VK_LEFT:
parent.teamDir = 2;
break;
default:
return false;
}
if (parent.txtMsg.getText().equals(""))
parent.sendGame();
return false;
}
}
文章定位: