source: 2010/24/anlakane/Muistipeli/Muistipeli.cs @ 1033

Revision 1033, 20.7 KB checked in by anlakane, 11 years ago (diff)
Line 
1using System;
2using System.IO;
3using System.Collections.Generic;
4using Jypeli;
5using Jypeli.Widgets;
6using Jypeli.ScreenObjects;
7using Jypeli.Assets;
8using Jypeli.Effects;
9
10namespace Muistipeli
11{
12    public struct Paikka
13    {
14        public int Rivi;
15        public int Sarake;
16
17        public Paikka(int rivi, int sarake)
18        {
19            Rivi = rivi;
20            Sarake = sarake;
21        }
22    }
23
24    public struct Pelaaja
25    {
26        public int Numero;
27        public String Nimi;
28        public int Pisteet;
29        public Color Vari;
30
31        public Pelaaja(String nimi, int numero, Color vari)
32        {
33            Numero = numero;
34            Nimi = nimi;
35            Pisteet = 0;
36            Vari = vari;
37        }
38    }
39
40
41    public class Muistipeli : Game
42    {
43        List<GameObject> valikonKohdat;
44
45        int montakoRivia;
46        int montakoSaraketta;
47
48        double korttienVali = 20.0;
49        double kortinLeveys = 50;
50        double kortinKorkeus = 70;
51
52        Kortti[,] kortit; // rivit, sarakkeet
53        Paikka korostettuKortti;
54        int montakoKorttia;
55        int[] montakoKutakinKorttitunnusta;
56
57        public enum Suunta { Vasen, Oikea, Ylos, Alas }
58        Suunta mihinSuuntaanMenossa;
59
60        GameObject highlighter;
61        List<Kortti> kaannetyt; // Yhdellä vuorolla käännetyt kortit. Tyhjennetään vuoron päätteeksi. Listassa voi olla siis 0, 1 tai 2 alkiota.
62        Timer piilotusAjastin;
63        const double aikaaEnnenPiilottamista = 2;
64
65        String korttisarja;
66
67        Pelaaja pelaaja1;
68        Pelaaja pelaaja2;
69        Pelaaja vuorossaOlevaPelaaja;
70        Label vuoronaytto;
71
72        IntMeter pelaajan1Pisteet;
73        IntMeter pelaajan2Pisteet;
74        IntMeter korttejaLoydetty;
75
76        protected override void Begin()
77        {
78            //montakoKorttia = 16; // Pitää olla ennen laskureiden lisäämistä
79            Valikko();
80        }
81
82        public void Valikko()
83        {
84            valikonKohdat = new List<GameObject>();
85            Level.BackgroundColor = Color.White;
86
87            GameObject elaimet = new GameObject(538, 256);
88            elaimet.Image = LoadImage("elaimet");
89            elaimet.Tag = "elaimet";
90            elaimet.Y = elaimet.Height / 2 + 10;
91            valikonKohdat.Add(elaimet);
92
93            GameObject ihmiset = new GameObject(538, 256);
94            ihmiset.Image = LoadImage("ihmiset");
95            ihmiset.Tag = "ihmiset";
96            ihmiset.Y = -ihmiset.Height / 2 - 10;
97            valikonKohdat.Add(ihmiset);
98
99            foreach (var valikonKohta in valikonKohdat)
100            {
101                Add(valikonKohta);
102                Mouse.ListenOn(valikonKohta, MouseButton.Left, ButtonState.Pressed, ValikonValinta, null, valikonKohta);
103            }
104
105            Mouse.IsCursorVisible = true;
106            Mouse.ListenMovement(1.0, ValikossaLiikkuminen, null);
107            Keyboard.Listen(Key.Escape, ButtonState.Pressed, Lopeta, "");
108           
109        }
110
111        public void ValikonValinta(GameObject mitaPainettiin)
112        {
113            AloitaUusiPeli(mitaPainettiin.Tag.ToString());
114        }
115       
116        public void ValikossaLiikkuminen(AnalogState hiirenTila)
117        {
118            foreach (var kohta in valikonKohdat)
119            {
120                if (Mouse.IsCursorOn(kohta))
121                {
122                    kohta.Image = LoadImage(kohta.Tag.ToString() + "_");
123                }
124                else
125                {
126                    kohta.Image = LoadImage(kohta.Tag.ToString());
127                }               
128               
129            }
130        }
131
132
133
134        public void AloitaUusiPeli(String korttisarja)
135        {
136            ClearAll();
137            LisaaPelaajat(2);
138            LisaaPiilotusajastin();
139            this.korttisarja = korttisarja;
140            int montakoKuvaa = LataaKuvat();
141            montakoKorttia = montakoKuvaa * 2;
142
143            // Laitetaan ensin rivejä ja sarakkeita yhtä paljon
144            montakoSaraketta = (int)Math.Sqrt(montakoKorttia);
145            // Kortit vähän mukavempaan muotoon, koska näytöt on yleensä leveämpiä kuin korkeita
146            montakoSaraketta = (int)Math.Floor((3.0 / 2.0) * montakoSaraketta);
147            // Tarvittavien rivien määrä saadaan korttien määrän ja saadun sarakkeiden määrän suhteesta
148            montakoRivia = (int)Math.Ceiling((double)montakoKorttia / (double)montakoSaraketta);
149            kortit = new Kortti[montakoRivia, montakoSaraketta];
150
151            // kortin tunnusNro indeksistä, alkiot tulkitaan siten että "montako tämän tunnuksen alkiota on lisätty peliin"
152            // Tämä pitää olla ennen kuin kortit lisätään ruudulle
153            montakoKutakinKorttitunnusta = new int[montakoKorttia / 2];
154
155            KortitRuudulle();
156            //LisaaKuvat();  // Pitää olla ennen laskureiden lisäämistä
157
158            LisaaLaskurit();
159            LisaaVuoronaytto();
160            LisaaHighLighter();
161
162            // Laitetaan kenttä sopivan kokoiseksi että kortit täyttävät aina mahollisimman paljon ruutukapasiteetista
163            Level.Width = montakoSaraketta * (korttienVali + kortinLeveys) + kortinLeveys;
164            Level.Height = montakoRivia * (korttienVali + kortinKorkeus) + kortinKorkeus;
165            Camera.ZoomToLevel();
166
167            PeliKayntiin();
168            AsetaNappaimet();
169        }
170
171        public void LisaaPiilotusajastin()
172        {
173            piilotusAjastin = new Timer();
174            piilotusAjastin.Interval = aikaaEnnenPiilottamista;
175            piilotusAjastin.Trigger += PiilotaKaannetyt;
176            Add(piilotusAjastin);
177        }
178
179        public void LisaaLaskurit()
180        {
181            pelaajan1Pisteet = new IntMeter(0);
182            Label p1teksti = new Label("Pelaaja 1 pisteet: ");
183            Label pisteNaytto1 = new Label();
184            Label p1VoitotTeksti = new Label("Pelaaja 1 voitot: ");
185            Label p1Voitot = new Label(pelaaja1.Pisteet.ToString());
186
187            p1teksti.TextColor = Color.Black;
188            p1teksti.Position = new Vector(Screen.Left + 140, Screen.Bottom + 70);
189            pisteNaytto1.Position = new Vector(p1teksti.X + (p1teksti.Width / 2) + 10, p1teksti.Y);
190            pisteNaytto1.TextColor = Color.Blue;
191            pisteNaytto1.BindTo(pelaajan1Pisteet);
192            p1VoitotTeksti.Position = new Vector(Screen.Left + 140 - ((p1teksti.Width - p1VoitotTeksti.Width) / 2), p1teksti.Y - 30);
193            p1Voitot.Position = new Vector(p1VoitotTeksti.X + (p1VoitotTeksti.Width / 2) + 10, p1VoitotTeksti.Y);
194
195            Add(p1teksti);
196            Add(pisteNaytto1);
197            Add(p1VoitotTeksti);
198            Add(p1Voitot);
199
200            pelaajan2Pisteet = new IntMeter(0);
201            Label p2teksti = new Label("Pelaaja 2 pisteet: ");
202            Label pisteNaytto2 = new Label();
203            Label p2VoitotTeksti = new Label("Pelaaja 1 voitot: ");
204            Label p2Voitot = new Label(pelaaja2.Pisteet.ToString());
205
206            p2teksti.TextColor = Color.Black;
207            p2teksti.X = Screen.Right - 140;
208            p2teksti.Y = Screen.Bottom + 70;
209            pisteNaytto2.X = p2teksti.X + (p2teksti.Width / 2) + 10;
210            pisteNaytto2.Y = p2teksti.Y;
211            pisteNaytto2.TextColor = Color.Red;
212            pisteNaytto2.BindTo(pelaajan2Pisteet);
213            p2VoitotTeksti.X = Screen.Right - 140 + ((p2teksti.Width - p2VoitotTeksti.Width) / 2);
214            p2VoitotTeksti.Y = p2teksti.Y - 30;
215            p2Voitot.Position = new Vector(p2VoitotTeksti.X + (p2VoitotTeksti.Width / 2) + 10, p2VoitotTeksti.Y);
216
217            Add(p2teksti);
218            Add(pisteNaytto2);
219            Add(p2VoitotTeksti);
220            Add(p2Voitot);
221
222            korttejaLoydetty = new IntMeter(0);
223            korttejaLoydetty.MaxValue = montakoKorttia;
224            korttejaLoydetty.UpperLimit += KaikkiLoydetty;
225        }
226
227        /// <summary>
228        /// Korostetaan ensimmäinen kortti.
229        /// </summary>
230        public void PeliKayntiin()
231        {
232            kaannetyt = new List<Kortti>();
233            korostettuKortti = new Paikka(0, 0);
234            KorostaKortti(new Paikka(0, 0));
235            vuorossaOlevaPelaaja = pelaaja1;
236            Level.BackgroundColor = pelaaja1.Vari;
237            vuoronaytto.Text = "Pelaaja 1";
238            MessageDisplay.Add("Pelaaja 1 aloittaa pelin!");
239        }
240
241
242        public void KaikkiLoydetty(int arvo)
243        {
244            Mouse.IsCursorVisible = true;
245            String voittoteksti;
246            if (pelaajan1Pisteet > pelaajan2Pisteet)
247            {
248                voittoteksti = "Pelaaja 1 voitti! ";
249                pelaaja1.Pisteet++;
250            }
251            else if (pelaajan2Pisteet > pelaajan1Pisteet)
252            {
253                voittoteksti = "Pelaaja 2 voitti! ";
254                pelaaja2.Pisteet++;
255            }
256            else
257            {
258                voittoteksti = "Tasapeli! ";
259            }
260
261            MessageBox m = new MessageBox(
262                "Peli päättyi",
263                "" + voittoteksti + "Aloita uusi peli painamalla OK.");
264            m.OkButton.Clicked += OKPainettu;
265            Add(m);
266        }
267
268        public void OKPainettu()
269        {
270            AloitaUusiPeli(korttisarja);
271        }
272
273        public void LisaaVuoronaytto()
274        {
275            Label vuorossaNyt = new Label("Vuorossa nyt");
276            vuorossaNyt.X = 0;
277            vuorossaNyt.Y = Screen.Bottom + 70;
278            vuoronaytto = new Label();
279            vuoronaytto.X = 0;
280            vuoronaytto.Y = vuorossaNyt.Y - 30;
281            Add(vuorossaNyt);
282            Add(vuoronaytto);
283        }
284
285        void LisaaHighLighter()
286        {
287            highlighter = new GameObject(kortinLeveys, kortinKorkeus);
288            highlighter.Image = LoadImage("highlight1");
289            Add(highlighter);
290        }
291
292        private int LataaKuvat()
293        {
294            List<String> kuvat = new List<string>();
295            String[] kuvatiedostot = Directory.GetFiles(korttisarja);
296            return kuvatiedostot.Length;
297        }
298
299        void LisaaPelaajat(int montakoPelaajaa)
300        {
301            // Toistaiseksi tehdään "manuaalisesti" kaksi pelaajaa
302            pelaaja1 = new Pelaaja("", 1, Color.Cyan);
303            pelaaja2 = new Pelaaja("", 2, Color.MediumPurple);
304        }
305
306        void AsetaNappaimet()
307        {
308            Keyboard.Listen(Key.Left, ButtonState.Pressed, KortinValinta, null, Suunta.Vasen);
309            Keyboard.Listen(Key.Right, ButtonState.Pressed, KortinValinta, null, Suunta.Oikea);
310            Keyboard.Listen(Key.Up, ButtonState.Pressed, KortinValinta, null, Suunta.Ylos);
311            Keyboard.Listen(Key.Down, ButtonState.Pressed, KortinValinta, null, Suunta.Alas);
312            Keyboard.Listen(Key.Space, ButtonState.Pressed, KaannaKortti, null);
313            Keyboard.Listen(Key.Escape, ButtonState.Pressed, Lopeta, null);
314        }
315
316        void Lopeta()
317        {
318            Exit();
319        }
320
321        #region Liikkuminen
322        void KorostaKortti(Paikka korostettavaKortti)
323        {
324            korostettavaKortti = TarkistaKortinNro(korostettavaKortti);
325            highlighter.Position = new Vector(KortinX(korostettavaKortti.Sarake), KortinY(korostettavaKortti.Rivi));
326            Kortti.PuoliEsilla puoliesilla = kortit[korostettavaKortti.Rivi, korostettavaKortti.Sarake].KumpiPuoliEsilla();
327            korostettuKortti = korostettavaKortti;
328        }
329
330        /// <summary>
331        /// Aliohjelma pitää huolen, että valittu kortti on aina
332        /// rivi- ja sarakeindeksien sisäpuolella. Toisin sanoen
333        /// rivistä/sarakkeesta "yli" hypättäessä kursori palautuu
334        /// oikeaan paikkaan.
335        /// </summary>
336        /// <param name="kortinNro">Kortin rivi, sarake</param>
337        /// <returns>"Korjatut" koordinaatit</returns>
338        private Paikka TarkistaKortinNro(Paikka paikka)
339        {
340            // Viimeisen rivin jälkeen palataan ensimmäiselle riville
341            if (paikka.Rivi >= montakoRivia)
342                paikka.Rivi = 0;
343
344            // Viimeisen sarakkeen jälkeen palataan ensimmäiseen sarakkeeseen
345            if (paikka.Sarake >= montakoSaraketta)
346                paikka.Sarake = 0;
347
348            // Ensimmäisestä rivistä "taaksepäin" liikuttaessa
349            // hypätään viimeiselle riville
350            if (paikka.Rivi < 0)
351                paikka.Rivi = montakoRivia - 1;
352
353            // Ensimmäisestä sarakkeesta "taaksepäin" liikuttaessa
354            // hypätään viimeiseen sarakkeeseen
355            if (paikka.Sarake < 0)
356                paikka.Sarake = montakoSaraketta - 1;
357
358            // Mentiin pelipakan "tyhjälle alueelle"
359            if (kortit[paikka.Rivi, paikka.Sarake] == null)
360                paikka = TultiinNullViitteeseen(paikka);
361
362            return paikka;
363        }
364
365        private Paikka TultiinNullViitteeseen(Paikka kortinPaikka)
366        {
367            if (mihinSuuntaanMenossa == Suunta.Vasen)
368                return new Paikka(kortinPaikka.Rivi, (montakoKorttia % montakoSaraketta) - 1);
369            if (mihinSuuntaanMenossa == Suunta.Oikea)
370                return new Paikka(kortinPaikka.Rivi, 0);
371            if (mihinSuuntaanMenossa == Suunta.Ylos)
372                return new Paikka(montakoRivia - 2, kortinPaikka.Sarake);
373
374            // alas
375            return new Paikka(0, kortinPaikka.Sarake);
376        }
377
378        void KortinValinta(Suunta suunta)
379        {
380            mihinSuuntaanMenossa = suunta;
381            if (mihinSuuntaanMenossa == Suunta.Vasen)
382                KorostaKortti(new Paikka(korostettuKortti.Rivi, korostettuKortti.Sarake - 1));
383
384            if (mihinSuuntaanMenossa == Suunta.Oikea)
385                KorostaKortti(new Paikka(korostettuKortti.Rivi, korostettuKortti.Sarake + 1));
386
387            if (mihinSuuntaanMenossa == Suunta.Ylos)
388                KorostaKortti(new Paikka(korostettuKortti.Rivi - 1, korostettuKortti.Sarake));
389
390            if (mihinSuuntaanMenossa == Suunta.Alas)
391                KorostaKortti(new Paikka(korostettuKortti.Rivi + 1, korostettuKortti.Sarake));
392        }
393        #endregion
394
395        #region Kääntäminen ja parin löytyminen
396
397        public bool VoikoKorttiaKaantaa(Kortti kortti)
398        {
399            // Ei käännetä kahta kertaa samaa korttia
400            if (kaannetyt.Count == 0 || kortit[korostettuKortti.Rivi, korostettuKortti.Sarake] != kaannetyt[0])
401            {
402                // Jos kortti "on jo löydetty", niin sitä ei voi missään tapauksessa kääntää
403                bool onkoPoistettuPelista = kortit[korostettuKortti.Rivi, korostettuKortti.Sarake].PoistettuPelista;
404
405                if (!onkoPoistettuPelista)
406                {
407                    return true;
408                }
409            }
410            return false;
411        }
412
413        void KaannaKortti()
414        {
415            if (VoikoKorttiaKaantaa(kortit[korostettuKortti.Rivi, korostettuKortti.Sarake]))
416            {
417                kortit[korostettuKortti.Rivi, korostettuKortti.Sarake].Kaanna();
418                kaannetyt.Add(kortit[korostettuKortti.Rivi, korostettuKortti.Sarake]);
419
420                if (kaannetyt.Count == 2) // Tasan kaksi korttia käännetään yhdellä vuorolla
421                {
422                    if (kaannetyt[0].Tunniste == kaannetyt[1].Tunniste) // Käännetyt kortit muodostavat parin
423                    {
424                        foreach (Kortti kaannetty in kaannetyt)
425                        {
426                            RajaytaKortti(kaannetty);
427                            kaannetty.PoistettuPelista = true;
428                        }
429                        PariLoytyi();
430                    }
431                    else
432                    {
433                        // Jos kaksi korttia on käännetty niin ajastin lähtee käyntiin eikä sinä aikana voi kääntää kortteja
434                        Keyboard.Disable(Key.Space);
435                        piilotusAjastin.Start();
436                    }
437                }
438            }
439        }
440
441        void PiilotaKaannetyt(Timer t)
442        {
443            foreach (var item in kaannetyt)
444            {
445                item.Kaanna();
446            }
447            kaannetyt.Clear();
448            piilotusAjastin.Stop();
449            Keyboard.Enable(Key.Space);
450            VuoroVaihtuu();
451        }
452
453        public void PariLoytyi()
454        {
455            MediaPlayer.Play("tada");
456            kaannetyt.Clear();
457
458            if (vuorossaOlevaPelaaja.Equals(pelaaja1))
459            {
460                pelaajan1Pisteet.Value++;
461            }
462            else if (vuorossaOlevaPelaaja.Equals(pelaaja2))
463            {
464                pelaajan2Pisteet.Value++;
465            }
466
467            korttejaLoydetty.Value += 2;
468        }
469
470        /// <summary>
471        /// Näpsäkkä korttiin kohdistettu "räjähdys" tai mikä efekti lie.
472        /// </summary>
473        /// <param name="kaannetty">Kortti jonka päälle räjähdys tulee.</param>
474        public void RajaytaKortti(Kortti kortti)
475        {
476            Image i = kortti.KuvaPuoliTekstuuri;
477            ExplosionSystem e = new ExplosionSystem(i, 10);
478            e.MinLifetime = 0.3;
479            e.MaxLifetime = 1.5;
480            e.MinVelocity = 1;
481            e.MaxVelocity = 300;
482            e.MinScale = 0.01;
483            e.MaxScale = 0.05;
484            Add(e);
485            e.AddEffect(kortti.Position.X, kortti.Position.Y, 10);
486        }
487
488        public void VuoroVaihtuu()
489        {
490            if (vuorossaOlevaPelaaja.Equals(pelaaja1))
491            {
492                vuorossaOlevaPelaaja = pelaaja2;
493                highlighter.Image = LoadImage("highlight2");
494                vuoronaytto.Text = "Pelaaja 2";
495                Level.BackgroundColor = pelaaja2.Vari;
496                return;
497            }
498
499            if (vuorossaOlevaPelaaja.Equals(pelaaja2))
500            {
501                vuorossaOlevaPelaaja = pelaaja1;
502                highlighter.Image = LoadImage("highlight1");
503                vuoronaytto.Text = "Pelaaja 1";
504                Level.BackgroundColor = pelaaja1.Vari;
505                return;
506            }
507        }
508
509        #endregion
510
511        #region Kortit ruudulle
512
513        /// <summary>
514        /// Aliohjelma lisää halutun määrän kortteja
515        /// taulukkoon ja edelleen ruudulle.
516        /// </summary>
517        /// <param name="montakoKorttiaLisataan">Kuinka monta korttia taulukkoon (attribuutti) lisätään.</param>
518        void KortitRuudulle()
519        {
520            int montakoKorttiaLisatty = 0;
521
522            for (int r = 0; r < kortit.GetLength(0); r++) // Rivit
523            {
524                for (int s = 0; s < kortit.GetLength(1); s++) // Sarakkeet
525                {
526                    // Jos tarvittava määrä kortteja on lisätty,
527                    // laitetaan loppuihin taulukon alkioihin null-viite
528                    if (montakoKorttia == montakoKorttiaLisatty)
529                    {
530                        kortit[r, s] = null;
531                        continue;
532                    }
533
534                    kortit[r, s] = TeeKortti();
535                    kortit[r, s].KuvaPuoliTekstuuri = Image.FromFile(korttisarja + "/" + kortit[r, s].Tunniste.ToString() + ".jpg");
536                    Add(kortit[r, s]);
537
538                    kortit[r, s].X = KortinX(s);
539                    kortit[r, s].Y = KortinY(r);
540                    montakoKorttiaLisatty++;
541                }
542            }
543        }
544
545        public double KortinX(int sarake)
546        {
547            return (-(montakoSaraketta * (kortinLeveys + korttienVali)) / 2) + (sarake * (kortinLeveys + korttienVali)) + korttienVali;
548        }
549
550        public double KortinY(int rivi)
551        {
552            // Viimeinen termi tulee siitä että viimeisen kortin perässä ei tarvita välistystä
553            return ((montakoRivia) * (kortinKorkeus + korttienVali)) / 2 - rivi * (kortinKorkeus + korttienVali) - korttienVali;
554        }
555
556        public Kortti TeeKortti()
557        {
558            Image takaTekstuuri = LoadImage("taka");
559            int tunniste = AnnaTunniste();
560            return new Kortti(kortinLeveys, kortinKorkeus, false, takaTekstuuri, tunniste);
561        }
562
563        private int AnnaTunniste()
564        {
565            int tunniste;
566            while (true)
567            {
568                tunniste = RandomGen.NextInt(0, montakoKutakinKorttitunnusta.Length - 1);
569                if (montakoKutakinKorttitunnusta[tunniste] < 2)
570                {
571                    montakoKutakinKorttitunnusta[tunniste]++;
572                    break;
573                }
574            }
575            return tunniste;
576        }
577        #endregion
578    }
579}
Note: See TracBrowser for help on using the repository browser.