More debug utility
[troll.git] / src / main / java / com / codingame / game / View.java
1 package com.codingame.game;
2
3 import java.util.Random;
4 import java.util.ArrayList;
5 import java.util.Comparator;
6
7 import com.codingame.gameengine.core.MultiplayerGameManager;
8 import com.codingame.gameengine.module.entities.GraphicEntityModule;
9 import com.codingame.gameengine.module.entities.Rectangle;
10 import com.codingame.gameengine.module.entities.Sprite;
11 import com.codingame.gameengine.module.entities.SpriteAnimation;
12 import com.codingame.gameengine.module.entities.Text;
13 import com.codingame.gameengine.module.entities.Group;
14 import com.codingame.gameengine.module.entities.Curve;
15 import com.codingame.gameengine.module.toggle.ToggleModule;
16 import com.google.inject.Inject;
17
18 class View {
19     @Inject private MultiplayerGameManager<com.codingame.game.Player> gameManager;
20     @Inject private GraphicEntityModule graphicEntityModule;
21     @Inject ToggleModule toggleModule;
22
23     class Player {
24         Model.Player model;
25
26         int colorToken;
27         String nicknameToken;
28         String avatarToken;
29
30         double frameRot;
31
32         Group avatar;
33         Text stoneCounter;
34         Text message;
35         Sprite castle;
36         Text stone;
37         Text stoneReminder;
38
39         void init(com.codingame.game.Player p) {
40             model = p.model;
41             colorToken = p.getColorToken();
42             nicknameToken = p.getNicknameToken();
43             avatarToken = p.getAvatarToken();
44
45             boolean p0 = model.index == 0;
46             int x = p0 ? 280 : 1920 - 280;
47             int y = 220;
48
49             Sprite frame = graphicEntityModule.createSprite()
50                 .setImage("frame.png")
51                 .setAnchor(0.5)
52                 .setRotation(frameRot)
53                 .setZIndex(22)
54                 .setTint(colorToken);
55
56             Sprite frameBg = graphicEntityModule.createSprite()
57                 .setImage("frame_bg.png")
58                 .setAnchor(0.5)
59                 .setRotation(frameRot)
60                 .setZIndex(20);
61
62             Sprite avatarSprite = graphicEntityModule.createSprite()
63                 .setZIndex(21)
64                 .setImage(avatarToken)
65                 .setAnchor(0.5)
66                 .setBaseHeight(116)
67                 .setBaseWidth(116);
68
69             avatar = graphicEntityModule
70                 .createGroup(frame, frameBg, avatarSprite)
71                 .setX(x).setY(y);
72
73             Text text = graphicEntityModule.createText(nicknameToken)
74                     .setX(x)
75                     .setY(y + 120)
76                     .setZIndex(20)
77                     .setFontSize(40)
78                     .setFillColor(0x7f3f00)
79                     .setAnchor(0.5);
80
81             stoneCounter = graphicEntityModule.createText()
82                 .setX(x)
83                 .setY(y+200)
84                 .setZIndex(20)
85                 .setFontSize(40)
86                 .setFillColor(0x7f3f00)
87                 .setAnchor(0.5);
88             updateStoneCounter();
89
90             message = graphicEntityModule.createText()
91                 .setX(p0 ? 15 : 1920-15)
92                 .setY(680)
93                 .setZIndex(1)
94                 .setFontSize(40)
95                 .setFillColor(0xffbf7f)
96                 .setAnchorX(p0 ? 0 : 1)
97                 .setAnchorY(1);
98
99             castle = graphicEntityModule.createSprite()
100                 .setImage("castle.png")
101                 .setTint(colorToken)
102                 .setX(p0 ? 160 : 1920-160)
103                 .setY(p0 ? 890 : 880)
104                 .setZIndex(1)
105                 .setAnchorX(0.5)
106                 .setAnchorY(1)
107                 .setScaleX(p0 ? 1 : -1);
108
109             stone = graphicEntityModule.createText()
110                 .setZIndex(3)
111                 .setFontSize(150)
112                 .setFillColor(0x12322a)
113                 .setAnchor(0.5)
114                 .setAlpha(0);
115
116             stoneReminder = graphicEntityModule.createText()
117                 .setX(p0 ? x + 100 : x - 100)
118                 .setY(y)
119                 .setZIndex(20)
120                 .setFontSize(75)
121                 .setFillColor(0x3f3f3f)
122                 .setAnchorX(p0 ? 0 : 1)
123                 .setAnchorY(0.5);
124         }
125
126         void updateStoneCounter() {
127             int stones = model.getStones();
128             if (stones <= 0) {
129                 stoneCounter.setText("Out of stones!");
130                 stoneCounter.setFillColor(0xff7777);
131             }
132             else if (stones == 1) {
133                 stoneCounter.setText("1 stone");
134                 stoneCounter.setFillColor(0xffbb77);
135             }
136             else {
137                 stoneCounter.setText(stones + " stones");
138             }
139         }
140
141         void animateStones(int stones) {
142             String stonesString = new Integer(stones).toString();
143             stone.setX(castle.getX());
144             stone.setY(castle.getY() - 100);
145             stone.setText(stonesString);
146             stone.setAlpha(1);
147             graphicEntityModule.commitEntityState(0, stone);
148     
149             int peakX = (castle.getX() + troll.getX()) / 2;
150             int peakY = 540;
151             stone.setX(peakX);
152             stone.setY(peakY, Curve.EASE_OUT);
153             graphicEntityModule.commitEntityState(0.25,
154                                                   stone,
155                                                   stoneCounter);
156     
157             stone.setX(troll.getX());
158             stone.setY(troll.getY() - 50, Curve.EASE_IN);
159             stone.setAlpha(0, Curve.EASE_IN);
160             graphicEntityModule.commitEntityState(0.5, stone);
161
162             stoneReminder.setText(stonesString);
163             graphicEntityModule.commitEntityState(0.25, stoneReminder);
164             stoneReminder.setAlpha(1);
165             graphicEntityModule.commitEntityState(0.5, stoneReminder);
166         }
167
168         void displayMessage(String msg) {
169             message.setText(msg);
170             graphicEntityModule.commitEntityState(0, message);
171         }
172
173         void markLoser() {
174             graphicEntityModule.commitEntityState(0.5, avatar);
175             int dir = random.nextInt(2) == 1 ? 1 : -1;
176             avatar.setRotation(dir * 170 * Math.PI / 180, Curve.ELASTIC);
177         }
178
179         void destroy() {
180             graphicEntityModule.commitEntityState(0.5, castle);
181             castle.setX(castle.getX(), Curve.ELASTIC);
182             castle.setScaleY(-0.2, Curve.EASE_IN);
183         }
184
185         void startTurn() {
186             stoneReminder.setAlpha(0);
187             graphicEntityModule.commitEntityState(0, stoneReminder);
188         }
189     }
190
191     Model model;
192     Random random = new Random();
193     Sprite troll;
194     Text trollPositionGauge;
195     Player p0 = new Player(), p1 = new Player();
196     Text turnCounter; int _turns = 0;
197
198     void init(Model m) {
199         model = m;
200         drawBackground();
201
202         /*
203          * Random π/2-grained rotation of the avatar frames.  Avoid
204          * having them π/2 apart, though, as one of them is likely
205          * going to end upside-down and the trick would be revealed.
206          * And I'd have to "draw" a new frame. Ewww.
207          */
208         p0.frameRot = random.nextInt(4) * Math.PI / 2;
209         p0.init(gameManager.getPlayer(0));
210         p1.frameRot = p1.frameRot +
211             (random.nextInt(2) == 1 ? 1 : -1) * Math.PI / 2;
212         p1.init(gameManager.getPlayer(1));
213
214         drawTroll();
215
216         drawDebug();
217     }
218
219     void startTurn() {
220         p0.startTurn();
221         p1.startTurn();
222
223         animateTurnCounter();
224     }
225
226     private class Pos {
227         int x, y;
228         Pos(int _x, int _y) { x = _x; y = _y; }
229     }
230
231     private void drawBackground() {
232         graphicEntityModule.createSprite()
233                 .setImage("background.png")
234                 .setAnchor(0);
235
236         int numMountains = random.nextInt(5);
237         while (numMountains --> 0) {
238             final int pngWidth = 366;
239             double scale = 0.5 * (1 + random.nextDouble());
240             int x = random.nextInt(1920 + (int) (scale*pngWidth))
241                 - (int) (scale*pngWidth/2);
242             int baseTint = 64 + random.nextInt(128);
243             Sprite mountain = graphicEntityModule.createSprite()
244                 .setImage("mountain.png")
245                 .setX(x)
246                 .setY(680)
247                 .setAnchorX(0.5)
248                 .setAnchorY(283.0 / 321.0)
249                 .setRotation((random.nextDouble() - 0.5) * Math.PI / 1800)
250                 .setScaleX(random.nextInt(2) == 0 ? scale : -scale)
251                 .setScaleY(scale * (1 + (random.nextDouble() - 0.5) / 2))
252                 .setSkewX((random.nextDouble() - 0.5) / 4)
253                 .setSkewY((random.nextDouble() - 0.5) / 8)
254                 .setTint((baseTint + random.nextInt(16) - 8) * 0x010000
255                          + (baseTint + random.nextInt(16) - 8) * 0x0100
256                          + (baseTint + random.nextInt(16) - 8) * 0x01);
257             graphicEntityModule.createSprite().setImage("mountaintop.png")
258                 .setX(mountain.getX())
259                 .setY(mountain.getY())
260                 .setAnchorX(mountain.getAnchorX())
261                 .setAnchorY(mountain.getAnchorY())
262                 .setRotation(mountain.getRotation())
263                 .setScaleX(mountain.getScaleX())
264                 .setScaleY(mountain.getScaleY())
265                 .setSkewX(mountain.getSkewX())
266                 .setSkewY(mountain.getSkewY());
267         }
268
269         int numTrees = random.nextInt(21);
270         ArrayList<Pos> poss = new ArrayList<Pos>(numTrees);
271         while (numTrees --> 0) {
272             int x, y;
273             do {
274                 x = random.nextInt(1920);
275                 // yes, this biases randomness wrt perspective! :-(
276                 y = 700 + random.nextInt(175);
277             } while (y > 880 && (x < 200 || x > 1720));
278             poss.add(new Pos(x, y));
279         }
280         poss.sort(new Comparator<Pos>() {
281                 public int compare(Pos a, Pos b) { return a.y < b.y ? -1 : 1; }
282             });
283
284         for (Pos p : poss) {
285             double scale = ( 90.0 / 433.0           // base height from PNG
286                              * (p.y - 680) / (875 - 680) ); // perspective
287             graphicEntityModule.createSprite()
288                 .setImage(random.nextInt(2) == 0 ? "Alshockv1.png"
289                                                  : "Alshockv2.png")
290                 .setAnchorX(0.5)
291                 .setAnchorY(1)
292                 .setX(p.x)
293                 .setY(p.y)
294                 .setScaleX(scale * (random.nextInt(2) == 0 ? -1 : 1)
295                            * (1 + (random.nextDouble() - 0.5) / 6))
296                 .setScaleY(scale * (1 + (random.nextDouble() -0.5) / 6))
297                 .setRotation((random.nextDouble() - 0.5) * Math.PI / 1800)
298                 .setSkewX((random.nextDouble() - 0.5) /4)
299                 .setSkewY((random.nextDouble() - 0.5) /8);
300         }
301     }
302
303     private void drawTroll() {
304         troll = graphicEntityModule.createSprite()
305             .setImage("troll.png")
306             .setAnchorX(0.5)
307             .setAnchorY(1)
308             .setX(1920/2)
309             .setY(880)
310             .setZIndex(2);
311         trollPositionGauge = graphicEntityModule.createText()
312             .setZIndex(2)
313             .setAnchor(0.5)
314             .setFontSize(40)
315             .setX(1980/2)
316             .setY(980)
317             .setFillColor(0xffffff);
318
319         moveTroll();
320     }
321
322     void moveTroll() {
323         graphicEntityModule.commitEntityState(0.5, troll, trollPositionGauge);
324         int x0 = p0.castle.getX(), x1 = p1.castle.getX();
325         int y0 = p0.castle.getY(), y1 = p1.castle.getY();
326         troll.setX(x0 + model.trollPosition * (x1-x0) / model.roadLength,
327                    Curve.ELASTIC);
328         troll.setY(y0 + model.trollPosition * (y1-y0) / model.roadLength,
329                    Curve.ELASTIC);
330
331         trollPositionGauge.setX((trollPositionGauge.getX() + troll.getX()) / 2);
332         int distLeft = model.trollPosition;
333         int distRight = model.roadLength - model.trollPosition;
334         if (distLeft <= 0) {
335             trollPositionGauge.setText("← " + distRight);
336         }
337         else if (distRight <= 0) {
338             trollPositionGauge.setText(distLeft + " →");
339         }
340         else {
341             trollPositionGauge.setText(distLeft + " ↔ " + distRight);
342         }
343         graphicEntityModule.commitEntityState(0.75, trollPositionGauge);
344         trollPositionGauge.setX(troll.getX());
345     }
346
347     void animateTurnCounter() {
348         for (int i = 0; i < 10; i++) {
349             turnCounter.setText("T" + _turns + "." + i);
350             // The following line is likely not a bug.
351             graphicEntityModule.commitEntityState((double) i/9, turnCounter);
352         }
353         _turns++;
354     }
355
356     void drawDebug() {
357         String[] debugModePngs = graphicEntityModule.createSpriteSheetSplitter()
358             .setSourceImage("debug.png")
359             .setImageCount(2)
360             .setWidth(900)
361             .setHeight(150)
362             .setOrigRow(0)
363             .setOrigCol(0)
364             .setImagesPerRow(1)
365             .setName("debug")
366             .split();
367         SpriteAnimation debugMode = graphicEntityModule.createSpriteAnimation()
368             .setImages(debugModePngs)
369             .setX(1920 / 2)
370             .setY(80)
371             .setAnchorX(0.5)
372             .setLoop(true);
373         toggleModule.displayOnToggleState(debugMode, "debug", true);
374
375         turnCounter = graphicEntityModule.createText()
376             .setAnchorX(0.5)
377             .setAnchorY(0)
378             .setX(1920 / 2)
379             .setY(280)
380             .setStrokeColor(0xff0080)
381             .setFillColor(0xff0080)
382             .setFontFamily("monospace")
383             .setFontWeight(Text.FontWeight.BOLD)
384             .setFontSize(100);
385         toggleModule.displayOnToggleState(turnCounter, "debug", true);
386         animateTurnCounter();
387     }
388 }