source: 2015/27/ohjaajat/TheLegendOfGabriel/TheLegendOfGabriel/TheLegendOfGabriel/TheLegendOfGabriel.cs @ 6705

Revision 6705, 21.0 KB checked in by sieerinn, 4 years ago (diff)

Junabossia, savua, sekä kaikenlaista ihme säätöä tehty.

Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Reflection;
5using Jypeli;
6using Jypeli.Assets;
7using Jypeli.Controls;
8using Jypeli.Effects;
9using Jypeli.Widgets;
10
11public class StoryItem
12{
13    // Iso kuvake joka näkyy inventoryssä.
14    public Image InventoryImage { get; set; }
15
16    public Queue<string> Message { get; set; }
17
18    public StoryItem(Queue<String> message, Image image)
19    {
20        this.InventoryImage = image;
21        this.Message = message;
22    }
23}
24
25class CycleSlot : Label
26{
27    public Label UsageLabel { get; set; }
28
29    public CycleSlot(double left, double top)
30    {
31        this.Left = left;
32        this.Top = top;
33        this.Size = new Vector(60, 40);
34
35        UsageLabel = new Label("10");
36        UsageLabel.IsVisible = false;
37        UsageLabel.TextColor = Color.White;
38        UsageLabel.X = this.X + 10;
39        UsageLabel.Top = this.Bottom;
40        UsageLabel.Font = Font.DefaultSmallBold;
41    }
42
43    public void UpdateImage(Item item)
44    {
45        if (item != null)
46        {
47            this.Image = item.InventoryImage;
48            UsageLabel.IsVisible = false;
49            if (item.Usages.MaxValue > 0)
50            {
51                UsageLabel.IsVisible = true;
52                UsageLabel.BindTo(item.Usages);
53            }
54        }
55    }
56}
57
58public partial class TheLegendOfGabriel : PhysicsGame
59{
60    public const int TILE_SIZE = 20;
61
62    private Player player;
63    private List<Creature> enemies = new List<Creature>(); 
64
65    private bool transition;
66    List<GameObject> oldObjects = new List<GameObject>();
67    List<Exit> exits = new List<Exit>();
68
69    private bool viewing;
70    private double midpoint;
71    private double second;
72    GameObject frame;
73    Queue<string> messagesviewed;
74
75    private const int STORYITEM_COUNT = 3;
76    StoryItem[] storyItem = new StoryItem[3];
77
78    public IntMeter BossHealth;
79    private List<Vector> bossSpawnPositions = new List<Vector>(); 
80
81    private CycleSlot currentItem; // Laatikossa näkyvä nykyinen kama.
82    private CycleSlot nextItem; // Seuraavan kaman kuva.
83    private CycleSlot prevItem; // Edellisen kaman kuva.
84    private Label swordItem; // Laatikossa näkyvä miekka.
85
86    #region Resources
87
88    public static SoundEffect SwordSound = LoadSoundEffect("swordsound");
89    public static SoundEffect GunSound = LoadSoundEffect("gunsound");
90    public static SoundEffect EnemyDieSound = LoadSoundEffect("enemydie");
91
92    public static Image GunImage = LoadImage("gun");
93    public static Image BulletImage = LoadImage("bullet");
94    public static Image LetterImage = LoadImage("letter");
95    public static Image SmallSwordImage = LoadImage("smallsword");
96    public static Image MonocleImage = LoadImage("monocle");
97    public static Image BigMonocleImage = LoadImage("bigmonocle");
98    public static Image BigSwordImage = LoadImage("bigsword");
99    public static Image GrenadeImage = LoadImage("gran");
100    public static Image GrenadeSmallImage = LoadImage("gransmall");
101
102    public static Image GrenadeBoxImage = LoadImage("grenadebox");
103    public static Image AmmoBoxImage = LoadImage("ammobox");
104
105    public static Image FrameImage = LoadImage("frame");
106    public static Image ActiveItemFrameImageX = LoadImage("activeitemframe");
107    public static Image ActiveItemFrameImageZ = LoadImage("activeitemframez");
108
109    public static Image PlayerHealthImage = LoadImage("playerhealth");
110    public static Image PlayerHealthEmptyImage = LoadImage("playerhealthempty");
111
112    [AssetName("walkright")]
113    internal Animation playerWalkRight;
114    [AssetName("walkright", mirror: true)]
115    internal Animation playerWalkLeft;
116    [AssetName("walkup")]
117    private Animation playerWalkUp;
118    [AssetName("walkdown")]
119    private Animation playerWalkDown;
120
121    [AssetName("swingup")]
122    private Animation playerSwingUp;
123    [AssetName("swingright")]
124    private Animation playerSwingRight;
125    [AssetName("swingright", mirror: true)]
126    private Animation playerSwingLeft;
127    [AssetName("swingdown")]
128    private Animation playerSwingDown;
129
130    [AssetName("shootup")]
131    private Animation playerShootUp;
132    [AssetName("shootright")]
133    private Animation playerShootRight;
134    [AssetName("shootright", mirror: true)]
135    private Animation playerShootLeft;
136    [AssetName("shootdown")]
137    private Animation playerShootDown;
138
139    [AssetName("coyoteup")]
140    private Animation coyoteUp;
141    [AssetName("coyoteright")]
142    private Animation coyoteRight;
143    [AssetName("coyoteright", mirror: true)]
144    private Animation coyoteLeft;
145    [AssetName("coyotedown")]
146    private Animation coyoteDown;
147
148    [AssetName("train")]
149    private Animation trainAnimation;
150    [AssetName("carriage")]
151    private Animation carriageAnimation;
152
153    [AssetName("smoke")]
154    private Animation smokeAnimation;
155
156    #endregion
157
158    public override void Begin()
159    {
160        Mouse.IsCursorVisible = true;
161        SmoothTextures = false;
162        LoadAnimations();
163        StartGame();
164        Intro();
165        BuildUI();
166    }
167
168    void Victory()
169    {
170        ClearAll();
171        Level.Background.Color = Color.Black;
172
173        var text = new Label("Voitit muutes belin."); // Tekstin voisi vaihtaa.
174        text.TextColor = Color.White;
175        Add(text);
176    }
177
178    void BuildUI()
179    {
180        BuildRightBar();
181        BuildInventoryCycle();
182        BuildHealthBar();
183        UpdateItemCycleImages();
184    }
185   
186    void BuildHealthBar()
187    {
188        var bar = new ProgressBar(32 * 10, 32);
189        bar.Right = Screen.Right - 50;
190        bar.Top = Screen.Top - 50;
191        bar.Image = PlayerHealthEmptyImage;
192        bar.BarImage = PlayerHealthImage;
193        bar.BindTo(player.Health);
194        Add(bar);
195    }
196
197    void BuildInventoryCycle()
198    {
199        const int spacing = 20;
200
201        prevItem = new CycleSlot(Screen.Left + 50, Screen.Top - 30);
202        Add(prevItem);
203        Add(prevItem.UsageLabel);
204
205        currentItem = new CycleSlot(prevItem.Right + spacing, prevItem.Top);
206        Add(currentItem);
207        Add(currentItem.UsageLabel);
208
209        nextItem = new CycleSlot(currentItem.Right + spacing, prevItem.Top);
210        Add(nextItem);
211        Add(nextItem.UsageLabel);
212
213        // Ruutu jonka sisällä käytössä oleva kama on.
214        var frame = new Label();
215        frame.Size = new Vector(60, 60);
216        frame.Image = ActiveItemFrameImageX;
217        frame.X = currentItem.X;
218        frame.Top = currentItem.Top;
219        Add(frame);
220
221        // Miekan kuva.
222        swordItem = new Label();
223        swordItem.Size = prevItem.Size;
224        swordItem.Left = nextItem.Right + spacing * 2;
225        swordItem.Top = currentItem.Top;
226        Add(swordItem);
227
228        // Miekan kuvan ympärillä oleva ruutu.
229        var swordFrame = new Label();
230        swordFrame.Size = new Vector(60, 60);
231        swordFrame.Image = ActiveItemFrameImageZ;
232        swordFrame.X = swordItem.X;
233        swordFrame.Top = swordItem.Top;
234        Add(swordFrame);
235    }
236
237    void BuildRightBar()
238    {
239        for (int i = 0; i < STORYITEM_COUNT; i++)
240        {
241            Label member = new Label(FrameImage);
242            member.Size = new Vector(40, 40);
243            member.Position = new Vector(Screen.Right - FrameImage.Width, Screen.Top - Screen.Width * 0.25 - FrameImage.Height * i * 1.5);
244            Add(member);
245
246            GameObject inner = new GameObject(TILE_SIZE, TILE_SIZE);
247            inner.Color = Color.Black;
248            if (storyItem[i] != null)
249            {
250                inner.Image = storyItem[i].InventoryImage;
251                Mouse.ListenOn(inner, MouseButton.Left, ButtonState.Pressed, ShowTextItem, "View those precious memories", storyItem[i]);
252            }
253            member.Add(inner);
254        }
255    }
256
257    /// <summary>
258    /// Lataa automaagisesti kaikki animaatiot.
259    /// </summary>
260    private void LoadAnimations()
261    {
262        // Haetaan tämän luokan kaikki ei-julkiset attribuutit.
263        foreach (var field in GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
264        {
265            // Jos attribuutille on laitettu AsseName, niin ladataan sen niminen animaatio.
266            var assetAttr = Attribute.GetCustomAttribute(field, typeof(AssetNameAttribute)) as AssetNameAttribute;
267            if (assetAttr == null) continue;
268            var anim = LoadAnimation(assetAttr.AssetName);
269            field.SetValue(this, assetAttr.Mirror ? MirrorAnimation(anim) : anim);
270        }
271    }
272
273    Dictionary<Direction, Animation> DirectionalAnimations(Animation left, Animation right, Animation up, Animation down)
274    {
275        var dict = new Dictionary<Direction, Animation>();
276        dict[Direction.Left] = left;
277        dict[Direction.Right] = right;
278        dict[Direction.Up] = up;
279        dict[Direction.Down] = down;
280        return dict;
281    }
282
283    void Intro()
284    {
285        storyItem[0] = new StoryItem(new Queue<string>(new[] { "Dear Alexander,", 
286            "",
287            "",
288            "I have accepted a position at the Communal Assets for Justice.",
289            "Please do not consider this an act of rejection. I am simply",
290            "a victim to the scathing uncertainty of your release from service.",
291            "",
292            "I still see your face in my dreams. I believe that when",
293            "our immediate circumstances change, we'll meet again, we'll",
294            "work it out. Were you here, we'd certainly fall in love.",
295            "",
296            "And perhaps then nothing could keep us apart.",
297            "-Ana" 
298        }), LetterImage);
299
300        //ShowTextItem(storyItem[0]);
301    }
302
303    void ShowTextItem(StoryItem item)
304    {
305        viewing = true;
306        messagesviewed = new Queue<string>(item.Message);
307        Pause();
308
309        Level.AmbientLight -= 0.75;
310
311        frame = new GameObject(LetterImage);
312        frame.Image = LetterImage;
313        frame.Width = Window.Width * 0.25;
314        frame.Height = Window.Height * 0.25;
315        frame.Width = Level.Width * 0.25;
316        frame.Height = Level.Height * 0.25;
317        Add(frame);
318
319        midpoint = 26 * item.Message.Count() * 0.5;
320
321    }
322
323    /// <summary>
324    /// Peilaa kaikki animaation kuvat.
325    /// </summary>
326    private static Animation MirrorAnimation(Animation anim)
327    {
328        return new Animation(anim.Select(Image.Mirror).ToArray()) { FPS = anim.FPS };
329    }
330
331    private void StartGame()
332    {
333        ClearAll();
334        CreatePlayer(new Vector(0, -300), TILE_SIZE, TILE_SIZE, Angle.Zero, Shape.Rectangle, "", null);
335        CreateLevel("level1");
336        //CreatePlayer(new Vector(-Level.Width/3, Level.Bottom + TILE_SIZE * 2));
337        SetControls();
338        //Camera.ZoomToLevel();
339        Camera.Follow(player);
340        Camera.ZoomFactor = 2.0;
341    }
342
343    void SetControls()
344    {
345        Keyboard.Listen(Key.Left, ButtonState.Down, player.Move, null, Direction.Left);
346        Keyboard.Listen(Key.Right, ButtonState.Down, player.Move, null, Direction.Right);
347        Keyboard.Listen(Key.Up, ButtonState.Down, player.Move, null, Direction.Up);
348        Keyboard.Listen(Key.Down, ButtonState.Down, player.Move, null, Direction.Down);
349
350        Keyboard.Listen(Key.X, ButtonState.Pressed, delegate { UseItem(player.ActiveItem, player.Sword, () => player.ActiveItem.UseKeyPressed()); }, null);
351        Keyboard.Listen(Key.X, ButtonState.Released, delegate { UseItem(player.ActiveItem, player.Sword, () => player.ActiveItem.UseKeyReleased()); }, null);
352        Keyboard.Listen(Key.X, ButtonState.Down, delegate { UseItem(player.ActiveItem, player.Sword, () => player.ActiveItem.UseKeyDown()); }, null);
353
354        Keyboard.Listen(Key.Z, ButtonState.Pressed, delegate { UseItem(player.Sword, player.ActiveItem, () => player.Sword.UseKeyPressed()); }, null);
355        Keyboard.Listen(Key.Z, ButtonState.Released, delegate { UseItem(player.Sword, player.ActiveItem, () => player.Sword.UseKeyReleased()); }, null);
356        Keyboard.Listen(Key.Z, ButtonState.Down, delegate { UseItem(player.Sword, player.ActiveItem, () => player.Sword.UseKeyDown()); }, null);
357
358        Keyboard.Listen(Key.Space, ButtonState.Pressed, CycleItems, null);
359
360        Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, null);
361    }
362
363    /// <summary>
364    /// Luo pelaajan.
365    /// </summary>
366    void CreatePlayer(Vector position, double width, double height, Angle angle, Shape shape, string name, Dictionary<string, string> properties)
367    {
368        player = new Player();
369        player.CanRotate = false;
370        player.MovementSpeed = new DoubleMeter(2300, 0, 2300);
371        player.Position = position;
372        player.MoveAnimations = DirectionalAnimations(playerWalkLeft, playerWalkRight, playerWalkUp, playerWalkDown);
373        player.SwingAnimations = DirectionalAnimations(playerSwingLeft, playerSwingRight, playerSwingUp, playerSwingDown);
374        player.ShootAnimations = DirectionalAnimations(playerShootLeft, playerShootRight, playerShootUp, playerShootDown);
375        player.Image = playerWalkDown.CurrentFrame;
376        Add(player, 1);
377
378        player.Sword = new Sword(player);
379        player.Inventory.Add(new Pistol(player));
380        player.Inventory.Add(new Monocle(player));
381        player.Inventory.Add(new Grenade(player));
382
383        //player.Health.Value = 3; // Alkuun vain kolme sydäntä.
384        player.Health.Value = player.Health.MaxValue = 100;
385
386        AddCollisionHandler(player, "exit", CollidesWithExit);
387        AddCollisionHandler(player, "enemy", delegate(PhysicsObject p, PhysicsObject e)
388        {
389            player.Health.Value--;
390        });
391
392        AddCollisionHandler(player, "ammobox", delegate(PhysicsObject p, PhysicsObject box)
393        {
394            box.Destroy();
395            var gun = player.Inventory.FirstOrDefault(i => i is Pistol);
396            if (gun != null)
397            {
398                gun.Usages.Value += 5;
399            }
400        });
401
402        AddCollisionHandler(player, "grenadebox", delegate(PhysicsObject p, PhysicsObject box)
403        {
404            box.Destroy();
405            var grenades = player.Inventory.FirstOrDefault(i => i is Grenade);
406            if (grenades != null)
407            {
408                grenades.Usages.Value += 5;
409            }
410        });
411    }
412
413    void UseItem(Item item, Item otherItem, Action action)
414    {
415        if (player.IsDestroyed)
416            return;
417
418        bool inUse = false;
419        if (otherItem != null)
420        {
421            inUse = otherItem.InUse;
422        }
423
424        if (item != null && !inUse)
425        {
426            action();
427        }
428    }
429
430    void CycleItems()
431    {
432        // Kaman vaihtossa simuloidaan että oltaisiin laskettu irti käyttönäppäimestä.
433        if (player.ActiveItem != null)
434        {
435            player.ActiveItem.CancelUse();
436        }
437        if (player.Sword != null)
438        {
439            player.Sword.CancelUse();
440        }
441
442        player.CycleItems();
443        UpdateItemCycleImages();
444    }
445
446    void UpdateItemCycleImages()
447    {
448        prevItem.UpdateImage(player.PrevItem);
449        currentItem.UpdateImage(player.ActiveItem);
450        nextItem.UpdateImage(player.NextItem);
451
452        if (player.Sword != null)
453        {
454            swordItem.Image = BigSwordImage;
455        }
456    }
457
458    void CollidesWithEnemy(PhysicsObject player, PhysicsObject enemy)
459    {
460
461    }
462
463    void CollidesWithExit(PhysicsObject pPlayer, PhysicsObject pExit)
464    {
465        var oldExit = pExit as Exit;
466        if (oldExit == null || transition || oldExit.TargetLevel == null || pExit.IsDestroying || pExit.IsDestroyed)
467            return;
468
469        oldExit.Destroy();
470
471        var oldExitDirection = GetExitDirection(oldExit);
472        transition = true;
473
474        enemies.Clear();
475
476        // Otetaan vanhat objektit talteen.
477        oldObjects.Clear();
478        foreach (var obj in GetObjects(o => o != player))
479        {
480            if (obj != player)
481            {
482                oldObjects.Add(obj);
483            }
484        }
485
486        // Luodaan seuraava kenttä.
487        exits.Clear();
488        CreateLevel(oldExit.TargetLevel);
489
490        // Etsitään seuraavan kentän kohde exitti johon siirrytään.
491        var targetExit = exits.FirstOrDefault(e => e.Name == oldExit.TargetExitName);
492
493        if (targetExit == null)
494        {
495            throw new Exception("Tarkisita kenttien exittien nimet.");
496        }
497
498        // Jompikumpi uloskäynti ei ole kentän laidalla, sulava siirtyminen ei ole mahdollista.
499        if (GetExitDirection(targetExit) == Direction.None || oldExitDirection == Direction.None)
500        {
501            transition = false;
502            oldObjects.ForEach(o => o.Destroy());
503            oldObjects.Clear();
504
505            BuildUI();
506
507            // Yritetään päätellä pelaajalle joku järkevä paikka.
508            player.Position = targetExit.Position + Direction.Inverse(targetExit.Position.Angle.MainDirection).GetVector() * TILE_SIZE * 2;
509           
510            Camera.Follow(player);
511            Camera.ZoomFactor = 2.0;
512            return;
513        }
514
515        // Pysäytetään peli siirtymän ajaksi.
516        Pause();
517        PhysicsEnabled = false;
518
519        // Lasketaan siirtymävektorit.
520        Direction dir = GetExitDirection(targetExit);
521        Vector exitDelta = targetExit.Position - oldExit.Position;
522        Vector transitionVector = Level.Size;
523        if (dir == Direction.Left || dir == Direction.Right)
524        {
525            transitionVector.X *= dir.GetVector().X;
526            transitionVector.Y = exitDelta.Y;
527        }
528        else
529        {
530            transitionVector.Y *= dir.GetVector().Y;
531            transitionVector.X = exitDelta.X;
532        }
533
534        // Siirretään vanhoja objekteja ja pelaajaa.
535        foreach (var obj in oldObjects)
536        {
537            obj.Position += transitionVector;
538        }
539        player.Position += transitionVector + Direction.Inverse(dir).GetVector() * TILE_SIZE * 4;
540
541        // Zoomataan kameraa sopivasti ja liikutetaan se vanhan kentän päälle, josta se sitten siirtyy uuden kentän päälle.
542        Camera.Position += transitionVector;
543        Vector pos = Camera.Position;
544        Camera.Follow(player);
545        Camera.ZoomFactor = 2.0;
546        Camera.Position = pos;
547    }
548
549    /// <summary>
550    /// Palauttaa suunnan millä puolella kenttää uloskäynti on.
551    /// </summary>   
552    Direction GetExitDirection(Exit exit)
553    {
554        const double epsilon = 1e-3;
555        Func<double, double, bool> isSame = (x, y) => Math.Abs(y - x) < epsilon;
556
557        if (isSame(exit.Top, Level.Top))
558        {
559            return Direction.Up;
560        }
561        if (isSame(exit.Bottom, Level.Bottom))
562        {
563            return Direction.Down;
564        }
565        if (isSame(exit.Left, Level.Left))
566        {
567            return Direction.Left;
568        }
569        if (isSame(exit.Right, Level.Right))
570        {
571            return Direction.Right;
572        }
573        return Direction.None;
574    }
575
576    protected override void PausedUpdate(Time gameTime)
577    {
578        base.PausedUpdate(gameTime);
579        double dt = gameTime.SinceLastUpdate.TotalSeconds;
580
581        const double transitionSpeed = 500.0;
582
583        if (transition && !viewing)
584        {
585            Camera.Position += Camera.Position.Normalize() * -transitionSpeed * dt;
586
587            // Siirtymä on ohi, jatketaan peliä ja poistetaan edellinen kenttä.
588            if (Camera.Position.Magnitude < transitionSpeed * dt)
589            {
590                transition = false;
591                Pause();
592                PhysicsEnabled = true;
593                Camera.Position = Vector.Zero;
594
595                foreach (var obj in oldObjects)
596                {
597                    obj.Destroy();
598                }
599                oldObjects.Clear();
600
601                BuildUI();
602            }
603        }
604
605        if(viewing && !transition)  //!transition perhaps being somewhat unnecessary, but now I do feel a bit safer.
606        {
607            second += dt;
608            if(second > 1)
609            {
610                if (messagesviewed.Count < 1)   //The letter's read, better head back.
611                {
612                    Level.AmbientLight = 1;
613                    frame.Destroy();
614                    GetObjectsWithTag("labelWaitingToDie").ForEach(g => g.Destroy());
615                    viewing = false;
616                    Pause();
617                    return;
618                }
619
620                second = 0;
621                var storyLabel = new Label(messagesviewed.Dequeue()) { TextColor = Color.White };
622                storyLabel.Y = -midpoint + storyLabel.Height * messagesviewed.Count() + 1;
623                storyLabel.Tag = "labelWaitingToDie";
624                Add(storyLabel);
625
626            }
627        }
628    }
629
630    protected override void Update(Time time)
631    {
632        player.UpdateCreature(time);
633        enemies.ForEach(e => e.UpdateCreature(time));
634        base.Update(time);
635    }
636}
Note: See TracBrowser for help on using the repository browser.