diff options
Diffstat (limited to 'src/ch/epfl/xblast/client/XBlastComponent.java')
-rw-r--r-- | src/ch/epfl/xblast/client/XBlastComponent.java | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/ch/epfl/xblast/client/XBlastComponent.java b/src/ch/epfl/xblast/client/XBlastComponent.java new file mode 100644 index 0000000..388a208 --- /dev/null +++ b/src/ch/epfl/xblast/client/XBlastComponent.java | |||
@@ -0,0 +1,178 @@ | |||
1 | package ch.epfl.xblast.client; | ||
2 | |||
3 | import ch.epfl.xblast.Cell; | ||
4 | import ch.epfl.xblast.Lists; | ||
5 | import ch.epfl.xblast.PlayerID; | ||
6 | |||
7 | import javax.swing.*; | ||
8 | import java.awt.*; | ||
9 | import java.awt.image.ImageObserver; | ||
10 | import java.util.*; | ||
11 | import java.util.List; | ||
12 | import java.util.stream.Collectors; | ||
13 | import java.util.stream.IntStream; | ||
14 | |||
15 | /** | ||
16 | * The game graphical component. | ||
17 | * | ||
18 | * @author Pacien TRAN-GIRARD (261948) | ||
19 | * @author Timothée FLOURE (257420) | ||
20 | */ | ||
21 | public final class XBlastComponent extends JComponent { | ||
22 | |||
23 | private static class Grid { | ||
24 | |||
25 | private static final Dimension CELL_DIMENSION = new Dimension(64, 48); | ||
26 | private static final Dimension SCORE_IMG_DIMENSION = new Dimension(48, 48); | ||
27 | private static final Dimension TIME_LED_DIMENSION = new Dimension(16, 16); | ||
28 | private static final Dimension FRAME_DIMENSION = totalDimension(); | ||
29 | |||
30 | private static final List<Point> CELL_POSITIONS = buildCellGrid(CELL_DIMENSION); | ||
31 | private static final List<Point> SCORE_BG_POSITIONS = buildScoreGrid(); | ||
32 | private static final List<Point> TIME_LINE_POSITIONS = buildTimeLineGrid(); | ||
33 | private static final Map<PlayerID, Point> SCORE_TXT_POSITIONS = buildScoreMap(659); | ||
34 | |||
35 | private static Dimension totalDimension() { | ||
36 | return new Dimension( | ||
37 | CELL_DIMENSION.width * Cell.COLUMNS, | ||
38 | CELL_DIMENSION.height * Cell.ROWS + SCORE_IMG_DIMENSION.height + TIME_LED_DIMENSION.height); | ||
39 | } | ||
40 | |||
41 | private static List<Point> buildCellGrid(Dimension elementDim) { | ||
42 | return Collections.unmodifiableList(Cell.ROW_MAJOR_ORDER.stream() | ||
43 | .map(c -> new Point(c.x() * elementDim.width, c.y() * elementDim.height)) | ||
44 | .collect(Collectors.toList())); | ||
45 | } | ||
46 | |||
47 | private static List<Point> buildLine(Dimension elementDim, int len, Point shift) { | ||
48 | return Collections.unmodifiableList(IntStream.range(0, len) | ||
49 | .mapToObj(x -> new Point(x * elementDim.width + shift.x, shift.y)) | ||
50 | .collect(Collectors.toList())); | ||
51 | } | ||
52 | |||
53 | private static List<Point> buildScoreGrid() { | ||
54 | return buildLine( | ||
55 | SCORE_IMG_DIMENSION, | ||
56 | FRAME_DIMENSION.width / SCORE_IMG_DIMENSION.width, | ||
57 | new Point(0, CELL_DIMENSION.height * Cell.ROWS)); | ||
58 | } | ||
59 | |||
60 | private static List<Point> buildTimeLineGrid() { | ||
61 | return buildLine( | ||
62 | TIME_LED_DIMENSION, | ||
63 | FRAME_DIMENSION.width / TIME_LED_DIMENSION.width, | ||
64 | new Point(0, CELL_DIMENSION.height * Cell.ROWS + SCORE_IMG_DIMENSION.height)); | ||
65 | } | ||
66 | |||
67 | private static Map<PlayerID, Point> buildScoreMap(int vShift) { | ||
68 | Map<PlayerID, Point> m = new EnumMap<>(PlayerID.class); | ||
69 | m.put(PlayerID.PLAYER_1, new Point(96, vShift)); | ||
70 | m.put(PlayerID.PLAYER_2, new Point(240, vShift)); | ||
71 | m.put(PlayerID.PLAYER_3, new Point(768, vShift)); | ||
72 | m.put(PlayerID.PLAYER_4, new Point(912, vShift)); | ||
73 | return m; | ||
74 | } | ||
75 | |||
76 | private static Point positionForPlayer(GameState.Player p) { | ||
77 | return new Point( | ||
78 | 4 * p.position().x() - 24, | ||
79 | 3 * p.position().y() - 52); | ||
80 | } | ||
81 | |||
82 | } | ||
83 | |||
84 | private static class Painter { | ||
85 | |||
86 | private static final ImageObserver IMG_OBSERVER = null; | ||
87 | private static final Font TXT_FONT = new Font("Arial", Font.BOLD, 25); | ||
88 | private static final Color TXT_COLOR = Color.WHITE; | ||
89 | |||
90 | private static void drawString(Graphics2D g, Point pos, String str) { | ||
91 | g.setColor(TXT_COLOR); | ||
92 | g.setFont(TXT_FONT); | ||
93 | g.drawString(str, pos.x, pos.y); | ||
94 | } | ||
95 | |||
96 | private static void drawImage(Graphics2D g, Point pos, Image img) { | ||
97 | g.drawImage(img, pos.x, pos.y, IMG_OBSERVER); | ||
98 | } | ||
99 | |||
100 | private static void drawImageMap(Graphics2D g, Map<Point, Image> m) { | ||
101 | for (Map.Entry<Point, Image> e : m.entrySet()) | ||
102 | drawImage(g, e.getKey(), e.getValue()); | ||
103 | } | ||
104 | |||
105 | private static <T> void drawStringMap(Graphics2D g, Map<Point, T> m) { | ||
106 | for (Map.Entry<Point, T> e : m.entrySet()) | ||
107 | drawString(g, e.getKey(), e.getValue().toString()); | ||
108 | } | ||
109 | |||
110 | } | ||
111 | |||
112 | private static Comparator<GameState.Player> buildPlayerComparator(PlayerID blackSheep) { | ||
113 | Comparator<GameState.Player> coordinateComparator = | ||
114 | (p1, p2) -> p1.position().compareTo(p2.position()); | ||
115 | |||
116 | Comparator<GameState.Player> idComparator = | ||
117 | (p1, p2) -> p1.id() == blackSheep ? -1 : 0; | ||
118 | |||
119 | return coordinateComparator.thenComparing(idComparator); | ||
120 | } | ||
121 | |||
122 | private GameState gameState; | ||
123 | private PlayerID playerID; | ||
124 | |||
125 | /** | ||
126 | * Display the given GameState from the point of view of the given playerID. | ||
127 | * | ||
128 | * @param gs GameState to be displayed | ||
129 | * @param pid playerID related to the view | ||
130 | */ | ||
131 | public void setGameState(GameState gs, PlayerID pid) { | ||
132 | this.gameState = gs; | ||
133 | this.playerID = pid; | ||
134 | this.repaint(); | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * Returns the value of the preferredSize property. | ||
139 | * | ||
140 | * @return the value of the preferredSize property | ||
141 | */ | ||
142 | @Override | ||
143 | public Dimension getPreferredSize() { | ||
144 | return Grid.FRAME_DIMENSION; | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * Draw the component. | ||
149 | * | ||
150 | * @param g0 the Graphics context | ||
151 | */ | ||
152 | @Override | ||
153 | protected void paintComponent(Graphics g0) { | ||
154 | Graphics2D g = (Graphics2D) g0; | ||
155 | |||
156 | if (Objects.isNull(this.gameState)) | ||
157 | return; | ||
158 | |||
159 | Painter.drawImageMap(g, Lists.linearMap(Grid.CELL_POSITIONS, this.gameState.board())); | ||
160 | Painter.drawImageMap(g, Lists.linearMap(Grid.CELL_POSITIONS, this.gameState.explosions())); | ||
161 | Painter.drawImageMap(g, Lists.linearMap(Grid.SCORE_BG_POSITIONS, this.gameState.scores())); | ||
162 | Painter.drawImageMap(g, Lists.linearMap(Grid.TIME_LINE_POSITIONS, this.gameState.ticks())); | ||
163 | Painter.drawStringMap(g, Lists.traverseMaps(Lists.invertMap(Grid.SCORE_TXT_POSITIONS), this.gameState.playerScores())); | ||
164 | drawPlayers(g, Lists.sorted(this.gameState.players(), buildPlayerComparator(this.playerID))); | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * Draw the players on the graphic context. | ||
169 | * | ||
170 | * @param g the graphic context | ||
171 | * @param players the list of players to be displayed | ||
172 | */ | ||
173 | private void drawPlayers(Graphics2D g, List<GameState.Player> players) { | ||
174 | for (GameState.Player p : players) | ||
175 | Painter.drawImage(g, Grid.positionForPlayer(p), p.image()); | ||
176 | } | ||
177 | |||
178 | } | ||