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

Revision 6630, 17.2 KB checked in by sieerinn, 5 years ago (diff)

Alustavia ääniefektejä lisätty.

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