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

Revision 6407, 51.5 KB checked in by sieerinn, 5 years ago (diff)

Kolmanteen kenttään pohjalle laavaa.

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