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