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

Revision 6547, 9.1 KB checked in by empaheik, 4 years ago (diff)

Kriittisenloistavaa kuvitusta.

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
11sealed class Exit : PhysicsObject
12{
13    /// <summary>
14    /// Kentän nimi johon siirrytään.
15    /// </summary>
16    public string TargetLevel { get; set; }
17
18    /// <summary>
19    /// Kohdekentässä olevan exitin nimi jonka päältä aloitetaan.
20    /// </summary>
21    public string TargetExitName { get; set; }
22
23    /// <summary>
24    /// Tämän uloskäynnin nimi.
25    /// </summary>
26    public string Name { get; set; }
27
28    public Exit(double width, double height)
29        : base(width, height)
30    {
31        Color = new Color(255, 0, 0, 60); // Debuggausta varten jotta näkee uloskäynnit.
32        IgnoresCollisionResponse = true;
33        Tag = "exit";
34    }
35}
36
37class Creature : PhysicsObject
38{
39    public double MovementSpeed { get; set; }
40
41    public Dictionary<Direction, Animation> MoveAnimations { get; set; }
42
43    public Creature(double width, double height)
44        : base(width, height)
45    {
46        MoveAnimations = new Dictionary<Direction, Animation>();
47        LinearDamping = 0.5;
48    }
49
50    public void Move(Direction direction)
51    {
52        if (!Game.IsPaused)
53        {
54            Push(direction.GetVector() * MovementSpeed);
55        }
56    }
57
58    public override void Update(Time time)
59    {
60        if (Velocity.MagnitudeSquared > 10.0)
61        {
62            // Animaation vaihto nopeuden suunnan perusteella.
63            Animation newAnim;
64            var dir = Velocity.Angle.MainDirection;
65            if (MoveAnimations.TryGetValue(dir, out newAnim))
66            {
67                if (Animation != newAnim)
68                {
69                    Animation = newAnim;
70                }
71            }
72
73            // Käynnistetään animaatio jos se ei ole jo käynnissä.
74            if (!Animation.IsPlaying)
75                Animation.Resume();
76        }
77        else if (Animation != null && Animation.IsPlaying)
78        {
79            // Paikallaan ollessa pysäytetään animaatio.
80            Animation.Pause();
81        }
82        base.Update(time);
83    }
84}
85
86public partial class TheLegendOfGabriel : PhysicsGame
87{
88    public const int TILE_SIZE = 20;
89
90    private Creature player;
91
92    private bool transition;
93    List<GameObject> oldObjects = new List<GameObject>();
94    List<Exit> exits = new List<Exit>();
95
96    #region Resources
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    #endregion
108
109    public override void Begin()       
110    {
111        SmoothTextures = false;
112        LoadAnimations();
113        StartGame();
114    }
115
116    /// <summary>
117    /// Lataa automaagisesti kaikki animaatiot.
118    /// </summary>
119    private void LoadAnimations()
120    {
121        // Haetaan tämän luokan kaikki ei-julkiset attribuutit.
122        foreach (var field in GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
123        {
124            // Jos attribuutille on laitettu AsseName, niin ladataan sen niminen animaatio.
125            var assetAttr = Attribute.GetCustomAttribute(field, typeof(AssetNameAttribute)) as AssetNameAttribute;
126            if (assetAttr == null) continue;
127            var anim = LoadAnimation(assetAttr.AssetName);
128            field.SetValue(this, assetAttr.Mirror ? MirrorAnimation(anim) : anim);
129        }
130    }
131
132    /// <summary>
133    /// Peilaa kaikki animaation kuvat.
134    /// </summary>
135    private static Animation MirrorAnimation(Animation anim)
136    {
137        return new Animation(anim.Select(Image.Mirror).ToArray()) { FPS = anim.FPS };
138    }
139
140    private void StartGame()
141    {
142        ClearAll();
143        CreateLevel("level1");
144        //CreatePlayer(new Vector(-Level.Width/3, Level.Bottom + TILE_SIZE * 2));
145        SetControls();
146        Camera.ZoomToLevel();
147    }
148
149    void SetControls()
150    {
151        Keyboard.Listen(Key.Left, ButtonState.Down, player.Move, null, Direction.Left);
152        Keyboard.Listen(Key.Right, ButtonState.Down, player.Move, null, Direction.Right);
153        Keyboard.Listen(Key.Up, ButtonState.Down, player.Move, null, Direction.Up);
154        Keyboard.Listen(Key.Down, ButtonState.Down, player.Move, null, Direction.Down);
155
156        Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, null);
157    }
158
159    ///// <summary>
160    ///// Luo pelaajan.
161    ///// </summary>
162    //void CreatePlayer(Vector position)
163    //{
164    //    player = new Creature(TILE_SIZE, TILE_SIZE);
165    //    player.MovementSpeed = 2300;
166    //    player.Position = position;
167    //    Add(player);
168
169    //    AddCollisionHandler(player, "exit", CollidesWithExit);
170    //}
171
172    void CollidesWithExit(PhysicsObject pPlayer, PhysicsObject pExit)
173    {
174        var oldExit = pExit as Exit;
175        if (oldExit == null || transition)
176            return;
177
178        transition = true;
179
180        // Otetaan vanhat objektit talteen.
181        oldObjects.Clear();
182        foreach (var obj in GetObjects(o => o != player))
183        {
184            if (obj != player)
185            {
186                oldObjects.Add(obj);
187            }
188        }
189
190        // Luodaan seuraava kenttä.
191        exits.Clear();
192        CreateLevel(oldExit.TargetLevel);
193
194        // Etsitään seuraavan kentän kohde exitti johon siirrytään.
195        var targetExit = exits.FirstOrDefault(e => e.Name == oldExit.TargetExitName);
196
197        // Jompikumpi uloskäynti ei ole kentän laidalla, sulava siirtyminen ei ole mahdollista.
198        if (GetExitDirection(targetExit) == Direction.None || GetExitDirection(oldExit) == Direction.None)
199        {
200            transition = false;
201            oldObjects.ForEach(o => o.Destroy());
202            oldObjects.Clear();
203
204            // Yritetään päätellä pelaajalle joku järkevä paikka.
205            player.Position = targetExit.Position + Direction.Inverse(targetExit.Position.Angle.MainDirection).GetVector() * TILE_SIZE * 2;
206            Camera.ZoomToLevel();
207            return;
208        }
209
210        // Pysäytetään peli siirtymän ajaksi.
211        Pause();
212        PhysicsEnabled = false;
213
214        // Lasketaan siirtymävektorit.
215        Direction dir = GetExitDirection(targetExit);
216        Vector exitDelta = targetExit.Position - oldExit.Position;
217        Vector transitionVector = Level.Size;
218        if (dir == Direction.Left || dir == Direction.Right)
219        {
220            transitionVector.X *= dir.GetVector().X;
221            transitionVector.Y = exitDelta.Y;
222        }
223        else
224        {
225            transitionVector.Y *= dir.GetVector().Y;
226            transitionVector.X = exitDelta.X;
227        }
228
229        // Siirretään vanhoja objekteja ja pelaajaa.
230        foreach (var obj in oldObjects)
231        {
232            obj.Position += transitionVector;
233        }
234        player.Position += transitionVector + Direction.Inverse(dir).GetVector() * TILE_SIZE * 4;
235
236        // Zoomataan kameraa sopivasti ja liikutetaan se vanhan kentän päälle, josta se sitten siirtyy uuden kentän päälle.
237        Camera.Position += transitionVector;
238        Vector pos = Camera.Position;
239        Camera.ZoomToLevel();
240        Camera.Position = pos;
241    }
242
243    /// <summary>
244    /// Palauttaa suunnan millä puolella kenttää uloskäynti on.
245    /// </summary>   
246    Direction GetExitDirection(Exit exit)
247    {
248        const double epsilon = 1e-3;
249        Func<double, double, bool> isSame = (x, y) => Math.Abs(y - x) < epsilon;
250
251        if (isSame(exit.Top, Level.Top))
252        {
253            return Direction.Up;
254        }
255        if (isSame(exit.Bottom, Level.Bottom))
256        {
257            return Direction.Down;
258        }
259        if (isSame(exit.Left, Level.Left))
260        {
261            return Direction.Left;
262        }
263        if (isSame(exit.Right, Level.Right))
264        {
265            return Direction.Right;
266        }
267        return Direction.None;
268    }
269
270    protected override void PausedUpdate(Time gameTime)
271    {
272        base.PausedUpdate(gameTime);
273        double dt = gameTime.SinceLastUpdate.TotalSeconds;
274
275        const double transitionSpeed = 500.0;
276
277        if (transition)
278        {
279            Camera.Position += Camera.Position.Normalize() * -transitionSpeed * dt;
280
281            // Siirtymä on ohi, jatketaan peliä ja poistetaan edellinen kenttä.
282            if (Camera.Position.Magnitude < transitionSpeed * dt)
283            {
284                transition = false;
285                Pause();
286                PhysicsEnabled = true;
287                Camera.Position = Vector.Zero;
288
289                foreach (var obj in oldObjects)
290                {
291                    obj.Destroy();
292                }
293                oldObjects.Clear();
294            }
295        }
296    }
297
298    protected override void Update(Time time)
299    {
300        player.Update(time);
301        base.Update(time);
302    }
303}
Note: See TracBrowser for help on using the repository browser.