From 7f8773837601f2ba3b4e0bffbf958dc4d7cce847 Mon Sep 17 00:00:00 2001 From: junhaa Date: Tue, 19 Dec 2023 19:21:59 +0900 Subject: [PATCH 1/6] =?UTF-8?q?:recycle:=20REFACTOR.=20=EC=86=8C=EC=BC=93?= =?UTF-8?q?=20=ED=86=B5=EC=8B=A0=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=9E=98?= =?UTF-8?q?=ED=94=BD=ED=86=A0=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit socket in, out 클래스 스레드 변경 및 작업 queue 추가 related to : #3 --- src/Controller/Client.java | 138 ++++++++++++++++++++-------- src/Controller/ClientHandler.java | 120 +++++++++++++++++------- src/Controller/GameController.java | 60 +++++++++--- src/Controller/SerializeObject.java | 7 +- src/Controller/Server.java | 31 ++++--- src/View/GameView.java | 30 ++++++ 6 files changed, 290 insertions(+), 96 deletions(-) diff --git a/src/Controller/Client.java b/src/Controller/Client.java index 60ff7b1..09957a2 100644 --- a/src/Controller/Client.java +++ b/src/Controller/Client.java @@ -1,23 +1,25 @@ 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 implements Runnable{ +public class Client{ private Socket curSocket; - private ObjectOutputStream objectOutputStream; - private ObjectInputStream objectInputStream; - private SerializeObject obj = null; + private ClientOutput output; + private ClientInput input; - private Object input = null; private GameController gameController; - public void setObject(SerializeObject object){ - obj = object; + + public void sendObject(SerializeObject object){ + output.addObject(object); } public Client(GameController gameController, String address, int port, String name) throws UnknownHostException, NotEmptySpaceException, OnProgressException{ @@ -25,11 +27,20 @@ public Client(GameController gameController, String address, int port, String na try { curSocket = new Socket(address, port); - this.objectOutputStream = new ObjectOutputStream(curSocket.getOutputStream()); - this.objectInputStream = new ObjectInputStream(curSocket.getInputStream()); + output = new ClientOutput(curSocket); + input = new ClientInput(curSocket); + + SerializeObject answer = null; - SerializeObject answer = (SerializeObject) objectInputStream.readObject(); - System.out.println("받은 객체 : " + answer + " " + answer.getObjectType()); + while (answer == null) { + try { + answer = (SerializeObject) input.getObjectInputStream().readObject(); + } catch (IOException e) { + // IOException 처리 + e.printStackTrace(); + } + } + System.out.println("받은 객체 : " + answer.getEventObject()); String answerStr = (String)answer.getEventObject(); if(answerStr.equals("방이 가득찼습니다.")) { throw new NotEmptySpaceException(); @@ -37,43 +48,98 @@ public Client(GameController gameController, String address, int port, String na else if(answerStr.equals("현재 게임이 진행중입니다.")){ throw new OnProgressException(); } - setObject(new SerializeObject("received", "String")); - Thread clientThread = new Thread(this); - clientThread.start(); + sendObject(new SerializeObject("received", "String", gameController.getIndex())); + Thread outputThread = new Thread(output); + Thread inputThread = new Thread(input); + + outputThread.start(); + inputThread.start(); + System.out.println("서버에 연결되었습니다."); - setObject(new SerializeObject(name, "Name")); + sendObject(new SerializeObject(name, "Name", gameController.getIndex())); - }catch (IOException e){ - e.printStackTrace(); } catch (ClassNotFoundException e) { System.out.println("클래스가 맞지 않습니다."); + } catch (IOException e) { + e.printStackTrace(); } } - @Override - public void run() { - try { - System.out.println("클라이언트 소켓 통신 중..."); - while (true) { - if(obj != null || (input = objectInputStream.readObject()) != null) { - // 입력 - if (obj != null) { - objectOutputStream.writeObject(obj); - System.out.println(obj.getObjectType() + " " + obj.getEventObject() + " 전달"); - obj = null; - } else { - gameController.excuteQuery((SerializeObject) input, -1); + 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); + System.out.println(object.getEventObject() + " 큐에 추가됨"); + System.out.println(outputQueue.toString()); + } + + + @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 | ClassNotFoundException e) { - e.printStackTrace(); - } finally { - try { - curSocket.close(); - } catch (IOException e) { + 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 index 72d15f5..009b236 100644 --- a/src/Controller/ClientHandler.java +++ b/src/Controller/ClientHandler.java @@ -2,66 +2,122 @@ import java.io.*; import java.net.Socket; +import java.util.LinkedList; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; -public class ClientHandler implements Runnable { + +public class ClientHandler{ private Socket clientSocket; - private ObjectOutputStream objectOutputStream; - private ObjectInputStream objectInputStream; private Object input = null; + private ServerOutput out; + private ServerInput in; private Server server; private int index; - private SerializeObject obj = null; // 클라이언트에 객체 전달 - public void setObject(SerializeObject obj){ - this.obj = obj; + public void sendObject(SerializeObject obj){ + out.addObject(obj); } - public void update(SerializeObject object){ - // 현재 오브젝트 파싱 및 처리 - server.excute(object, index); - } + 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 { - objectOutputStream = new ObjectOutputStream(clientSocket.getOutputStream()); - objectInputStream = new ObjectInputStream(clientSocket.getInputStream()); + out = new ServerOutput(clientSocket); + in = new ServerInput(clientSocket); } catch (IOException e) { e.printStackTrace(); } } - @Override - public void run() { - try { - while (true) { - if(obj != null || (input = objectInputStream.readObject()) != null) { - // 입력 - if (obj != null) { - System.out.println("출력 추가됨 " + obj.getEventObject() + " "); - objectOutputStream.writeObject(obj); - obj = null; - } else { - SerializeObject sinput = (SerializeObject) input; - System.out.println("입력 추가됨 " + sinput.getEventObject()); - update((SerializeObject) input); + 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); + System.out.println(object.getEventObject() + " 큐에 추가됨"); + System.out.println(outputQueue.toString()); + } + + + @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.getEventObject() + " index : " + index); } } } - } catch (IOException | ClassNotFoundException e) { - e.printStackTrace(); - } finally { - try { - clientSocket.close(); - } catch (IOException e) { + 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 c2150b4..72511f6 100644 --- a/src/Controller/GameController.java +++ b/src/Controller/GameController.java @@ -16,6 +16,8 @@ public enum GameState{ private GameView view; + private int index = -1; + public static final int PORT = 12345; // 포트 번호 private boolean isServer = false; // 현재 서버로 운영되는 사용자인지 @@ -64,6 +66,10 @@ public Player getCurPlayer() { } + public int getIndex(){ + return index; + } + public static GameState getGameState() { return gameState; } @@ -76,14 +82,11 @@ protected Player[] getPlayers() { return players; } - protected void setPlayers(Player[] players) { - this.players = players; - } - // 방 만드는 함수 - 서버 public void makeRoom() { 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; @@ -98,19 +101,20 @@ public void connectRoom(String address) { String name = view.getNameTF().getText(); try { client = new Client(this, address, PORT, name); + view.changePanel("RoomPanel"); } catch (UnknownHostException e) { view.getLoginErrorLabel().setText("IP주소로 접속할 수 없습니다. IP주소를 다시 확인해주세요."); } catch (NotEmptySpaceException e){ - view.getLoginErrorLabel().setText("현재 방이 가득 차 참가할 수 없습니다."); + view.getLoginErrorLabel().setText("현재 방 인원이 가득 차 참가할 수 없습니다."); } catch (OnProgressException e){ view.getLoginErrorLabel().setText("현재 게임이 진행 중인 방입니다."); } - view.changePanel("RoomPanel"); + } // 플레이어 ready 상태 변경 함수 - public void changeReadyState(int index, Player.ReadyState readyState){ + 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); @@ -122,6 +126,24 @@ else if(readyState == Player.ReadyState.NOT_READY && players[index].getReadyStat 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 changeGamePanel(){ + // TODO 데이터 전송 및 UI 연동 + view.changePanel("GamePanel"); + } + // 서버로 플레이어 추가시 서버 뷰 추가 public void updatePlayers(){ view.updatePlayers(players); @@ -136,9 +158,19 @@ public void changePlayers(Player[] getPlayers){ 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 excuteQuery(SerializeObject object, int index){ + public void excuteQuery(SerializeObject object){ System.out.println("받은 객체 : " + object.getEventObject()); switch (object.getObjectType()){ case "String" : @@ -158,17 +190,19 @@ public void excuteQuery(SerializeObject object, int index){ players[index].setName(name); view.updateNameLabel(name, index); System.out.println(playersStr()); - server.notifiObservers(new SerializeObject(players, "Player[]")); + server.notifiObservers(new SerializeObject(players, "Player[]", object.getIndex()), -1); } break; + case "Index" : + this.index = (int) object.getEventObject(); + break; + case "ReadyState" : - if(isServer) { Player.ReadyState readyState = (Player.ReadyState) object.getEventObject(); - changeReadyState(index, readyState); - server.notifiObservers(new SerializeObject(players, "Player[]")); + updateReadyState(object.getIndex(), readyState); + if(isServer) server.notifiObservers(new SerializeObject(readyState, "ReadyState", object.getIndex()), index); break; - } default: break; } diff --git a/src/Controller/SerializeObject.java b/src/Controller/SerializeObject.java index 0846e57..7561087 100644 --- a/src/Controller/SerializeObject.java +++ b/src/Controller/SerializeObject.java @@ -7,9 +7,12 @@ class SerializeObject implements Serializable { private Object eventObject; // 실제 객체를 포장하는 필드 private String objectType; // 객체의 유형을 나타내는 필드 - public SerializeObject(Object eventObject, 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() { @@ -18,4 +21,6 @@ public Object getEventObject() { 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 index b186e58..7f99094 100644 --- a/src/Controller/Server.java +++ b/src/Controller/Server.java @@ -15,6 +15,10 @@ public class Server { static private GameController gameController; + public static GameController getGameController() { + return gameController; + } + public Server(int port, GameController gameController) { this.port = port; this.gameController = gameController; @@ -22,27 +26,27 @@ public Server(int port, GameController gameController) { openServer(); } - public void notifiObservers(SerializeObject object) { + 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) continue; - System.out.println("notify => " + object.getEventObject()); - handlers[i].setObject(object); + if (players[i] == null || i == eIndex) continue; + handlers[i].sendObject(object); } } - public void excute(SerializeObject object, int index){ - gameController.excuteQuery(object, index); + 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); - Thread clientThread = new Thread(curHandler); - curHandler.setObject(new SerializeObject("connected", "String")); - clientThread.start(); handlers[idx] = curHandler; players[idx] = new Player(""); + curHandler.sendObject(new SerializeObject("connected", "String", gameController.getIndex())); + curHandler.sendObject(new SerializeObject(idx, "Index", gameController.getIndex())); + curHandler.startThread(); System.out.println("플레이어 추가됨"); gameController.updatePlayers(); } @@ -61,19 +65,18 @@ public void run() { InetAddress serverLocalIpAddress = serverSocket.getInetAddress(); System.out.println("Serversocket Local IP Address : " + serverLocalIpAddress.getHostAddress()); while (true) { - System.out.println("기다리는 중"); Socket clientSocket = serverSocket.accept(); System.out.println("클라이언트 연결됨: " + clientSocket.getInetAddress().getHostAddress()); - if (clientCnt < 4 || GameController.gameState == GameController.GameState.FINISHED) { + if (clientCnt < 4 && GameController.gameState == GameController.GameState.FINISHED) { // 클라이언트와 통신하는 스레드 생성 addPlayer(clientSocket); } else { - PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); + ObjectOutputStream out = new ObjectOutputStream(clientSocket.getOutputStream()); if (clientCnt >= 4) { - out.println("방이 가득찼습니다."); + out.writeObject(new SerializeObject("방이 가득찼습니다.", "String", gameController.getIndex())); } else { - out.println("현재 게임이 진행중입니다."); + out.writeObject(new SerializeObject("현재 게임이 진행중입니다.", "String", gameController.getIndex())); } clientSocket.close(); out.close(); diff --git a/src/View/GameView.java b/src/View/GameView.java index 5286c14..5294a7b 100644 --- a/src/View/GameView.java +++ b/src/View/GameView.java @@ -542,6 +542,24 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ startButton.setContentAreaFilled(false); startButton.setOpaque(true); + startButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + if(gameController.getIndex() == 0){ + if(gameController.checkReady()){ + gameController.changeGamePanel(); + } + else{ + roomNoticePanel.setText("모든 사람이 준비를 해야 시작할 수 있습니다."); + } + } + else{ + roomNoticePanel.setText("방장이 게임을 시작할 수 있습니다."); + } + } + }); + + panel_19.add(startButton, BorderLayout.CENTER); JPanel panel_20 = new JPanel(); @@ -579,6 +597,17 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ 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(); @@ -624,6 +653,7 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ 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); From 5af7ab1e2fd22a6e3cc9a91da3c4c0335067fa0a Mon Sep 17 00:00:00 2001 From: junhaa Date: Wed, 20 Dec 2023 00:23:04 +0900 Subject: [PATCH 2/6] =?UTF-8?q?:bug:=20FIX.=20=EC=86=8C=EC=BC=93=20?= =?UTF-8?q?=ED=86=B5=EC=8B=A0=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 클라이언트 플레이어 목록 버그 수정 related to : #3 --- src/Controller/Client.java | 20 +++++++++++--------- src/Controller/ClientHandler.java | 17 ++++++++++++----- src/Controller/GameController.java | 16 +++++++++++----- src/Controller/Server.java | 2 -- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/Controller/Client.java b/src/Controller/Client.java index 09957a2..023208f 100644 --- a/src/Controller/Client.java +++ b/src/Controller/Client.java @@ -40,15 +40,19 @@ public Client(GameController gameController, String address, int port, String na e.printStackTrace(); } } - System.out.println("받은 객체 : " + answer.getEventObject()); - String answerStr = (String)answer.getEventObject(); - if(answerStr.equals("방이 가득찼습니다.")) { - throw new NotEmptySpaceException(); + 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 if(answerStr.equals("현재 게임이 진행중입니다.")){ - throw new OnProgressException(); + else{ + gameController.setIndex((int) answer.getEventObject()); } - sendObject(new SerializeObject("received", "String", gameController.getIndex())); Thread outputThread = new Thread(output); Thread inputThread = new Thread(input); @@ -83,8 +87,6 @@ public ObjectOutputStream getObjectOutputStream() { public void addObject(SerializeObject object){ this.outputQueue.offer(object); - System.out.println(object.getEventObject() + " 큐에 추가됨"); - System.out.println(outputQueue.toString()); } diff --git a/src/Controller/ClientHandler.java b/src/Controller/ClientHandler.java index 009b236..e861dc0 100644 --- a/src/Controller/ClientHandler.java +++ b/src/Controller/ClientHandler.java @@ -1,8 +1,9 @@ package Controller; +import Model.Player; + import java.io.*; import java.net.Socket; -import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; @@ -41,7 +42,7 @@ public ClientHandler(Socket socket, Server server, int index) { e.printStackTrace(); } } - +1 class ServerOutput implements Runnable{ private ObjectOutputStream objectOutputStream; private Socket serverSocket; @@ -60,8 +61,6 @@ public ObjectOutputStream getObjectOutputStream() { public void addObject(SerializeObject object){ this.outputQueue.offer(object); - System.out.println(object.getEventObject() + " 큐에 추가됨"); - System.out.println(outputQueue.toString()); } @@ -71,8 +70,16 @@ public void run() { while (true) { SerializeObject sendObj = outputQueue.poll(); if (sendObj != null) { - System.out.println(sendObj.getEventObject()); 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); } } diff --git a/src/Controller/GameController.java b/src/Controller/GameController.java index 72511f6..56b1801 100644 --- a/src/Controller/GameController.java +++ b/src/Controller/GameController.java @@ -45,7 +45,7 @@ public String playersStr() { tmp += "null\n"; } else { - tmp += players[i].toString() + "\n"; + tmp += players[i].toString() + " "; tmp += view.getRoomNameLabel()[i].getText() + "\n"; } } @@ -57,6 +57,10 @@ public GameController(GameView view) { view.setGameController(this); } + public void setIndex(int index) { + this.index = index; + } + public void start(){ view.startUI(); } @@ -181,16 +185,18 @@ public void excuteQuery(SerializeObject object){ case "Player[]": Player[] getPlayers = (Player[]) object.getEventObject(); changePlayers(getPlayers); + System.out.println(playersStr()); break; case "Name": if(isServer) { System.out.println(object.getEventObject() + " 플레이어 추가"); String name = (String) object.getEventObject(); - players[index].setName(name); - view.updateNameLabel(name, index); - System.out.println(playersStr()); - server.notifiObservers(new SerializeObject(players, "Player[]", object.getIndex()), -1); + int curIndex = object.getIndex(); + players[curIndex].setName(name); + view.updatePlayers(players); + System.out.println(players + " " + object.getIndex()); + server.notifiObservers(new SerializeObject(players, "Player[]", object.getIndex()), 0); } break; diff --git a/src/Controller/Server.java b/src/Controller/Server.java index 7f99094..2d04158 100644 --- a/src/Controller/Server.java +++ b/src/Controller/Server.java @@ -44,11 +44,9 @@ private void addPlayer(Socket clientSocket) throws SocketException { ClientHandler curHandler = new ClientHandler(clientSocket, this, idx); handlers[idx] = curHandler; players[idx] = new Player(""); - curHandler.sendObject(new SerializeObject("connected", "String", gameController.getIndex())); curHandler.sendObject(new SerializeObject(idx, "Index", gameController.getIndex())); curHandler.startThread(); System.out.println("플레이어 추가됨"); - gameController.updatePlayers(); } private void openServer() { From 333bc3bd060c209ff265296718f276870a54cf3a Mon Sep 17 00:00:00 2001 From: junhaa <2171326@hansung.ac.kr> Date: Wed, 20 Dec 2023 05:04:05 +0900 Subject: [PATCH 3/6] =?UTF-8?q?:sparkles:=20FEAT.=20=EB=A3=A8=EB=AF=B8?= =?UTF-8?q?=ED=81=90=EB=B8=8C=20=EB=A9=94=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run, group 정렬 버튼 기능 구현 및 게임 시작 기능 추가 Related to : #1 --- src/Controller/ClientHandler.java | 2 +- src/Controller/GameController.java | 237 +++++++++++++++++++++++++++-- src/Model/Board.java | 10 +- src/Model/Game.java | 136 ++++++++++------- src/Model/Player.java | 27 ++-- src/Model/TileDeck.java | 21 +-- src/View/GameView.java | 81 +++++++++- 7 files changed, 407 insertions(+), 107 deletions(-) diff --git a/src/Controller/ClientHandler.java b/src/Controller/ClientHandler.java index e861dc0..8d061a4 100644 --- a/src/Controller/ClientHandler.java +++ b/src/Controller/ClientHandler.java @@ -42,7 +42,7 @@ public ClientHandler(Socket socket, Server server, int index) { e.printStackTrace(); } } -1 + class ServerOutput implements Runnable{ private ObjectOutputStream objectOutputStream; private Socket serverSocket; diff --git a/src/Controller/GameController.java b/src/Controller/GameController.java index 56b1801..abdab00 100644 --- a/src/Controller/GameController.java +++ b/src/Controller/GameController.java @@ -2,9 +2,12 @@ import Exceptions.NotEmptySpaceException; import Exceptions.OnProgressException; -import Model.Player; +import Model.*; import View.GameView; +import javax.swing.*; +import java.util.*; + import java.net.UnknownHostException; // 서버 플레이어가 게임 진행을 관리 @@ -35,6 +38,11 @@ public enum GameState{ public Player curPlayer; + public Tile[][] handTiles; + + public Board boardTiles; + private boolean isTurnProgress = false; + private boolean isMyTurn = false; private Player[] players = new Player[MAX_PLAYER_COUNT]; @@ -142,12 +150,6 @@ public void changeReadyState(){ } - // 게임 패널로 전환 - public void changeGamePanel(){ - // TODO 데이터 전송 및 UI 연동 - view.changePanel("GamePanel"); - } - // 서버로 플레이어 추가시 서버 뷰 추가 public void updatePlayers(){ view.updatePlayers(players); @@ -172,6 +174,184 @@ public boolean checkReady(){ return true; } + // 메인 게임 함수 + public void serverStartGame(){ + gameState = GameState.IN_PROGRESS; + // 게임 관리 객체 생성 + Game game = new Game(players); + // 게임 타일 객체 생성 + + int playerCnt = game.getPlayerCount(); + // 플레이어들에게 첫 손패 타일 전달 + distributeTiles(game.getTileDeck()); + updateHandTiles(); + boardTiles = game.getBoard(); + updateBoardTiles(); + 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; + Tile[][] lastBoard = boardTiles.getLastBoardState(); + + } + + + + 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){ + } + + 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(){ + 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); + } + } + } + + // 보드 UI 적용 + public void updateBoardTiles(){ + Tile[][] tiles = boardTiles.getTiles(); + 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); + } + } + } + + 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){ + tmp.add(handTiles[i][j]); + } + } + } + + 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(); + } + + 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){ + tmp.add(handTiles[i][j]); + } + } + } + + 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); + + 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(); + } + // 클라이언트로 넘어온 쿼리 실행 함수 public void excuteQuery(SerializeObject object){ @@ -179,7 +359,17 @@ public void excuteQuery(SerializeObject object){ switch (object.getObjectType()){ case "String" : String content = (String)object.getEventObject(); - + // 게임 시작 + if(content.equals("startGame")){ + 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[]": @@ -188,6 +378,28 @@ public void excuteQuery(SerializeObject object){ System.out.println(playersStr()); break; + // 타일 첫 손패 + case "Hand": + if(object.getIndex() == index) { + handTiles = (Tile[][]) object.getEventObject(); + updateHandTiles(); + } + break; + + case "Board": + boardTiles = (Board) object.getEventObject(); + updateBoardTiles(); + break; + + case "Turn": + if((int)object.getEventObject() == index){ + startTurn(); + } + else{ + // 스레드로 30초 타이머 + } + break; + case "Name": if(isServer) { System.out.println(object.getEventObject() + " 플레이어 추가"); @@ -196,7 +408,7 @@ public void excuteQuery(SerializeObject object){ players[curIndex].setName(name); view.updatePlayers(players); System.out.println(players + " " + object.getIndex()); - server.notifiObservers(new SerializeObject(players, "Player[]", object.getIndex()), 0); + server.notifiObservers(new SerializeObject(Arrays.copyOf(players, MAX_PLAYER_COUNT), "Player[]", object.getIndex()), 0); } break; @@ -207,8 +419,13 @@ public void excuteQuery(SerializeObject object){ case "ReadyState" : Player.ReadyState readyState = (Player.ReadyState) object.getEventObject(); updateReadyState(object.getIndex(), readyState); - if(isServer) server.notifiObservers(new SerializeObject(readyState, "ReadyState", object.getIndex()), index); + 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/Model/Board.java b/src/Model/Board.java index f14157e..eedd91c 100644 --- a/src/Model/Board.java +++ b/src/Model/Board.java @@ -16,9 +16,12 @@ public Board(){ tiles = new Tile[BOARD_HEIGHT][BOARD_WIDTH]; } + public Tile[][] getTiles() { + return tiles; + } // 변경이전의 보드 상태를 반환하는 함수 - 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 ++){ @@ -67,11 +70,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){ diff --git a/src/Model/Game.java b/src/Model/Game.java index 2593c85..93e37ab 100644 --- a/src/Model/Game.java +++ b/src/Model/Game.java @@ -8,7 +8,6 @@ public class Game { // 게임 진행 플레이어들 - private Player[] players; // 현재 보드판 private Board board; // 현재 턴인 플레이어의 인덱스 번호 @@ -16,22 +15,41 @@ public class Game { 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; + 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; } // 현재 플레이어 수 @@ -46,73 +64,73 @@ 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 (true) { - Player currentPlayer = players[currentPlayerIndex]; - performPlayerTurn(currentPlayer); - - - // 게임이 끝난 경우 - if (checkWinCondition(currentPlayer)) { - //TODO - break; - } - - - // 다음 턴으로 변경 - 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; +// } +// +// +// // 다음 턴으로 변경 +// int curIdx = currentPlayerIndex + 1; +// +// while(true){ +// if(curIdx > GameController.MAX_PLAYER_COUNT) curIdx %= GameController.MAX_PLAYER_COUNT; +// if(players[curIdx] != null){ +// currentPlayerIndex = curIdx; +// break; +// } +// curIdx ++; +// } +// +// } +// } + + private 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 76c1d2b..61c1b27 100644 --- a/src/Model/Player.java +++ b/src/Model/Player.java @@ -14,14 +14,22 @@ 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; } // 이름을 반환하는 메서드 @@ -33,21 +41,6 @@ public void setName(String name){ this.name = name; } - // 유저가 가진 타일 리스트를 반환하는 메서드 - public List getTiles() { - return tiles; - } - - // 타일을 유저의 타일 리스트에 추가하는 메서드 - public void addTile(Tile tile) { - tiles.add(tile); - } - - // 특정 타일을 유저의 타일 리스트에서 제거하는 메서드 - public void removeTile(Tile tile) { - tiles.remove(tile); - } - public void setReadyState(ReadyState changeReadyState){ this.readyState = changeReadyState; } diff --git a/src/Model/TileDeck.java b/src/Model/TileDeck.java index 51fdbcd..2951e3d 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(){ + private 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/View/GameView.java b/src/View/GameView.java index 5294a7b..0c2b1e5 100644 --- a/src/View/GameView.java +++ b/src/View/GameView.java @@ -2,17 +2,15 @@ import Controller.GameController; import Model.Player; +import Model.Tile; import java.awt.*; import javax.swing.*; import javax.swing.border.EmptyBorder; -import javax.swing.border.LineBorder; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -28,6 +26,7 @@ public class GameView { private JTextField nameTF, addressTF; private JButton makeRoomButton, connectButton, QuitButton, RunSortButton, GroupSortButton, DrawTileButton, readyButton, startButton; private JLabel loginErrorLabel, roomNoticePanel; + private JPanel[][] board = new JPanel[BOARD_HEIGHT][BOARD_WIDTH]; // 보드의 타일들 private JPanel[][] hand = new JPanel[HAND_HEIGHT][HAND_WIDTH]; @@ -35,6 +34,7 @@ public class GameView { private JPanel[] roomReadyPanel = new JPanel[MAX_PLAYER_COUNT]; private JLabel[] roomNameLabel = new JLabel[MAX_PLAYER_COUNT]; + private JLabel[][] tileNumberLabel = new JLabel[HAND_HEIGHT][HAND_WIDTH]; private JPanel[] roomPlayerPanel = new JPanel[MAX_PLAYER_COUNT]; private GameController gameController; @@ -48,6 +48,51 @@ public void updateRoomReadyPanel(Player.ReadyState readyState, int index){ } } + public void updateTile(String color, int num, int row, int col){ + Color fontColor; + JLabel curLabel = tileNumberLabel[row][col]; + 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("14"); + 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){ + JPanel[][] curPanel; + if(isHand){ + curPanel = hand; + } + else{ + curPanel = board; + } + curPanel[row][col].setOpaque(false); + } + public void updateRoomNameLabel(String name, int index){ roomNameLabel[index].setText(name); } @@ -148,6 +193,7 @@ public JLabel getLoginErrorLabel() { // 패널 전환 함수 LoginPanel, RoomPanel, GamePanel public void changePanel(String panelName){ + System.out.println(panelName + "패널로 변경합니다."); CardLayout cardLayout = (CardLayout)frame.getContentPane().getLayout(); cardLayout.show(frame.getContentPane(), panelName); } @@ -424,6 +470,8 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ } } + + Font tileNumFont = new Font("Arial", Font.BOLD, 40); // hand 배열에 패널 추가 for (int i = 0; i < HAND_HEIGHT; i++) { JPanel curRowPanel = new JPanel(); @@ -433,7 +481,16 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ hand[i][j] = tmp; curRowPanel.add(tmp); hand[i][j].setPreferredSize(new Dimension(80, 120)); - hand[i][j].setBackground(Color.black); + hand[i][j].setBackground(Color.yellow); + hand[i][j].setLayout(null); + JLabel tmpLabel = new JLabel(""); + tileNumberLabel[i][j] = tmpLabel; + tmpLabel.setForeground(Color.cyan); + tmpLabel.setFont(tileNumFont); + tmpLabel.setHorizontalAlignment(SwingConstants.CENTER); + tmpLabel.setBounds(10, 15, 60, 60); + tmpLabel.setOpaque(false); + hand[i][j].add(tmpLabel); } } @@ -463,12 +520,24 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ // Run 정렬 버튼 RunSortButton = new JButton("New button"); 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); + GroupSortButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + gameController.sortByGroup(); + } + }); panel_4.add(GroupSortButton); JPanel panel_10 = new JPanel(); @@ -542,12 +611,14 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ startButton.setContentAreaFilled(false); startButton.setOpaque(true); + + // 시작 버튼 리스너 startButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { if(gameController.getIndex() == 0){ if(gameController.checkReady()){ - gameController.changeGamePanel(); + gameController.serverStartGame(); } else{ roomNoticePanel.setText("모든 사람이 준비를 해야 시작할 수 있습니다."); From 93dbf8432b85056bd22cda8d3faacebdf70c1a77 Mon Sep 17 00:00:00 2001 From: junhaa <2171326@hansung.ac.kr> Date: Wed, 20 Dec 2023 06:15:53 +0900 Subject: [PATCH 4/6] =?UTF-8?q?:sparkles:=20FEAT.=20=EB=A3=A8=EB=AF=B8?= =?UTF-8?q?=ED=81=90=EB=B8=8C=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 타일 드래그 기능 추가 Related to : #2 --- src/View/GameView.java | 43 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/View/GameView.java b/src/View/GameView.java index 0c2b1e5..50d26b0 100644 --- a/src/View/GameView.java +++ b/src/View/GameView.java @@ -9,8 +9,7 @@ import javax.swing.*; import javax.swing.border.EmptyBorder; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; +import java.awt.event.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -27,6 +26,13 @@ public class GameView { private JButton makeRoomButton, connectButton, QuitButton, RunSortButton, GroupSortButton, DrawTileButton, readyButton, startButton; private JLabel loginErrorLabel, roomNoticePanel; + private JPanel curClickedPanel; + private boolean isDragging = false; + private Point originalPoint; + + int offsetX = 0; + int offsetY = 0; + private JPanel[][] board = new JPanel[BOARD_HEIGHT][BOARD_WIDTH]; // 보드의 타일들 private JPanel[][] hand = new JPanel[HAND_HEIGHT][HAND_WIDTH]; @@ -406,10 +412,12 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ JPanel westPanel = new JPanel(); westPanel.setPreferredSize(new Dimension(150, 1)); + westPanel.setOpaque(false); panel_1.add(westPanel, BorderLayout.WEST); JPanel eastPanel = new JPanel(); eastPanel.setPreferredSize(new Dimension(150, 1)); + eastPanel.setOpaque(false); panel_1.add(eastPanel, BorderLayout.EAST); JPanel HandLayoutPanel = new JPanel(); @@ -491,6 +499,37 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ tmpLabel.setBounds(10, 15, 60, 60); tmpLabel.setOpaque(false); hand[i][j].add(tmpLabel); + + tmp.addMouseListener(new MouseAdapter() { + + @Override + public void mousePressed(MouseEvent e) { + curClickedPanel = tmp; + originalPoint = tmp.getLocation(); + offsetX = e.getX(); + offsetY = e.getY(); + isDragging = true; + } + + @Override + public void mouseReleased(MouseEvent e) { + System.out.println(e.getXOnScreen() + " " + e.getYOnScreen()); + tmp.setVisible(false); + curClickedPanel = null; + originalPoint = null; + isDragging = false; + } + }); + 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); + } + } + }); } } From 9249574d379351dbd7beaaf4cf39bd77f1382263 Mon Sep 17 00:00:00 2001 From: junhaa <2171326@hansung.ac.kr> Date: Wed, 20 Dec 2023 07:15:03 +0900 Subject: [PATCH 5/6] =?UTF-8?q?:sparkles:=20FEAT.=20=EB=A3=A8=EB=AF=B8?= =?UTF-8?q?=ED=81=90=EB=B8=8C=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 상위 패널 삭제 Related to : #2 --- src/Controller/GameController.java | 17 +++--- src/View/GameView.java | 84 ++++++++---------------------- 2 files changed, 30 insertions(+), 71 deletions(-) diff --git a/src/Controller/GameController.java b/src/Controller/GameController.java index abdab00..7d0220c 100644 --- a/src/Controller/GameController.java +++ b/src/Controller/GameController.java @@ -96,14 +96,15 @@ protected Player[] getPlayers() { // 방 만드는 함수 - 서버 public void makeRoom() { - 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"); + 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"); } diff --git a/src/View/GameView.java b/src/View/GameView.java index 50d26b0..1ead155 100644 --- a/src/View/GameView.java +++ b/src/View/GameView.java @@ -406,91 +406,46 @@ 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)); - westPanel.setOpaque(false); - panel_1.add(westPanel, BorderLayout.WEST); - - JPanel eastPanel = new JPanel(); - eastPanel.setPreferredSize(new Dimension(150, 1)); - eastPanel.setOpaque(false); - 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_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); - - 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)); + panel_5.add(BoardPanel, BorderLayout.CENTER); + BoardPanel.setLayout(null); + BoardPanel.setPreferredSize(new Dimension(1150, 10)); + + int boardY = 20; // board 배열에 패널 추가 for (int i = 0; i < BOARD_HEIGHT; i++) { - JPanel curRowPanel = new JPanel(); - BoardPanel.add(curRowPanel); + int boardX = 95; 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)); + BoardPanel.add(tmp); + board[i][j].setBounds(boardX, boardY, 50, 75); board[i][j].setBackground(Color.black); + boardX += 55; } + boardY += 80; } + + + int handY = 600; Font tileNumFont = new Font("Arial", Font.BOLD, 40); // hand 배열에 패널 추가 for (int i = 0; i < HAND_HEIGHT; i++) { - JPanel curRowPanel = new JPanel(); - HandPanel.add(curRowPanel); + int handX = 220; 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)); + BoardPanel.add(tmp); hand[i][j].setBackground(Color.yellow); hand[i][j].setLayout(null); + hand[i][j].setBounds(handX, handY, 80, 120); JLabel tmpLabel = new JLabel(""); tileNumberLabel[i][j] = tmpLabel; tmpLabel.setForeground(Color.cyan); @@ -499,12 +454,14 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ tmpLabel.setBounds(10, 15, 60, 60); tmpLabel.setOpaque(false); hand[i][j].add(tmpLabel); + handX += 85; tmp.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { curClickedPanel = tmp; + System.out.println("presssed"); originalPoint = tmp.getLocation(); offsetX = e.getX(); offsetY = e.getY(); @@ -513,8 +470,8 @@ public void mousePressed(MouseEvent e) { @Override public void mouseReleased(MouseEvent e) { - System.out.println(e.getXOnScreen() + " " + e.getYOnScreen()); - tmp.setVisible(false); + System.out.println("released"); + curClickedPanel.setLocation(originalPoint); curClickedPanel = null; originalPoint = null; isDragging = false; @@ -531,6 +488,7 @@ public void mouseDragged(MouseEvent e) { } }); } + handY += 125; } From d05de0c318b7f5ecb67eec5932534c56c4f3a26a Mon Sep 17 00:00:00 2001 From: junhaa <2171326@hansung.ac.kr> Date: Wed, 20 Dec 2023 08:56:56 +0900 Subject: [PATCH 6/6] =?UTF-8?q?:sparkles:=20FEAT.=20=EB=A3=A8=EB=AF=B8?= =?UTF-8?q?=ED=81=90=EB=B8=8C=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 패널 변경 기능 추가 Related to : #1, #2 --- src/Controller/GameController.java | 53 ++++++-- src/Model/Board.java | 13 +- src/View/GameView.java | 199 ++++++++++++++++++++++++++--- src/View/LayeredPaneUtils.java | 21 +++ 4 files changed, 255 insertions(+), 31 deletions(-) create mode 100644 src/View/LayeredPaneUtils.java diff --git a/src/Controller/GameController.java b/src/Controller/GameController.java index 7d0220c..fcf26ab 100644 --- a/src/Controller/GameController.java +++ b/src/Controller/GameController.java @@ -6,9 +6,11 @@ import View.GameView; import javax.swing.*; +import java.awt.*; import java.util.*; import java.net.UnknownHostException; +import java.util.List; // 서버 플레이어가 게임 진행을 관리 public class GameController { @@ -46,6 +48,11 @@ public enum GameState{ 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 ++){ @@ -60,6 +67,10 @@ public String playersStr() { return tmp; } + public boolean isInMyTurn(){ + return isMyTurn; + } + public GameController(GameView view) { this.view = view; view.setGameController(this); @@ -96,18 +107,42 @@ protected Player[] getPlayers() { // 방 만드는 함수 - 서버 public void makeRoom() { - 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"); + 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 void changeTiles(boolean startInBoard, boolean endInBoard, int sr, int sc, int er, int ec){ + 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{ + System.out.println("에러 발생"); + handTiles[er][ec] = start; + } + } + else{ + handTiles[sr][sc] = end; + if(endInBoard){ + boardTiles.setTile(er, ec, start); + } + else{ + handTiles[er][ec] = start; + } + } + } + public void connectRoom(String address) { view.getLoginErrorLabel().setText("연결 중 입니다..."); isServer = false; diff --git a/src/Model/Board.java b/src/Model/Board.java index eedd91c..2fd3c4e 100644 --- a/src/Model/Board.java +++ b/src/Model/Board.java @@ -20,6 +20,14 @@ public Tile[][] getTiles() { return 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; + } + // 변경이전의 보드 상태를 반환하는 함수 public Tile[][] getLastBoardState(){ Tile[][] newTiles = new Tile[BOARD_HEIGHT][BOARD_WIDTH]; @@ -33,9 +41,8 @@ public 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; @@ -83,7 +90,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/View/GameView.java b/src/View/GameView.java index 1ead155..09deefb 100644 --- a/src/View/GameView.java +++ b/src/View/GameView.java @@ -5,7 +5,7 @@ import Model.Tile; import java.awt.*; - +import java.util.List; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -19,6 +19,53 @@ import static Controller.GameController.HAND_HEIGHT; import static Controller.GameController.HAND_WIDTH; +class TileComponent extends JPanel{ + 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 + + '}'; + } +} + + + + public class GameView { private JFrame frame; @@ -33,9 +80,10 @@ public class GameView { int offsetX = 0; int offsetY = 0; - private JPanel[][] board = new JPanel[BOARD_HEIGHT][BOARD_WIDTH]; // 보드의 타일들 - private JPanel[][] hand = new JPanel[HAND_HEIGHT][HAND_WIDTH]; + private TileComponent[][] board = new TileComponent[BOARD_HEIGHT][BOARD_WIDTH]; // 보드의 타일들 + + private TileComponent[][] hand = new TileComponent[HAND_HEIGHT][HAND_WIDTH]; private JPanel[] playerIcon = new JPanel[MAX_PLAYER_COUNT]; private JPanel[] roomReadyPanel = new JPanel[MAX_PLAYER_COUNT]; private JLabel[] roomNameLabel = new JLabel[MAX_PLAYER_COUNT]; @@ -43,6 +91,9 @@ public class GameView { private JLabel[][] tileNumberLabel = new JLabel[HAND_HEIGHT][HAND_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; public void updateRoomReadyPanel(Player.ReadyState readyState, int index){ @@ -205,17 +256,72 @@ public void changePanel(String 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); + } + + } + // 타일 패널 이동 함수 - 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]; + 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()]; - if (startHand) hand[startRow][startCol] = desPanel; - else board[startRow][startCol] = desPanel; + System.out.println(startPanel + " " + endPanel); + + + if (!startPanel.isInBoard()){ + // hand -> hand + if(!endPanel.isInBoard()){ + 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); + return true; + } + // hand -> board + else{ + if(!gameController.isInMyTurn()) return false; + if(gameController.canAdd(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); + return true; + } + else{ + return false; + } + } + } - if (toHand) hand[endRow][endCol] = movePanel; - else board[endRow][endCol] = movePanel; + else{ + if(!gameController.isInMyTurn()) return false; + if(endPanel.isInBoard()){ + 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); + return true; + } + else return false; + } } public void startUI() { @@ -410,9 +516,8 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ panel_3.add(panel_5, BorderLayout.CENTER); panel_5.setLayout(new BorderLayout(0, 0)); - JPanel BoardPanel = new JPanel(); + JLayeredPane BoardPanel = new JLayeredPane(); panel_5.add(BoardPanel, BorderLayout.CENTER); - BoardPanel.setLayout(null); BoardPanel.setPreferredSize(new Dimension(1150, 10)); @@ -421,12 +526,46 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ for (int i = 0; i < BOARD_HEIGHT; i++) { int boardX = 95; for (int j = 0; j < BOARD_WIDTH; j++) { - JPanel tmp = new JPanel(); + TileComponent tmp = new TileComponent(i, j, true); board[i][j] = tmp; BoardPanel.add(tmp); - board[i][j].setBounds(boardX, boardY, 50, 75); + Rectangle tPoint = new Rectangle(boardX, boardY, 50, 75); + board[i][j].setBounds(tPoint); + 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) { + 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; } @@ -440,12 +579,14 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ for (int i = 0; i < HAND_HEIGHT; i++) { int handX = 220; for (int j = 0; j < HAND_WIDTH; j++) { - JPanel tmp = new JPanel(); + 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); - hand[i][j].setBounds(handX, handY, 80, 120); + Rectangle tPoint = new Rectangle(handX, handY, 80, 120); + hand[i][j].setBounds(tPoint); + handPoints[i][j] = tPoint; JLabel tmpLabel = new JLabel(""); tileNumberLabel[i][j] = tmpLabel; tmpLabel.setForeground(Color.cyan); @@ -461,20 +602,40 @@ else if(address.isEmpty() || address.isBlank() || !isValidIP(address)){ @Override public void mousePressed(MouseEvent e) { curClickedPanel = tmp; - System.out.println("presssed"); originalPoint = tmp.getLocation(); offsetX = e.getX(); offsetY = e.getY(); isDragging = true; + BoardPanel.setLayer(tmp, JLayeredPane.DRAG_LAYER); } @Override public void mouseReleased(MouseEvent e) { - System.out.println("released"); - curClickedPanel.setLocation(originalPoint); + + List foundComponents = LayeredPaneUtils.getAllComponentsAt(BoardPanel, e.getLocationOnScreen()); + 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)){ + gameController.changeTiles(tmp.isInBoard(), tcomp.isInBoard(), tmp.getRow(), tmp.getCol(), tcomp.getRow(), tcomp.getCol()); + } + 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() { diff --git a/src/View/LayeredPaneUtils.java b/src/View/LayeredPaneUtils.java new file mode 100644 index 0000000..abf62ee --- /dev/null +++ b/src/View/LayeredPaneUtils.java @@ -0,0 +1,21 @@ +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); + System.out.println(comp.getBounds()); + if (comp.getBounds().contains(p)) { + components.add(comp); + } + } + return components; + } +} \ No newline at end of file