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

Revision 6386, 41.4 KB checked in by sieerinn, 6 years ago (diff)

Kolmatta kenttää tehty. Vipu ja portti lisätty.

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