source: 2015/26/ohjaajat/HillbillyRun/HillbillyRun/HillbillyRun/HillbillyRun/HillbillyRun.cs @ 6412

Revision 6412, 53.0 KB checked in by jotapoti, 5 years ago (diff)

Kenttiin taustamusiikki

Line 
1using System;
2using System.Collections.Generic;
3using System.Diagnostics.CodeAnalysis;
4using System.Linq;
5using System.Runtime.InteropServices;
6using Jypeli;
7using Jypeli.Assets;
8using Jypeli.Controls;
9using Jypeli.Effects;
10using Jypeli.Widgets;
11
12/* Muistutuksia.
13 *
14 * Layerit
15 *   3 -
16 *   2 -
17 *   1 -
18 *   0 -
19 *  -1 - Näkyvä maanpinta.
20 *  -2 - Talot taustalla.
21 * 
22 * CollisionIgnoreGroupit
23 *  3 - Ryömivät ja liekit. //TODO: lisätä noidatkin tänne
24 *  2 - Kärry.
25 *
26*/
27
28#region Improvement
29public abstract class Improvement : PlatformCharacter
30{
31    public List<Animation> Animations { get; set; }
32
33    protected Improvement(double width, double height)
34        : base(width, height)
35    {
36
37    }
38
39    public HillBilly Owner
40    {
41        get { return owner; }
42        set { owner = value; }
43    }
44    private HillBilly owner;
45
46    public virtual void DoTheThing(HillbillyRun game) { }
47
48    public SoundEffect sound;
49
50    public void Rid()
51    {
52        Owner.AnimWalk = Owner.Animations[0];
53        Owner.AnimIdle = Owner.Animations[1];
54        Owner.Improvement = null;
55        Owner = null;
56    }
57}
58
59public class MilkImprovement : Improvement
60{
61    public override void DoTheThing(HillbillyRun game)
62    {
63        //HillbillyRun game = this.Game as HillbillyRun;
64        Owner.PlayAnimation(Animations[1]);
65        game.CreateMilkParticles(this.Owner, 10, 200, 300, new Vector(0, -30), "milkparticle");
66        this.sound.Play();
67    }
68
69    public MilkImprovement(double width, double height)
70        : base(width, height)
71    {
72
73    }
74}
75
76
77public class PitchForkImprovement : Improvement
78{
79    public override void DoTheThing(HillbillyRun game)
80    {
81        //HillbillyRun game = this.Game as HillbillyRun;
82        //game.CreateMilkParticles(this.Owner, 10, 200, 300, new Vector(0, -30), "milkparticle");
83        //TODO: hitting things w/ pitchfork
84        game.ForkThings(Owner);
85    }
86
87    public PitchForkImprovement(double width, double height)
88        : base(width, height)
89    {
90
91    }
92}
93#endregion
94
95public class HillBilly : PlatformCharacter
96{
97    public List<Animation> Animations { get; set; }
98
99    private IntMeter lifeCounter = new IntMeter(4, 0, 4);
100    public IntMeter Life
101    {
102        set { lifeCounter = value; }
103        get { return lifeCounter; }
104    }
105
106    public Improvement Improvement { get; set; }
107
108    public Label Name { get; set; }
109
110    private ProgressBar visibleLife;
111    public ProgressBar VisibleLife
112    {
113        get { return visibleLife; }
114        set { visibleLife = value; }
115    }
116
117    public void GainImprovement(Improvement improvement)
118    {
119
120        this.AnimWalk = improvement.Animations[0];
121        this.AnimIdle = new Animation(improvement.Animations[0].CurrentFrame);
122        this.Improvement = improvement;
123        improvement.Owner = this;
124
125        //improvement.Destroy();
126    }
127
128    public void UseImprovement()
129    {
130        HillbillyRun game = this.Game as HillbillyRun;
131        if (this.Improvement == null)
132        {
133            game.CreateMilkParticles(this, 5, 100, 100, new Vector(0, Height / 3), "tears");
134        }
135        else if (Animation != this.Improvement.Animations[1])
136        {
137            this.Improvement.DoTheThing(game);
138        }
139    }
140
141    public HillBilly(double leveys, double korkeus, String name)
142        : base(leveys, korkeus)
143    {
144
145        this.visibleLife = new ProgressBar(50, 15); //(this.Width, this.Height/8);
146        this.Add(visibleLife);
147        this.visibleLife.Position += new Vector(0, this.Height / 2 + this.Height / 5);
148        this.visibleLife.BindTo(this.lifeCounter);
149        this.visibleLife.Color = Color.Black;
150
151        this.Name = new Label(name);
152        this.Add(Name);
153        this.Name.Position += new Vector(0, this.Height / 2 + this.Height / 3);
154    }
155}
156
157/// <summary>
158/// An MMO where you go to war with mages in the lava kingdom.
159/// </summary>
160public class HillbillyRun : PhysicsGame
161{
162    private List<HillBilly> players = new List<HillBilly>();
163    private List<HillBilly> startingPlayers = new List<HillBilly>();
164
165    //private List<double> playerPositionsX = new List<double>();
166    //private List<double> playerPositionsY = new List<double>();
167
168    private const double PLAYER_SPEED = 180;
169    public const double TILE_SIZE = 70;
170
171    public String[] names = new String[] { "Adolfiina", "Rasputiina", "Hermanniina", "Joosefiina" };
172
173    private double cameraTargetX; // Sijainti jossa kameran pitäisi olla.
174    private Vector cameraTarget;
175
176    private double cameraOffset; //= 400; // TODO: Tämän voisi ehkä laskea jostain (esim. ikkunan leveydestä kolmasosa tai jotain).
177    private double cameraSpeed = 2.0; // Kameran liikkumisnopeus.
178
179    # region Images
180    private Image[] groundImages = LoadImages("ground", "ground_forest", "ground_volcano");
181    private Image[] groundTopImages = LoadImages("ground_top", "ground_top_forest", "ground_top_volcano");
182    private Image[] foregroundDecorations = LoadImages("viljaa", "grass", "grass");
183    private Image[] blockImages = LoadImages("box2", "rock");
184
185    private Image[] houseImages = LoadImages("house", "houseburned");
186
187    private Image cartImage = LoadImage("cart");
188    private Image milkImage = LoadImage("tonkkaitem");
189    private Image pitchforkImage = LoadImage("fork");
190
191    private Image cartWheelImage = LoadImage("cartwheel");
192
193    private Image smokeImage1 = LoadImage("smoke1");
194    private Image smokeImage2 = LoadImage("smoke2");
195
196    private Image treeTrunkImage = LoadImage("bigtree");
197    private Image treeBottomImage = LoadImage("bigtree3x2");
198    private Image treeBranchImage = LoadImage("bigtreebranch");
199    private Image forestBackgroundImage = LoadImage("forestbackground");
200    private Image volcanoBackgroundImage = LoadImage("volcanobackground");
201    private Image swingTrapImage = LoadImage("tukki");
202
203    private Image gateImage = LoadImage("gate");
204    private Image leverLeftImage = LoadImage("lever_left");
205    private Image leverRightImage = LoadImage("lever_right");
206
207    private Image lavaWallImage = LoadImage("lavawall");
208    private Image lavaFloorImage = LoadImage("lavafloor");
209    private Image spikeImage = LoadImage("spikes");
210    private Image spikeLeftImage = LoadImage("spikeleft");
211
212    private Image prisonerImage = LoadImage("prisoner");
213
214    private Image deathImage = LoadImage("loppukuva");
215
216    private Animation crawl;
217    private Animation blaze;
218
219    private Animation pitchforkAttack;
220    private Animation pitchforkWalk;
221    private Animation milkThrow;
222    private Animation milkWalk;
223    private Animation normalWalk;
224    private Animation playerIdle;
225    private Animation playerJump;
226    private Animation playerFall;
227    private Animation firemageAnimation;
228    private Animation firemageCastAnimation;
229    private Animation wormAnimation;
230    private Animation tattiMageAnimation;
231    private Animation tattiMageCastAnimation;
232    private Animation fireballAnimation;
233
234    private Animation bossRiseAnimation;
235    private Animation bossFallAnimation;
236    private Animation bossHitAnimation;
237    private Animation bossHurtAnimation;
238    #endregion
239
240    #region Sounds
241    private SoundEffect splash = LoadSoundEffect("splash");
242    #endregion
243
244    private double leftCamLimit;
245    private double rightCamLimit;
246    private double bottomCamLimit;
247
248    private int levelNumber = 0;
249
250    private Action activateBoss;
251    private Timer fireballTimer;
252
253    public override void Begin()
254    {
255        Initializing();
256        IntroSequence();
257        //MainMenu();
258        //StartGame();
259    }
260
261    #region Intro
262    void IntroSequence()
263    {
264        Level.Background.Color = Color.Black;
265
266        Keyboard.Listen(Key.Escape, ButtonState.Pressed, SkipIntro, "Skip");
267        Keyboard.Listen(Key.Enter, ButtonState.Pressed, SkipIntro, "Skip");
268
269        ShowMadeWithJypeli();
270
271        Timer.SingleShot(4.0, delegate // TODO get rid of fixed amount of seconds
272        {
273            ShowBackgroundStory();
274        });
275
276
277
278    }
279
280    void ShowMadeWithJypeli()
281    {
282        Image madewithImage = LoadImage("madewithjypeli");
283
284        double w = Window.Width / 4;
285        double h = w * (madewithImage.Height / (double)madewithImage.Width); // take aspect ratio from the picture
286
287        GameObject madewithjypeliObject = new GameObject(w, h);
288        madewithjypeliObject.Image = madewithImage;
289        Add(madewithjypeliObject);
290
291        // Tässä oli jotain epätehokasta feidailua tuolle Made with Jypeli -kuvalle. Ei tunnu päivittyvän joka framella tai on muuten vain tosi raskas...
292
293        //fadeTimer = new Timer();
294        //fadeTimer.Interval = 0.5;
295        //fadeTimer.Timeout += delegate
296        //{
297        //    madewithjypeliObject.Image = LerpImage(madewithjypeliObject.Image, Color.Black, 0.6);
298        //};
299        //fadeTimer.Start(5);
300
301        Timer.SingleShot(1.2, delegate
302        {
303            madewithjypeliObject.Destroy();
304        });
305
306    }
307
308    Image LerpImage(Image original, Color targetColor, double ratio)
309    {
310        Image newImage = new Image(original.Width, original.Height, Color.Transparent);
311        for (int y = 0; y < original.Height; y++)
312        {
313            for (int x = 0; x < original.Width; x++)
314            {
315                newImage[y, x] = Color.Lerp(original[y, x], targetColor, ratio);
316            }
317        }
318        return newImage;
319    }
320
321    void ShowBackgroundStory()
322    {
323        MediaPlayer.Play("hillbilly_intro");
324        ShowStoryText(new Queue<string>(new[] { "Innit just da warmest here, sis?", "Seems to me our establishment's a-burnin'.", "...Must've been 'em nasty witches!" }));
325    }
326
327    void ShowStoryText(Queue<string> messages)
328    {
329        // Mennään alkuvalikkoon jos ei ole enää viestejä.
330        if (messages.Count == 0)
331        {
332            MainMenu();
333            return;
334        }
335
336        // Näytetään nykyinen viesti.
337        var storyLabel = new Label(messages.Dequeue()) { TextColor = Color.Black, TextScale = new Vector(3, 3) };
338        Add(storyLabel);
339
340        var textTimer = new Timer { Interval = 0.05 };
341        textTimer.Timeout += () => storyLabel.TextColor = Color.Lerp(storyLabel.TextColor, Color.White, 0.05);
342        textTimer.Start();
343
344        // Näytetään seuraava viesti muutaman sekunnin päästä.
345        Timer.SingleShot(4, delegate { storyLabel.Destroy(); ShowStoryText(messages); });
346    }
347
348    void SkipIntro()
349    {
350        ClearTimers();
351        ClearAll();
352        Keyboard.Clear();
353        MainMenu();
354    }
355
356    void MainMenu()
357    {
358        Level.Background.CreateGradient(Color.DarkBrown, Color.Black);
359       
360        if (MediaPlayer.IsPlaying == false) MediaPlayer.Play("hillbilly_intro");
361
362        MultiSelectWindow mainmenu = new MultiSelectWindow("Main menu", "Start game", "Credits", "Exit");
363        mainmenu.AddItemHandler(0, StartGame);
364        mainmenu.AddItemHandler(1, ShowCredits);
365        mainmenu.AddItemHandler(2, Exit);
366        mainmenu.DefaultCancel = 2;
367        Add(mainmenu);
368        mainmenu.Color = Color.DarkBrown;
369        mainmenu.FadeColorTo(Color.Brown, 30);
370        mainmenu.SetButtonColor(Color.Charcoal);
371        mainmenu.SelectionColor = Color.DarkBlue;
372        mainmenu.SetButtonTextColor(Color.LightGray);
373       
374
375    }
376
377    void ShowCredits()
378    {
379        MessageWindow win = new MessageWindow("This game was made in one week by\nSimo Rinne,\nEmma Heikura,\n and Jouni Potila\n using University of Jyväskylä's\n game programming library Jypeli");
380        win.Closed += delegate
381        {
382            ClearAll();
383            MainMenu();
384        };
385        Add(win);
386    }
387    #endregion
388
389    void StartGame()
390    {
391        ClearAll();
392        CreateLevel();
393        MediaPlayer.Play("hillbilly_level0");
394        MediaPlayer.IsRepeating = true;
395        ScreenSettings();
396        SetControls();
397    }
398
399    public void NextLevel()
400    {
401        levelNumber++;
402        StartGame();
403    }
404
405    void Initializing()
406    {
407        crawl = LoadAnimation("crawl");
408        blaze = LoadAnimation("flame");
409        pitchforkAttack = LoadAnimation("attack");
410        pitchforkWalk = LoadAnimation("hanko");
411        milkThrow = LoadAnimation("heitto");
412        milkWalk = LoadAnimation("tonkka");
413        normalWalk = LoadAnimation("pwalk");
414        playerIdle = LoadAnimation("idle");
415        playerJump = LoadAnimation("jump");
416        playerFall = LoadAnimation("fall");
417        firemageAnimation = LoadAnimation("firemage");
418        firemageCastAnimation = LoadAnimation("firemagecast");
419        wormAnimation = LoadAnimation("worm");
420        tattiMageAnimation = LoadAnimation("tattimage");
421        tattiMageCastAnimation = LoadAnimation("tattimagecast");
422        bossRiseAnimation = LoadAnimation("bossrise");
423        bossFallAnimation = LoadAnimation("bossfall");
424        bossHitAnimation = LoadAnimation("bosshit");
425        bossHurtAnimation = LoadAnimation("bosshurt");
426        fireballAnimation = LoadAnimation("fireball");
427
428        cameraOffset = Window.Width / 4;
429    }
430
431    void ScreenSettings()
432    {
433        Window.Width = 1800;
434        Window.Height = 900;
435
436        leftCamLimit = Level.Left + Window.Width / 2.0;
437        rightCamLimit = Level.Right - Window.Width / 2.0;
438        bottomCamLimit = Level.Bottom + Window.Height / 2.0;
439
440        Camera.X = cameraTarget.X = cameraTargetX = leftCamLimit;
441
442        Timer cameraTimer = new Timer();
443        cameraTimer.Interval = 1 / 30.0;
444        cameraTimer.Timeout += UpdateCamera;
445        cameraTimer.Start();
446
447        // Background trees.
448        if (levelNumber < 2)
449        {
450            GameObject forestBackground = new GameObject(Level.Width, Level.Height);
451            forestBackground.Image = forestBackgroundImage;
452            forestBackground.TextureWrapSize = new Vector(5, 1);
453            Add(forestBackground, -3);
454            Layers[-3].RelativeTransition = new Vector(0.5, 1.0);
455        }
456
457        // Background color.
458        if (levelNumber == 0)
459        {
460            Level.Background.CreateGradient(Color.Black, Color.SkyBlue);
461        }
462        else if (levelNumber == 1)
463        {
464            Level.Background.CreateGradient(Color.Black, Color.FromHexCode("495147"));
465        }
466        else if (levelNumber == 2)
467        {
468            Level.Background.Image = volcanoBackgroundImage;
469            Level.Background.FitToLevel();
470        }
471    }
472
473    #region LevelCreation
474    void CreateLevel()
475    {
476        startingPlayers.Clear();
477        players.Clear();
478        Gravity = new Vector(0, -1000);
479
480        //Tilemap
481        ColorTileMap level = ColorTileMap.FromLevelAsset("level" + levelNumber);
482        //ColorTileMap level = ColorTileMap.FromLevelAsset("bosstest");
483        level.SetTileMethod(Color.Black, CreateGroundTop);
484        level.SetTileMethod(Color.Brown, CreateGround);
485
486        level.SetTileMethod(Color.Cyan, CreateHouse);
487        level.SetTileMethod(Color.PaintDotNetBlue, CreateBurnedHouse);
488
489        level.SetTileMethod(Color.Gold, CreatePlayer);
490        level.SetTileMethod(Color.Harlequin, CreateCart);
491        level.SetTileMethod(Color.FromHexCode("A17FFF"), CreatePitchfork);
492
493        level.SetTileMethod(Color.Gray, (new AbstractTileMap<Color>.TileMethod[] { CreateCrawly, CreateWorm, null })[levelNumber]); // ಠ_ಠ
494        level.SetTileMethod(Color.Red, (new AbstractTileMap<Color>.TileMethod[] { CreateFireMage, CreateShroom, CreateBoss })[levelNumber]);
495        level.SetTileMethod(Color.White, CreateBlockObject);
496        level.SetTileMethod(Color.DarkGray, CreateMilk);
497        level.SetTileMethod(Color.Rose, CreateFlame, true);
498        //level.SetTileMethod(Color.Azure, CreateDummy, Color.Azure);   //TODO: CreateSmoke
499        //level.SetTileMethod(Color.Orange, CreateDummy, Color.Orange); //TODO: CreateTombstone
500
501        level.SetTileMethod(Color.FromHexCode("FF6A00"), CreateTreeTrunk);  //Pihhh jostain heksoista. Ikävästi haisee luovuttamiselta! :----D
502        level.SetTileMethod(Color.FromHexCode("57007F"), CreateTreeRoot);   // Heksojen käytössä ei ole mitään hävettävää :P
503        level.SetTileMethod(Color.FromHexCode("00FF21"), CreateTreeBranch);
504        level.SetTileMethod(Color.FromHexCode("5B7F00"), CreateSwingTrap);
505
506        level.SetTileMethod(Color.FromHexCode("7FBA00"), CreateGate);
507        level.SetTileMethod(Color.FromHexCode("4C7F00"), CreateLevel);
508
509        level.SetTileMethod(Color.FromHexCode("FF00DC"), CreateSpike, spikeImage);
510        level.SetTileMethod(Color.FromHexCode("C600AC"), CreateSpike, spikeLeftImage);
511
512        level.SetTileMethod(Color.FromHexCode("FF8C8C"), CreateLava);
513
514        level.SetTileMethod(Color.FromHexCode("BADA55"), CreatePrisoner); // Lempivärini.
515
516        level.Optimize(Color.Brown);    //Color.Black   //Tekee jännittäviä asioita wheatille, jos optimoidaan (tietysti). Jotenn.
517        level.Execute(TILE_SIZE, TILE_SIZE);
518
519        // Kolmanteen kenttään laavaseinä ja tulipalloja
520        if (levelNumber == 2)
521        {
522            GameObject lava = new GameObject(300, Level.Height);
523            lava.Image = lavaWallImage;
524            lava.X = Camera.ScreenToWorld(new Vector(-Window.Width / 2.0, 0)).X;
525            Add(lava, 3);
526
527            PhysicsObject lavaCollision = PhysicsObject.CreateStaticObject(50, Level.Height);
528            lavaCollision.IsVisible = false;
529            lavaCollision.Left = lava.Left;
530            lavaCollision.Tag = "lava";
531            Add(lavaCollision);
532
533            var updateTimer = new Timer { Interval = 0.01 };
534            updateTimer.Timeout += delegate
535            {
536                lava.Left = Camera.X - Window.Width / 2.0;
537                lavaCollision.Left = lava.Left;
538            };
539            updateTimer.Start();
540
541            fireballTimer = new Timer { Interval = 10.0 };
542            fireballTimer.Timeout += delegate
543            {
544                var fireball = PhysicsObject.CreateStaticObject(100, 40);
545                fireball.IgnoresCollisionResponse = true;
546                fireball.Animation = new Animation(fireballAnimation);
547                fireball.Animation.Start();
548                fireball.Y = RandomGen.SelectOne<HillBilly>(players).Position.Y;
549                fireball.X = Camera.X + Window.Width / 2.0;
550                fireball.Velocity = new Vector(-100, 0);
551                fireball.LifetimeLeft = TimeSpan.FromSeconds(20);
552                fireball.Tag = "burn";
553                Add(fireball);
554            };
555            fireballTimer.Start();
556        }
557    }
558
559    void CreateBoss(Vector position, double width, double height)
560    {
561        GameObject boss = new GameObject(700, 522);
562        boss.Position = position;
563        boss.Top = position.Y - height * 0.5;
564        boss.Animation = bossRiseAnimation;
565        Add(boss, -3);
566
567        List<PhysicsObject> eyes = null; // Lista jotta voi käyttää kätevästi ForEach:ia.
568        var health = new IntMeter(3, 0, 3); // Vähenee vain heinähangolla.
569        var eyeHealth = new IntMeter(30, 0, 30); // Vähenee maidon loiskutuksella.
570
571        eyeHealth.LowerLimit += delegate
572        {
573            // Bossi kaatuaa maahan.
574            eyes.ForEach(e => e.IsVisible = false);
575            boss.Animation = bossFallAnimation;
576            boss.Animation.StopOnLastFrame = true;
577            boss.Animation.Start(1);
578
579            // Bossi palautuu takaisin lyöntianimaatioonsa hetken päästä.
580            Timer.SingleShot(5.0, delegate
581            {
582                boss.Animation = bossHitAnimation;
583                eyeHealth.Value = eyeHealth.MaxValue;
584                eyes.ForEach(e => e.IsVisible = true);
585            });
586        };
587
588        // Alue johon pitää lyödä heinähangolla.
589        var headCollision = PhysicsObject.CreateStaticObject(50, 50);
590        headCollision.IsVisible = false;
591        headCollision.IgnoresCollisionResponse = true;
592        Add(headCollision);
593        AddCollisionHandler(headCollision, "pitchfork", delegate(PhysicsObject h, PhysicsObject fork)
594        {
595            if (boss.Animation == bossFallAnimation)
596            {
597                health.Value--;
598
599                boss.Animation = bossHurtAnimation;
600                boss.Animation.Start(1);
601                boss.Animation.Played += () => boss.Animation = bossFallAnimation;
602            }
603        });
604        var headMoveTimer = new Timer { Interval = 0.01 };
605        headMoveTimer.Timeout += delegate
606        {
607            headCollision.Position = boss.Position + new Vector(-10, 0);
608        };
609        headMoveTimer.Start();
610        headCollision.Destroyed += headMoveTimer.Stop;
611
612        // Lyöntianimaation päätteeksi lisätään kiviä.
613        bossHitAnimation.Played += delegate
614        {
615            var rock = new PhysicsObject(30, 30);
616            rock.Position = boss.Position + new Vector(RandomGen.NextDouble(-650, 100), 300);
617            rock.Image = blockImages[1];
618            rock.Tag = "burn";
619            rock.LifetimeLeft = TimeSpan.FromSeconds(2.0);
620            Add(rock);
621        };
622
623        // Silmien luonti funktio.
624        Func<int, int, PhysicsObject> eyeFlame = (x, y) =>
625        {
626            var flame = PhysicsObject.CreateStaticObject(width * 0.3, height * 0.6);
627            flame.Animation = new Animation(blaze);
628            flame.IgnoresCollisionResponse = true;
629            flame.IsVisible = false;
630            flame.Animation.Start();
631            Add(flame);
632            AddCollisionHandler(flame, "milkparticle", delegate(PhysicsObject f, PhysicsObject particle)
633            {
634                // Otetaan vahinkoa vain kun ollaan näkyvillä.
635                if (flame.IsVisible)
636                {
637                    particle.Destroy();
638                    eyeHealth.Value--;
639                }
640            });
641            var moveTimer = new Timer { Interval = 0.01 };
642            moveTimer.Timeout += delegate
643            {
644                flame.Position = boss.Position + new Vector(x, y);
645            };
646            moveTimer.Start();
647            flame.Destroyed += moveTimer.Stop;
648            return flame;
649        };
650
651        eyes = new List<PhysicsObject>(new[] { eyeFlame(0, 150), eyeFlame(40, 145) });
652
653        // Tuhotaan bossi kun se kuolee.
654        health.LowerLimit += delegate
655        {
656            eyes.ForEach(e => e.Destroy());
657            boss.Destroy();
658            headCollision.Destroy();
659            Timer.SingleShot(4.0, Victory);
660        };
661
662        // Kutsutaan kun pelaajat saapuu kentän päähän.
663        activateBoss = delegate
664        {
665            // Nostetaan bossi ylös maasta.
666            boss.MoveTo(position + new Vector(0, boss.Height * 0.4), 500);
667            boss.Animation.Start(1);
668            boss.Animation.StopOnLastFrame = true;
669            boss.Animation.Played += delegate
670            {
671                // Taistelu alkaa.
672                eyes.ForEach(e => e.IsVisible = true);
673
674                // Laitetaan lyöntianimaatio päälle.
675                boss.Animation = bossHitAnimation;
676                boss.Animation.Start();
677            };
678        };
679    }
680
681    void CreatePrisoner(Vector position, double width, double height)
682    {
683        GameObject prisoner = new GameObject(width * 1.2, height * 2);
684        prisoner.Position = position;
685        prisoner.Y -= height / 2.0;
686        prisoner.Image = prisonerImage;
687        Add(prisoner, 1);
688    }
689
690    void CreateSpike(Vector position, double width, double height, Image img)
691    {
692        PhysicsObject spike = PhysicsObject.CreateStaticObject(width, height);
693        spike.Image = img;
694        spike.Position = position;
695        spike.Y -= (img == spikeImage) ? height * 0.5 : 0.0;
696        spike.Tag = "burn";
697        Add(spike);
698    }
699
700    void CreateLava(Vector position, double width, double height)
701    {
702        GameObject lava = new GameObject(width * 13, height * 5);
703        lava.Image = lavaFloorImage;
704        lava.Position = position;
705        lava.Left = position.X - width * 0.5;
706        lava.Bottom = position.Y - height * 0.5;
707        Add(lava, 3);
708
709        PhysicsObject lavaCollision = PhysicsObject.CreateStaticObject(width * 13, height);
710        lavaCollision.IsVisible = false;
711        lavaCollision.Position = position;
712        lavaCollision.Left = position.X - width * 0.5;
713        lavaCollision.Tag = "lava";
714        Add(lavaCollision);
715    }
716
717    void CreateGate(Vector position, double width, double height)
718    {
719        PhysicsObject gate = PhysicsObject.CreateStaticObject(width, height);
720        gate.Image = gateImage;
721        gate.Color = Color.HotPink;
722        gate.Position = position;
723        gate.Y -= height / 2.0;
724        gate.Tag = "gate";
725        Add(gate);
726    }
727
728    void CreateLevel(Vector position, double width, double height)
729    {
730        PhysicsObject lever = PhysicsObject.CreateStaticObject(width * 0.5, height);
731        lever.Image = leverLeftImage;
732        lever.Color = Color.Green;
733        lever.Position = position;
734        lever.Y -= height / 2.0;
735        lever.IgnoresCollisionResponse = true;
736        Add(lever);
737
738        AddCollisionHandler(lever, "player", delegate(PhysicsObject p, PhysicsObject l)
739        {
740            if (lever.Image == leverLeftImage)
741            {
742                lever.Image = leverRightImage;
743                GetObjectsWithTag("gate").ForEach(g => g.Destroy());
744            }
745        });
746    }
747
748    void CreateSwingTrap(Vector position, double width, double height)
749    {
750        const double swingArc = 30; // Heiluu 30 astetta edestakaisin.
751        const double swingSpeed = 1.5;
752        const double ropeLength = 400;
753        var center = position + new Vector(0, ropeLength);
754
755        // Ajastukset heilutteluun.
756        double deltaTime = 1 / 60.0;
757        double time = 0.0;
758
759        PhysicsObject swing = PhysicsObject.CreateStaticObject(width, height);
760        swing.Image = swingTrapImage;
761        swing.Position = position;
762        Add(swing);
763
764        GameObject rope = new GameObject(ropeLength, 10);
765        rope.Color = new Color(10, 30, 10);
766        Add(rope);
767
768        var updateTimer = new Timer { Interval = deltaTime };
769        updateTimer.Timeout += delegate
770        {
771            time += deltaTime;
772
773            // Heilurin kulma on sinimuotoinen funktio ajan suhteen.
774            var angle = Angle.FromDegrees(-90.0 + Math.Sin(time * swingSpeed) * swingArc);
775            swing.Position = center + angle.GetVector() * ropeLength;
776            swing.Angle = angle;
777
778            // Päivitetään narun sijainti ja kulma.
779            rope.Angle = angle;
780            rope.Position = center + angle.GetVector() * ropeLength * 0.5;
781        };
782        updateTimer.Start();
783    }
784
785    void CreatePitchfork(Vector position, double width, double height)
786    {
787        double size = 30;
788        double ratio = pitchforkImage.Width / pitchforkImage.Height;
789
790        Improvement fork = new PitchForkImprovement(size * ratio, size);
791        fork.Image = pitchforkImage;
792        fork.Animations = new List<Animation> { pitchforkWalk, pitchforkAttack };
793        fork.Position = position;
794        fork.Tag = "improvement";
795        Add(fork);
796
797    }
798
799    void CreateTreeBranch(Vector position, double width, double height)
800    {
801        PhysicsObject branch = PhysicsObject.CreateStaticObject(width, height);
802        branch.Position = position;
803        branch.Image = treeBranchImage;
804        Add(branch, -1);
805    }
806
807    void CreateTreeTrunk(Vector position, double width, double height)
808    {
809        GameObject trunk = new GameObject(width * 3, height);
810        trunk.Position = position;
811        trunk.Image = treeTrunkImage;
812        Add(trunk, -1);
813    }
814
815    void CreateTreeRoot(Vector position, double width, double height)
816    {
817        GameObject roots = new GameObject(width * 9, height * 4);
818        roots.Position = position;
819        roots.Y -= height;
820        roots.Image = treeBottomImage;
821        Add(roots, -1);
822    }
823
824    void CreateFlame(Vector position, double width, double height, bool suuri)
825    {
826        PhysicsObject flame = new PhysicsObject(width, height * 2);
827        //flame.Image = flameImage;
828        flame.Color = Color.Red;
829        double hieman = height * 0.3;
830        flame.Position = position - new Vector(0, hieman);
831        flame.CollisionIgnoreGroup = 3;
832        flame.Tag = "burn";
833        flame.Animation = new Animation(blaze) { FPS = RandomGen.NextInt(20, 26) };
834        flame.Animation.Step(RandomGen.NextInt(0, 12));
835        flame.Animation.Resume();
836        flame.CanRotate = false;
837        Add(flame, 1);
838
839        Smoke savu = new Smoke();
840        if (suuri)
841        {
842            flame.IgnoresCollisionResponse = true;
843
844            savu.ParticleImage = smokeImage1;
845            savu.OuterParticleImage = smokeImage2;
846            savu.MaxLifetime = 1.0;
847            savu.MaxScale = 200;
848            savu.MinScale = 10;
849            savu.Position = flame.Position;
850            Wind = new Vector(-10, 0);
851            Add(savu);
852            flame.MakeStatic();
853        }
854
855        AddCollisionHandler(flame, "milkparticle", delegate(PhysicsObject c, PhysicsObject particle)
856        {
857            particle.Destroy();
858            flame.Destroy();
859            savu.Destroy();
860
861        });
862    }
863
864    void CreateBlockObject(Vector position, double width, double height)
865    {
866        // Säädin vähän tätä jotta laatikko näkyy hyvin. Pitää ehkä tehdä laatikolle ihan oma metodi.
867        PhysicsObject block = PhysicsObject.CreateStaticObject(width, height);
868        block.IsVisible = false;
869        //block.Image = blockImages[levelNumber];
870        block.Position = position;
871        block.Y -= height / 2.0;
872        Add(block, 1);
873
874        GameObject visibleBlock = new GameObject(width, height * 1.5);
875        visibleBlock.Position = position;
876        visibleBlock.Image = blockImages[levelNumber];
877        visibleBlock.Y -= height / 2.0;
878        Add(visibleBlock, -1);
879    }
880
881    void CreateMilk(Vector position, double width, double height)
882    {
883        double size = 30;
884        double ratio = milkImage.Height / milkImage.Width;
885
886        Improvement milk = new MilkImprovement(size, size * ratio);
887        milk.Image = milkImage;
888        milk.Animations = new List<Animation> { milkWalk, milkThrow };
889        milk.Position = position;
890        //milk.Tag = "milk";
891        milk.Tag = "improvement";
892        milk.sound = splash;
893        Add(milk);
894
895        //PhysicsObject milk = new PhysicsObject(size, size * ratio);
896        //milk.Image = milkImage;
897        //milk.Position = position;
898        //milk.Tag = "milk";
899        //Add(milk);
900    }
901
902    void CreateWorm(Vector position, double width, double height)
903    {
904        PlatformCharacter worm = new PlatformCharacter(width, height * 0.6);
905        worm.Position = position;
906        worm.Animation = new Animation(wormAnimation);
907        worm.Animation.FPS = RandomGen.NextInt(18, 24);
908        worm.Animation.Step(RandomGen.NextInt(0, 16));
909        worm.Animation.Resume();
910        worm.Tag = "worm";
911        worm.CollisionIgnoreGroup = 3;
912        Add(worm, 1);
913
914        PlatformWandererBrain brain = new PlatformWandererBrain();
915        brain.Speed = 60;
916        brain.FallsOffPlatforms = false;
917        brain.TriesToJump = true;
918        worm.Brain = brain;
919
920        AddCollisionHandler(worm, "pitchfork", delegate(PhysicsObject w, PhysicsObject p) { w.Destroy(); });
921    }
922
923    void CreateCrawly(Vector position, double width, double height)
924    {
925        PlatformCharacter crawly = new PlatformCharacter(width * 2, height * 0.6);
926        crawly.Position = position;
927        crawly.Color = Color.Gray;
928        crawly.Animation = new Animation(crawl);
929        crawly.Animation.FPS = RandomGen.NextInt(18, 24);
930        crawly.Animation.Step(RandomGen.NextInt(0, 16));
931        crawly.Animation.Resume();
932        crawly.Tag = "burn";
933        crawly.CollisionIgnoreGroup = 3;
934        Add(crawly, 1);
935
936        GameObject flame = new GameObject(width * 1.4, height * 2);
937        flame.Animation = new Animation(blaze) { FPS = RandomGen.NextInt(20, 26) };
938        flame.Animation.Step(RandomGen.NextInt(0, 12));
939        flame.Animation.Resume();
940        Add(flame);
941
942        // Pakko liikutella näin koska lapsioliona liekki näkyisi ryömijän päällä.
943        Timer flameMover = new Timer { Interval = 0.05 };
944        flameMover.Timeout += delegate
945        {
946            double hieman = height * 0.75;
947            flame.Position = crawly.Position + new Vector(0, hieman);
948        };
949        flameMover.Start();
950
951        PlatformWandererBrain brain = new PlatformWandererBrain();
952        brain.Speed = 20;
953        brain.FallsOffPlatforms = true;
954
955        crawly.Brain = brain;
956
957        // Sammuu törmätessään maitoon.
958        AddCollisionHandler(crawly, "milkparticle", delegate(PhysicsObject c, PhysicsObject particle)
959        {
960            particle.Destroy();
961            crawly.Brain = null;
962            crawly.Animation = new Animation(crawly.Animation.CurrentFrame);
963            crawly.Tag = "";
964            flame.Destroy();
965            RemoveCollisionHandlers(crawly);
966        });
967    }
968
969    void CreateShroom(Vector position, double width, double height)
970    {
971        PlatformCharacter shroom = new PlatformCharacter(width, height * 2);
972        shroom.Position = position + new Vector(0, shroom.Height / 2);
973        shroom.Tag = "burn";
974        shroom.Tag += "shroom";
975        //shroom.AnimWalk = new Animation();
976        shroom.CollisionIgnoreGroup = 3;
977        Add(shroom, 1);
978        //bool immune = false;
979
980        PlatformWandererBrain brain = new PlatformWandererBrain();
981        brain.Speed = 20;
982        brain.FallsOffPlatforms = false;
983        shroom.Brain = brain;
984
985        FollowerBrain attackBrain = new FollowerBrain("player");
986        attackBrain.DistanceFar = Window.Width / 2.5;
987        attackBrain.DistanceClose = Window.Width / 2;
988        attackBrain.StopWhenTargetClose = false;
989        attackBrain.Speed = brain.Speed * 6;
990        attackBrain.FarBrain = brain;
991        shroom.Brain = attackBrain;
992
993        int matoja = RandomGen.NextInt(1, 3);
994        int rahkeet = 10;
995
996        //// Taiotaan matoja
997        var castTimer = new Timer { Interval = 6.0 };
998        castTimer.Timeout += delegate
999        {
1000            //shroom.PlayAnimation();
1001
1002            Timer.SingleShot(RandomGen.NextDouble(3, 5), delegate { shroom.Brain = attackBrain; });
1003
1004            Timer.SingleShot(1.5,
1005                delegate
1006                {
1007                    for (int i = 0; i < matoja; i++)
1008                    {
1009                        CreateWorm(shroom.Position + RandomGen.NextVector(-200, 0, 200, 0), TILE_SIZE, TILE_SIZE);
1010                        shroom.Brain = brain;
1011                    }
1012                });
1013
1014
1015        };
1016
1017        attackBrain.TargetClose += delegate()
1018        {
1019            if (!castTimer.Enabled)
1020            {
1021                castTimer.Start();
1022            }
1023        };
1024
1025        AddCollisionHandler(shroom, "pitchfork", delegate(PhysicsObject s, PhysicsObject f)
1026        {
1027            matoja += RandomGen.NextInt(1, 5);
1028            rahkeet--;
1029            if (rahkeet < 1)
1030            {
1031                shroom.Destroy();
1032                castTimer.Stop();
1033                //Timer.SingleShot(6, NextLevel);
1034            }
1035        });
1036    }
1037
1038    void CreateFireMage(Vector position, double width, double height)
1039    {
1040        PlatformCharacter mage = new PlatformCharacter(width * 3, height * 4);
1041        mage.Position = position;
1042        mage.Y += mage.Height / 2.0;
1043        mage.Tag = "burn";
1044        mage.Tag += "fireMage";
1045        mage.AnimWalk = new Animation(firemageAnimation);
1046        mage.CollisionIgnoreGroup = 3;
1047        Add(mage, 1);
1048        bool immune = false;
1049
1050        // Pään päällä oleva liekki (taitaa olla vähän huonossa kohtaa tällä hetkellä)
1051        PhysicsObject flame = new PhysicsObject(width * 1.4, height * 2);
1052        flame.Y += mage.Height * 0.65;
1053        flame.X += mage.FacingDirection.GetVector().X + 30;
1054        flame.Animation = new Animation(blaze);
1055        flame.IgnoresPhysicsLogics = true;
1056        flame.Animation.Start();
1057        mage.Add(flame);
1058
1059        PlatformWandererBrain brain = new PlatformWandererBrain();
1060        brain.Speed = 20;
1061        brain.FallsOffPlatforms = false;
1062        //mage.Brain = brain;
1063
1064        //PhysicsObject trigger = PhysicsObject.CreateStaticObject(10, Level.Height); //A truly cool and efficient way to make the boogeyman react only to our closeness
1065        //trigger.Position = mage.Position - new Vector(Window.Width / 2, 0);
1066        ////trigger.Color = Color.Red;
1067        //trigger.IsVisible = false;
1068        //trigger.IgnoresCollisionResponse = true;
1069        //Add(trigger);
1070
1071        FollowerBrain attackBrain = new FollowerBrain("player");
1072        attackBrain.DistanceFar = Window.Width / 2.5;
1073        attackBrain.DistanceClose = Window.Width / 2;
1074        attackBrain.StopWhenTargetClose = false;
1075        attackBrain.Speed = brain.Speed * 6;
1076        attackBrain.FarBrain = brain;
1077        mage.Brain = attackBrain;
1078
1079        // Taiotaan tulta välillä.
1080        var castTimer = new Timer { Interval = 10.0 };
1081        castTimer.Timeout += delegate
1082        {
1083            // TODO: Kävelyanimaatio pysähtyy jostain syystä tämän animaation jälkeen.
1084            mage.PlayAnimation(firemageCastAnimation);
1085
1086            Timer.SingleShot(RandomGen.NextDouble(5, 8), delegate { mage.Brain = attackBrain; });
1087
1088            Timer.SingleShot(1.5,
1089                delegate
1090                {
1091                    for (int i = 0; i < 6; i++)
1092                    {
1093                        CreateFlame(new Vector(attackBrain.CurrentTarget.X + RandomGen.NextDouble(-300, 300), mage.Y + mage.Height * 1.5), 30, 60, false);
1094                        mage.Brain = brain;
1095                    }
1096                });
1097
1098        };
1099
1100        attackBrain.DistanceToTarget.AddTrigger(Window.Width / 2, TriggerDirection.Down, delegate()
1101        {
1102            castTimer.Start();
1103            attackBrain.DistanceToTarget.RemoveTriggers(Window.Width / 2);
1104        });
1105
1106        //castTimer.Start();
1107
1108        AddCollisionHandler(mage, "milkparticle", delegate(PhysicsObject fireMage, PhysicsObject milk)
1109        {
1110            if (milk.Y > fireMage.Y + fireMage.Height * 0.15 && !immune)
1111            {
1112                flame.Size *= 0.95;
1113                immune = true;
1114                if (flame.Height < height)
1115                {
1116                    castTimer.Stop();
1117                    CreatePitchfork(mage.Position, TILE_SIZE, TILE_SIZE);
1118                    mage.Destroy();
1119                    Timer.SingleShot(6, NextLevel);
1120                }
1121                Timer.SingleShot(0.5, delegate { immune = false; });
1122
1123            }
1124        });
1125
1126        //AddCollisionHandler(trigger, "player", delegate(PhysicsObject a, PhysicsObject b) { castTimer.Start(); });
1127    }
1128
1129    void CreateHouse(Vector position, double width, double height)
1130    {
1131        // Näkyvä talo
1132        GameObject house = new GameObject(width * 10, height * 8);
1133        house.Image = houseImages[0];
1134        house.Position = position - new Vector(0, height * 2.5);
1135        Add(house, -2);
1136
1137        //Seisottava tasanne
1138        PhysicsObject platform = PhysicsObject.CreateStaticObject(house.Width - (TILE_SIZE * 3.25), 1);     //Tätä kohtaa on nyt vähän hakemalla haettu.
1139        platform.IsVisible = false;
1140        platform.Position = new Vector(house.X + (TILE_SIZE * 0.5), house.Top);
1141        Add(platform);
1142    }
1143
1144    void CreateBurnedHouse(Vector position, double width, double height)
1145    {
1146        GameObject house = new GameObject(width * 10, height * 8);
1147        house.Image = houseImages[1];
1148        house.Position = position - new Vector(0, height * 2.5);
1149        Add(house, -2);
1150
1151        PhysicsObject platform = PhysicsObject.CreateStaticObject(house.Width * 0.25, 1);
1152        platform.IsVisible = false;
1153        platform.Position = new Vector(house.X + platform.Width * 0.5, house.Top);
1154        Add(platform);
1155    }
1156
1157    private void CreateCart(Vector position, double width, double height)
1158    {
1159        double size = 0.7;
1160        PhysicsObject cart = new PhysicsObject(400 * size, 80 * size);
1161        cart.Position = position;
1162        cart.Image = cartImage;
1163        cart.CollisionIgnoreGroup = 2;
1164        Add(cart);
1165        PhysicsObject cartWheel = new PhysicsObject(160 * size, 160 * size, Shape.Circle);
1166        cartWheel.Image = cartWheelImage;
1167        cartWheel.Position = cart.Position + new Vector(-110, -30) * size;
1168        cartWheel.CollisionIgnoreGroup = 2;
1169        Add(cartWheel);
1170        AxleJoint joint = new AxleJoint(cart, cartWheel);
1171        Add(joint);
1172    }
1173
1174    private void CreateDummy(Vector position, double width, double height, Color color)
1175    {
1176        PhysicsObject dummy = PhysicsObject.CreateStaticObject(width, height);
1177        dummy.Position = position;
1178        dummy.Color = color;
1179        Add(dummy);
1180    }
1181
1182    void CreatePlayer(Vector position, double width, double height)
1183    {
1184        HillBilly player = new HillBilly(width, height * 2, names[players.Count()]);
1185        player.Shape = Shape.Rectangle;
1186        player.Position = position + new Vector(0, height * 0.5);
1187        player.Color = Color.White;
1188        player.AnimWalk = new Animation(normalWalk);
1189        player.AnimIdle = new Animation(playerIdle);
1190        player.AnimJump = new Animation(playerJump);
1191        player.AnimFall = new Animation(playerFall);
1192        player.Animations = new List<Animation>();
1193        player.Animations.Add(normalWalk);
1194        player.Animations.Add(playerIdle);
1195        player.AnimFall.StopOnLastFrame = true;
1196        players.Add(player);
1197        startingPlayers.Add(player);
1198        player.Tag = "player";
1199        Add(player);
1200
1201        AddCollisionHandler(player, "burn", delegate(PhysicsObject p, PhysicsObject t)
1202        {
1203            player.Life.Value--;
1204        });
1205
1206        AddCollisionHandler(player, "lava", delegate(PhysicsObject p, PhysicsObject t)
1207        {
1208            player.Life.Value = player.Life.MinValue;
1209        });
1210
1211        AddCollisionHandler(player, "worm", delegate(PhysicsObject p, PhysicsObject worm)
1212        {
1213            if (player.Y > worm.Y && Math.Abs(player.X - worm.X) < worm.Width / 2.0)
1214            {
1215                worm.Destroy();
1216            }
1217            else
1218            {
1219                player.Life.Value--;
1220            }
1221        });
1222
1223
1224        player.Life.LowerLimit += delegate
1225        {
1226            if (players.Count < 2)
1227            {
1228                Loss();
1229            }
1230            else
1231            {
1232                players.Remove(player);
1233                GetRidOfImprovement(player);
1234                player.Destroy();
1235            }
1236        };
1237
1238        AddCollisionHandler(player, "improvement", CollectImprovement);
1239    }
1240
1241    void CreateGroundTop(Vector position, double width, double height)
1242    {
1243        // Puolet pienempi näkymätön palikka alla johon törmää.
1244        PhysicsObject ground = PhysicsObject.CreateStaticObject(width, height / 2.0);
1245        ground.IsVisible = false;
1246        ground.Position = position - new Vector(0.0, TILE_SIZE / 4.0);
1247        Add(ground);
1248
1249        // Maanpinnan näkyvä osa.
1250        GameObject visibleGround = new GameObject(width, height);
1251        visibleGround.Image = groundTopImages[levelNumber];
1252        visibleGround.Position = position;
1253        visibleGround.TextureWrapSize = new Vector(width / TILE_SIZE, height / TILE_SIZE);
1254        Add(visibleGround, -1);
1255
1256        int probability = RandomGen.NextInt(100);
1257        bool wheat = probability < 20;
1258
1259        if (wheat && levelNumber < 2)
1260        {
1261            GameObject wheatBlock = new GameObject(width * 1.5, height * 2);
1262            wheatBlock.Image = foregroundDecorations[levelNumber];
1263            wheatBlock.X = visibleGround.X;
1264            wheatBlock.Bottom = visibleGround.Bottom;
1265            wheatBlock.TextureWrapSize = new Vector(width / TILE_SIZE, height / TILE_SIZE);
1266            Add(wheatBlock, 2);
1267        }
1268    }
1269
1270    void CreateGround(Vector position, double width, double height)
1271    {
1272        PhysicsObject ground = PhysicsObject.CreateStaticObject(width, height);
1273        ground.Image = groundImages[levelNumber];
1274        ground.Position = position;
1275        ground.TextureWrapSize = new Vector(width / TILE_SIZE, height / TILE_SIZE);
1276        Add(ground, -1);
1277    }
1278    #endregion
1279
1280    void Victory()
1281    {
1282        ClearAll();
1283        MessageDisplay.Add("Voitit muutes belin.");
1284    }
1285
1286    void SetControls()
1287    {
1288        Keyboard.Listen(Key.A, ButtonState.Down, delegate { startingPlayers[0].Walk(-PLAYER_SPEED); }, "Player 1 moves left");
1289        Keyboard.Listen(Key.D, ButtonState.Down, delegate { startingPlayers[0].Walk(PLAYER_SPEED); }, "Player 1 moves right");
1290        Keyboard.Listen(Key.W, ButtonState.Down, delegate { startingPlayers[0].Jump(PLAYER_SPEED * 2); }, "Player 1 jumps");    //Just PLAYER_SPEED felt alright as well
1291        Keyboard.Listen(Key.E, ButtonState.Pressed, delegate { startingPlayers[0].UseImprovement(); }, "Player 1 uses their tools");
1292        Keyboard.Listen(Key.Tab, ButtonState.Pressed, GetRidOfImprovement, "Player 1 throws their tools away", startingPlayers[0]);
1293
1294        Keyboard.Listen(Key.Left, ButtonState.Down, delegate { startingPlayers[1].Walk(-PLAYER_SPEED); }, "Player 2 moves left");
1295        Keyboard.Listen(Key.Right, ButtonState.Down, delegate { startingPlayers[1].Walk(PLAYER_SPEED); }, "Player 2 moves right");
1296        Keyboard.Listen(Key.Up, ButtonState.Down, delegate { startingPlayers[1].Jump(PLAYER_SPEED * 2); }, "Player 2 jumps");
1297        Keyboard.Listen(Key.RightShift, ButtonState.Pressed, delegate { startingPlayers[1].UseImprovement(); }, "Player 2 uses their tools");
1298        Keyboard.Listen(Key.Enter, ButtonState.Pressed, GetRidOfImprovement, "Player 1 throws their tools away", startingPlayers[1]);
1299
1300        Keyboard.Listen(Key.F9, ButtonState.Pressed, Loss, null);
1301        Keyboard.Listen(Key.F12, ButtonState.Pressed, NextLevel, null);
1302        Keyboard.Listen(Key.R, ButtonState.Pressed, StartGame, null);
1303
1304        Keyboard.Listen(Key.F1, ButtonState.Pressed, ShowControlHelp, "Show help");
1305        Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Exit game");
1306    }
1307
1308    void GetRidOfImprovement(HillBilly player)
1309    {
1310        if (player.Improvement != null)
1311        {
1312            Improvement parannus = player.Improvement;
1313            parannus.Position = player.Position + player.FacingDirection.GetVector() * 100;
1314            parannus.IsVisible = true;
1315            parannus.IgnoresCollisionResponse = false;
1316            parannus.Tag = "improvement";
1317            player.Improvement.Rid();
1318        }
1319    }
1320
1321    public void CreateMilkParticles(HillBilly billy, int size, int xBase, int yBase, Vector position, String tag)
1322    {
1323        for (int i = 0; i < 10; i++)
1324        {
1325            const double maxLife = 1.0;
1326            PhysicsObject milkParticle = new PhysicsObject(size, size, Shape.Circle);
1327            milkParticle.Color = new Color(255, 255, 255, 128);
1328            milkParticle.Position = billy.Position + position;
1329            milkParticle.IgnoresCollisionResponse = true;
1330            milkParticle.Tag = tag;
1331            milkParticle.LifetimeLeft = TimeSpan.FromSeconds(maxLife);
1332            Add(milkParticle);
1333
1334            // Väri muuttuu läpinäkyväksi.
1335            var fadeTimer = new Timer { Interval = 0.07 };
1336            fadeTimer.Timeout += delegate
1337            {
1338                byte c = 255;
1339                milkParticle.Color = new Color(c, c, c, (byte)(128 * milkParticle.LifetimeLeft.TotalSeconds / maxLife));
1340            };
1341            fadeTimer.Start();
1342            milkParticle.Destroyed += fadeTimer.Stop;
1343
1344            // Random lentonopeus.
1345            var rx = RandomGen.NextDouble(-50, 50);
1346            var ry = RandomGen.NextDouble(-50, 50);
1347            milkParticle.Hit(new Vector(billy.FacingDirection.GetVector().X * (xBase + rx), yBase + ry));
1348        }
1349    }
1350
1351    void Loss()
1352    {
1353        ClearAll();
1354        cameraTarget = Camera.Position = Vector.Zero;
1355        Level.Background.Color = Color.Black;
1356
1357        GameObject img = new GameObject(Window.Width * 0.3, Window.Height * 0.5);
1358        img.Image = deathImage;
1359        Add(img);
1360
1361        Label gameover = new Label("Game Over");
1362        gameover.Position = new Vector(0, Screen.Top - 150);
1363        gameover.TextColor = Color.White;
1364        gameover.TextScale *= 3;
1365        Add(gameover);
1366
1367        Keyboard.Listen(Key.Escape, ButtonState.Pressed, StartGame, null);
1368    }
1369
1370    void CollectImprovement(PhysicsObject player, PhysicsObject milk)
1371    {
1372        HillBilly billy = player as HillBilly;
1373        if (billy == null || billy.Improvement != null)
1374            return;
1375
1376        Improvement milkI = milk as Improvement;
1377        billy.GainImprovement(milkI);
1378
1379        milk.IsVisible = false;
1380        milk.IgnoresCollisionResponse = true;
1381        milk.Tag = "none";
1382
1383        //Remove(milk);
1384        //billy.AnimWalk = new Animation(milkWalk);
1385        //billy.AnimIdle = new Animation(milkWalk.CurrentFrame);
1386    }
1387
1388    public void ForkThings(HillBilly Owner)
1389    {
1390        PhysicsObject evilClone = new PhysicsObject(Owner.Width, Owner.Height * 0.7);
1391        evilClone.Position = Owner.Position + Owner.FacingDirection.GetVector() * 40 + new Vector(0, -(Owner.Height * 0.3));
1392        evilClone.Color = Color.Red;
1393        evilClone.IsVisible = false;
1394        evilClone.Tag = "pitchfork";
1395        evilClone.IgnoresCollisionResponse = true;
1396        evilClone.IgnoresPhysicsLogics = true;
1397        evilClone.LifetimeLeft = TimeSpan.FromSeconds(Owner.Animation.FPS * Owner.Animation.FrameCount);
1398        Add(evilClone);
1399
1400        Owner.PlayAnimation(Owner.Improvement.Animations[1], evilClone.Destroy);
1401    }
1402
1403    #region Camera
1404    void UpdateCamera()
1405    {
1406        double minY = players.Min(p => p.Y);
1407        double maxY = players.Max(p => p.Y);
1408        double minX = players.Min(p => p.X) + cameraOffset;
1409
1410        Vector minPosition = new Vector(Math.Max(minX, cameraTargetX), minY);
1411        Vector maxPosition = new Vector(minX, maxY);
1412
1413        if (levelNumber < 2)
1414        {
1415            cameraTarget = (minPosition + maxPosition) * 0.5;
1416            cameraTarget.X = Math.Max(cameraTargetX, minX); //Lellllll.
1417
1418            //cameraTarget.Y = Math.Max(cameraTarget.X, Level.Bottom + Window.Height/2.0);
1419
1420            cameraTargetX = Math.Max(cameraTargetX, minX);
1421
1422            cameraTarget.X = Math.Min(cameraTargetX, rightCamLimit);
1423            cameraTarget.Y = Math.Max(cameraTarget.Y, bottomCamLimit);
1424        }
1425        else if (levelNumber == 2)
1426        {
1427            cameraTarget.Y = ((minPosition + maxPosition) * 0.5).Y;
1428            cameraTarget.Y = Math.Max(cameraTarget.Y, bottomCamLimit);
1429
1430            // Pakotetaan kameraa eteenpäin. Jos kaikki pelaajat on näytön oikealla puolella, niin liikutetaan nopeammin.
1431            double cameraSpeed = players.All(p => Camera.WorldToScreen(p.Position).X > 0) ? 4.0 : 1.0;
1432            cameraTarget.X += cameraSpeed;
1433
1434            cameraTarget.X = Math.Min(cameraTarget.X, rightCamLimit);
1435
1436            if (cameraTarget.X == rightCamLimit && activateBoss != null)
1437            {
1438                fireballTimer.Stop();
1439                activateBoss();
1440                activateBoss = null;
1441            }
1442        }
1443
1444        // Pelaajien sijainnin rajaus ikkunaan.
1445        double windowMax = Camera.ScreenToWorld(new Vector(Window.Width / 2.0, 0)).X;
1446        double windowMin = Camera.ScreenToWorld(new Vector(-Window.Width / 2.0, 0)).X;
1447        foreach (var player in players)
1448        {
1449            player.Left = Math.Max(player.Left, windowMin);
1450            player.Right = Math.Min(player.Right, windowMax);
1451        }
1452    }
1453
1454
1455    protected override void Update(Time time)
1456    {
1457        Camera.Position += (cameraTarget - Camera.Position) * time.SinceLastUpdate.TotalSeconds * cameraSpeed;
1458        //Camera.X += (cameraTargetX - Camera.X) * time.SinceLastUpdate.TotalSeconds * cameraSpeed;
1459
1460
1461        base.Update(time);
1462    }
1463
1464    /// <summary>
1465    /// Yritän leikkiä kameralla. Vielä varmaan hetken pidempään.
1466    /// </summary>
1467    /// <param name="gameTime"></param>
1468    /*
1469    protected override void Update(Microsoft.Xna.Framework.GameTime gameTime)
1470    {
1471        foreach(HillBilly player in players)
1472        {
1473            playerPositionsX.Add(player.Position.X);
1474            playerPositionsY.Add(player.Position.Y);
1475        }
1476
1477        double maxX = playerPositionsX.Max();
1478        double maxY = playerPositionsY.Max();
1479        double minX = playerPositionsX.Min();
1480        double minY = playerPositionsY.Min();
1481
1482        Vector minPosition = new Vector(minX, minY);
1483        Vector maxPosition = new Vector(maxX, maxY);
1484
1485        Camera.Position = (minPosition + maxPosition) * 0.5;
1486
1487        playerPositionsX.Clear();
1488        playerPositionsY.Clear();
1489
1490        base.Update(gameTime);
1491    }
1492     */
1493    #endregion
1494
1495
1496}
Note: See TracBrowser for help on using the repository browser.