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

Revision 6632, 19.3 KB checked in by sieerinn, 4 years ago (diff)

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