diff --git a/asset/images/AddTilesBTN.png b/asset/images/AddTilesBTN.png new file mode 100644 index 0000000..2a538be Binary files /dev/null and b/asset/images/AddTilesBTN.png differ diff --git a/asset/images/BUGIKUB.png b/asset/images/BUGIKUB.png new file mode 100644 index 0000000..8a09f39 Binary files /dev/null and b/asset/images/BUGIKUB.png differ diff --git a/asset/images/GroupSortBTN.png b/asset/images/GroupSortBTN.png new file mode 100644 index 0000000..03a1c75 Binary files /dev/null and b/asset/images/GroupSortBTN.png differ diff --git a/asset/images/QuitBTN.png b/asset/images/QuitBTN.png new file mode 100644 index 0000000..ae516f2 Binary files /dev/null and b/asset/images/QuitBTN.png differ diff --git a/asset/images/RunSortBTN.png b/asset/images/RunSortBTN.png new file mode 100644 index 0000000..7ca9d04 Binary files /dev/null and b/asset/images/RunSortBTN.png differ diff --git a/asset/images/emptyProfile.png b/asset/images/emptyProfile.png new file mode 100644 index 0000000..8abac7d Binary files /dev/null and b/asset/images/emptyProfile.png differ diff --git a/asset/images/minitile.png b/asset/images/minitile.png new file mode 100644 index 0000000..806199e Binary files /dev/null and b/asset/images/minitile.png differ diff --git a/asset/images/ready.png b/asset/images/ready.png new file mode 100644 index 0000000..e3ae6e9 Binary files /dev/null and b/asset/images/ready.png differ diff --git a/asset/images/start.png b/asset/images/start.png new file mode 100644 index 0000000..6556e1a Binary files /dev/null and b/asset/images/start.png differ diff --git a/asset/images/tile.png b/asset/images/tile.png new file mode 100644 index 0000000..5f3306b Binary files /dev/null and b/asset/images/tile.png differ diff --git a/src/Application.java b/src/Application.java index 472befa..0b37f2a 100644 --- a/src/Application.java +++ b/src/Application.java @@ -7,4 +7,4 @@ public static void main(String[] args) { GameController controller = new GameController(view); controller.start(); } -} +} \ No newline at end of file diff --git a/src/Controller/Client.java b/src/Controller/Client.java new file mode 100644 index 0000000..023208f --- /dev/null +++ b/src/Controller/Client.java @@ -0,0 +1,147 @@ +package Controller; +import java.io.*; +import java.net.*; +import java.util.LinkedList; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +import Exceptions.NotEmptySpaceException; +import Exceptions.OnProgressException; + +public class Client{ + + + private Socket curSocket; + private ClientOutput output; + private ClientInput input; + + private GameController gameController; + + + public void sendObject(SerializeObject object){ + output.addObject(object); + } + + public Client(GameController gameController, String address, int port, String name) throws UnknownHostException, NotEmptySpaceException, OnProgressException{ + this.gameController = gameController; + try { + curSocket = new Socket(address, port); + + output = new ClientOutput(curSocket); + input = new ClientInput(curSocket); + + SerializeObject answer = null; + + while (answer == null) { + try { + answer = (SerializeObject) input.getObjectInputStream().readObject(); + } catch (IOException e) { + // IOException 처리 + e.printStackTrace(); + } + } + System.out.println("받은 객체 : " + answer.getEventObject() + answer.getObjectType()); + + if(!answer.getObjectType().equals("Index")) { + String answerStr = (String) answer.getEventObject(); + if (answerStr.equals("방이 가득찼습니다.")) { + throw new NotEmptySpaceException(); + } else if (answerStr.equals("현재 게임이 진행중입니다.")) { + throw new OnProgressException(); + } + } + else{ + gameController.setIndex((int) answer.getEventObject()); + } + Thread outputThread = new Thread(output); + Thread inputThread = new Thread(input); + + outputThread.start(); + inputThread.start(); + + System.out.println("서버에 연결되었습니다."); + sendObject(new SerializeObject(name, "Name", gameController.getIndex())); + + } catch (ClassNotFoundException e) { + System.out.println("클래스가 맞지 않습니다."); + } catch (IOException e) { + e.printStackTrace(); + } + } + + class ClientOutput implements Runnable{ + private ObjectOutputStream objectOutputStream; + private Socket clientSocket; + + private Queue outputQueue; + + public ClientOutput(Socket clientSocket) throws IOException { + this.clientSocket = clientSocket; + objectOutputStream = new ObjectOutputStream(clientSocket.getOutputStream()); + outputQueue = new ConcurrentLinkedQueue<>(); + } + + public ObjectOutputStream getObjectOutputStream() { + return objectOutputStream; + } + + public void addObject(SerializeObject object){ + this.outputQueue.offer(object); + } + + + @Override + public void run() { + try { + while (true) { + SerializeObject sendObj = outputQueue.poll(); + if (sendObj != null) { + System.out.println(sendObj.getEventObject()); + objectOutputStream.writeObject(sendObj); + System.out.println(sendObj.getObjectType() + " " + sendObj.getEventObject() + " 전달"); + } + } + } + catch (IOException e){ + e.printStackTrace(); + } + finally{ + try { + clientSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + class ClientInput implements Runnable{ + ObjectInputStream objectInputStream; + Socket clientSocker; + + Object curInput = null; + + public ClientInput(Socket clientSocker) throws IOException { + this.clientSocker = clientSocker; + objectInputStream = new ObjectInputStream(clientSocker.getInputStream()); + } + + public ObjectInputStream getObjectInputStream() { + return objectInputStream; + } + + @Override + public void run() { + while(true){ + try { + if((curInput = objectInputStream.readObject()) != null){ + SerializeObject sInput = (SerializeObject) curInput; + gameController.excuteQuery(sInput); + } + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + } + } + } +} \ No newline at end of file diff --git a/src/Controller/ClientHandler.java b/src/Controller/ClientHandler.java new file mode 100644 index 0000000..8d061a4 --- /dev/null +++ b/src/Controller/ClientHandler.java @@ -0,0 +1,130 @@ +package Controller; + +import Model.Player; + +import java.io.*; +import java.net.Socket; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + + +public class ClientHandler{ + private Socket clientSocket; + private Object input = null; + + private ServerOutput out; + private ServerInput in; + private Server server; + private int index; + + + // 클라이언트에 객체 전달 + public void sendObject(SerializeObject obj){ + out.addObject(obj); + } + + public void startThread(){ + Thread outThread = new Thread(out); + Thread inThread = new Thread(in); + + outThread.start(); + inThread.start(); + } + + public ClientHandler(Socket socket, Server server, int index) { + this.clientSocket = socket; + this.server = server; + this.index = index; + try { + out = new ServerOutput(clientSocket); + in = new ServerInput(clientSocket); + } catch (IOException e) { + e.printStackTrace(); + } + } + + class ServerOutput implements Runnable{ + private ObjectOutputStream objectOutputStream; + private Socket serverSocket; + + private Queue outputQueue; + + public ServerOutput(Socket serverSocket) throws IOException { + this.serverSocket = serverSocket; + objectOutputStream = new ObjectOutputStream(serverSocket.getOutputStream()); + outputQueue = new ConcurrentLinkedQueue<>(); + } + + public ObjectOutputStream getObjectOutputStream() { + return objectOutputStream; + } + + public void addObject(SerializeObject object){ + this.outputQueue.offer(object); + } + + + @Override + public void run() { + try { + while (true) { + SerializeObject sendObj = outputQueue.poll(); + if (sendObj != null) { + objectOutputStream.writeObject(sendObj); + if(sendObj.getObjectType() == "Player[]") { + Player[] cur = (Player[]) sendObj.getEventObject(); + for(int i = 0 ; i < 4 ; i ++){ + if(cur[i] != null) { + System.out.println(cur[i].getName()); + } + } + System.out.println(sendObj.getEventObject()); + } + System.out.println("출력 추가됨 " + sendObj.getEventObject() + " index : " + index); + } + } + } + catch (IOException e){ + e.printStackTrace(); + } + finally{ + try { + clientSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + + class ServerInput implements Runnable{ + ObjectInputStream objectInputStream; + Socket serverSocket; + + Object curInput = null; + + public ServerInput(Socket serverSocket) throws IOException { + this.serverSocket = serverSocket; + objectInputStream = new ObjectInputStream(serverSocket.getInputStream()); + } + + public ObjectInputStream getObjectInputStream() { + return objectInputStream; + } + + @Override + public void run() { + while(true){ + try { + if((curInput = objectInputStream.readObject()) != null){ + SerializeObject sInput = (SerializeObject) curInput; + server.getGameController().excuteQuery(sInput); + } + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/src/Controller/GameController.java b/src/Controller/GameController.java index 7bd3e0b..e1e1f8d 100644 --- a/src/Controller/GameController.java +++ b/src/Controller/GameController.java @@ -1,26 +1,30 @@ package Controller; -import Model.Client; -import Model.Player; -import Model.Server; +import Exceptions.NotEmptySpaceException; +import Exceptions.OnProgressException; +import Model.*; import View.GameView; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.UnknownHostException; -import java.sql.SQLOutput; +import javax.swing.*; +import java.awt.*; +import java.io.ObjectStreamException; +import java.io.Serial; +import java.util.*; +import java.net.UnknownHostException; +import java.util.List; // 서버 플레이어가 게임 진행을 관리 public class GameController { + + public enum GameState{ + IN_PROGRESS, FINISHED + } + private GameView view; + private int index = -1; + public static final int PORT = 12345; // 포트 번호 private boolean isServer = false; // 현재 서버로 운영되는 사용자인지 @@ -34,37 +38,557 @@ public class GameController { public static final int HAND_HEIGHT = 2; public static final int HAND_WIDTH = 10; + private Game game; + + public static GameState gameState = GameState.FINISHED; + + public Player curPlayer; + + public Tile[][] handTiles; + public Tile[][] lastBoardTiles; + public Tile[][] lastHandTiles; + + public Board boardTiles; + private boolean isTurnProgress = false; + private boolean isMyTurn = false; private Player[] players = new Player[MAX_PLAYER_COUNT]; + + public boolean canAdd(int row, int col){ + return boardTiles.canAddTile(row, col); + } + + public String playersStr() { + String tmp = ""; + for(int i = 0 ; i < MAX_PLAYER_COUNT ; i ++){ + if(players[i] == null){ + tmp += "null\n"; + } + else { + tmp += players[i].toString() + " "; + tmp += view.getRoomNameLabel()[i].getText() + "\n"; + } + } + return tmp; + } + + public boolean isInMyTurn(){ + return isMyTurn; + } + public GameController(GameView view) { this.view = view; view.setGameController(this); } + public void setIndex(int index) { + this.index = index; + } + public void start(){ view.startUI(); } + public Player getCurPlayer() { + return curPlayer; + } + + + public int getIndex(){ + return index; + } + + public static GameState getGameState() { + return gameState; + } + + public static void setGameState(GameState gameState) { + GameController.gameState = gameState; + } + + protected Player[] getPlayers() { + return players; + } // 방 만드는 함수 - 서버 public void makeRoom() { - server = new Server(PORT); +// view.changePanel("GamePanel"); + players[0] = new Player(view.getNameTF().getText()); + players[0].setReadyState(Player.ReadyState.READY); + index = 0; + view.updatePlayers(players); + server = new Server(PORT, this); isServer = true; // 뷰에서 화면 전환함수 + view.changePanel("RoomPanel"); } - public boolean connectRoom(String address) { - client = new Client(); + public void changeTiles(boolean startInBoard, boolean endInBoard, int sr, int sc, int er, int ec){ + System.out.println("타일 변경 저장" + startInBoard + " " + endInBoard); + + Tile start = startInBoard ? boardTiles.getTile(sr, sc) : handTiles[sr][sc]; + Tile end = endInBoard ? boardTiles.getTile(er, ec) : handTiles[er][ec]; + + if(startInBoard) { + boardTiles.setTile(sr, sc, end); + if(endInBoard){ + boardTiles.setTile(er, ec, start); + } + else{ + handTiles[er][ec] = start; + } + } + else{ + handTiles[sr][sc] = end; + if(endInBoard){ + boardTiles.setTile(er, ec, start); + } + else{ + handTiles[er][ec] = start; + } + } + + for(int i = 0 ; i < BOARD_HEIGHT ; i ++){ + for(int j = 0 ; j < BOARD_WIDTH ; j ++){ + System.out.print(boardTiles.getTile(i, j) == null ? null : boardTiles.getTile(i ,j).toString()); + } + System.out.println(); + } + for(int i = 0 ; i < HAND_HEIGHT ; i ++){ + for(int j = 0 ; j < HAND_WIDTH ; j ++){ + System.out.print(handTiles[i][j] == null ? null : handTiles[i][j].toString()); + } + System.out.println(); + } + } + + public void connectRoom(String address) { + view.getLoginErrorLabel().setText("연결 중 입니다..."); isServer = false; + String name = view.getNameTF().getText(); try { - client.connect(address, PORT); + client = new Client(this, address, PORT, name); + view.changePanel("RoomPanel"); } catch (UnknownHostException e) { - return false; + view.getLoginErrorLabel().setText("IP주소로 접속할 수 없습니다. IP주소를 다시 확인해주세요."); + } catch (NotEmptySpaceException e){ + view.getLoginErrorLabel().setText("현재 방 인원이 가득 차 참가할 수 없습니다."); + } catch (OnProgressException e){ + view.getLoginErrorLabel().setText("현재 게임이 진행 중인 방입니다."); + } + + } + + + // 플레이어 ready 상태 변경 함수 + public void updateReadyState(int index, Player.ReadyState readyState){ + // ready + if(readyState == Player.ReadyState.READY && players[index].getReadyState() == Player.ReadyState.NOT_READY){ + players[index].setReadyState(Player.ReadyState.READY); + } + // ready 해제 + else if(readyState == Player.ReadyState.NOT_READY && players[index].getReadyState() == Player.ReadyState.READY){ + players[index].setReadyState(Player.ReadyState.NOT_READY); + } + view.updateRoomReadyPanel(players[index].getReadyState(), index); + } + + public void changeReadyState(){ + players[index].setReadyState(players[index].getReadyState() == Player.ReadyState.READY ? Player.ReadyState.NOT_READY : Player.ReadyState.READY); + view.updateRoomReadyPanel(players[index].getReadyState(), index); + if(isServer){ + server.notifiObservers(new SerializeObject(players[index].getReadyState(), "ReadyState", index), index); + } + else{ + client.sendObject(new SerializeObject(players[index].getReadyState(), "ReadyState", index)); + } + } + + + + // 플레이어 정보 변경 함수 + public void changePlayers(Player[] getPlayers){ + // Model 플레이어 변경 + players = getPlayers; + + // 플레이어 정보 UI 적용 + view.updatePlayers(players); + } + + // 모든 플레이어가 Ready 상태인지 체크 + public boolean checkReady(){ + for(int i = 0 ; i < MAX_PLAYER_COUNT ; i ++){ + if(players[i] != null && players[i].getReadyState() == Player.ReadyState.NOT_READY){ + return false; + } } return true; } + + // 메인 게임 함수 + public void serverStartGame(){ + gameState = GameState.IN_PROGRESS; + // 게임 관리 객체 생성 + game = new Game(players); + // 게임 타일 객체 생성 + + int playerCnt = game.getPlayerCount(); + // 플레이어들에게 첫 손패 타일 전달 + distributeTiles(game.getTileDeck()); + updateHandTiles(handTiles); + boardTiles = new Board(); + server.notifiObservers(new SerializeObject(boardTiles, "Board", 0), 0); + + + // 클라이언트들에게 게임 시작을 알림 + server.notifiObservers(new SerializeObject("startGame", "String", 0), 0); + + System.out.println("게임 패널 변경"); + view.changePanel("GamePanel"); + + + + manageGameProcess(game); + + for(int i = 1 ; i < MAX_PLAYER_COUNT ; i ++){ + if(players[i] != null){ + players[i].setReadyState(Player.ReadyState.NOT_READY); + } + } + + server.notifiObservers(new SerializeObject(players, "Player[]", 0), 0); + + server.notifiObservers(new SerializeObject("finishGame", "String", 0), 0); + view.updatePlayers(players); + view.changePanel("RoomPanel"); + } + + public void startTurn(){ + isMyTurn = true; + lastBoardTiles = boardTiles.getLastBoardState(); + lastHandTiles = getLastHandTiles(); + } + + // 턴 종료 버튼 클릭 + public void clickFinishTurn(){ + // 수가 줄었는지 체크해야함 + if(isInMyTurn()) { + System.out.println(boardTiles.validateCombination() + " ########## "); + if (boardTiles.validateCombination()) { + isMyTurn = false; + if (isServer) { + excuteQuery(new SerializeObject(boardTiles, "Board", index)); + excuteQuery(new SerializeObject("finishTurn", "String", index)); + } else { + client.sendObject(new SerializeObject(boardTiles, "Board", index)); + client.sendObject(new SerializeObject("finishTurn", "String", index)); + } + + } else { + boardTiles.setTiles(lastBoardTiles); + updateBoardTiles(boardTiles.getTiles()); + handTiles = lastHandTiles; + updateHandTiles(handTiles); + } + } + } + + public Tile[][] getLastHandTiles(){ + Tile[][] tmpTiles = new Tile[HAND_HEIGHT][HAND_WIDTH]; + for(int i = 0 ; i < HAND_HEIGHT ; i ++){ + for(int j = 0 ; j < HAND_WIDTH ; j ++){ + tmpTiles[i][j] = handTiles[i][j]; + } + } + return tmpTiles; + } + + public void manageGameProcess(Game game){ + while(true){ + isTurnProgress = true; + server.notifiObservers(new SerializeObject(game.getCurrentPlayerIndex(), "Turn", 0), 0); + if(game.getCurrentPlayerIndex() == 0){ + startTurn(); + } + + while(isTurnProgress){ + } + System.out.println("턴이 종료되었습니다."); + + game.getNextTurnPlayerIndex(); + + + if(canFinish(game.getTileDeck())) break; + } + } + + public boolean canFinish(TileDeck tileDeck){ + if(tileDeck.isEmpty()) return true; + for(int i = 0 ; i < MAX_PLAYER_COUNT ; i ++){ + if(players[i] != null && players[i].getTileCount() == 0) return true; + } + return false; + } + + public void distributeTiles(TileDeck tileDeck){ + handTiles = tileDeck.getFirstHandTiles(HAND_HEIGHT, HAND_WIDTH); + for(int i = 1 ; i < MAX_PLAYER_COUNT ; i ++){ + if(players[i] != null){ + server.notifiObservers(new SerializeObject(tileDeck.getFirstHandTiles(HAND_HEIGHT, HAND_WIDTH), "Hand", i), 0); + server.notifiObservers(new SerializeObject(TileDeck.TILES_PER_PLAYER, "TileCount", i), 0); + players[i].setTileCount(TileDeck.TILES_PER_PLAYER); + } + } + } + + public void clientStartGame(){ + + } + + + // 핸드 UI 적용 + public void updateHandTiles(Tile[][] handTiles){ + System.out.println("타일 UI 업데이트"); + for(int i = 0 ; i < HAND_HEIGHT ; i ++){ + for(int j = 0 ; j < HAND_WIDTH ; j ++){ + Tile cur = handTiles[i][j]; + if(cur == null) { + view.setTransParentPanel(i, j, true); + + continue; + } + view.updateTile(cur.getColor(), cur.getNumber(), i, j, false); + } + } + } + + // 보드 UI 적용 + public void updateBoardTiles(Tile[][] tiles){ + System.out.println("보드 UI 업데이트"); + for(int i = 0 ; i < BOARD_HEIGHT ; i ++){ + for(int j = 0 ; j < BOARD_WIDTH ; j ++){ + Tile cur = tiles[i][j]; + if(cur == null){ + view.setTransParentPanel(i, j, false); + continue; + } + view.updateTile(cur.getColor(), cur.getNumber(), i, j, true); + } + } + } + + public void sortByRun(){ + ArrayList tmp = new ArrayList<>(); + for(int i = 0 ; i < HAND_HEIGHT ; i ++){ + for(int j = 0 ; j < HAND_WIDTH ; j ++){ + if(handTiles[i][j] != null){ + Tile cop = new Tile(handTiles[i][j].getNumber(), handTiles[i][j].getColor()); + tmp.add(cop); + } + } + } + + Collections.sort(tmp, (tile1, tile2) -> Integer.compare(tile1.getNumber(), tile2.getNumber())); + int idx = 0; + for(int i = 0 ; i < HAND_HEIGHT * HAND_WIDTH ; i ++){ + if(i < tmp.size()){ + handTiles[i / HAND_WIDTH][i % HAND_WIDTH] = tmp.get(i); + } + else{ + handTiles[i / HAND_WIDTH][i % HAND_WIDTH] = null; + } + } + + updateHandTiles(handTiles); + } + + public void sortByGroup(){ + ArrayList tmp = new ArrayList<>(); + for(int i = 0 ; i < HAND_HEIGHT ; i ++){ + for(int j = 0 ; j < HAND_WIDTH ; j ++){ + if(handTiles[i][j] != null){ + System.out.println(handTiles[i][j].toString()); + Tile cop = new Tile(handTiles[i][j].getNumber(), handTiles[i][j].getColor()); + tmp.add(cop); + } + } + } + + List customOrder = Arrays.asList("Red", "Orange", "Blue", "Black", "Bugi"); + + Comparator customComparator = (tile1, tile2) -> { + int order1 = customOrder.indexOf(tile1.getColor()); + int order2 = customOrder.indexOf(tile2.getColor()); + + if (order1 != order2) { + return Integer.compare(order1, order2); + } else { + return Integer.compare(tile1.getNumber(), tile2.getNumber()); + } + }; + Collections.sort(tmp, customComparator); + + + System.out.println("변경 후"); + int idx = 0; + for(int i = 0 ; i < HAND_HEIGHT * HAND_WIDTH ; i ++){ + if(i < tmp.size()){ + System.out.println(tmp.get(i).toString()); + handTiles[i / HAND_WIDTH][i % HAND_WIDTH] = tmp.get(i); + } + else{ + handTiles[i / HAND_WIDTH][i % HAND_WIDTH] = null; + } + } + + updateHandTiles(handTiles); + } + + + public void drawTile(){ + if(isInMyTurn()){ + isMyTurn = false; + + //이전 보드 상태로 돌려놓기 + boardTiles.setTiles(lastBoardTiles); + updateBoardTiles(boardTiles.getTiles()); + handTiles = lastHandTiles; + updateHandTiles(handTiles); + + if(!isServer){ + // 턴이 끝났음을 서버에 알림 + client.sendObject(new SerializeObject("finishTurn", "String", index)); + client.sendObject(new SerializeObject("drawTile", "String", index)); + + + } + else{ + server.notifiObservers(new SerializeObject("finishTurn", "String", index), index); + Tile tile = game.getTileDeck().draw(); + addTile(tile); + isTurnProgress = false; + } + } + } + + public void addTile(Tile tile){ + for(int i = 0 ; i < HAND_HEIGHT ; i ++) { + for(int j = 0 ; j < HAND_WIDTH ; j ++){ + if(handTiles[i][j] == null){ + handTiles[i][j] = tile; + view.updateTile(tile.getColor(), tile.getNumber(), i, j, false); + + return; + } + } + } + } + + // 클라이언트로 넘어온 쿼리 실행 함수 + public void excuteQuery(SerializeObject object){ + System.out.println("받은 객체 : " + object.getEventObject()); + switch (object.getObjectType()){ + case "String" : + String content = (String)object.getEventObject(); + // 게임 시작 + if(content.equals("startGame")){ + for(int i = 0 ; i < MAX_PLAYER_COUNT ; i ++){ + if(players[i] == null){ + view.updateGamePlayerIcon(i, null, true); + } + else{ + view.updateGamePlayerIcon(i, players[i].getName(), false); + } + } + view.changePanel("GamePanel"); + } + else if(content.equals("finishTurn")){ + isTurnProgress = false; + if(isServer) server.notifiObservers(new SerializeObject("finishTurn", "String", index), 0); + } + else if(content.equals("finishGame")){ + // 게임 끝 TODO + } + break; + + case "Player[]": + Player[] getPlayers = (Player[]) object.getEventObject(); + changePlayers(getPlayers); + System.out.println(playersStr()); + break; + + // 타일 첫 손패 + case "Hand": + if(object.getIndex() == index) { + handTiles = (Tile[][]) object.getEventObject(); + updateHandTiles(handTiles); + } + break; + + case "Board": + boardTiles = (Board) object.getEventObject(); + updateBoardTiles(boardTiles.getTiles()); + if(isServer) server.notifiObservers(new SerializeObject(boardTiles ,"Board", index), object.getIndex()); + break; + + + case "Turn": + if((int)object.getEventObject() == index){ + System.out.println("나의 턴입니다."); + startTurn(); + } + else{ + isTurnProgress = true; + System.out.println("다른 플레이어의 턴입니다." + (int)object.getEventObject()); + } + break; + + case "Name": + if(isServer) { + System.out.println(object.getEventObject() + " 플레이어 추가"); + String name = (String) object.getEventObject(); + int curIndex = object.getIndex(); + players[curIndex].setName(name); + view.updatePlayers(players); + System.out.println(players + " " + object.getIndex()); + server.notifiObservers(new SerializeObject(Arrays.copyOf(players, MAX_PLAYER_COUNT), "Player[]", object.getIndex()), 0); + } + break; + + case "Index" : + this.index = (int) object.getEventObject(); + break; + + case "drawTile": + if(isServer){ + server.notifiObservers(new SerializeObject(game.getTileDeck().draw(), "getTile", index), 0); + } + break; + + case "getTile": + if(object.getIndex() == index){ + Tile getTile = (Tile) object.getEventObject(); + addTile(getTile); + } + break; + case "ReadyState" : + Player.ReadyState readyState = (Player.ReadyState) object.getEventObject(); + updateReadyState(object.getIndex(), readyState); + if(isServer) server.notifiObservers(new SerializeObject(readyState, "ReadyState", object.getIndex()), object.getIndex()); + break; + + case "TileCount" : + int cnt = (int)object.getEventObject(); + players[object.getIndex()].setTileCount(cnt); + if(isServer) server.notifiObservers(new SerializeObject(cnt, "TileCount", object.getIndex()), object.getIndex()); + default: + break; + } + + } + } diff --git a/src/Controller/SerializeObject.java b/src/Controller/SerializeObject.java new file mode 100644 index 0000000..7561087 --- /dev/null +++ b/src/Controller/SerializeObject.java @@ -0,0 +1,26 @@ +package Controller; + +import java.io.Serializable; + +// 직렬화 객체 +class SerializeObject implements Serializable { + private Object eventObject; // 실제 객체를 포장하는 필드 + private String objectType; // 객체의 유형을 나타내는 필드 + + private int index; // 객체의 인덱스 번호 + + public SerializeObject(Object eventObject, String objectType, int index) { + this.eventObject = eventObject; + this.objectType = objectType; + this.index = index; + } + + public Object getEventObject() { + return eventObject; + } + public String getObjectType() { + return objectType; + } + + public int getIndex(){ return index; } +} \ No newline at end of file diff --git a/src/Controller/Server.java b/src/Controller/Server.java new file mode 100644 index 0000000..2d04158 --- /dev/null +++ b/src/Controller/Server.java @@ -0,0 +1,92 @@ +package Controller; + +import Model.Player; + +import java.io.*; +import java.net.*; + +public class Server { + + + static int clientCnt = 1; + static int port; + static Player[] players; + static ClientHandler[] handlers = new ClientHandler[GameController.MAX_PLAYER_COUNT]; + static private GameController gameController; + + + public static GameController getGameController() { + return gameController; + } + + public Server(int port, GameController gameController) { + this.port = port; + this.gameController = gameController; + players = gameController.getPlayers(); + openServer(); + } + + public void notifiObservers(SerializeObject object, int eIndex) { + System.out.println("notify => " + object.getEventObject()); + for (int i = 1; i < GameController.MAX_PLAYER_COUNT; i++) { + if (players[i] == null || i == eIndex) continue; + handlers[i].sendObject(object); + } + } + + public void excute(SerializeObject object){ + gameController.excuteQuery(object); + } + + private void addPlayer(Socket clientSocket) throws SocketException { + clientCnt++; + int idx = clientCnt - 1; + ClientHandler curHandler = new ClientHandler(clientSocket, this, idx); + handlers[idx] = curHandler; + players[idx] = new Player(""); + curHandler.sendObject(new SerializeObject(idx, "Index", gameController.getIndex())); + curHandler.startThread(); + System.out.println("플레이어 추가됨"); + } + + private void openServer() { + + Thread serverWaitThread = new Thread(new Runnable() { + @Override + public void run() { + ServerSocket serverSocket; + try { + serverSocket = new ServerSocket(port); + System.out.println("server 소켓 생성, IP : " + serverSocket.getLocalSocketAddress()); + System.out.println(InetAddress.getLocalHost().getHostAddress()); + + InetAddress serverLocalIpAddress = serverSocket.getInetAddress(); + System.out.println("Serversocket Local IP Address : " + serverLocalIpAddress.getHostAddress()); + while (true) { + Socket clientSocket = serverSocket.accept(); + System.out.println("클라이언트 연결됨: " + clientSocket.getInetAddress().getHostAddress()); + + if (clientCnt < 4 && GameController.gameState == GameController.GameState.FINISHED) { + // 클라이언트와 통신하는 스레드 생성 + addPlayer(clientSocket); + } else { + ObjectOutputStream out = new ObjectOutputStream(clientSocket.getOutputStream()); + if (clientCnt >= 4) { + out.writeObject(new SerializeObject("방이 가득찼습니다.", "String", gameController.getIndex())); + } else { + out.writeObject(new SerializeObject("현재 게임이 진행중입니다.", "String", gameController.getIndex())); + } + clientSocket.close(); + out.close(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + serverWaitThread.start(); + } + + +} diff --git a/src/Exceptions/NotEmptySpaceException.java b/src/Exceptions/NotEmptySpaceException.java new file mode 100644 index 0000000..a091ae6 --- /dev/null +++ b/src/Exceptions/NotEmptySpaceException.java @@ -0,0 +1,7 @@ +package Exceptions; + +public class NotEmptySpaceException extends Exception{ + public NotEmptySpaceException(){ + super("현재 방이 가득찬 상태입니다."); + } +} diff --git a/src/Exceptions/OnProgressException.java b/src/Exceptions/OnProgressException.java new file mode 100644 index 0000000..3a691df --- /dev/null +++ b/src/Exceptions/OnProgressException.java @@ -0,0 +1,7 @@ +package Exceptions; + +public class OnProgressException extends Exception{ + public OnProgressException() { + super("현재 게임이 진행중인 방입니다."); + } +} diff --git a/src/Model/Board.java b/src/Model/Board.java index 28e5be6..f8b172f 100644 --- a/src/Model/Board.java +++ b/src/Model/Board.java @@ -2,10 +2,11 @@ import Controller.GameController; +import java.io.Serializable; import java.util.HashSet; import java.util.Set; -public class Board { +public class Board implements Serializable { final int BOARD_WIDTH = GameController.BOARD_WIDTH; // 보드판 가로 길이 final int BOARD_HEIGHT = GameController.BOARD_HEIGHT; // 보드판 세로 길이 @@ -15,9 +16,24 @@ public Board(){ tiles = new Tile[BOARD_HEIGHT][BOARD_WIDTH]; } + public Tile[][] getTiles() { + return tiles; + } + + public void setTiles(Tile[][] tiles) { + this.tiles = tiles; + } + + public Tile getTile(int row, int col){ + return tiles[row][col]; + } + + public void setTile(int row, int col, Tile tile){ + tiles[row][col] = tile; + } // 변경이전의 보드 상태를 반환하는 함수 - private Tile[][] getLastBoardState(){ + public Tile[][] getLastBoardState(){ Tile[][] newTiles = new Tile[BOARD_HEIGHT][BOARD_WIDTH]; for(int i = 0 ; i < BOARD_HEIGHT ; i ++){ for(int j = 0 ; j < BOARD_WIDTH ; j ++){ @@ -29,9 +45,8 @@ private Tile[][] getLastBoardState(){ // 타일을 보드판에 추가하는 메서드 => 보드판에 추가 가능하면 true, 불가능하면 false 반환 - public boolean canAddTile(Tile tile, int tileRow, int tileCol) { + public boolean canAddTile(int tileRow, int tileCol) { if(tiles[tileRow][tileCol] == null){ - tiles[tileRow][tileCol] = tile; return true; } else return false; @@ -66,11 +81,6 @@ else if(start != -1 && tiles[i][j] == null){ // 타일의 끝 부분 return true; // 반환값 } - // 보드판 상태를 출력하는 메서드 - public void displayBoard() { - // 보드판 상태 출력 로직 - // TODO - } // 타일 세트가 Run 상태인지 private boolean isRun(int start, int end, int row){ @@ -84,7 +94,7 @@ private boolean isRun(int start, int end, int row){ num = cur.getNumber(); } else{ - if(!color.equals(cur.getColor()) || num + 1 != cur.getNumber()){ // 색이 다르거나 번호가 Run이 아닌 경우 + if(!color.equals(cur.getColor ()) || num + 1 != cur.getNumber()){ // 색이 다르거나 번호가 Run이 아닌 경우 return false; } } diff --git a/src/Model/Client.java b/src/Model/Client.java deleted file mode 100644 index 9202493..0000000 --- a/src/Model/Client.java +++ /dev/null @@ -1,30 +0,0 @@ -package Model; - -import Controller.GameController; - -import java.io.*; -import java.net.*; - -public class Client { - public void connect(String address, int port) throws UnknownHostException{ - try (Socket socket = new Socket(address, port); - PrintWriter out = new PrintWriter(socket.getOutputStream(), true); - BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); - BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) { - - System.out.println("서버에 연결되었습니다."); - - String userInput; - - while ((userInput = stdIn.readLine()) != null) { - out.println(userInput); - System.out.println("서버로 전송한 메시지: " + userInput); - - String response = in.readLine(); - System.out.println("서버로부터 받은 응답: " + response); - } - } catch (IOException e) { - e.printStackTrace(); - } - } -} \ No newline at end of file diff --git a/src/Model/Game.java b/src/Model/Game.java index 42f797c..c9c327f 100644 --- a/src/Model/Game.java +++ b/src/Model/Game.java @@ -7,37 +7,49 @@ import java.util.Random; public class Game { - - private enum GameState{ - IN_PROGRESS, FINISHED - } // 게임 진행 플레이어들 - private Player[] players; // 현재 보드판 private Board board; // 현재 턴인 플레이어의 인덱스 번호 private int currentPlayerIndex; - private GameState gameState; private int playerCount = 0; - public Game(){ - players = new Player[GameController.MAX_PLAYER_COUNT]; + private TileDeck tileDeck; + + private Player[] players; + + public TileDeck getTileDeck() { + return tileDeck; + } + + public Game(Player[] players){ + this.players = players; + this.tileDeck = new TileDeck(); this.board = new Board(); this.currentPlayerIndex = 0; - gameState = GameState.IN_PROGRESS; + playerCount = getPlayerCount(); + setStartPlayerIndex(); } + public Board getBoard() { + return board; + } - // 플레이어 목록에 플레이어 추가 - public boolean addPlayer(Player player){ - for(int i = 0 ; i < GameController.MAX_PLAYER_COUNT ; i ++){ - if(players[i] == null){ - players[i] = player; - return true; - } - } - return false; + public void setBoard(Board board) { + this.board = board; + } + + public int getCurrentPlayerIndex() { + return currentPlayerIndex; + } + + public void setCurrentPlayerIndex(int currentPlayerIndex) { + this.currentPlayerIndex = currentPlayerIndex; + } + + public void setPlayerCount(int playerCount) { + this.playerCount = playerCount; } // 현재 플레이어 수 @@ -52,73 +64,63 @@ public int getPlayerCount(){ } // 처음 시작할 사람 랜덤으로 결정 - private int getStartPlayerIndex(){ + public void setStartPlayerIndex(){ int startIdx = new Random().nextInt(playerCount); for(int i = 0 ; i < GameController.MAX_PLAYER_COUNT ; i ++){ if(players[i] != null){ if(startIdx == 0){ - return i; + currentPlayerIndex = i; + return; } startIdx --; } } - return -1; } - // 게임 시작 메서드 - public void start(){ - - playerCount = getPlayerCount(); - - currentPlayerIndex = getStartPlayerIndex(); - - manageGameProgress(); - - - } - - // 게임 진행 상태를 관리하는 메서드 - public void manageGameProgress() { - while (gameState == GameState.IN_PROGRESS) { - Player currentPlayer = players[currentPlayerIndex]; - performPlayerTurn(currentPlayer); - - - // 게임이 끝난 경우 - if (checkWinCondition(currentPlayer)) { - //TODO - gameState = GameState.FINISHED; - } - - - // 다음 턴으로 변경 - int curIdx = currentPlayerIndex + 1; +// // 게임 시작 메서드 +// public void start(){ +// +// playerCount = getPlayerCount(); +// +// currentPlayerIndex = getStartPlayerIndex(); +// +// manageGameProgress(); +// +// +// } + +// // 게임 진행 상태를 관리하는 메서드 +// public void manageGameProgress() { +// while (true) { +// Player currentPlayer = players[currentPlayerIndex]; +// performPlayerTurn(currentPlayer); +// +// +// // 게임이 끝난 경우 +// if (checkWinCondition(currentPlayer)) { +// //TODO +// break; +// } +// +// +// +// +// } +// } + + public void getNextTurnPlayerIndex(){ + int curIdx = currentPlayerIndex + 1; while(true){ if(curIdx > GameController.MAX_PLAYER_COUNT) curIdx %= GameController.MAX_PLAYER_COUNT; if(players[curIdx] != null){ currentPlayerIndex = curIdx; - break; + return; } curIdx ++; } - - } - } - - // 플레이어의 턴을 진행하는 메서드 - private void performPlayerTurn(Player player) { - // 플레이어의 턴에 대한 로직 구현 - // 예: 타일 놓기, 조합 변경 등 } - // 승리 조건을 확인하는 메서드 - private boolean checkWinCondition(Player player) { - // 승리 조건 확인 로직 - // 플레이어가 모든 타일을 사용하면 우승 - if(player.getTiles().size() == 0) return true; - return false; - } } diff --git a/src/Model/Player.java b/src/Model/Player.java index a9366c7..61c1b27 100644 --- a/src/Model/Player.java +++ b/src/Model/Player.java @@ -1,17 +1,35 @@ package Model; +import Controller.ClientHandler; + +import java.io.Serializable; import java.util.ArrayList; import java.util.List; -// 루미큐브 플레이어 객체 -public class Player { +// 루미큐브 플레이어의 내용을 담근 객체 + +public class Player implements Serializable{ + + public enum ReadyState{ + READY, NOT_READY; + } private String name; // 유저의 이름 - private List tiles; // 유저가 가지고 있는 타일들 + + private ReadyState readyState = ReadyState.NOT_READY; + + private int tileCount = -1; // 유저 클래스의 생성자 public Player(String name) { this.name = name; - this.tiles = new ArrayList<>(); // 타일 리스트 초기화 + } + + public void setTileCount(int tileCount) { + this.tileCount = tileCount; + } + + public int getTileCount() { + return tileCount; } // 이름을 반환하는 메서드 @@ -19,20 +37,25 @@ public String getName() { return name; } - // 유저가 가진 타일 리스트를 반환하는 메서드 - public List getTiles() { - return tiles; + public void setName(String name){ + this.name = name; } - // 타일을 유저의 타일 리스트에 추가하는 메서드 - public void addTile(Tile tile) { - tiles.add(tile); + public void setReadyState(ReadyState changeReadyState){ + this.readyState = changeReadyState; } - // 특정 타일을 유저의 타일 리스트에서 제거하는 메서드 - public void removeTile(Tile tile) { - tiles.remove(tile); + public ReadyState getReadyState(){ + return readyState; } - // 추가 유저 행동 메서드 + + @Override + public String toString() { + return "name : " + name + " ReadyState : " + this.readyState; + } + +// public PlayerDTO toDTO(){ +// return new PlayerDTO(this.name, this.readyState); +// } } diff --git a/src/Model/Server.java b/src/Model/Server.java deleted file mode 100644 index f15cdc8..0000000 --- a/src/Model/Server.java +++ /dev/null @@ -1,73 +0,0 @@ -package Model; - -import Controller.GameController; - -import java.io.*; -import java.net.*; -public class Server { - - - static int clientCnt = 0; - static int port; - static ClientHandler[] handlers = new ClientHandler[GameController.MAX_PLAYER_COUNT]; - public Server(int port) { - this.port = port; - openServer(); - } - - static void openServer() { - - try (ServerSocket serverSocket = new ServerSocket(port)) { - System.out.println("서버가 " + port + " 포트에서 대기 중..."); - - while (clientCnt < GameController.MAX_PLAYER_COUNT) { - Socket clientSocket = serverSocket.accept(); - clientCnt ++; - System.out.println("클라이언트 연결됨: " + clientSocket.getInetAddress().getHostAddress()); - - // 클라이언트와 통신하는 스레드 생성 - ClientHandler curHandler = new ClientHandler(clientSocket); - handlers[clientCnt - 1] = curHandler; - Thread clientThread = new Thread(curHandler); - clientThread.start(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } -} - -class ClientHandler implements Runnable { - private Socket clientSocket; - private PrintWriter out; - private BufferedReader in; - - public ClientHandler(Socket socket) { - this.clientSocket = socket; - try { - out = new PrintWriter(clientSocket.getOutputStream(), true); - in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public void run() { - String message; - try { - while ((message = in.readLine()) != null) { - System.out.println("클라이언트로부터 받은 메시지: " + message); - out.println("서버에서 응답: " + message); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - clientSocket.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } -} diff --git a/src/Model/Tile.java b/src/Model/Tile.java index 4f2f18c..f73d25f 100644 --- a/src/Model/Tile.java +++ b/src/Model/Tile.java @@ -1,6 +1,8 @@ package Model; -public class Tile { +import java.io.Serializable; + +public class Tile implements Serializable { private int number; // 타일의 숫자 만약, 부기(조커)타일이라면 -1, -2 private String color; // 타일의 색상 @@ -32,14 +34,14 @@ public boolean isBugi() { } // 타일 정보를 문자열로 반환하는 메서드 - @Override - public String toString() { - if(isBugi()) return "Model.Tile{ BUGI }"; - else { - return "Model.Tile{" + - "number=" + number + - ", color='" + color + '\'' + - "}"; - } - } +// @Override +// public String toString() { +// if(isBugi()) return "Model.Tile{ BUGI }"; +// else { +// return "Model.Tile{" + +// "number=" + number + +// ", color='" + color + '\'' + +// "}"; +// } +// } } \ No newline at end of file diff --git a/src/Model/TileDeck.java b/src/Model/TileDeck.java index 51fdbcd..7ffcf25 100644 --- a/src/Model/TileDeck.java +++ b/src/Model/TileDeck.java @@ -5,16 +5,17 @@ // 타일 전체를 관리하는 클래스 public class TileDeck { private List tiles; - private static final int TILES_PER_PLAYER = 14; // 플레이어당 타일 수 - public TileDeck(List tiles) { + public static final int TILES_PER_PLAYER = 14; // 플레이어당 타일 수 + + public TileDeck() { this.tiles = new ArrayList<>(); initializeTiles(); // 모든 타일을 추가한 후, shuffleTiles(); // 타일을 섞는다 } // 풀에 남은 타일이 있는 지 확인하는 함수 - private boolean isEmpty() { + public boolean isEmpty() { if (tiles.isEmpty()) return true; else return false; } @@ -45,8 +46,8 @@ private void initializeTiles() { } // 두 개의 부기(조커) 타일 추가 - tiles.add(new Tile(-1, "Bugi")); - tiles.add(new Tile(-2, "Bugi")); + tiles.add(new Tile(14, "Bugi")); + tiles.add(new Tile(14, "Bugi")); } // 풀에 있는 타일들을 섞는 함수 @@ -55,18 +56,20 @@ public void shuffleTiles() { } // Deck에서 하나의 타일을 뽑는 함수 - private Tile popTileFromDeck(){ + public Tile draw(){ if(this.isEmpty()) return null; Tile tmp = tiles.get(0); tiles.remove(0); return tmp; } - // 플레이어에게 타일을 나누어 주는 함수 - public void distributeTilesToPlayer(Player player){ + // 플레이어의 첫 핸드 타일 + public Tile[][] getFirstHandTiles(int row, int col){ + Tile[][] curTileList = new Tile[row][col]; for(int i = 0 ; i < TILES_PER_PLAYER ; i ++){ - if(!this.isEmpty()) player.addTile(this.popTileFromDeck()); + curTileList[i / col][i % col] = draw(); } + return curTileList; } } diff --git a/src/RummikubMainFrame.java b/src/RummikubMainFrame.java deleted file mode 100644 index 052068b..0000000 --- a/src/RummikubMainFrame.java +++ /dev/null @@ -1,2 +0,0 @@ -public class RummikubMainFrame { -} diff --git a/src/View/GameView.java b/src/View/GameView.java index 82f9253..8821023 100644 --- a/src/View/GameView.java +++ b/src/View/GameView.java @@ -1,21 +1,14 @@ package View; import Controller.GameController; +import Model.Player; -import java.awt.EventQueue; -import java.awt.FlowLayout; - +import java.awt.*; +import java.util.List; import javax.swing.*; -import java.awt.BorderLayout; -import java.awt.CardLayout; -import java.awt.Color; - -import java.awt.GridLayout; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.net.InetAddress; -import java.net.UnknownHostException; +import javax.swing.border.EmptyBorder; + +import java.awt.event.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -25,19 +18,388 @@ import static Controller.GameController.HAND_HEIGHT; import static Controller.GameController.HAND_WIDTH; -public class GameView { +class TileComponent extends JLabel{ + private int row, col; + private boolean inBoard; + public TileComponent(int row, int col, boolean inBoard) { + this.row = row; + this.col = col; + this.inBoard = inBoard; + } + public boolean isInBoard() { + return inBoard; + } + + public int getRow() { + return row; + } + + public int getCol() { + return col; + } + + public void setRow(int row) { + this.row = row; + } + + public void setCol(int col) { + this.col = col; + } + + public void setInBoard(boolean inBoard) { + this.inBoard = inBoard; + } + + @Override + public String toString() { + return "TileComponent{" + + "row=" + row + + ", col=" + col + + ", inBoard=" + inBoard + + ", Bound=" + getBounds() + + '}'; + } + +} + + + + +public class GameView { private JFrame frame; private JTextField nameTF, addressTF; - private JButton makeRoomButton, connectButton, QuitButton, RunSortButton, GroupSortButton, DrawTileButton; - private JLabel errorLabel; - private JPanel[][] board = new JPanel[BOARD_HEIGHT][BOARD_WIDTH]; // 보드의 타일들 + private JButton makeRoomButton, connectButton, QuitButton, RunSortButton, GroupSortButton, DrawTileButton, readyButton, startButton; + private JLabel loginErrorLabel, roomNoticePanel; + + static ImageIcon handTileIcon = new ImageIcon(new ImageIcon("asset/images/tile.png").getImage()); + static ImageIcon boardTileIcon = new ImageIcon(new ImageIcon("asset/images/minitile.png").getImage()); + private TileComponent curClickedPanel; + private boolean isDragging = false; + private Point originalPoint; + + int offsetX = 0; + int offsetY = 0; - private JPanel[][] hand = new JPanel[HAND_HEIGHT][HAND_WIDTH]; - private JPanel[] playerIcon = new JPanel[MAX_PLAYER_COUNT]; + private Font boardNumFont = new Font("Arial", Font.BOLD, 26); + private Font handNumFont = new Font("Arial", Font.BOLD, 40); + + private TileComponent[][] board = new TileComponent[BOARD_HEIGHT][BOARD_WIDTH]; // 보드의 타일들 + + private TileComponent[][] hand = new TileComponent[HAND_HEIGHT][HAND_WIDTH]; + private JPanel[] gamePlayerIcon = new JPanel[MAX_PLAYER_COUNT]; + private JLabel[] gamePlayerName = new JLabel[MAX_PLAYER_COUNT]; + private JPanel[] roomReadyPanel = new JPanel[MAX_PLAYER_COUNT]; + private JLabel[] roomNameLabel = new JLabel[MAX_PLAYER_COUNT]; + + private JLabel[][] handNumberLabel = new JLabel[HAND_HEIGHT][HAND_WIDTH]; + + private JLabel[][] boardNumberLabel = new JLabel[BOARD_HEIGHT][BOARD_WIDTH]; + private JPanel[] roomPlayerPanel = new JPanel[MAX_PLAYER_COUNT]; + + + private Rectangle[][] handPoints = new Rectangle[HAND_HEIGHT][HAND_WIDTH]; + private Rectangle[][] boardPoints = new Rectangle[BOARD_HEIGHT][BOARD_WIDTH]; private GameController gameController; + private JLayeredPane BoardPanel; + + private Player [] players; + + public void initBoard(){ + int boardY = 20; + + // board 배열에 패널 추가 + for (int i = 0; i < BOARD_HEIGHT; i++) { + int boardX = 45; + for (int j = 0; j < BOARD_WIDTH; j++) { + TileComponent tmp = new TileComponent(i, j, true); + board[i][j] = tmp; + BoardPanel.add(tmp); + tmp.setIcon(handTileIcon); + Rectangle tPoint = new Rectangle(boardX, boardY, 50, 75); + board[i][j].setBounds(tPoint); + + + JLabel tmpLabel=new JLabel(""); + boardNumberLabel[i][j] = tmpLabel; + tmpLabel.setForeground(Color.cyan); + tmpLabel.setFont(boardNumFont); + tmpLabel.setHorizontalAlignment(SwingConstants.CENTER); + tmpLabel.setBounds(6, 7, 40, 40); + tmp.add(tmpLabel); + + boardPoints[i][j] = tPoint; + board[i][j].setBackground(Color.black); + boardX += 55; + + tmp.addMouseListener(new MouseAdapter() { + + @Override + public void mousePressed(MouseEvent e) { + curClickedPanel = tmp; + originalPoint = tmp.getLocation(); + offsetX = e.getX(); + offsetY = e.getY(); + isDragging = true; + BoardPanel.setLayer(tmp, JLayeredPane.DRAG_LAYER); + } + + @Override + public void mouseReleased(MouseEvent e) { + if(isDragging) { + List foundComponents = LayeredPaneUtils.getAllComponentsAt(BoardPanel, SwingUtilities.convertPoint(tmp, e.getPoint(), BoardPanel)); + boolean flag = false; + System.out.println(foundComponents.size()); + + for (Component comp : foundComponents) { + System.out.println(comp); + if (comp != tmp && comp instanceof TileComponent) { + System.out.println(comp); + TileComponent tcomp = (TileComponent) comp; + if (moveTileUI(tmp, tcomp)) { + flag = true; + } else { + curClickedPanel.setLocation(originalPoint); + } + break; + } + } + if (!flag) curClickedPanel.setLocation(originalPoint); + + curClickedPanel = null; + originalPoint = null; + isDragging = false; + BoardPanel.setLayer(tmp, JLayeredPane.DEFAULT_LAYER); + } + } + }); + tmp.addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseDragged(MouseEvent e) { + if(isDragging){ + int newX = curClickedPanel.getX() + e.getX() - offsetX; + int newY = curClickedPanel.getY() + e.getY() - offsetY; + curClickedPanel.setLocation(newX, newY); + } + } + }); + } + boardY += 80; + } + } + + public void initHandPanel(){ + int handY = 600; + + // hand 배열에 패널 추가 + for (int i = 0; i < HAND_HEIGHT; i++) { + int handX = 170; + for (int j = 0; j < HAND_WIDTH; j++) { + TileComponent tmp = new TileComponent(i, j, false); + hand[i][j] = tmp; + BoardPanel.add(tmp); + hand[i][j].setBackground(Color.yellow); + hand[i][j].setLayout(null); + Rectangle tPoint = new Rectangle(handX, handY, 80, 120); + hand[i][j].setBounds(tPoint); + handPoints[i][j] = tPoint; + + tmp.setIcon(handTileIcon); + JLabel tmpLabel=new JLabel(""); + handNumberLabel[i][j] = tmpLabel; + tmpLabel.setForeground(Color.cyan); + tmpLabel.setFont(handNumFont); + tmpLabel.setHorizontalAlignment(SwingConstants.CENTER); + tmpLabel.setBounds(10, 13, 60, 60); + tmpLabel.setOpaque(false); + hand[i][j].add(tmpLabel); + handX += 85; + + tmp.addMouseListener(new MouseAdapter() { + + @Override + public void mousePressed(MouseEvent e) { + curClickedPanel = tmp; + originalPoint = tmp.getLocation(); + offsetX = e.getX(); + offsetY = e.getY(); + isDragging = true; + BoardPanel.setLayer(tmp, JLayeredPane.DRAG_LAYER); + } + + @Override + public void mouseReleased(MouseEvent e) { + if(isDragging) { + List foundComponents = LayeredPaneUtils.getAllComponentsAt(BoardPanel, SwingUtilities.convertPoint(tmp, e.getPoint(), BoardPanel)); + boolean flag = false; + System.out.println(foundComponents.size()); + + for (Component comp : foundComponents) { + System.out.println(comp); + if (comp != tmp && comp instanceof TileComponent) { + System.out.println(comp); + TileComponent tcomp = (TileComponent) comp; + if (moveTileUI(tmp, tcomp)) { + flag = true; + } else { + curClickedPanel.setLocation(originalPoint); + } + break; + } + } + if (!flag) curClickedPanel.setLocation(originalPoint); + + curClickedPanel = null; + originalPoint = null; + isDragging = false; + BoardPanel.setLayer(tmp, JLayeredPane.DEFAULT_LAYER); + } + } + }); + tmp.addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseDragged(MouseEvent e) { + if(isDragging){ + int newX = curClickedPanel.getX() + e.getX() - offsetX; + int newY = curClickedPanel.getY() + e.getY() - offsetY; + curClickedPanel.setLocation(newX, newY); + } + } + }); + } + handY += 125; + } + } + + + public void updateRoomReadyPanel(Player.ReadyState readyState, int index){ + if(readyState == Player.ReadyState.READY){ + roomReadyPanel[index].setBackground(Color.green); + } + else{ + roomReadyPanel[index].setBackground(Color.red); + } + } + + public void updateGamePlayerIcon(int index, String name, boolean isNull){ + if(isNull){ + gamePlayerIcon[index].setVisible(false); + } + else{ + gamePlayerIcon[index].setVisible(true); + gamePlayerName[index].setText(name); + } + } + + public void updateTile(String color, int num, int row, int col, boolean isInBoard){ + Color fontColor; + + JLabel curLabel; + if(isInBoard) { + board[row][col].setIcon(boardTileIcon); + curLabel = (JLabel) board[row][col].getComponent(0); + } + else { + hand[row][col].setIcon(handTileIcon); + curLabel = (JLabel) hand[row][col].getComponent(0); + } + if(color.equals("Red")){ + fontColor = Color.red; + } + else if(color.equals("Orange")){ + fontColor = Color.orange; + } + else if(color.equals("Blue")){ + fontColor = Color.blue; + } + else if(color.equals("Black")){ + fontColor = Color.BLACK; + } + else{ + //TODO 부기 이미지로 변경 + curLabel.setForeground(Color.cyan); + curLabel.setText("0"); + return; + } + curLabel.setForeground(fontColor); + curLabel.setText(String.valueOf(num)); + } + + public void setInvisibleTile(int row, int col, boolean isHand){ + if(isHand){ + hand[row][col].setVisible(false); + } + else{ + board[row][col].setVisible(false); + } + } + + public void setTransParentPanel(int row, int col, boolean isHand){ + TileComponent[][] curPanel; + if(isHand){ + curPanel = hand; + } + else{ + curPanel = board; + } + curPanel[row][col].setOpaque(false); + curPanel[row][col].setIcon(null); + JLabel label = (JLabel) curPanel[row][col].getComponent(0); + label.setText(""); + + } + + public void updateRoomNameLabel(String name, int index){ + roomNameLabel[index].setText(name); + } + + public JPanel[] getRoomReadyPanel() { + return roomReadyPanel; + } + + public void setRoomReadyPanel(JPanel[] roomReadyPanel) { + this.roomReadyPanel = roomReadyPanel; + } + + public JLabel[] getRoomNameLabel() { + return roomNameLabel; + } + + public void setRoomNameLabel(JLabel[] roomNameLabel) { + this.roomNameLabel = roomNameLabel; + } + + public JPanel[] getRoomPlayerPanel() { + return roomPlayerPanel; + } + + public void setRoomPlayerPanel(JPanel[] roomPlayerPanel) { + this.roomPlayerPanel = roomPlayerPanel; + } + + public void updateNameLabel(String name, int index){ + roomNameLabel[index].setText(name); + } + + public void updatePlayers(Player[] players){ + for(int i = 0 ; i < MAX_PLAYER_COUNT ; i ++){ + if(players[i] != null){ + if(i == 0){ + roomReadyPanel[i].setBackground(Color.cyan); + //JLabel tileCountLabel = new JLabel("Tiles: " + players[i].getTiles()); + } + else updateRoomReadyPanel(players[i].getReadyState(), i); + updateNameLabel(players[i].getName(), i); + roomPlayerPanel[i].setVisible(true); + } + else{ + roomPlayerPanel[i].setVisible(false); + } + } + + } public void setGameController(GameController gameController){ this.gameController = gameController; @@ -79,25 +441,122 @@ public JButton getDrawTileButton() { return DrawTileButton; } - public JLabel getErrorLabel() { - return errorLabel; + public JLabel getLoginErrorLabel() { + return loginErrorLabel; } /** * Launch the application. */ + + // 패널 전환 함수 LoginPanel, RoomPanel, GamePanel + public void changePanel(String panelName){ + System.out.println(panelName + "패널로 변경합니다."); + CardLayout cardLayout = (CardLayout)frame.getContentPane().getLayout(); + cardLayout.show(frame.getContentPane(), panelName); + } + + + public void changeTileComponent(TileComponent a, TileComponent b, boolean isHandToBoard){ + int sr = a.getRow(); + int sc = a.getCol(); + int er = b.getRow(); + int ec = b.getCol(); + b.setCol(sc); + b.setRow(sr); + + + a.setCol(ec); + a.setRow(er); + + if(isHandToBoard){ + a.setInBoard(true); + b.setInBoard(false); + } + + } + + + private void updateIcon(TileComponent tile){ + if(tile.isInBoard()){ + JLabel label = (JLabel) tile.getComponent(0); + label.setFont(boardNumFont); + label.setBounds(6, 7, 40, 40); + if(!label.getText().isEmpty()) { + tile.setIcon(boardTileIcon); + } + else{ + tile.setIcon(null); + } + } + else if(!tile.isInBoard()){ + JLabel label = (JLabel) tile.getComponent(0); + label.setFont(handNumFont); + label.setBounds(10, 13, 60, 60); + if(!label.getText().isEmpty()) tile.setIcon(handTileIcon); + else tile.setIcon(null); + } + } + // 타일 패널 이동 함수 - public void moveTileUI(boolean startHand, boolean toHand, int startRow, int startCol, int endRow, int endCol) { + public boolean moveTileUI(TileComponent start, TileComponent end) { // 손패에 있는 타일일 경우 - JPanel movePanel = startHand ? hand[startRow][startCol] : board[startRow][startCol]; - JPanel desPanel = toHand ? hand[endRow][endCol] : board[endRow][endCol]; - - if (startHand) hand[startRow][startCol] = desPanel; - else board[startRow][startCol] = desPanel; + TileComponent startPanel = start.isInBoard() ? board[start.getRow()][start.getCol()] : hand[start.getRow()][start.getCol()]; + TileComponent endPanel = end.isInBoard() ? board[end.getRow()][end.getCol()] : hand[end.getRow()][end.getCol()]; + + System.out.println(startPanel + " " + endPanel + " ############### " + gameController.isInMyTurn()); + + if (!startPanel.isInBoard()){ + // hand -> hand + if(!endPanel.isInBoard()){ + gameController.changeTiles(startPanel.isInBoard(), endPanel.isInBoard(), startPanel.getRow(), startPanel.getCol(), endPanel.getRow(), endPanel.getCol()); + hand[start.getRow()][start.getCol()] = endPanel; + endPanel.setBounds(handPoints[start.getRow()][start.getCol()]); + hand[end.getRow()][end.getCol()] = startPanel; + startPanel.setBounds(handPoints[end.getRow()][end.getCol()]); + changeTileComponent(startPanel, endPanel, false); + updateIcon(startPanel); + updateIcon(endPanel); + return true; + } + // hand -> board + else{ + if(!gameController.isInMyTurn()) return false; + if(gameController.canAdd(endPanel.getRow(), endPanel.getCol())){ + gameController.changeTiles(startPanel.isInBoard(), endPanel.isInBoard(), startPanel.getRow(), startPanel.getCol(), endPanel.getRow(), endPanel.getCol()); + hand[start.getRow()][start.getCol()] = endPanel; + endPanel.setBounds(handPoints[start.getRow()][start.getCol()]); + board[end.getRow()][end.getCol()] = startPanel; + startPanel.setBounds(boardPoints[end.getRow()][end.getCol()]); + changeTileComponent(startPanel, endPanel, true); + updateIcon(startPanel); + updateIcon(endPanel); + + return true; + } + else{ + return false; + } + } + } - if (toHand) hand[endRow][endCol] = movePanel; - else board[endRow][endCol] = movePanel; + else{ + if(!gameController.isInMyTurn()) return false; + // board -> board + if(endPanel.isInBoard()){ + gameController.changeTiles(startPanel.isInBoard(), endPanel.isInBoard(), startPanel.getRow(), startPanel.getCol(), endPanel.getRow(), endPanel.getCol()); + board[start.getRow()][start.getCol()] = endPanel; + endPanel.setBounds(boardPoints[start.getRow()][start.getCol()]); + board[end.getRow()][end.getCol()] = startPanel; + startPanel.setBounds(boardPoints[end.getRow()][end.getCol()]); + changeTileComponent(startPanel, endPanel, false); + updateIcon(startPanel); + updateIcon(endPanel); + return true; + } + else return false; + } } public void startUI() { @@ -123,13 +582,24 @@ private void initialize() { frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().setLayout(new CardLayout(0, 0)); + // 로그인 패널 구현 부분 JPanel LoginPanel = new JPanel(); - frame.getContentPane().add(LoginPanel, "name_1157230094774500"); + frame.getContentPane().add(LoginPanel, "LoginPanel"); LoginPanel.setLayout(null); + // ADD BUGIKUB LOGO + ImageIcon bugi=new ImageIcon(new ImageIcon("asset/images/Bugikub.png").getImage()); + JLabel bugiLogo=new JLabel(); + bugiLogo.setIcon(bugi); + + JPanel panel = new JPanel(); panel.setBounds(0, 0, 1584, 861); + + //BackGroundColor + panel.setBackground(new Color(223, 241, 239)); + LoginPanel.add(panel); SpringLayout sl_panel = new SpringLayout(); panel.setLayout(sl_panel); @@ -177,8 +647,8 @@ private void initialize() { @Override public void actionPerformed(ActionEvent e) { // valid test - if(nameTF.getText() == ""){ - errorLabel.setText("이름을 입력해주세요."); + if(nameTF.getText().isEmpty() || nameTF.getText().isBlank()){ + loginErrorLabel.setText("이름을 입력해주세요."); return; } gameController.makeRoom(); @@ -187,7 +657,9 @@ public void actionPerformed(ActionEvent e) { panel.add(makeRoomButton); - JPanel LoginImagePanel = new JPanel(); + JPanel LoginImagePanel = new JPanel(/*new GridLayout(1,1,5,5)*/); + LoginImagePanel.add(bugiLogo); + LoginImagePanel.setBackground(new Color(223, 241,239)); sl_panel.putConstraint(SpringLayout.NORTH, LoginImagePanel, 60, SpringLayout.NORTH, panel); sl_panel.putConstraint(SpringLayout.WEST, LoginImagePanel, 300, SpringLayout.WEST, panel); sl_panel.putConstraint(SpringLayout.SOUTH, LoginImagePanel, 320, SpringLayout.NORTH, panel); @@ -208,37 +680,32 @@ public void actionPerformed(ActionEvent e) { String name = nameTF.getText(); String address = addressTF.getText(); - System.out.println(isValidIP(address)); - if(name.isEmpty() || name.isBlank()){ - errorLabel.setText("이름을 입력해주세요."); + loginErrorLabel.setText("이름을 입력해주세요."); return; } else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ - errorLabel.setText("올바른 IP주소를 입력해주세요."); + loginErrorLabel.setText("올바른 IP주소를 입력해주세요."); return; } - System.out.println(nameTF.getText().isEmpty()); System.out.println("IP주소 : " + addressTF.getText() + "로 연결을 시도합니다."); - if(gameController.connectRoom(address)) { - errorLabel.setText("IP주소로 연결할 수 없습니다. IP주소를 확인해주세요."); - } + gameController.connectRoom(addressTF.getText()); } }); // 오류 표시 라벨 - errorLabel = new JLabel(""); - errorLabel.setHorizontalAlignment(SwingConstants.CENTER); - sl_panel.putConstraint(SpringLayout.NORTH, errorLabel, 37, SpringLayout.SOUTH, makeRoomButton); - sl_panel.putConstraint(SpringLayout.WEST, errorLabel, 300, SpringLayout.WEST, panel); - sl_panel.putConstraint(SpringLayout.SOUTH, errorLabel, -80, SpringLayout.SOUTH, panel); - sl_panel.putConstraint(SpringLayout.EAST, errorLabel, -300, SpringLayout.EAST, panel); - panel.add(errorLabel); + loginErrorLabel = new JLabel(""); + loginErrorLabel.setHorizontalAlignment(SwingConstants.CENTER); + sl_panel.putConstraint(SpringLayout.NORTH, loginErrorLabel, 37, SpringLayout.SOUTH, makeRoomButton); + sl_panel.putConstraint(SpringLayout.WEST, loginErrorLabel, 300, SpringLayout.WEST, panel); + sl_panel.putConstraint(SpringLayout.SOUTH, loginErrorLabel, -80, SpringLayout.SOUTH, panel); + sl_panel.putConstraint(SpringLayout.EAST, loginErrorLabel, -300, SpringLayout.EAST, panel); + panel.add(loginErrorLabel); - // 게 패널 레이아웃 설정 + // 게임 패널 레이아웃 설정 JPanel GamePanel = new JPanel(); - frame.getContentPane().add(GamePanel, "name_1157230101844400"); + frame.getContentPane().add(GamePanel, "GamePanel"); GamePanel.setLayout(new FlowLayout(FlowLayout.LEADING, 5, 5)); GamePanel.setLayout(new BoxLayout(GamePanel, BoxLayout.X_AXIS)); @@ -255,23 +722,45 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ playerIconBorder.setLayout(new BorderLayout(0, 0)); JPanel playerIconWest = new JPanel(); + playerIconWest.setBackground(new Color(223, 241, 239)); playerIconWest.setPreferredSize(new Dimension(50, 10)); playerIconBorder.add(playerIconWest, BorderLayout.WEST); + // "player" + (i+1) Label add JPanel playerIconSouth = new JPanel(); - playerIconSouth.setPreferredSize(new Dimension(10, 50)); + playerIconSouth.setLayout(new BorderLayout()); + JPanel centerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + centerPanel.setBackground(new Color(223, 241, 239)); + centerPanel.add(Box.createRigidArea(new Dimension(40, 0))); + JLabel playerName = new JLabel("Player " + (i + 1)); + JLabel remainTiles = new JLabel("n tiles remain"); // 남아있는 타일 개수 출력 + JPanel playerNamePanel = new JPanel(); + playerNamePanel.setBackground(new Color(223, 241, 239)); + playerNamePanel.add(playerName); +// playerNamePanel.add(remainTiles); + centerPanel.add(playerNamePanel); + playerIconSouth.add(centerPanel, BorderLayout.CENTER); playerIconBorder.add(playerIconSouth, BorderLayout.SOUTH); + JPanel playerIconNorth = new JPanel(); + playerIconNorth.setBackground(new Color(223, 241, 239)); playerIconNorth.setPreferredSize(new Dimension(10, 50)); playerIconBorder.add(playerIconNorth, BorderLayout.NORTH); JPanel playerIconPanel = new JPanel(); + playerIconPanel.setBackground(new Color(223, 241, 239)); playerIconBorder.add(playerIconPanel, BorderLayout.CENTER); - playerIcon[i] = playerIconPanel; + gamePlayerIcon[i] = playerIconPanel; + gamePlayerName[i] = playerName; - playerIcon[i].setBackground(Color.black); + ImageIcon empProfileIcon=new ImageIcon(new ImageIcon("asset/images/emptyProfile.png").getImage()); + Image scaledImage = empProfileIcon.getImage().getScaledInstance(150, 120, Image.SCALE_SMOOTH); + empProfileIcon = new ImageIcon(scaledImage); + JLabel emtPlayerIcon=new JLabel(); + emtPlayerIcon.setIcon(empProfileIcon); + gamePlayerIcon[i].add(emtPlayerIcon); } @@ -279,88 +768,18 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ panel_3.setLayout(new BorderLayout(0, 0)); GamePanel.add(panel_3); - JPanel panel_1 = new JPanel(); - panel_3.add(panel_1, BorderLayout.SOUTH); - panel_1.setLayout(new BorderLayout(0, 0)); - - JPanel westPanel = new JPanel(); - westPanel.setPreferredSize(new Dimension(150, 1)); - panel_1.add(westPanel, BorderLayout.WEST); - - JPanel eastPanel = new JPanel(); - eastPanel.setPreferredSize(new Dimension(150, 1)); - panel_1.add(eastPanel, BorderLayout.EAST); - - JPanel HandLayoutPanel = new JPanel(); - HandLayoutPanel.setPreferredSize(new Dimension(1, 250)); - panel_1.add(HandLayoutPanel, BorderLayout.CENTER); - HandLayoutPanel.setLayout(new BorderLayout(0, 0)); - - JPanel HandWestPanel = new JPanel(); - HandWestPanel.setPreferredSize(new Dimension(20, 1)); - HandLayoutPanel.add(HandWestPanel, BorderLayout.WEST); - - JPanel HandEastPanel = new JPanel(); - HandEastPanel.setPreferredSize(new Dimension(20, 1)); - HandLayoutPanel.add(HandEastPanel, BorderLayout.EAST); - - JPanel HandPanel = new JPanel(); - HandLayoutPanel.add(HandPanel, BorderLayout.CENTER); - HandPanel.setLayout(new GridLayout(2, 10, 0, 0)); - - JPanel panell = new JPanel(); - panell.setPreferredSize(new Dimension(10, 20)); - panel_1.add(panell, BorderLayout.SOUTH); - JPanel panel_5 = new JPanel(); + panel_5.setBackground(new Color(223, 241, 239)); panel_3.add(panel_5, BorderLayout.CENTER); panel_5.setLayout(new BorderLayout(0, 0)); - JPanel panel_6 = new JPanel(); - panel_6.setPreferredSize(new Dimension(1, 20)); - panel_5.add(panel_6, BorderLayout.NORTH); - - JPanel panel_7 = new JPanel(); - panel_5.add(panel_7, BorderLayout.CENTER); - panel_7.setLayout(new BorderLayout(0, 0)); - - JPanel panel_8 = new JPanel(); - panel_8.setPreferredSize(new Dimension(15, 10)); - panel_7.add(panel_8, BorderLayout.WEST); + BoardPanel = new JLayeredPane(); + panel_5.add(BoardPanel, BorderLayout.CENTER); + BoardPanel.setPreferredSize(new Dimension(1150, 10)); + BoardPanel.setBackground(new Color(223, 241, 239)); - JPanel panel_9 = new JPanel(); - panel_9.setPreferredSize(new Dimension(15, 10)); - panel_7.add(panel_9, BorderLayout.EAST); - - JPanel BoardPanel = new JPanel(); - panel_7.add(BoardPanel, BorderLayout.CENTER); - BoardPanel.setLayout(new GridLayout(BOARD_HEIGHT, BOARD_WIDTH, 0, 5)); - - // board 배열에 패널 추가 - for (int i = 0; i < BOARD_HEIGHT; i++) { - JPanel curRowPanel = new JPanel(); - BoardPanel.add(curRowPanel); - for (int j = 0; j < BOARD_WIDTH; j++) { - JPanel tmp = new JPanel(); - board[i][j] = tmp; - curRowPanel.add(tmp); - board[i][j].setPreferredSize(new Dimension(50, 75)); - board[i][j].setBackground(Color.black); - } - } - - // hand 배열에 패널 추가 - for (int i = 0; i < HAND_HEIGHT; i++) { - JPanel curRowPanel = new JPanel(); - HandPanel.add(curRowPanel); - for (int j = 0; j < HAND_WIDTH; j++) { - JPanel tmp = new JPanel(); - hand[i][j] = tmp; - curRowPanel.add(tmp); - hand[i][j].setPreferredSize(new Dimension(80, 120)); - hand[i][j].setBackground(Color.black); - } - } + initBoard(); + initHandPanel(); // 오른쪽 패널 @@ -369,43 +788,314 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ MenuPanel.setLayout(new BoxLayout(MenuPanel, BoxLayout.Y_AXIS)); JPanel panel_2 = new JPanel(); + panel_2.setBackground(new Color(223, 241, 239)); panel_2.setPreferredSize(new Dimension(150, 50)); MenuPanel.add(panel_2); panel_2.setLayout(null); - // 종료 버튼 - QuitButton = new JButton("New button"); + ImageIcon quitBtnIcon = new ImageIcon(new ImageIcon("asset/images/QuitBTN.png").getImage()); + QuitButton = new JButton(); + QuitButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + gameController.clickFinishTurn(); + } + }); + QuitButton.setIcon(quitBtnIcon); + QuitButton.setBackground(new Color(223, 241, 239)); + QuitButton.setBorder(new EmptyBorder(0, 0, 0, 0)); + QuitButton.setContentAreaFilled(false); + QuitButton.setFocusPainted(false); + QuitButton.setOpaque(false); QuitButton.setBounds(25, 43, 100, 100); panel_2.add(QuitButton); + JPanel panel_4 = new JPanel(); + panel_4.setBackground(new Color(223, 241, 239)); panel_4.setPreferredSize(new Dimension(100, 200)); MenuPanel.add(panel_4); panel_4.setLayout(null); // Run 정렬 버튼 - RunSortButton = new JButton("New button"); + ImageIcon runIcon=new ImageIcon(new ImageIcon("asset/images/RunSortBTN.png").getImage()); + RunSortButton = new JButton(); + RunSortButton.setIcon(runIcon); + RunSortButton.setBackground(new Color(223, 241, 239)); + RunSortButton.setBorder(new EmptyBorder(0, 0, 0, 0)); + RunSortButton.setContentAreaFilled(false); + RunSortButton.setFocusPainted(false); + RunSortButton.setOpaque(false); RunSortButton.setBounds(12, 45, 126, 123); + RunSortButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + gameController.sortByRun(); + } + }); panel_4.add(RunSortButton); // Group 정렬 버튼 - GroupSortButton = new JButton("New button"); - GroupSortButton.setBounds(12, 178, 126, 107); + ImageIcon groupIcon=new ImageIcon(new ImageIcon("asset/images/GroupSortBTN.png").getImage()); + GroupSortButton = new JButton(); + GroupSortButton.setIcon(groupIcon); + GroupSortButton.setBackground(new Color(223, 241, 239)); + GroupSortButton.setBorder(new EmptyBorder(0, 0, 0, 0)); + GroupSortButton.setBounds(12, 178, 126, 113); + GroupSortButton.setContentAreaFilled(false); + GroupSortButton.setFocusPainted(false); + GroupSortButton.setOpaque(false); + GroupSortButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + gameController.sortByGroup(); + } + }); panel_4.add(GroupSortButton); JPanel panel_10 = new JPanel(); + panel_10.setBackground(new Color(223, 241, 239)); panel_10.setPreferredSize(new Dimension(100, 200)); MenuPanel.add(panel_10); panel_10.setLayout(null); // 타일 드로우 버튼 - DrawTileButton = new JButton("New button"); + ImageIcon drawTile=new ImageIcon(new ImageIcon("asset/images/AddTilesBTN.png").getImage()); + DrawTileButton = new JButton(); + DrawTileButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + gameController.drawTile(); + } + }); + DrawTileButton.setIcon(drawTile); + DrawTileButton.setBackground(new Color(223, 241, 239)); + DrawTileButton.setBorder(new EmptyBorder(0,0,0,0)); DrawTileButton.setBounds(12, 10, 126, 316); + DrawTileButton.setContentAreaFilled(false); + DrawTileButton.setFocusPainted(false); + DrawTileButton.setOpaque(false); panel_10.add(DrawTileButton); + // 플레이어 방 + JPanel RoomPanel = new JPanel(); + RoomPanel.setBackground(new Color(223, 241, 239)); + frame.getContentPane().add(RoomPanel, "RoomPanel"); + RoomPanel.setLayout(new BorderLayout(0, 0)); + + JPanel panel_11 = new JPanel(); + panel_11.setPreferredSize(new Dimension(10, 100)); + RoomPanel.add(panel_11, BorderLayout.NORTH); + panel_11.setLayout(new BorderLayout(0, 0)); + + JPanel panel_22 = new JPanel(); + panel_22.setBackground(new Color(223, 241, 239)); + panel_11.add(panel_22, BorderLayout.CENTER); + panel_22.setLayout(null); + + roomNoticePanel = new JLabel("New label"); + roomNoticePanel.setHorizontalAlignment(SwingConstants.CENTER); + roomNoticePanel.setBounds(160, 33, 1264, 35); + panel_22.add(roomNoticePanel); + + JPanel panel_12 = new JPanel(); + panel_12.setPreferredSize(new Dimension(300, 10)); + RoomPanel.add(panel_12, BorderLayout.EAST); + panel_12.setLayout(new BoxLayout(panel_12, BoxLayout.Y_AXIS)); + + JPanel panel_19 = new JPanel(); + panel_12.add(panel_19); + panel_19.setLayout(new BorderLayout(0, 0)); + + JPanel panel_21 = new JPanel(); + panel_21.setPreferredSize(new Dimension(10, 30)); + panel_21.setBackground(new Color(223,241,239)); + panel_19.add(panel_21, BorderLayout.NORTH); + + JPanel panel_27 = new JPanel(); + panel_27.setPreferredSize(new Dimension(30, 10)); + panel_27.setBackground(new Color(223,241,239)); + panel_19.add(panel_27, BorderLayout.WEST); + + JPanel panel_28 = new JPanel(); + panel_28.setPreferredSize(new Dimension(30, 10)); + panel_28.setBackground(new Color(223,241,239)); + panel_19.add(panel_28, BorderLayout.EAST); + + JPanel panel_31 = new JPanel(); + panel_31.setPreferredSize(new Dimension(10, 15)); + panel_31.setBackground(new Color(223,241,239)); + panel_19.add(panel_31, BorderLayout.SOUTH); + + // start button + ImageIcon start=new ImageIcon(new ImageIcon("asset/images/start.png").getImage()); + startButton = new JButton(); + startButton.setIcon(start); + startButton.setBackground(new Color(223, 241, 239)); + startButton.setBorder(new EmptyBorder(0, 0, 0, 0)); + startButton.setContentAreaFilled(false); + startButton.setFocusPainted(false); + startButton.setContentAreaFilled(false); + startButton.setOpaque(true); + + + // 시작 버튼 리스너 + startButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + if(gameController.getIndex() == 0){ + if(gameController.checkReady()){ + gameController.serverStartGame(); + } + else{ + roomNoticePanel.setText("모든 사람이 준비를 해야 시작할 수 있습니다."); + } + } + else{ + roomNoticePanel.setText("방장이 게임을 시작할 수 있습니다."); + } + } + }); + + + panel_19.add(startButton, BorderLayout.CENTER); + + JPanel panel_20 = new JPanel(); + panel_12.add(panel_20); + panel_20.setLayout(new BorderLayout(0, 0)); + + JPanel panel_24 = new JPanel(); + panel_24.setPreferredSize(new Dimension(10, 30)); + panel_24.setBackground(new Color(223,241,239)); + panel_20.add(panel_24, BorderLayout.SOUTH); + + JPanel panel_29 = new JPanel(); + panel_29.setPreferredSize(new Dimension(30, 10)); + panel_29.setBackground(new Color(223,241,239)); + panel_20.add(panel_29, BorderLayout.WEST); + + JPanel panel_30 = new JPanel(); + panel_30.setPreferredSize(new Dimension(30, 10)); + panel_30.setBackground(new Color(223,241,239)); + panel_20.add(panel_30, BorderLayout.EAST); + + JPanel panel_32 = new JPanel(); + panel_32.setPreferredSize(new Dimension(10, 15)); + panel_32.setBackground(new Color(223,241,239)); + panel_20.add(panel_32, BorderLayout.NORTH); + + //ready button + ImageIcon ready=new ImageIcon(new ImageIcon("asset/images/ready.png").getImage()); + readyButton = new JButton("New button"); + readyButton.setIcon(ready); + readyButton.setBackground(new Color(223, 241, 239)); + readyButton.setBorder(new EmptyBorder(0,0,0,0)); + readyButton.setContentAreaFilled(false); + readyButton.setFocusPainted(false); + readyButton.setContentAreaFilled(false); + readyButton.setOpaque(true); + + readyButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + if(gameController.getIndex() != 0){ + gameController.changeReadyState(); + } + } + }); + + + + panel_20.add(readyButton, BorderLayout.CENTER); + + JPanel panel_13 = new JPanel(); + RoomPanel.add(panel_13, BorderLayout.CENTER); + panel_13.setLayout(new BorderLayout(0, 0)); + + JPanel panel_14 = new JPanel(); + panel_14.setPreferredSize(new Dimension(50, 10)); + panel_14.setBackground(new Color(223,241,239)); + panel_13.add(panel_14, BorderLayout.WEST); + + JPanel panel_15 = new JPanel(); + panel_15.setPreferredSize(new Dimension(50, 10)); + panel_15.setBackground(new Color(223,241,239)); + panel_13.add(panel_15, BorderLayout.EAST); + + JPanel panel_16 = new JPanel(); + panel_16.setPreferredSize(new Dimension(10, 50)); + panel_16.setBackground(new Color(223,241,239)); + panel_13.add(panel_16, BorderLayout.NORTH); + + JPanel panel_17 = new JPanel(); + panel_17.setPreferredSize(new Dimension(10, 50)); + panel_17.setBackground(new Color(223,241,239)); + panel_13.add(panel_17, BorderLayout.SOUTH); + + JPanel panel_18 = new JPanel(); + panel_13.add(panel_18, BorderLayout.CENTER); + panel_18.setBackground(new Color(223,241,239)); + panel_18.setLayout(new GridLayout(2, 2, 50, 20)); + + + for(int i = 0 ; i < 2 ; i ++) { + JPanel roomRowPanel = new JPanel(); + FlowLayout fl_playerRoomRow1 = (FlowLayout) roomRowPanel.getLayout(); + fl_playerRoomRow1.setHgap(30); + panel_18.add(roomRowPanel); + roomRowPanel.setBackground(new Color(223, 241, 239)); + + for(int j = 0 ; j < 2 ; j ++) { + JPanel RoomPlayerPanel = new JPanel(); + roomPlayerPanel[i * 2 + j] = RoomPlayerPanel; + RoomPlayerPanel.setBackground(new Color(0, 144, 81)); +// RoomPlayerPanel.setBackground(Color.cyan); + JPanel tmpPanel = new JPanel(); + tmpPanel.setBackground(new Color(223,241,239)); + tmpPanel.setPreferredSize(new Dimension(550, 310)); + RoomPlayerPanel.setPreferredSize(new Dimension(550, 310)); + roomRowPanel.add(tmpPanel); + tmpPanel.add(RoomPlayerPanel, BorderLayout.CENTER); + RoomPlayerPanel.setLayout(new BorderLayout(0, 0)); + + JPanel readyPanel = new JPanel(); + roomReadyPanel[i * 2 + j] = readyPanel; + readyPanel.setPreferredSize(new Dimension(10, 50)); + RoomPlayerPanel.add(readyPanel, BorderLayout.SOUTH); +// readyPanel.setBackground(Color.red); + + JPanel tmp1 = new JPanel(); + RoomPlayerPanel.add(tmp1, BorderLayout.CENTER); + tmp1.setLayout(new BorderLayout(0, 0)); + tmp1.setBackground(new Color(223,241,239)); + + JPanel tmp2 = new JPanel(); + tmp2.setPreferredSize(new Dimension(110, 10)); + tmp1.add(tmp2, BorderLayout.WEST); + tmp2.setBackground(new Color(223,241,239)); + + JPanel tmp3 = new JPanel(); + tmp3.setPreferredSize(new Dimension(110, 10)); + tmp1.add(tmp3, BorderLayout.EAST); + tmp3.setBackground(new Color(223,241,239)); + + ImageIcon empProfileIcon=new ImageIcon(new ImageIcon("asset/images/emptyProfile.png").getImage()); + JLabel playerImageLabel = new JLabel(); + playerImageLabel.setIcon(empProfileIcon); + playerImageLabel.setHorizontalAlignment(SwingConstants.CENTER); + tmp1.add(playerImageLabel, BorderLayout.CENTER); + + JLabel playerNameLabel = new JLabel("player_name"); + roomNameLabel[i * 2 + j] = playerNameLabel; + playerNameLabel.setHorizontalAlignment(SwingConstants.CENTER); + playerNameLabel.setPreferredSize(new Dimension(57, 30)); + RoomPlayerPanel.add(playerNameLabel, BorderLayout.NORTH); + + } + } } } \ No newline at end of file diff --git a/src/View/LayeredPaneUtils.java b/src/View/LayeredPaneUtils.java new file mode 100644 index 0000000..4e44b6b --- /dev/null +++ b/src/View/LayeredPaneUtils.java @@ -0,0 +1,20 @@ +package View; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class LayeredPaneUtils { + public static List getAllComponentsAt(JLayeredPane layeredPane, Point p) { + List components = new ArrayList<>(); + System.out.println(p); + for (int i = 0; i < layeredPane.getComponentCount(); i++) { + Component comp = layeredPane.getComponent(i); + if (comp.getBounds().contains(p)) { + components.add(comp); + } + } + return components; + } +} \ No newline at end of file