Decreased Animation time.
[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         const int c_AnimationTime = 100;
245
246         public BombermanBlock(double posX, double posY)
247         {
248             Source = ImageSource.FromResource(Playground.c_ImageNamespace + ".Images.Unknown.png");
249
250             WidthRequest = BlockSize + 1;
251             TranslationX = BlockSize * posY + BlockSize / 2;    // Xamarin X is Bomberman Y and vise-versa. 
252             HeightRequest = BlockSize + 1;
253             TranslationY = BlockSize * posX + BlockSize / 2;    // Xamarin X is Bomberman Y and vise-versa. 
254         }
255
256         public void MoveTo(double posX, double posY)
257         {
258             this.TranslateTo(BlockSize * posY + BlockSize / 2, BlockSize * posX + BlockSize / 2, c_AnimationTime);      // Xamarin X is Bomberman Y and vise-versa.
259         }
260
261     }
262
263     class MoveableBombermanBlock : BombermanBlock
264     {
265         public MoveableBombermanBlock(double posX, double posY) : base(posX - 0.5, posY - 0.5) { }
266
267         public new void MoveTo(double posX, double posY)
268         {
269             base.MoveTo(posX-0.5, posY-0.5);    // Xamarin X is Bomberman Y and vise-versa.
270         }
271     }
272
273
274     class WallBlock : BombermanBlock
275     {
276         public WallBlock(double posX, double posY) : base(posX, posY)
277         {
278             Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Wall.png");
279         }
280     }
281
282     class BombBlock : MoveableBombermanBlock
283     {
284         public BombBlock(double posX, double posY) : base(posX, posY)
285         {
286             Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Bomb.png");
287         }
288     }
289
290     class FlameBlock : BombermanBlock
291     {
292         public FlameBlock(double posX, double posY) : base(posX, posY)
293         {
294             Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Flame.png");
295         }
296     }
297
298     class PlayerBlock : MoveableBombermanBlock
299     {
300         public PlayerBlock(double posX, double posY, int playerId) : base(posX, posY)   // Server sets offset itself for now..
301         {
302             const int c_NumOfAvailablePictures = 4;
303
304             switch ((playerId / c_NumOfAvailablePictures) % 5)
305             {
306                 case 0:
307                     Rotation = 0;
308                     break;
309                 case 1:
310                     Rotation = 45;
311                     break;
312                 case 2:
313                     Rotation = -45;
314                     break;
315                 case 3:
316                     Rotation = 90;
317                     break;
318                 case 4:
319                     Rotation = -90;
320                     break;
321             }
322
323
324             switch (playerId % c_NumOfAvailablePictures)
325             {
326                 case 0:
327                     Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Player1.png");
328                     break;
329
330                 case 1:
331                     Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Player2.png");
332                     break;
333
334                 case 2:
335                     Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Player3.png");
336                     break;
337
338                 case 3:
339                     Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.Player4.png");
340                     break;
341             }
342         }
343
344     }
345
346     class ItemBlock : BombermanBlock
347     {
348         public ItemBlock(double posX, double posY) : base(posX, posY)
349         {
350             Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.BombCountUp.png");
351         }
352     }
353
354     class DestroyableBlock : BombermanBlock
355     {
356         public DestroyableBlock(double posX, double posY) : base(posX, posY)
357         {
358             Source = ImageSource.FromResource(Playground.c_ImageNamespace+".Images.BrickWallBreakable.png");
359         }
360     }
361
362 }