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

Revision 6423, 56.7 KB checked in by sieerinn, 5 years ago (diff)

Tuliseinän animointi. Maidolla voi myös sammuttaa tulipallot.

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