Added new Image for (Bomb-)Items.
[clanbomber-xamarin-client.git] / src / visualization / Playground / HelloMovingImage / HelloMovingImage / Playground.cs
1 ´╗┐using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Threading.Tasks;
5 using Bomberman;
6 using Xamarin.Forms;
7 using static Bomberman.TcpJsonConnection;
8
9 namespace BombermanPlayground
10 {
11     class Playground : Xamarin.Forms.AbsoluteLayout
12     {
13
14         public static string c_ImageNamespace = "HelloMovingImage";
15
16
17         class PlaygroundException : Exception {
18             public PlaygroundException(string str) : base(str) { }
19         }
20
21
22         private readonly int fieldSize; // Lets leave this readonly
23         public int FieldSize { get { return fieldSize; } }
24
25
26         private BombermanBlock[,] playgroungBlocks;
27         private Dictionary<int,PlayerBlock> players = new Dictionary<int, PlayerBlock>();
28         //private List<PlayerBlock> players = new List<PlayerBlock>();
29         private List<BombBlock> bombs = new List<BombBlock>();
30         private List<FlameBlock> flames = new List<FlameBlock>();
31
32         public Playground(int fieldSize)
33         {
34             this.fieldSize = fieldSize;
35             playgroungBlocks = new BombermanBlock[fieldSize, fieldSize];
36         }
37
38         public void Update(ServerPackage pkg)
39         {
40             if(pkg.Field.Count != fieldSize)
41             {
42                 throw new PlaygroundException("Error: Fieldsize in Playground does not match Package fieldsize");
43             }
44
45             //---------------------------------------------------------------------------------------------
46             //----------------------------------Update Field-----------------------------------------------
47
48             for (int i = 0; i < pkg.Field.Count; i++)
49             {
50                 if (pkg.Field[i].Count != fieldSize)
51                 {
52                     throw new PlaygroundException("Error: Fieldsize in Playground does not match Package fieldsize");
53                 }
54
55                 for (int j = 0; j < pkg.Field[i].Count; j++)
56                 {
57                     BombermanBlock block = null;
58                     switch(pkg.Field[i][j])
59                     {
60                         case ServerPackage.FieldTypes.EmptyField:
61                             block = null;
62                             break;
63                         case ServerPackage.FieldTypes.DynamicOrDestroyableBlock:
64                             block = new DestroyableBlock(i,j);
65                             break;
66                         case ServerPackage.FieldTypes.ItemOrMoreBombs:
67                             block = new ItemBlock(i, j);
68                             break;
69                         case ServerPackage.FieldTypes.StaticOrUndestroyableBlock:
70                             block = new WallBlock(i, j);
71                             break;
72                     }
73
74                     ChangePlaygroundElement(i, j, block);
75
76                 }
77             }
78
79             //---------------------------------------------------------------------------------------------
80             //----------------------------------Update Players---------------------------------------------
81
82
83             for (int i = 0; i < pkg.Players.Count; i++)
84             {
85                 if(players.ContainsKey(i))
86                 {
87                     if (pkg.Players[i].Life != 0)
88                     {
89                         players[i].MoveTo(pkg.Players[i].X, pkg.Players[i].Y);
90                     }
91                     else
92                     {
93                         if(Children.Contains(players[i]))
94                         {
95                             Children.Remove(players[i]);
96                         }
97                     }
98                 }
99                 else
100                 {
101                     players[i]=new PlayerBlock(pkg.Players[i].X, pkg.Players[i].Y, i);
102                     Children.Add(players[i]);
103                 }
104             }
105
106             //---------------------------------------------------------------------------------------------
107             const double c_maxKeepOldElementDistance = 0.1;
108             //---------------------------------------------------------------------------------------------
109             //----------------------------------Update Bombs-----------------------------------------------
110
111
112
113             List<BombBlock> newBombs = new List<BombBlock>();
114             List<BombBlock> unchangedBombs = new List<BombBlock>();
115             List<BombBlock> removeOldBombs = new List<BombBlock>();
116
117             for (int i = 0; i < pkg.Bombs.Count; i++)
118             {
119                 newBombs.Add(new BombBlock(pkg.Bombs[i].X, pkg.Bombs[i].Y));
120             }
121
122             foreach (var oldBomb in bombs)
123             {
124                 bool IsOldBombStillHere = false;
125                 foreach (var newBomb in newBombs)
126                 {
127                     if (newBomb.TranslationX < oldBomb.TranslationX + c_maxKeepOldElementDistance && newBomb.TranslationX > oldBomb.TranslationX - c_maxKeepOldElementDistance &&
128                         newBomb.TranslationY < oldBomb.TranslationY + c_maxKeepOldElementDistance && newBomb.TranslationY > oldBomb.TranslationY - c_maxKeepOldElementDistance)
129                     {
130                         IsOldBombStillHere = true;
131                         unchangedBombs.Add(newBomb);
132                     }
133
134                 }
135                 if (!IsOldBombStillHere)
136                 {
137                     removeOldBombs.Add(oldBomb);
138                 }
139             }
140
141             foreach (var newBomb in newBombs)
142             {
143                 if (!unchangedBombs.Contains(newBomb))
144                 {
145                     bombs.Add(newBomb);
146                     Children.Add(newBomb);
147                 }
148             }
149
150             foreach (var oldBomb in removeOldBombs)
151             {
152                 bombs.Remove(oldBomb);
153                 Children.Remove(oldBomb);
154             }
155
156
157             //---------------------------------------------------------------------------------------------
158             //----------------------------------Update Flames-----------------------------------------------
159
160             List<FlameBlock> newFlames = new List<FlameBlock>();
161             List<FlameBlock> unchangedFlames = new List<FlameBlock>();
162             List<FlameBlock> removeOldFlames = new List<FlameBlock>();
163
164             for (int i = 0; i < pkg.Flames.Count; i++)
165             {
166                 newFlames.Add(new FlameBlock(pkg.Flames[i].X, pkg.Flames[i].Y));
167             }
168
169             foreach (var oldFlame in flames)
170             {
171                 bool IsOldFlameStillHere = false;
172                 foreach (var newFlame in newFlames)
173                 {
174                     if (newFlame.TranslationX < oldFlame.TranslationX + c_maxKeepOldElementDistance && newFlame.TranslationX > oldFlame.TranslationX - c_maxKeepOldElementDistance &&
175                         newFlame.TranslationY < oldFlame.TranslationY + c_maxKeepOldElementDistance && newFlame.TranslationY > oldFlame.TranslationY - c_maxKeepOldElementDistance)
176                     {
177                         IsOldFlameStillHere = true;
178                         unchangedFlames.Add(newFlame);
179                     }
180
181                 }
182                 if (!IsOldFlameStillHere)
183                 {
184                     removeOldFlames.Add(oldFlame);
185                 }
186             }
187
188             foreach (var newFlame in newFlames)
189             {
190                 if (!unchangedFlames.Contains(newFlame))
191                 {
192                     flames.Add(newFlame);
193                     Children.Add(newFlame);
194                 }
195             }
196
197             foreach (var oldFlame in removeOldFlames)
198             {
199                 flames.Remove(oldFlame);
200                 Children.Remove(oldFlame);
201             }
202
203
204         }
205
206         /// <summary>
207         /// Change Element to the new object, but only if it has different type
208         /// </summary>
209         /// <param name="posX"></param>
210         /// <param name="posY"></param>
211         /// <param name="newBlock"></param>
212         private void ChangePlaygroundElement(int posX, int posY, BombermanBlock newBlock)
213         {
214             if (playgroungBlocks[posX, posY] != null)
215             {
216                 if (newBlock == null || playgroungBlocks[posX, posY].GetType() != newBlock.GetType())
217                 {
218                     Children.Remove(playgroungBlocks[posX, posY]);
219
220                     if (newBlock != null)
221                     {
222                         playgroungBlocks[posX, posY] = newBlock;
223                         Children.Add(newBlock);
224                     }
225                 }
226             }
227             else
228             {
229                 if (newBlock != null)
230                 {
231                     playgroungBlocks[posX, posY] = newBlock;
232                     Children.Add(newBlock);
233                 }
234             }
235
236         }
237     }
238
239
240     class BombermanBlock : Xamarin.Forms.Image
241     {
242         public static double BlockSize { get; set; } = 1.0;
243
244         public BombermanBlock(double posX, double posY)
245         {
246             Source = ImageSource.FromResource(Playground.c_ImageNamespace + ".Images.Unknown.png");
247
248             WidthRequest = BlockSize + 1;
249             TranslationX = BlockSize * posY + BlockSize / 2;    // Xamarin X is Bomberman Y and vise-versa. 
250             HeightRequest = BlockSize + 1;
251             TranslationY = BlockSize * posX + BlockSize / 2;    // Xamarin X is Bomberman Y and vise-versa. 
252         }
253
254         public void MoveTo(double posX, double posY)
255         {
256             this.TranslateTo(BlockSize * posY + BlockSize / 2, BlockSize * posX + BlockSize / 2);       // Xamarin X is Bomberman Y and vise-versa.
257         }
258
259     }
260
261     class MoveableBombermanBlock : BombermanBlock
262     {
263         public MoveableBombermanBlock(double posX, double posY) : base(posX - 0.5, posY - 0.5) { }
264
265         public new void MoveTo(double posX, double posY)
266         {
267             base.MoveTo(posX-0.5, posY-0.5);    // Xamarin X is Bomberman Y and vise-versa.
268         }
269     }
270
271
272     class WallBlock : BombermanBlock
273     {
274         public WallBlock(double posX, double posY) : base(posX, posY)
275         {
276             Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Wall.png");
277         }
278     }
279
280     class BombBlock : MoveableBombermanBlock
281     {
282         public BombBlock(double posX, double posY) : base(posX, posY)
283         {
284             Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Bomb.png");
285         }
286     }
287
288     class FlameBlock : BombermanBlock
289     {
290         public FlameBlock(double posX, double posY) : base(posX, posY)
291         {
292             Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Flame.png");
293         }
294     }
295
296     class PlayerBlock : MoveableBombermanBlock
297     {
298         public PlayerBlock(double posX, double posY, int playerId) : base(posX, posY)   // Server sets offset itself for now..
299         {
300             const int c_NumOfAvailablePictures = 4;
301
302             switch ((playerId / c_NumOfAvailablePictures) % 5)
303             {
304                 case 0:
305                     Rotation = 0;
306                     break;
307                 case 1:
308                     Rotation = 45;
309                     break;
310                 case 2:
311                     Rotation = -45;
312                     break;
313                 case 3:
314                     Rotation = 90;
315                     break;
316                 case 4:
317                     Rotation = -90;
318                     break;
319             }
320
321
322             switch (playerId % c_NumOfAvailablePictures)
323             {
324                 case 0:
325                     Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Player1.png");
326                     break;
327
328                 case 1:
329                     Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Player2.png");
330                     break;
331
332                 case 2:
333                     Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Player3.png");
334                     break;
335
336                 case 3:
337                     Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Player4.png");
338                     break;
339             }
340         }
341
342     }
343
344     class ItemBlock : BombermanBlock
345     {
346         public ItemBlock(double posX, double posY) : base(posX, posY)
347         {
348             Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.BombCountUp.png");
349         }
350     }
351
352     class DestroyableBlock : BombermanBlock
353     {
354         public DestroyableBlock(double posX, double posY) : base(posX, posY)
355         {
356             Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.BrickWallBreakable.png");
357         }
358     }
359
360 }