source: 2015/24/ohjaajat/Dungeon/Dungeon/Dungeon/Dungeon.cs @ 6005

Revision 6005, 17.7 KB checked in by sieerinn, 6 years ago (diff)

Huonepäivityksia paranneltu, uusi reikäseinäkuva.

Line 
1using System;
2using System.Linq;
3using System.Collections.Generic;
4using Jypeli;
5using Jypeli.Assets;
6using Jypeli.Controls;
7using Jypeli.Effects;
8using Jypeli.Widgets;
9using Point = Microsoft.Xna.Framework.Point;
10
11/* Tässä on jotain dokumentaation tapaista:
12 *
13 * Layerit
14 *   3 - Kaivuunuoli ja partikkeliefektit
15 *   2 - Partikkelien varjot
16 *   1 - Huoneiden katto
17 *   0 - Huoneiden seinät ja barbaarit
18 *  -1 - Päivitykset
19 *  -2 - Huone (eli lattiat siis)
20*/
21
22/// <summary>
23/// Päivitys joka voi olla huoneessa.
24/// </summary>
25abstract class Upgrade : GameObject // Tämä on abstrakti luokka, koska tästä ei ole tarkoitus luoda instanssia suoraan.
26{
27    public int Price { get; set; }
28
29    public Upgrade()
30        : base(Dungeon.RUUDUN_KOKO, Dungeon.RUUDUN_KOKO)
31    {
32    }
33
34    /// <summary>
35    /// Tätä kutsutaan kun päivitys on rakennettu huoneeseen.
36    /// </summary>
37    public virtual void Built(Dungeon peli) { }
38}
39
40class TrapUpgrade : Upgrade
41{
42    public int Damage { get; set; }
43}
44
45class CultureUpgrade : Upgrade
46{
47    // Tämän päivityksen antama kultuurin määrä.
48    public IntMeter Culture { get; set; }
49
50    // Label joka näyttää päivityksen antaman kultuurin määrän.
51    public Label KultuuriNaytto { get; set; }
52
53    public override void Built(Dungeon peli)
54    {
55        base.Built(peli);
56
57        Culture = new IntMeter(0, 0, 1000);
58
59        // Luodaan kultuurin ilmaisin.
60        KultuuriNaytto = new Label("asd");
61        KultuuriNaytto.TextColor = Color.HotPink;
62        KultuuriNaytto.Color = Color.Black;
63        KultuuriNaytto.Position = this.Position + new Vector(0, Dungeon.RUUDUN_KOKO * 0.5);
64        KultuuriNaytto.BindTo(Culture);
65        peli.Add(KultuuriNaytto);
66
67        // Näytetään kultuurin määrä kun hiiri on päivityksen päällä.
68        var kuuntelija = peli.Mouse.ListenMovement(0.1, _ => KultuuriNaytto.IsVisible = peli.Mouse.IsCursorOn(this), null);
69
70        this.Destroyed += delegate
71        {
72            KultuuriNaytto.Destroy();
73            kuuntelija.Destroy();
74        };
75    }
76}
77
78class Room : GameObject
79{
80    // Sijainti pelin ruudukossa.
81    public Point Location { get; set; }
82
83    // Päällä näkyvä "katto" kun huone ei ole vielä kaivettu.
84    public GameObject Roof { get; set; }
85
86    // Neljä seinää, jotka on GameObjekteja.
87    public Dictionary<Direction, GameObject> Walls { get; set; }
88
89    // Huoneen sisältämä päivitys.
90    public Upgrade Upgrade { get; set; }
91
92    private bool dug; // Onko huone kaivettu?
93    public bool Dug
94    {
95        get { return dug; }
96        set
97        {
98            dug = value;
99            Roof.IsVisible = !Dug;
100        }
101    }
102
103    public Room(Point paikka)
104        : base(Dungeon.RUUDUN_KOKO, Dungeon.RUUDUN_KOKO)
105    {
106        Walls = new Dictionary<Direction, GameObject>();
107        Location = paikka;
108    }
109}
110
111public class Dungeon : PhysicsGame
112{
113    public const int RUUDUN_KOKO = 64;
114
115    #region Kuvat
116    Image lattiaKuva = LoadImage("floor");
117    Image seinaKuva = LoadImage("wall");
118    Image reikaSeinaKuva = LoadImage("wallhole");
119    Image kiviKuva = LoadImage("rock");
120    static Image kulttuuriKuva1 = LoadImage("es");
121    static Image kulttuuriKuva2 = LoadImage("nyan");
122    static Image kulttuuriKuva3 = LoadImage("spurdo");
123    Image[] kultuuriKuvat = new Image[] { kulttuuriKuva1, kulttuuriKuva2, kulttuuriKuva3 };
124    Image[] vihuKuvat = LoadImages((from i in Enumerable.Range(1, 10) select String.Format("v{0:0000}", i)).ToArray());
125    Image partikkeli = LoadImage("partikkeli");
126    #endregion
127
128    int[] hinnat = new int[] { 100, 200, 300 };
129    private int barbaariMaara = 3;
130
131    Room[,] huoneet;
132    Room spawn;
133    Timer barbaariAjastin = new Timer();
134    Upgrade ostamassa;
135    Point digStart; // Huoneen sijainti, josta kaivuu aloitetaan.
136    bool digging = false;
137
138    GameObject digArrow;
139    GameObject digArrowHead;
140
141    IntMeter kulttuuri = new IntMeter(300, 0, 2000);
142
143    int vaakaHuoneet = 12;
144    int pystyHuoneet = 8;
145
146    // Paljonko peliruudukko on siirtynyt origosta.
147    Vector huoneSiirtyma = new Vector(-300, 0);
148
149    public override void Begin()
150    {
151        ClearAll();
152        Kontrollit();
153        UlkoAsuRoskaa();
154        Kauppa();
155        Nuoli();
156
157        // Luodaan huoneet ruutuihin.
158        huoneet = new Room[vaakaHuoneet, pystyHuoneet];
159        foreach (var paikka in RuutujenPaikat())
160        {
161            var huone = CreateRoom(paikka);
162            Mouse.ListenOn(huone, MouseButton.Left, ButtonState.Pressed, () => RoomPressed(huone), null);
163            Mouse.ListenOn(huone, MouseButton.Left, ButtonState.Released, () => RoomReleased(huone), null);
164            huoneet[paikka.X, paikka.Y] = huone;
165        }
166
167        LuoSpawn();
168
169        barbaariAjastin.Timeout += delegate { LuoBarbaareja(); };
170        barbaariAjastin.Interval = 3;
171    }
172
173    void Nuoli()
174    {
175        digArrow = new GameObject(5, 5);
176        digArrowHead = new GameObject(15, 15);
177        digArrowHead.Shape = Shape.Triangle;
178        digArrowHead.IsVisible = digArrow.IsVisible = false;
179        Add(digArrow, 3);
180        Add(digArrowHead, 3);
181    }
182
183    void UlkoAsuRoskaa()
184    {
185        Level.Background.Color = Color.Black;
186
187        Label rahat = new Label();
188        rahat.BindTo(kulttuuri);
189        rahat.Position = new Vector(Level.Right + Level.Width * 0.2, Level.Bottom + Level.Height * 0.1);
190        rahat.TextColor = Color.White;
191        rahat.IntFormatString = "Käytettävää kulttuuria: {0:D3}";
192        Add(rahat);
193    }
194
195    void Kauppa()
196    {
197        for (int i = 0; i < kultuuriKuvat.Length; i++)
198        {
199            /*
200            Point lokaatio = new Point(0, 0);
201
202            Room kuva = new Room(lokaatio);
203            kuva.Position = new Vector((Level.Right + Level.Width * 0.05), (Level.Top - Level.Height * 0.25 - (i * RUUDUN_KOKO)));
204            kuva.Image = kultuuriKuvat[i];
205            kuva.Price = hinnat[i];
206            Add(kuva);
207
208            Mouse.ListenOn(kuva, MouseButton.Left, ButtonState.Pressed, delegate(Room a) { ostettu = a; }, "Asetetaan ostettu huone paikoilleen", kuva);
209            */
210
211            // Ostettavat päivitykset on nyt PushButtoneita huoneiden sijaan.
212
213            PushButton kuva = new PushButton(kultuuriKuvat[i]);
214            kuva.Size = new Vector(1, 1) * RUUDUN_KOKO;
215            kuva.Position = new Vector((Level.Right + Level.Width * 0.05), (Level.Top - Level.Height * 0.25 - (i * RUUDUN_KOKO)));
216            Add(kuva);
217
218            int indeksi = i; // Alla oleva delegaatti vaatii uuden indeksi muuttujan toimiakseen.
219            kuva.Clicked += delegate
220            {
221                ostamassa = LuoKultuuriPaivitys(kultuuriKuvat[indeksi], hinnat[indeksi]);
222            };
223
224            Label teksti = new Label();
225            teksti.Position = kuva.Position + new Vector((RUUDUN_KOKO * 1.2), 0);
226            teksti.TextColor = Color.White;
227            teksti.Text = hinnat[i].ToString();
228            Add(teksti);
229        }
230    }
231
232    Upgrade LuoKultuuriPaivitys(Image kuva, int hinta)
233    {
234        CultureUpgrade upg = new CultureUpgrade();
235        upg.Image = kuva;
236        upg.Size = new Vector(0.5, 0.5) * RUUDUN_KOKO;
237        upg.Price = hinta;
238        return upg;
239    }
240
241    void LuoBarbaareja()
242    {
243        PhysicsObject barbaari = new PhysicsObject(RUUDUN_KOKO * 0.4, RUUDUN_KOKO * 0.4);
244        barbaari.Color = Color.Red;
245        //barbaari.Position = RandomGen.NextVector(Level.Right, Level.Bottom, Level.Left, Level.Top);
246        barbaari.Position = spawn.Position;
247        barbaari.Animation = new Animation(vihuKuvat);
248        barbaari.Animation.FPS = 10;
249        barbaari.Animation.Start();
250        Add(barbaari);
251    }
252
253    void Kontrollit()
254    {
255        IsMouseVisible = true;
256        Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
257        Keyboard.Listen(Key.F1, ButtonState.Pressed, Begin, null);
258
259        Keyboard.Listen(Key.Space, ButtonState.Pressed, SeuraavaAalto, "Anna kivan barbaariaallon tulla");
260    }
261
262    void SeuraavaAalto()
263    {
264        barbaariMaara += 2;
265        barbaariAjastin.Start(barbaariMaara);
266    }
267
268    void LuoSpawn()
269    {
270        spawn = huoneet[(int)(huoneet.GetLength(0) * 0.5), 0];
271        spawn.Dug = true;
272
273        Direction oviSuunta = Direction.Down;
274        spawn.Walls[oviSuunta].Image = reikaSeinaKuva;
275
276        Light valo = new Light();
277        valo.Position = spawn.Position;
278        valo.Intensity = 1;
279        valo.Distance = 40;
280        Add(valo);
281    }
282
283    void RoomPressed(Room huone)
284    {
285        digStart = huone.Location;
286        digging = true;
287        digArrowHead.IsVisible = digArrow.IsVisible = true;
288    }
289
290    void RoomReleased(Room kohdeHuone)
291    {
292        digging = false;
293        digArrowHead.IsVisible = digArrow.IsVisible = false;
294        if (CanDig())
295        {
296            var alkuHuone = huoneet[digStart.X, digStart.Y];
297
298            // Hienot partikkeliefektit.
299            if (!kohdeHuone.Dug)
300                LuoKiviPartikkelit(kohdeHuone.Position);
301            if (!alkuHuone.Dug)
302                LuoKiviPartikkelit(alkuHuone.Position);
303
304            // Merkataan huoneet kaivetuksi.
305            kohdeHuone.Dug = alkuHuone.Dug = true;
306
307            // Reiät seinään.
308            Direction oviSuunta = (kohdeHuone.Position - alkuHuone.Position).Angle.MainDirection;
309            Direction toinenOviSuunta = Direction.Inverse(oviSuunta);
310            alkuHuone.Walls[oviSuunta].Image = reikaSeinaKuva;
311            kohdeHuone.Walls[toinenOviSuunta].Image = reikaSeinaKuva;
312
313            // Päivitetään huoneiden kultuuri-infot.
314            PaivitaHuoneidenKultuurit();
315        }
316    }
317
318    Room CreateRoom(Point paikka)
319    {
320        Room huone = new Room(paikka);
321        huone.Image = lattiaKuva;
322        huone.Position = new Vector(paikka.X - huoneet.GetLength(0) / 2, paikka.Y - huoneet.GetLength(1) / 2) * RUUDUN_KOKO;
323        huone.Position += huoneSiirtyma;
324        foreach (var suunta in Suunnat())
325            huone.Walls[suunta] = CreateWall(huone.Position, suunta);
326        Add(huone, -2);
327        huone.Roof = new GameObject(RUUDUN_KOKO, RUUDUN_KOKO);
328        huone.Roof.Image = kiviKuva;
329        huone.Roof.Position = huone.Position;
330        Add(huone.Roof, 1);
331
332        Mouse.ListenOn(huone, MouseButton.Left, ButtonState.Pressed, AsetaPaivitys, "Asetetaan ostettu päivitys paikoilleen", huone);
333
334        return huone;
335    }
336
337    void AsetaPaivitys(Room huone)
338    {
339        if (ostamassa != null && huone.Dug && kulttuuri.Value >= ostamassa.Price)
340        {
341            //huone.Damage = ostettu.Damage;
342            //huone.Culture = ostettu.Culture;
343            //huone.Image = ostettu.Image;
344            kulttuuri.Value -= ostamassa.Price;
345
346            // Lisätään päivitys huoneeseen.
347            huone.Upgrade = ostamassa;
348            Add(huone.Upgrade, -1);
349            huone.Upgrade.Position = huone.Position;
350            huone.Upgrade.Built(this);
351
352            ostamassa = null;
353            PaivitaHuoneenKultuuri(huone);
354        }
355    }
356
357    void PaivitaHuoneidenKultuurit()
358    {
359        RuutujenPaikat().Select(GetRoom).ToList().ForEach(PaivitaHuoneenKultuuri); // :D
360    }
361
362    void PaivitaHuoneenKultuuri(Room room)
363    {
364        if (room != null && room.Upgrade != null && room.Upgrade is CultureUpgrade)
365        {
366            var upg = room.Upgrade as CultureUpgrade;
367
368            List<Point> polku = FindPath(room.Location, spawn.Location);
369
370            // TODO: Tässä pitäisi laskea kunnolla polun pituuden perusteella kultuurin määrä, nyt
371            //       se on vain suoraan polun pituus.
372            upg.Culture.Value = polku.Count;
373        }
374    }
375
376    GameObject CreateWall(Vector paikka, Direction suunta)
377    {
378        GameObject wall = new GameObject(RUUDUN_KOKO + 2, RUUDUN_KOKO + 2);
379        wall.Position = paikka;
380        wall.Image = seinaKuva;
381        wall.Angle = suunta.Angle;
382        Add(wall, 0);
383        return wall;
384    }
385
386    bool CanDig()
387    {
388        Room kohdeHuone = GetRoom(MuunnaJypelista(Mouse.PositionOnWorld));
389        if (kohdeHuone == null)
390        {
391            return false;
392        }
393        int dx = Math.Abs(kohdeHuone.Location.X - digStart.X);
394        int dy = Math.Abs(kohdeHuone.Location.Y - digStart.Y);
395        return dx + dy == 1;
396    }
397
398    #region Reitinlöytö
399
400    List<Point> FindPath(Point alku, Point loppu)
401    {
402        if (GetRoom(alku) == null || GetRoom(loppu) == null)
403            return new List<Point>();
404
405        bool[,] walkable = new bool[huoneet.GetLength(0), huoneet.GetLength(1)];
406        foreach (var paikka in RuutujenPaikat())
407        {
408            walkable[paikka.X, paikka.Y] = huoneet[paikka.X, paikka.Y].Dug;
409        }
410        var finder = new AStar.PathFinder(new AStar.SearchParameters(alku, loppu, walkable), OviTarkistus);
411        return finder.FindPath();
412    }
413
414    bool OviTarkistus(Point a, Point b)
415    {
416        Room ra = GetRoom(a);
417        Room rb = GetRoom(b);
418        Direction suunta = (new Vector(b.X, b.Y) - new Vector(a.X, a.Y)).Angle.MainDirection;
419        if (ra != null && rb != null)
420        {
421            return ra.Walls[suunta].Image == reikaSeinaKuva && rb.Walls[Direction.Inverse(suunta)].Image == reikaSeinaKuva;
422        }
423        return false;
424    }
425
426    #endregion
427
428    #region Extra Juttuja
429
430    IEnumerable<Direction> Suunnat()
431    {
432        yield return Direction.Left;
433        yield return Direction.Right;
434        yield return Direction.Up;
435        yield return Direction.Down;
436    }
437
438    IEnumerable<Point> RuutujenPaikat()
439    {
440        return from y in Enumerable.Range(0, huoneet.GetLength(1))
441               from x in Enumerable.Range(0, huoneet.GetLength(0))
442               select new Point(x, y);
443    }
444
445    Room GetRoom(Point paikka)
446    {
447        if (paikka.X >= 0 && paikka.X < huoneet.GetLength(0) && paikka.Y >= 0 && paikka.Y < huoneet.GetLength(1))
448        {
449            return huoneet[paikka.X, paikka.Y];
450        }
451        return null;
452    }
453
454    /// <summary>
455    /// Muuntaa Jypeli-koordinaatin peliruudukon koordinaatiksi.
456    /// </summary>
457    Point MuunnaJypelista(Vector paikka)
458    {
459        Vector siirrettyOrigo = (paikka - huoneSiirtyma) + RUUDUN_KOKO * (0.5 * new Vector(huoneet.GetLength(0), huoneet.GetLength(1)) + new Vector(0.5, 0.5));
460        Vector wtf = new Vector(siirrettyOrigo.X < 0 ? -1 : 0, siirrettyOrigo.Y < 0 ? -1 : 0);
461        Vector valmis = wtf + siirrettyOrigo / RUUDUN_KOKO;
462        return new Point((int)valmis.X, (int)valmis.Y);
463    }
464
465    void LuoKiviPartikkelit(Vector alkupaikka)
466    {
467        // Feikki 3D partikkeli juttu.
468        // Heittää ilmaan GameObjekteja joiden alla on varjo.
469        for (int i = 0; i < 6; i++)
470        {
471            GameObject p = new GameObject(25, 25);
472            p.Image = partikkeli;
473            p.Position = alkupaikka + RandomGen.NextVector(0.0, RUUDUN_KOKO * 0.4);
474            Add(p, 3);
475
476            GameObject varjo = new GameObject(20, 10);
477            varjo.Position = p.Position;
478            varjo.Shape = Shape.Circle;
479            varjo.Color = Color.Lerp(Color.Black, Color.Transparent, 0.5);
480            Add(varjo, 2);
481
482            Vector paikka = p.Position;
483            Vector nopeus = RandomGen.NextVector(0.2, 3.0);
484            nopeus.Y *= 0.3;
485            double g = -0.2; // painovoima
486            double z = 0.0; // sijainti z-akselilla
487            double vz = RandomGen.NextDouble(3.5, 4.5); // nopeus z-akselilla
488            double angularVelocity = RandomGen.NextDouble(-1.0, 1.0) * 8;
489
490            Timer ajastin = new Timer();
491            ajastin.Interval = 0.02;
492            ajastin.Timeout += delegate
493            {
494                vz += g;
495                z += vz;
496                paikka += nopeus;
497                p.Position = paikka + new Vector(0.0, 1.0) * z;
498                p.Angle += Angle.FromDegrees(angularVelocity);
499                varjo.Position = paikka;
500
501                if (z < 0.0)
502                {
503                    ajastin.Stop();
504                    p.Destroy();
505                    varjo.Destroy();
506                }
507            };
508            ajastin.Start();
509        }
510    }
511
512    protected override void Update(Time time)
513    {
514        if (digging)
515        {
516            Color vari = CanDig() ? Color.White : Color.Red;
517            Vector alku = huoneet[digStart.X, digStart.Y].Position;
518            Vector loppu = Mouse.PositionOnWorld;
519            Vector suunta = loppu - alku;
520            double pituus = suunta.Magnitude;
521            if (pituus <= 2) pituus = 2;
522
523            digArrow.Color = vari;
524            digArrow.Position = alku + suunta * 0.5;
525            digArrow.Angle = suunta.Angle;
526            digArrow.Width = pituus;
527
528            digArrowHead.Color = vari;
529            digArrowHead.Position = alku + suunta;
530            digArrowHead.Angle = suunta.Angle - Angle.FromDegrees(90);
531        }
532
533        base.Update(time);
534    }
535
536    protected override void Paint(Canvas canvas)
537    {
538        canvas.BrushColor = Color.Purple;
539
540        var points = FindPath(new Point(6, 0), MuunnaJypelista(Mouse.PositionOnWorld));
541        for (int i = 0; i < points.Count - 1; i++)
542        {
543            Vector v = huoneSiirtyma + new Vector(points[i].X - huoneet.GetLength(0) / 2, points[i].Y - huoneet.GetLength(1) / 2) * RUUDUN_KOKO;
544            Vector v2 = huoneSiirtyma + new Vector(points[i + 1].X - huoneet.GetLength(0) / 2, points[i + 1].Y - huoneet.GetLength(1) / 2) * RUUDUN_KOKO;
545            canvas.DrawLine(v, v2);
546        }
547
548        base.Paint(canvas);
549    }
550
551    #endregion
552}
Note: See TracBrowser for help on using the repository browser.