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

Revision 6626, 17.1 KB checked in by sieerinn, 5 years ago (diff)

Kamoissa näkyy käyttökerrat. Kamasysteemin toimivuutta paranneltu. Kojootin kuvat.

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