source: 2016/27/ohjaajat/VenienteFragore/VenienteFragore/VenienteFragore/VenienteFragore.cs @ 7825

Revision 7825, 18.1 KB checked in by sieerinn, 3 years ago (diff)

Tippuvia pisaroita luolaan

Line 
1using System;
2using System.Collections.Generic;
3using Jypeli;
4using Jypeli.Assets;
5using Jypeli.Controls;
6using Jypeli.Effects;
7using Jypeli.Widgets;
8using System.Linq;
9using SimplePhysics;
10
11namespace VenienteFragore
12{
13    public class VenienteFragore : SimplePhysics.Game
14    {
15        private delegate void ObjectMethod(Vector position, double width, double height, Dictionary<string, string> properties);
16        private Dictionary<string, ObjectMethod> objectMethods;
17
18        private Image dripImage = LoadImage("drip");
19
20        private List<Player> advenae;
21
22        private Vector cameraSpeed = new Vector(2.0, 4.0);
23        private Vector cameraTarget;
24
25        SimplePhysics.Object borderleft;
26        SimplePhysics.Object borderright;
27
28        public VenienteFragore() : base(tileSize: 50)
29        {
30        }
31
32        public override void Begin()
33        {
34            StartLevel("desolatecaves");
35
36            Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
37        }
38
39
40
41        private void StartLevel(string lvlName)
42        {
43            ClearAll();
44            advenae = new List<Player>();
45            objectMethods = new Dictionary<string, ObjectMethod>();
46            objectMethods.Add("ball", TestBall);
47            objectMethods.Add("player", CreatePlayer);
48            objectMethods.Add("moving", CreateMovingPlatform);
49            objectMethods.Add("door", CreateDoor);
50            objectMethods.Add("goomba", CreateGoomba);
51            objectMethods.Add("drip", CreateWaterDrip);
52
53            var tileMap = TiledTileMap.FromLevelAsset(lvlName);
54            tileMap.SetTileMethod("Tiilet", TileMethod);
55            tileMap.SetObjectMethod("Oliot", CreateObject);
56            tileMap.SetTileMethod("Etuala", Foreground);
57            tileMap.Execute();
58
59            Gravity = new Vector(0, -800);
60
61            //Camera.ZoomToLevel();
62
63            Level.Background.CreateGradient(Color.Beige, Color.OrangeRed);
64
65            CameraInitialization();
66        }
67
68        void CameraInitialization()
69        {
70            Camera.StayInLevel = true;
71
72            Window.Width = 1500;
73            Window.Height = 750;
74
75            borderleft = new SimplePhysics.Object(TileSize, Level.Height) { X = Camera.X + Window.Width / 2, IsVisible = false };
76            Add(borderleft);
77            borderright = new SimplePhysics.Object(TileSize, Level.Height) { X = Camera.X - Window.Width / 2, IsVisible = false };
78            Add(borderright);
79
80            Timer checkit = new Timer();
81            checkit.Interval = 0.02;
82            checkit.Timeout += () => { UpdateCameraTarget(checkit); };
83            checkit.Start();
84        }
85
86        void UpdateCameraTarget(Timer checkit)
87        {
88            List<Player> activePlayers = advenae.FindAll(o => o.IsVisible == true);
89
90            switch (activePlayers.Count)
91            {
92                case 1:
93                    Camera.StopFollowing();
94                    Player soloYolo = activePlayers[0];
95                    cameraTarget.X = soloYolo.Position.X + (soloYolo.FacingDirection.GetVector().X * (TileSize * 4));
96                    if (soloYolo.IsCrouching) cameraTarget.Y = soloYolo.Position.Y - TileSize * 4;
97                    else if (soloYolo.IsGrounded) cameraTarget.Y = soloYolo.Position.Y;
98                    break;
99                case 2:
100                    Vector minPosition = new Vector(activePlayers.Max(p => p.X), activePlayers.Min(p => p.Y));
101                    Vector maxPosition = new Vector(activePlayers.Min(p => p.X), activePlayers.Max(p => p.Y));
102                    cameraTarget = (minPosition + maxPosition) * 0.5;
103                    break;
104                default:
105                    Camera.StopFollowing();
106                    checkit.Stop();
107                    break;
108            }
109
110            borderleft.X = Camera.X + Window.Width / 2;
111            borderright.X = Camera.X - Window.Width / 2;
112        }
113
114        protected override void Update(Time time)
115        {
116            Camera.X += (cameraTarget.X - Camera.X) * time.SinceLastUpdate.TotalSeconds * cameraSpeed.X;
117            Camera.Y += (cameraTarget.Y - Camera.Y) * time.SinceLastUpdate.TotalSeconds * cameraSpeed.Y;
118
119            base.Update(time);
120        }
121
122        private void CreateObject(Vector position, double width, double height, Angle angle, Shape shape, string name, Dictionary<string, string> properties)
123        {
124            if (objectMethods.ContainsKey(name))
125                objectMethods[name](position, width, height, properties);
126            else
127                throw new Exception("Unknown object type: " + name);
128        }
129
130        void TestBall(Vector position, double width, double height, Dictionary<string, string> properties)
131        {
132            var testObject = new InteractableObject(TileSize * 0.99, TileSize * 0.99);
133            testObject.Position = position;
134            testObject.Color = Color.DarkGreen;
135            testObject.Shape = Shape.Circle;
136            testObject.RestitutionX = 0.5;
137            testObject.RestitutionY = 0.5;
138            testObject.CollisionIgnoreGroup = 1;
139            testObject.OnInteractedWith += Pickup;
140            Add(testObject);
141        }
142
143        void CreateGoomba(Vector position, double width, double height, Dictionary<string, string> properties)
144        {
145            var goomba = new GoombaEnemy(TileSize * 0.99, TileSize * 0.99);
146            goomba.Position = position;
147            goomba.Color = Color.Pink;
148            goomba.Tag = "goomba";
149            goomba.Speed = 50;
150            goomba.FallOffPlatforms = true;
151            Add(goomba);
152
153            goomba.AddCollisionHandler("player", (a, player) =>
154            {
155                if (player.Bottom >= goomba.Top)
156                {
157                    goomba.Destroy();
158                    player.Velocity = new Vector(player.Velocity.X, 400);
159                }
160                else
161                {
162                    player.Destroy();
163                }
164            });
165        }
166
167        void CreatePlayer(Vector position, double width, double height, Dictionary<string, string> properties)
168        {
169            CreatePlayer1(position, width, height);
170            var p = CreatePlayer2(position, width, height);
171            p.Destroy();
172            SetGeneralKeys();
173        }
174
175        Player CreatePlayer1(Vector position, double width, double height)
176        {
177            if (advenae.Count > 0 && !advenae[0].IsVisible) { advenae[0].Reappear(); return advenae[0]; };
178
179            Player advenA = MakePlayer(position, width, height, 1, new List<Key> { Key.Up, Key.Down, Key.Left, Key.Right, Key.Enter });
180            advenA.Color = Color.HotPink;
181            advenae.Add(advenA);
182            return advenA;
183        }
184
185
186        Player CreatePlayer2(Vector position, double width, double height)
187        {
188            if (advenae.Count > 1 && !advenae[1].IsVisible) { advenae[1].Reappear(); return advenae[1]; };
189
190            Player advenA = MakePlayer(position, width, height, 2, new List<Key> { Key.W, Key.S, Key.A, Key.D, Key.E });
191            advenA.Color = Color.Harlequin;
192            advenae.Add(advenA);
193            return advenA;
194        }
195
196        void CreateWaterDrip(Vector position, double width, double height, Dictionary<string, string> properties)
197        {
198            // Luo ajastetusti vesipisaroita.
199            var dripTimer = new Timer { Interval = RandomGen.NextDouble(1.0, 4.0) };
200            dripTimer.Timeout += () =>
201            {
202                Add(new SimplePhysics.Object(10, 10)
203                {
204                    Position = position,
205                    Image = dripImage,
206                    LifetimeLeft = TimeSpan.FromSeconds(5),
207                    IgnoresCollisionResponse = true
208                }, -1);
209            };
210            dripTimer.Start();
211        }
212
213        private void SetMovementKeys(Player adven, List<Key> keys)
214        {
215            Keyboard.Listen(keys[3], ButtonState.Down, Walk, null, adven, 200.0);
216            Keyboard.Listen(keys[2], ButtonState.Down, Walk, null, adven, -200.0);
217            Keyboard.Listen(keys[0], ButtonState.Down, Jump, null, adven);
218            Keyboard.Listen(keys[1], ButtonState.Pressed, Crouch, null, adven, true);
219            Keyboard.Listen(keys[1], ButtonState.Released, Crouch, null, adven, false);
220            Keyboard.Listen(keys[4], ButtonState.Pressed, Interact, null, adven);
221            // Keyboard.Listen(keys[4], ButtonState.Pressed, SplitOrMorph, "Splits or morphs the player back to 1 player", adven);
222
223        }
224
225        private void Interact(Player adven)
226        {
227            //Jos kannetaan jotain, viskataan se
228            SimplePhysics.Object carryed = adven.Carrying;
229            if (carryed != null) //Throw
230            {
231                adven.Carrying = null;
232                double dir = adven.FacingDirection == Direction.Left ? -1 : 1;
233                carryed.Velocity = new Vector(dir * 350, 350);
234                carryed.Position = carryed.Position + new Vector(dir * 10, 30);
235                //Pitäisiköhän oma aliohjelma tehdä
236                carryed.IgnoresGravity = false;
237                carryed.IgnoresCollisionResponse = false;
238            }
239
240            Vector pingPoint = adven.Position + (adven.FacingDirection == Direction.Left ? new Vector(-adven.Width, 0) : new Vector(adven.Width, 0));
241            List<GameObject> interactedObjects = GetObjectsAt(pingPoint);
242
243            GameObject sphere = new GameObject(1, 1);
244            sphere.Position = pingPoint;
245            sphere.Shape = Shape.Circle;
246            sphere.Color = new Color(100, 0, 100, 25);
247            Add(sphere, 1);
248
249            TimerAddons.Until(() => sphere.Width == 100.0, delegate { sphere.Width += 1; sphere.Height += 1; }, 0.01, sphere.Destroy);
250
251            foreach (GameObject item in interactedObjects)
252            {
253                InteractableObject obj = item as InteractableObject;
254                if (obj == null)
255                    continue;
256                obj.InteractWith(adven);
257            }
258        }
259
260
261        void Pickup(SimplePhysics.Object player, InteractableObject target)
262        {
263            Player adven = player as Player;
264            if (adven.Carrying == null)
265            {
266                adven.Carrying = target;
267                target.IgnoresGravity = true;
268                target.IgnoresCollisionResponse = true;
269                //Lentävän palikan nostaminen
270            }
271
272        }
273
274        private void SetGeneralKeys()
275        {
276            Keyboard.Listen(Key.R, ButtonState.Pressed, () => { ClearAll(); advenae = new List<Player>(); Begin(); }, "Lopeta peli");
277            Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
278
279            //Keyboard.Listen(keys[4], ButtonState.Pressed, SplitOrMorph, "Splits or morphs the player back to 1 player", adven);
280            Keyboard.Listen(Key.X, ButtonState.Pressed, SplitOrMorph, "Splits or morphs the player", 2);
281            Keyboard.Listen(Key.RightShift, ButtonState.Pressed, SplitOrMorph, "Splits or morphs the player", 1);
282        }
283
284
285        private Player MakePlayer(Vector position, double width, double height, int playerNum, List<Key> keys)
286        {
287            Player adven = new Player(TileSize * 0.99, TileSize * 1.98);
288            adven.Position = position;
289            adven.Friction = 0.2;
290            adven.Tag = "player";
291            adven.Crushed += adven.Destroy;
292            adven.CollisionIgnoreGroup = playerNum;
293            adven.PlayerNumber = playerNum;
294            adven.ControlKeys = keys;
295            adven.OnInteractedWith += Pickup;
296            Add(adven);
297
298            adven.AddCollisionHandler("death", (a, b) => adven.Destroy());
299
300            SetMovementKeys(adven, keys);
301
302            return adven;
303        }
304
305        /// <summary>
306        /// Sotku
307        /// </summary>
308        /// <param name="playerNro">Sen pelaajan numero, joka haluaa toimia</param>
309        private void SplitOrMorph(int playerNro)
310        {
311            if (!advenae[playerNro - 1].IsVisible && advenae[1 - playerNro + 1].IsVisible)
312            {
313                Split(advenae[1 - playerNro + 1]);
314            }
315            else
316            {
317                Morph(advenae[1 - playerNro + 1]);
318            }
319        }
320
321        private void Morph(Player adven)
322        {
323            if (advenae.FindAll(o => o.IsVisible == true).Count != 2) return;
324
325            if (Vector.Distance(advenae[0].Position, advenae[1].Position) < adven.Width * 1.5)
326            {
327                Player destroyable = advenae.Find(o => o.PlayerNumber != adven.PlayerNumber);
328
329                destroyable.ControlKeys.ForEach(delegate (Key key)
330                {
331                    Keyboard.Disable(key);
332                });
333
334                destroyable.Destroy();
335            }
336
337            //TODO: Eeppinen hypäytys takaisin? Samalla voisi ajastimella tarkastaa jatkuvasti, ovatko pelaajat tarpeeksi lähellä toisiaan.
338            /*
339            Vector center = new Vector();
340
341            for (int i = 0; i < advenae.Count; i++)
342            {
343                center = (advenae[i].Position - center) * 0.5;
344            }
345            foreach (Player item in advenae)
346            {
347                item.Velocity = (center - item.Position) * 3.0;
348            }
349            morphing = true;
350            Timer.SingleShot(2.0, delegate { morphing = false; });
351            */
352        }
353
354        void Split(Player adven)
355        {
356            if (advenae.FindAll(o => o.IsVisible == true).Count == 2) return;
357
358            Player advenNew = new Player(adven.Width, adven.Height);
359            switch (adven.PlayerNumber)
360            {
361                case 1:
362                    advenNew = CreatePlayer2(adven.Position + new Vector(adven.Width, 0), adven.Width, adven.Height);
363                    break;
364                case 2:
365                    advenNew = CreatePlayer1(adven.Position + new Vector(adven.Width, 0), adven.Width, adven.Height);
366                    break;
367                default:
368                    break;
369            }
370
371            advenNew.Position = adven.Position + new Vector(adven.Width, 0);
372
373            if (Collisions(advenNew, Vector.Zero, true).Count > 0)
374            {
375                advenNew.Destroy();
376                return;
377            }
378
379            advenNew.ControlKeys.ForEach(delegate (Key key)
380            {
381                Keyboard.Enable(key);
382            });
383        }
384
385        void Walk(Player pelaaja, double nopeus)
386        {
387            pelaaja.Walk(nopeus);
388        }
389
390        private void Jump(SimplePlatformCharacter player)
391        {
392            if (player.IsGrounded)
393                player.Velocity = new Vector(player.Velocity.X, 500);
394        }
395
396        private void Crouch(Player player, bool crouch)
397        {
398            player.Crouch = crouch;
399        }
400
401        private void CreateMovingPlatform(Vector position, double width, double height, Dictionary<string, string> properties)
402        {
403            var dirX = double.Parse(properties["directionx"]);
404            var dirY = double.Parse(properties["directiony"]);
405            var distance = double.Parse(properties["distance"]);
406            var platform = new MovingPlatform(position, new Vector(dirX, dirY), distance, width, height);
407            Add(platform);
408        }
409
410
411        private void CreateDoor(Vector position, double width, double height, Dictionary<string, string> properties)
412        {
413            string lvlName = properties["levelName"];
414            InteractableObject door = new InteractableObject(width, height);
415            door.Position = position;
416            door.Color = Color.Purple;
417            door.OnInteractedWith += delegate (SimplePhysics.Object actor, InteractableObject actedDoor)
418            {
419                EnterDoor(actor, actedDoor, lvlName);
420            };
421            Add(door);
422        }
423
424        private void EnterDoor(SimplePhysics.Object actor, InteractableObject actedDoor, string lvlName)
425        {
426            //Tämä tänne, jotta anim. tai jotain jos joskus halutaan, muuten suoraan voi vaihtaa kenttää delegattissa
427            StartLevel(lvlName);
428        }
429
430        private void Foreground(int x, int y, Image image, string layerName, Dictionary<string, string> properties)
431        {
432            var tile = new SimplePhysics.Object(TileSize, TileSize) { IsStatic = true };
433            tile.Image = image;
434            tile.IgnoresCollisionResponse = true;
435            Add(tile, 3);
436            SetTile(x, y, tile);
437        }
438
439        private void TileMethod(int x, int y, Image image, string layerName, Dictionary<string, string> properties)
440        {
441            var tile = new SimplePhysics.Object(TileSize, TileSize) { IsStatic = true };
442            tile.Image = image;
443            Add(tile);
444            SetTile(x, y, tile);
445
446            if (properties.ContainsKey("type"))
447            {
448                var features = properties["type"].Split(',');
449                foreach (var feature in features)
450                {
451                    ApplyFeature(tile, feature);
452                }
453            }
454        }
455
456        private void ApplyFeature(SimplePhysics.Object tile, string feature)
457        {
458            switch (feature)
459            {
460                case "ice":
461                    tile.Friction = 0.0;
462                    break;
463
464                case "death":
465                    tile.Tag = "death";
466                    break;
467
468                case "oneway":
469                    tile.OneWayPlatform = true;
470                    break;
471
472                case "break":
473                    tile.AddCollisionHandler("player", (t, player) =>
474                    {
475                        if (player.Top <= tile.Bottom)
476                        {
477                            tile.Destroy();
478                        }
479                    });
480                    break;
481                default:
482                    throw new Exception("Unknown tile feature: " + feature);
483            }
484        }
485    }
486}
Note: See TracBrowser for help on using the repository browser.