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

Revision 6007, 19.7 KB checked in by empaheik, 5 years ago (diff)
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 Barbaari : GameObject
112{
113    public Barbaari(double width, double height)
114        :base(width, height)
115    { }
116
117    public int Askel { get; set; }
118
119}
120
121public class Dungeon : PhysicsGame
122{
123    public const int RUUDUN_KOKO = 64;
124
125    #region Kuvat
126    Image lattiaKuva = LoadImage("floor");
127    Image seinaKuva = LoadImage("wall");
128    Image reikaSeinaKuva = LoadImage("wallhole");
129    Image kiviKuva = LoadImage("rock");
130    static Image kulttuuriKuva1 = LoadImage("es");
131    static Image kulttuuriKuva2 = LoadImage("nyan");
132    static Image kulttuuriKuva3 = LoadImage("spurdo");
133    Image[] kultuuriKuvat = new Image[] { kulttuuriKuva1, kulttuuriKuva2, kulttuuriKuva3 };
134    Image[] vihuKuvat = LoadImages((from i in Enumerable.Range(1, 10) select String.Format("v{0:0000}", i)).ToArray());
135    Image partikkeli = LoadImage("partikkeli");
136    #endregion
137
138    int[] hinnat = new int[] { 100, 200, 300 };
139    private int barbaariMaara = 3;
140
141    Room[,] huoneet;
142    List<Room> kohteet = new List<Room>();
143    Room spawn;
144    Timer barbaariAjastin = new Timer();
145    Upgrade ostamassa;
146    Point digStart; // Huoneen sijainti, josta kaivuu aloitetaan.
147    bool digging = false;
148
149    GameObject digArrow;
150    GameObject digArrowHead;
151
152    IntMeter kulttuuri = new IntMeter(300, 0, 2000);
153
154    int vaakaHuoneet = 12;
155    int pystyHuoneet = 8;
156
157    // Paljonko peliruudukko on siirtynyt origosta.
158    Vector huoneSiirtyma = new Vector(-300, 0);
159
160    public override void Begin()
161    {
162        ClearAll();
163        Kontrollit();
164        UlkoAsuRoskaa();
165        Kauppa();
166        Nuoli();
167
168        // Luodaan huoneet ruutuihin.
169        huoneet = new Room[vaakaHuoneet, pystyHuoneet];
170        foreach (var paikka in RuutujenPaikat())
171        {
172            var huone = CreateRoom(paikka);
173            Mouse.ListenOn(huone, MouseButton.Left, ButtonState.Pressed, () => RoomPressed(huone), null);
174            Mouse.ListenOn(huone, MouseButton.Left, ButtonState.Released, () => RoomReleased(huone), null);
175            huoneet[paikka.X, paikka.Y] = huone;
176        }
177
178        LuoSpawn();
179
180        barbaariAjastin.Timeout += delegate { LuoBarbaareja(); };
181        barbaariAjastin.Interval = 3;
182    }
183
184    void Nuoli()
185    {
186        digArrow = new GameObject(5, 5);
187        digArrowHead = new GameObject(15, 15);
188        digArrowHead.Shape = Shape.Triangle;
189        digArrowHead.IsVisible = digArrow.IsVisible = false;
190        Add(digArrow, 3);
191        Add(digArrowHead, 3);
192    }
193
194    void UlkoAsuRoskaa()
195    {
196        Level.Background.Color = Color.Black;
197
198        Label rahat = new Label();
199        rahat.BindTo(kulttuuri);
200        rahat.Position = new Vector(Level.Right + Level.Width * 0.2, Level.Bottom + Level.Height * 0.1);
201        rahat.TextColor = Color.White;
202        rahat.IntFormatString = "Käytettävää kulttuuria: {0:D3}";
203        Add(rahat);
204    }
205
206    void Kauppa()
207    {
208        for (int i = 0; i < kultuuriKuvat.Length; i++)
209        {
210            /*
211            Point lokaatio = new Point(0, 0);
212
213            Room kuva = new Room(lokaatio);
214            kuva.Position = new Vector((Level.Right + Level.Width * 0.05), (Level.Top - Level.Height * 0.25 - (i * RUUDUN_KOKO)));
215            kuva.Image = kultuuriKuvat[i];
216            kuva.Price = hinnat[i];
217            Add(kuva);
218
219            Mouse.ListenOn(kuva, MouseButton.Left, ButtonState.Pressed, delegate(Room a) { ostettu = a; }, "Asetetaan ostettu huone paikoilleen", kuva);
220            */
221
222            // Ostettavat päivitykset on nyt PushButtoneita huoneiden sijaan.
223
224            PushButton kuva = new PushButton(kultuuriKuvat[i]);
225            kuva.Size = new Vector(1, 1) * RUUDUN_KOKO;
226            kuva.Position = new Vector((Level.Right + Level.Width * 0.05), (Level.Top - Level.Height * 0.25 - (i * RUUDUN_KOKO)));
227            Add(kuva);
228
229            int indeksi = i; // Alla oleva delegaatti vaatii uuden indeksi muuttujan toimiakseen.
230            kuva.Clicked += delegate
231            {
232                ostamassa = LuoKultuuriPaivitys(kultuuriKuvat[indeksi], hinnat[indeksi]);
233            };
234
235            Mouse.Listen(MouseButton.Right, ButtonState.Pressed, delegate() { ostamassa = null; }, "Perutaan ostos");
236
237            Label teksti = new Label();
238            teksti.Position = kuva.Position + new Vector((RUUDUN_KOKO * 1.2), 0);
239            teksti.TextColor = Color.White;
240            teksti.Text = hinnat[i].ToString();
241            Add(teksti);
242        }
243    }
244
245    Upgrade LuoKultuuriPaivitys(Image kuva, int hinta)
246    {
247        CultureUpgrade upg = new CultureUpgrade();
248        upg.Image = kuva;
249        upg.Size = new Vector(0.5, 0.5) * RUUDUN_KOKO;
250        upg.Price = hinta;
251        return upg;
252    }
253
254    void LuoBarbaareja()
255    {
256        Barbaari barbaari = new Barbaari(RUUDUN_KOKO * 0.4, RUUDUN_KOKO * 0.4);
257        barbaari.Color = Color.Red;
258        //barbaari.Position = RandomGen.NextVector(Level.Right, Level.Bottom, Level.Left, Level.Top);
259        barbaari.Position = spawn.Position;
260        barbaari.Animation = new Animation(vihuKuvat);
261        barbaari.Animation.FPS = 10;
262        barbaari.Animation.Start();
263        Add(barbaari);
264
265        EtsiBarbaarinReitti(barbaari);
266    }
267
268    void EtsiBarbaarinReitti(Barbaari barbaari)
269    {
270        Room kohde = kohteet[RandomGen.NextInt(kohteet.Count)];
271
272        List<Point> polku = FindPath(kohde.Location, spawn.Location);
273        //polku.Reverse();
274
275        KuljePolkua(barbaari, polku);
276    }
277
278    void KuljePolkua(Barbaari barbaari, List<Point> polku)
279    {
280
281        Timer siirtoAjastin = new Timer();
282        siirtoAjastin.Interval = 2;
283        siirtoAjastin.Timeout += delegate
284        {
285            barbaari.MoveTo(huoneet[polku[barbaari.Askel].X, polku[ barbaari.Askel++].Y].Position, 100);
286        };
287        siirtoAjastin.Start(polku.Count);
288
289    }
290
291    void Kontrollit()
292    {
293        IsMouseVisible = true;
294        Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
295        Keyboard.Listen(Key.F1, ButtonState.Pressed, Begin, null);
296
297
298        Keyboard.Listen(Key.Space, ButtonState.Pressed, SeuraavaAalto, "Anna kivan barbaariaallon tulla");
299    }
300
301    void SeuraavaAalto()
302    {
303        barbaariMaara += 2;
304        barbaariAjastin.Start(barbaariMaara);
305    }
306
307    void LuoSpawn()
308    {
309        spawn = huoneet[(int)(huoneet.GetLength(0) * 0.5), 0];
310        spawn.Dug = true;
311
312        Direction oviSuunta = Direction.Down;
313        spawn.Walls[oviSuunta].Image = reikaSeinaKuva;
314
315        Light valo = new Light();
316        valo.Position = spawn.Position;
317        valo.Intensity = 1;
318        valo.Distance = 40;
319        Add(valo);
320    }
321
322    void RoomPressed(Room huone)
323    {
324        digStart = huone.Location;
325        digging = true;
326        digArrowHead.IsVisible = digArrow.IsVisible = true;
327    }
328
329    void RoomReleased(Room kohdeHuone)
330    {
331        digging = false;
332        digArrowHead.IsVisible = digArrow.IsVisible = false;
333        if (CanDig())
334        {
335            int dx = kohdeHuone.Location.X - digStart.X;
336            int dy = kohdeHuone.Location.Y - digStart.Y;
337            Point[] kaivettavatPaikat = RuudutSuoralta(digStart, dx, dy).ToArray();
338            MessageDisplay.Add("" + kaivettavatPaikat.Length);
339            for (int i = 0; i < kaivettavatPaikat.Length - 1; i++)
340            {
341                Dig(GetRoom(kaivettavatPaikat[i]), GetRoom(kaivettavatPaikat[i + 1]));
342            }
343           
344            //var alkuHuone = huoneet[digStart.X, digStart.Y];
345
346            // Päivitetään huoneiden kultuuri-infot.
347            PaivitaHuoneidenKultuurit();
348        }
349    }
350
351    void Dig(Room alku, Room kohde)
352    {
353        // Hienot partikkeliefektit.
354        if (!alku.Dug)
355            LuoKiviPartikkelit(alku.Position);
356        if (!kohde.Dug)
357            LuoKiviPartikkelit(kohde.Position);
358
359        // Merkataan huoneet kaivetuksi.
360        alku.Dug = kohde.Dug = true;
361
362        // Reiät seinään.
363        Direction oviSuunta = (kohde.Position - alku.Position).Angle.MainDirection;
364        Direction toinenOviSuunta = Direction.Inverse(oviSuunta);
365        alku.Walls[oviSuunta].Image = reikaSeinaKuva;
366        kohde.Walls[toinenOviSuunta].Image = reikaSeinaKuva;
367    }
368
369    Room CreateRoom(Point paikka)
370    {
371        Room huone = new Room(paikka);
372        huone.Image = lattiaKuva;
373        huone.Position = new Vector(paikka.X - huoneet.GetLength(0) / 2, paikka.Y - huoneet.GetLength(1) / 2) * RUUDUN_KOKO;
374        huone.Position += huoneSiirtyma;
375        foreach (var suunta in Suunnat())
376            huone.Walls[suunta] = CreateWall(huone.Position, suunta);
377        Add(huone, -2);
378        huone.Roof = new GameObject(RUUDUN_KOKO, RUUDUN_KOKO);
379        huone.Roof.Image = kiviKuva;
380        huone.Roof.Position = huone.Position;
381        Add(huone.Roof, 1);
382
383        Mouse.ListenOn(huone, MouseButton.Left, ButtonState.Pressed, AsetaPaivitys, "Asetetaan ostettu päivitys paikoilleen", huone);
384
385        return huone;
386    }
387
388    void AsetaPaivitys(Room huone)
389    {
390        if (ostamassa != null && huone.Dug && kulttuuri.Value >= ostamassa.Price)
391        {
392            kulttuuri.Value -= ostamassa.Price;
393
394            // Lisätään päivitys huoneeseen.
395            huone.Upgrade = ostamassa;
396            Add(huone.Upgrade, -1);
397            huone.Upgrade.Position = huone.Position;
398            huone.Upgrade.Built(this);
399
400            ostamassa = null;
401            PaivitaHuoneenKultuuri(huone);
402        }
403    }
404
405    void PaivitaHuoneidenKultuurit()
406    {
407        RuutujenPaikat().Select(GetRoom).ToList().ForEach(PaivitaHuoneenKultuuri); // :D
408    }
409
410    void PaivitaHuoneenKultuuri(Room room)
411    {
412        if (room != null && room.Upgrade != null && room.Upgrade is CultureUpgrade)
413        {
414            var upg = room.Upgrade as CultureUpgrade;
415
416            List<Point> polku = FindPath(room.Location, spawn.Location);
417
418            // TODO: Tässä pitäisi laskea kunnolla polun pituuden perusteella kultuurin määrä, nyt
419            //       se on vain suoraan polun pituus.
420            upg.Culture.Value = polku.Count;
421
422            kohteet.Add(room);
423        }
424    }
425
426    GameObject CreateWall(Vector paikka, Direction suunta)
427    {
428        GameObject wall = new GameObject(RUUDUN_KOKO + 2, RUUDUN_KOKO + 2);
429        wall.Position = paikka;
430        wall.Image = seinaKuva;
431        wall.Angle = suunta.Angle;
432        Add(wall, 0);
433        return wall;
434    }
435
436    bool CanDig()
437    {
438        Room kohdeHuone = GetRoom(MuunnaJypelista(Mouse.PositionOnWorld));
439        if (kohdeHuone == null)
440        {
441            return false;
442        }
443
444        int dx = Math.Abs(kohdeHuone.Location.X - digStart.X);
445        int dy = Math.Abs(kohdeHuone.Location.Y - digStart.Y);
446        return (dx > 0 && dy == 0) || (dy > 0 && dx == 0);
447    }
448
449    #region Reitinlöytö
450
451    List<Point> FindPath(Point alku, Point loppu)
452    {
453        if (GetRoom(alku) == null || GetRoom(loppu) == null)
454            return new List<Point>();
455
456        bool[,] walkable = new bool[huoneet.GetLength(0), huoneet.GetLength(1)];
457        foreach (var paikka in RuutujenPaikat())
458        {
459            walkable[paikka.X, paikka.Y] = huoneet[paikka.X, paikka.Y].Dug;
460        }
461        var finder = new AStar.PathFinder(new AStar.SearchParameters(loppu, alku, walkable), OviTarkistus);
462        return finder.FindPath();
463    }
464
465    bool OviTarkistus(Point a, Point b)
466    {
467        Room ra = GetRoom(a);
468        Room rb = GetRoom(b);
469        Direction suunta = (new Vector(b.X, b.Y) - new Vector(a.X, a.Y)).Angle.MainDirection;
470        if (ra != null && rb != null)
471        {
472            return ra.Walls[suunta].Image == reikaSeinaKuva && rb.Walls[Direction.Inverse(suunta)].Image == reikaSeinaKuva;
473        }
474        return false;
475    }
476
477    #endregion
478
479    #region Extra Juttuja
480
481    IEnumerable<Direction> Suunnat()
482    {
483        yield return Direction.Left;
484        yield return Direction.Right;
485        yield return Direction.Up;
486        yield return Direction.Down;
487    }
488
489    IEnumerable<Point> RuutujenPaikat()
490    {
491        return from y in Enumerable.Range(0, huoneet.GetLength(1))
492               from x in Enumerable.Range(0, huoneet.GetLength(0))
493               select new Point(x, y);
494    }
495
496    /// <summary>
497    /// Palauttaa ruutuja suoralta pätkältä dx ja dy verran alkaen pisteestä "alku".
498    /// dx tai dy pitää olla nolla.
499    /// </summary>
500    IEnumerable<Point> RuudutSuoralta(Point alku, int dx, int dy)
501    {
502        if (dx != 0)
503        {
504            for (int i = 0; i < Math.Abs(dx) + 1; i++)
505            {
506                yield return new Point(alku.X + i * Math.Sign(dx), alku.Y);
507            }
508            yield break;
509        }
510        if (dy != 0)
511        {
512            for (int i = 0; i < Math.Abs(dy) + 1; i++)
513            {
514                yield return new Point(alku.X, alku.Y + i * Math.Sign(dy));
515            }
516        }
517    }
518
519    Room GetRoom(Point paikka)
520    {
521        if (paikka.X >= 0 && paikka.X < huoneet.GetLength(0) && paikka.Y >= 0 && paikka.Y < huoneet.GetLength(1))
522        {
523            return huoneet[paikka.X, paikka.Y];
524        }
525        return null;
526    }
527
528    /// <summary>
529    /// Muuntaa Jypeli-koordinaatin peliruudukon koordinaatiksi.
530    /// </summary>
531    Point MuunnaJypelista(Vector paikka)
532    {
533        Vector siirrettyOrigo = (paikka - huoneSiirtyma) + RUUDUN_KOKO * (0.5 * new Vector(huoneet.GetLength(0), huoneet.GetLength(1)) + new Vector(0.5, 0.5));
534        Vector wtf = new Vector(siirrettyOrigo.X < 0 ? -1 : 0, siirrettyOrigo.Y < 0 ? -1 : 0);
535        Vector valmis = wtf + siirrettyOrigo / RUUDUN_KOKO;
536        return new Point((int)valmis.X, (int)valmis.Y);
537    }
538
539    void LuoKiviPartikkelit(Vector alkupaikka)
540    {
541        // Feikki 3D partikkeli juttu.
542        // Heittää ilmaan GameObjekteja joiden alla on varjo.
543        for (int i = 0; i < 6; i++)
544        {
545            GameObject p = new GameObject(25, 25);
546            p.Image = partikkeli;
547            p.Position = alkupaikka + RandomGen.NextVector(0.0, RUUDUN_KOKO * 0.4);
548            Add(p, 3);
549
550            GameObject varjo = new GameObject(20, 10);
551            varjo.Position = p.Position;
552            varjo.Shape = Shape.Circle;
553            varjo.Color = Color.Lerp(Color.Black, Color.Transparent, 0.5);
554            Add(varjo, 2);
555
556            Vector paikka = p.Position;
557            Vector nopeus = RandomGen.NextVector(0.2, 3.0);
558            nopeus.Y *= 0.3;
559            double g = -0.2; // painovoima
560            double z = 0.0; // sijainti z-akselilla
561            double vz = RandomGen.NextDouble(3.5, 4.5); // nopeus z-akselilla
562            double angularVelocity = RandomGen.NextDouble(-1.0, 1.0) * 8;
563
564            Timer ajastin = new Timer();
565            ajastin.Interval = 0.02;
566            ajastin.Timeout += delegate
567            {
568                vz += g;
569                z += vz;
570                paikka += nopeus;
571                p.Position = paikka + new Vector(0.0, 1.0) * z;
572                p.Angle += Angle.FromDegrees(angularVelocity);
573                varjo.Position = paikka;
574
575                if (z < 0.0)
576                {
577                    ajastin.Stop();
578                    p.Destroy();
579                    varjo.Destroy();
580                }
581            };
582            ajastin.Start();
583        }
584    }
585
586    protected override void Update(Time time)
587    {
588        if (digging)
589        {
590            Color vari = CanDig() ? Color.White : Color.Red;
591            Vector alku = huoneet[digStart.X, digStart.Y].Position;
592            Vector loppu = Mouse.PositionOnWorld;
593            Vector suunta = loppu - alku;
594            double pituus = suunta.Magnitude;
595            if (pituus <= 2) pituus = 2;
596
597            digArrow.Color = vari;
598            digArrow.Position = alku + suunta * 0.5;
599            digArrow.Angle = suunta.Angle;
600            digArrow.Width = pituus;
601
602            digArrowHead.Color = vari;
603            digArrowHead.Position = alku + suunta;
604            digArrowHead.Angle = suunta.Angle - Angle.FromDegrees(90);
605        }
606
607        base.Update(time);
608    }
609
610    protected override void Paint(Canvas canvas)
611    {
612        canvas.BrushColor = Color.Purple;
613
614        var points = FindPath(new Point(6, 0), MuunnaJypelista(Mouse.PositionOnWorld));
615        for (int i = 0; i < points.Count - 1; i++)
616        {
617            Vector v = huoneSiirtyma + new Vector(points[i].X - huoneet.GetLength(0) / 2, points[i].Y - huoneet.GetLength(1) / 2) * RUUDUN_KOKO;
618            Vector v2 = huoneSiirtyma + new Vector(points[i + 1].X - huoneet.GetLength(0) / 2, points[i + 1].Y - huoneet.GetLength(1) / 2) * RUUDUN_KOKO;
619            canvas.DrawLine(v, v2);
620        }
621
622        base.Paint(canvas);
623    }
624
625    #endregion
626}
Note: See TracBrowser for help on using the repository browser.