package com.esir.sr.sweetsnake.view; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.text.DecimalFormat; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.annotation.PostConstruct; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import com.esir.sr.sweetsnake.api.IComponent; import com.esir.sr.sweetsnake.component.GameBoardPanel; import com.esir.sr.sweetsnake.component.Snake; import com.esir.sr.sweetsnake.component.Sweet; import com.esir.sr.sweetsnake.constants.ClientGuiConstants; import com.esir.sr.sweetsnake.constants.GameConstants; import com.esir.sr.sweetsnake.dto.ComponentDTO; import com.esir.sr.sweetsnake.dto.GameBoardDTO; import com.esir.sr.sweetsnake.dto.GameBoardRefreshDTO; import com.esir.sr.sweetsnake.dto.PlayerDTO; import com.esir.sr.sweetsnake.enumeration.MoveDirection; import com.esir.sr.sweetsnake.enumeration.RefreshAction; /** * * @author Herminaël Rougier * @author Damien Jouanno * */ @Component public class GameView extends AbstractView { /********************************************************************************************** * [BLOCK] STATIC FIELDS **********************************************************************************************/ /** The serial version UID */ private static final long serialVersionUID = 6919247419837806743L; /** The logger */ private static final Logger log = LoggerFactory.getLogger(GameView.class); /********************************************************************************************** * [BLOCK] FIELDS **********************************************************************************************/ /** The game board DTO */ private GameBoardDTO gameBoardDto; /** The top panel */ private JPanel topPL; /** The center panel */ private JPanel centerPL; /** The game board panel */ private GameBoardPanel gameBoardPL; /** The bottom panel */ private JPanel bottomPL; /** The players' scores label */ private JLabel[] playersScoresLB; /** The quit button */ private JButton quitBTN; /** The current player's number */ private int playerNb; /** The players' numbers & snakes map */ private Map<Integer, String> playersSnakes; /********************************************************************************************** * [BLOCK] CONSTRUCTOR & INIT **********************************************************************************************/ /** * */ protected GameView() { super(); } /* * (non-Javadoc) * * @see com.esir.sr.sweetsnake.view.SweetSnakeAbstractView#init() */ @PostConstruct @Override protected void init() { super.init(); log.info("Initializing the Game View"); playersSnakes = new LinkedHashMap<Integer, String>(); } /********************************************************************************************** * [BLOCK] PUBLIC METHODS **********************************************************************************************/ /* * (non-Javadoc) * * @see com.esir.sr.sweetsnake.view.SweetSnakeAbstractView#buildImpl() */ @Override public void buildImpl() { setLayout(new BorderLayout()); // top panel initTopPL(); add(topPL, BorderLayout.NORTH); initPlayersScoresLB(); final GridBagConstraints gbc = new GridBagConstraints(); final int[][] positions = { { 0, 3, 2, 1 }, { 1, 2, 3, 0 }, { 2, 0, 1, 3 }, { 3, 1, 0, 2 } }; gbc.gridx = 0; gbc.gridy = 0; gbc.insets = new Insets(0, 0, 5, 170); topPL.add(playersScoresLB[positions[playerNb - 1][0]], gbc); gbc.gridx = 1; gbc.insets = new Insets(0, 170, 5, 0); topPL.add(playersScoresLB[positions[playerNb - 1][1]], gbc); // center panel initCenterPL(); add(centerPL, BorderLayout.CENTER); initGameBoardPL(); centerPL.add(gameBoardPL); // bottom panel initBottomPL(); add(bottomPL, BorderLayout.SOUTH); gbc.gridx = 0; gbc.gridy = 0; gbc.insets = new Insets(5, 0, 0, 120); bottomPL.add(playersScoresLB[positions[playerNb - 1][2]], gbc); initQuitBTN(); gbc.gridx = 1; gbc.insets = new Insets(5, 0, 0, 0); bottomPL.add(quitBTN, gbc); gbc.gridx = 2; gbc.insets = new Insets(5, 120, 0, 0); bottomPL.add(playersScoresLB[positions[playerNb - 1][3]], gbc); addKeyListener(new KeyboardListener()); } /** * * @param playersScores */ public void refreshScores(final List<PlayerDTO> players) { for (final PlayerDTO player : players) { playersScoresLB[player.getNumber() - 1].setText(intToString(player.getScore(), 3)); } } public void hideScore(final int _playerNb) { playersScoresLB[_playerNb - 1].setForeground(findSnakeColor(null, _playerNb)); } /** * * @param _gameBoardDto */ public void setGameboardDto(final GameBoardDTO _gameBoardDto) { gameBoardDto = _gameBoardDto; } /** * * @param _playerNb */ public void setPlayerNb(final int _playerNb) { playerNb = _playerNb; } /** * * @param _playersSnakes */ public void setPlayersSnakesMap(final Map<Integer, String> _playersSnakes) { playersSnakes = _playersSnakes; } /********************************************************************************************** * [BLOCK] PRIVATE METHODS **********************************************************************************************/ /** * */ private void initTopPL() { topPL = new JPanel(); topPL.setLayout(new GridBagLayout()); topPL.setOpaque(false); } /** * */ private void initCenterPL() { centerPL = new JPanel(); centerPL.setOpaque(true); centerPL.setBackground(Color.cyan); centerPL.setLayout(new GridBagLayout()); } /** * */ private void initBottomPL() { bottomPL = new JPanel(); bottomPL.setLayout(new GridBagLayout()); bottomPL.setOpaque(false); } /** * */ private void initGameBoardPL() { if (gameBoardDto != null) { gameBoardPL = new GameBoardPanel(gameBoardDto.getWidth(), gameBoardDto.getHeight(), playerNb); gameBoardPL.setBorder(new EmptyBorder(0, 0, 10, 0)); drawGameboard(); } } /** * */ private void initPlayersScoresLB() { playersScoresLB = new JLabel[GameConstants.MAX_NUMBER_OF_PLAYERS]; for (int i = 0; i < playersScoresLB.length; i++) { playersScoresLB[i] = new JLabel(intToString(0, 3)); playersScoresLB[i].setForeground(findSnakeColor(playersSnakes.get(i + 1), i + 1)); playersScoresLB[i].setFont(new Font("sans-serif", Font.BOLD, 20)); } } /** * */ private void initQuitBTN() { quitBTN = new JButton("quit game"); quitBTN.addActionListener(new QuitGameListener()); } /** * */ public void drawGameboard() { final List<GameBoardRefreshDTO> refreshes = gameBoardDto.getComponentsToRefresh(); for (final GameBoardRefreshDTO refresh : refreshes) { final ComponentDTO componentDto = refresh.getComponentDto(); final RefreshAction action = refresh.getAction(); final IComponent component = gameBoardPL.getComponentById(componentDto.getId()); switch (action) { case ADD: IComponent newComponent = null; final int x = componentDto.getX(), y = componentDto.getY(); switch (componentDto.getType()) { case SNAKE: newComponent = new Snake(componentDto.getId(), x, y, findSnakeIconPath(componentDto.getId())); break; case SWEET: newComponent = new Sweet(componentDto.getId(), x, y); break; } gameBoardPL.addComponent(newComponent); break; case MOVE: component.setXYPos(componentDto.getX(), componentDto.getY()); gameBoardPL.moveComponent(component); break; case REMOVE: gameBoardPL.removeComponent(component); break; } } } /** * * @param snakeId * @return */ private String findSnakeIconPath(final String snakeId) { for (final int player : playersSnakes.keySet()) { if (playersSnakes.get(player).equals(snakeId)) { switch (player) { case 2: return ClientGuiConstants.RED_SNAKE_ICON_PATH; case 3: return ClientGuiConstants.BLUE_SNAKE_ICON_PATH; case 4: return ClientGuiConstants.BLACK_SNAKE_ICON_PATH; default: return ClientGuiConstants.GREEN_SNAKE_ICON_PATH; } } } return ClientGuiConstants.GREEN_SNAKE_ICON_PATH; } /** * * @param snakeId * @param i * @return */ private Color findSnakeColor(final String snakeId, final int i) { switch (i) { case 2: return new Color(255, 0, 0, snakeId == null ? 0 : 255); case 3: return new Color(12, 12, 235, snakeId == null ? 0 : 255); case 4: return new Color(0, 0, 0, snakeId == null ? 0 : 255); default: return new Color(39, 109, 31, snakeId == null ? 0 : 255); } } /** * * @param num * @param digits * @return */ private static String intToString(final int num, final int digits) { final char[] zeros = new char[digits]; Arrays.fill(zeros, '0'); final DecimalFormat df = new DecimalFormat(String.valueOf(zeros)); return df.format(num); } /********************************************************************************************** * [BLOCK] INTERNAL LISTENERS **********************************************************************************************/ /** * * @author Herminaël Rougier * @author Damien Jouanno * */ private class QuitGameListener implements ActionListener { /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent e) { client.leaveSession(); } } /** * * @author Herminaël Rougier * @author Damien Jouanno * */ private class KeyboardListener implements KeyListener { /** */ private final Map<Integer, MoveDirection> moveTable; /** * */ public KeyboardListener() { moveTable = new LinkedHashMap<Integer, MoveDirection>(); switch (playerNb) { case 2: moveTable.put(KeyEvent.VK_DOWN, MoveDirection.UP); moveTable.put(KeyEvent.VK_UP, MoveDirection.DOWN); moveTable.put(KeyEvent.VK_LEFT, MoveDirection.RIGHT); moveTable.put(KeyEvent.VK_RIGHT, MoveDirection.LEFT); break; case 3: moveTable.put(KeyEvent.VK_DOWN, MoveDirection.RIGHT); moveTable.put(KeyEvent.VK_UP, MoveDirection.LEFT); moveTable.put(KeyEvent.VK_LEFT, MoveDirection.DOWN); moveTable.put(KeyEvent.VK_RIGHT, MoveDirection.UP); break; case 4: moveTable.put(KeyEvent.VK_DOWN, MoveDirection.LEFT); moveTable.put(KeyEvent.VK_UP, MoveDirection.RIGHT); moveTable.put(KeyEvent.VK_LEFT, MoveDirection.UP); moveTable.put(KeyEvent.VK_RIGHT, MoveDirection.DOWN); break; default: moveTable.put(KeyEvent.VK_DOWN, MoveDirection.DOWN); moveTable.put(KeyEvent.VK_UP, MoveDirection.UP); moveTable.put(KeyEvent.VK_LEFT, MoveDirection.LEFT); moveTable.put(KeyEvent.VK_RIGHT, MoveDirection.RIGHT); break; } } /* * (non-Javadoc) * * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent) */ @Override public void keyPressed(final KeyEvent e) { final int keyCode = e.getKeyCode(); if (moveTable.containsKey(keyCode)) { client.moveSnake(moveTable.get(keyCode)); } } /* * (non-Javadoc) * * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent) */ @Override public void keyReleased(final KeyEvent e) { } /* * (non-Javadoc) * * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent) */ @Override public void keyTyped(final KeyEvent e) { } } }