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

Revision 1036, 20.4 KB checked in by anlakane, 11 years ago (diff)

Hierontaa.

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            Valikko();
79        }
80
81        public void Valikko()
82        {
83            ClearAll();
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        public void AloitaUusiPeli(String korttisarja)
134        {
135            ClearAll();
136            Level.BackgroundColor = Color.LightCyan;
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
157            LisaaLaskurit();
158            LisaaVuoronaytto();
159            LisaaHighLighter();
160
161            // Laitetaan kenttä sopivan kokoiseksi että kortit täyttävät aina mahollisimman paljon ruutukapasiteetista
162            Level.Width = montakoSaraketta * (korttienVali + kortinLeveys) + kortinLeveys;
163            Level.Height = montakoRivia * (korttienVali + kortinKorkeus) + kortinKorkeus;
164            Camera.ZoomToLevel();
165
166            PeliKayntiin();
167            AsetaNappaimet();
168        }
169
170        public void LisaaPiilotusajastin()
171        {
172            piilotusAjastin = new Timer();
173            piilotusAjastin.Interval = aikaaEnnenPiilottamista;
174            piilotusAjastin.Trigger += PiilotaKaannetyt;
175            Add(piilotusAjastin);
176        }
177
178        public void LisaaLaskurit()
179        {
180            pelaajan1Pisteet = new IntMeter(0);
181            Label p1teksti = new Label("Pelaaja 1 pisteet: ");
182            Label pisteNaytto1 = new Label();
183            Label p1VoitotTeksti = new Label("Pelaaja 1 voitot: ");
184            Label p1Voitot = new Label(pelaaja1.Pisteet.ToString());
185
186            p1teksti.TextColor = Color.Black;
187            p1teksti.Position = new Vector(Screen.Left + 140, Screen.Bottom + 70);
188            pisteNaytto1.Position = new Vector(p1teksti.X + (p1teksti.Width / 2) + 10, p1teksti.Y);
189            pisteNaytto1.TextColor = Color.Blue;
190            pisteNaytto1.BindTo(pelaajan1Pisteet);
191            p1VoitotTeksti.Position = new Vector(Screen.Left + 140 - ((p1teksti.Width - p1VoitotTeksti.Width) / 2), p1teksti.Y - 30);
192            p1Voitot.Position = new Vector(p1VoitotTeksti.X + (p1VoitotTeksti.Width / 2) + 10, p1VoitotTeksti.Y);
193
194            Add(p1teksti);
195            Add(pisteNaytto1);
196            Add(p1VoitotTeksti);
197            Add(p1Voitot);
198
199            pelaajan2Pisteet = new IntMeter(0);
200            Label p2teksti = new Label("Pelaaja 2 pisteet: ");
201            Label pisteNaytto2 = new Label();
202            Label p2VoitotTeksti = new Label("Pelaaja 1 voitot: ");
203            Label p2Voitot = new Label(pelaaja2.Pisteet.ToString());
204
205            p2teksti.TextColor = Color.Black;
206            p2teksti.X = Screen.Right - 140;
207            p2teksti.Y = Screen.Bottom + 70;
208            pisteNaytto2.X = p2teksti.X + (p2teksti.Width / 2) + 10;
209            pisteNaytto2.Y = p2teksti.Y;
210            pisteNaytto2.TextColor = Color.Red;
211            pisteNaytto2.BindTo(pelaajan2Pisteet);
212            p2VoitotTeksti.X = Screen.Right - 140 + ((p2teksti.Width - p2VoitotTeksti.Width) / 2);
213            p2VoitotTeksti.Y = p2teksti.Y - 30;
214            p2Voitot.Position = new Vector(p2VoitotTeksti.X + (p2VoitotTeksti.Width / 2) + 10, p2VoitotTeksti.Y);
215
216            Add(p2teksti);
217            Add(pisteNaytto2);
218            Add(p2VoitotTeksti);
219            Add(p2Voitot);
220
221            korttejaLoydetty = new IntMeter(0);
222            korttejaLoydetty.MaxValue = montakoKorttia;
223            korttejaLoydetty.UpperLimit += KaikkiLoydetty;
224        }
225
226        /// <summary>
227        /// Korostetaan ensimmäinen kortti.
228        /// </summary>
229        public void PeliKayntiin()
230        {
231            kaannetyt = new List<Kortti>();
232            korostettuKortti = new Paikka(0, 0);
233            KorostaKortti(new Paikka(0, 0));
234            vuorossaOlevaPelaaja = pelaaja1;
235            vuoronaytto.Text = "Pelaaja 1";
236            MessageDisplay.Add("Pelaaja 1 aloittaa pelin!");
237        }
238
239
240        public void KaikkiLoydetty(int arvo)
241        {
242            Mouse.IsCursorVisible = true;
243            String voittoteksti;
244            if (pelaajan1Pisteet > pelaajan2Pisteet)
245            {
246                voittoteksti = "Pelaaja 1 voitti! ";
247                pelaaja1.Pisteet++;
248            }
249            else if (pelaajan2Pisteet > pelaajan1Pisteet)
250            {
251                voittoteksti = "Pelaaja 2 voitti! ";
252                pelaaja2.Pisteet++;
253            }
254            else
255            {
256                voittoteksti = "Tasapeli! ";
257            }
258
259            MessageBox mb = new MessageBox(
260                "Peli päättyi",
261                "" + voittoteksti + "Aloita uusi peli painamalla OK.");
262            mb.OkButton.Clicked += OKPainettu;           
263            Add(mb);
264        }
265
266        public void OKPainettu()
267        {
268            AloitaUusiPeli(korttisarja);
269        }
270
271        public void LisaaVuoronaytto()
272        {
273            Label vuorossaNyt = new Label("Vuorossa nyt");
274            vuorossaNyt.X = 0;
275            vuorossaNyt.Y = Screen.Bottom + 70;
276            vuoronaytto = new Label();
277            vuoronaytto.X = 0;
278            vuoronaytto.Y = vuorossaNyt.Y - 30;
279            Add(vuorossaNyt);
280            Add(vuoronaytto);
281        }
282
283        void LisaaHighLighter()
284        {
285            highlighter = new GameObject(kortinLeveys, kortinKorkeus);
286            highlighter.Image = LoadImage("highlight1");
287            Add(highlighter);
288        }
289
290        private int LataaKuvat()
291        {
292            List<String> kuvat = new List<string>();
293            String[] kuvatiedostot = Directory.GetFiles(korttisarja);
294            return kuvatiedostot.Length;
295        }
296
297        void LisaaPelaajat(int montakoPelaajaa)
298        {
299            // Toistaiseksi tehdään "manuaalisesti" kaksi pelaajaa
300            pelaaja1 = new Pelaaja("", 1, Color.Cyan);
301            pelaaja2 = new Pelaaja("", 2, Color.MediumPurple);
302        }
303
304        void AsetaNappaimet()
305        {
306            Keyboard.Listen(Key.Left, ButtonState.Pressed, KortinValinta, null, Suunta.Vasen);
307            Keyboard.Listen(Key.Right, ButtonState.Pressed, KortinValinta, null, Suunta.Oikea);
308            Keyboard.Listen(Key.Up, ButtonState.Pressed, KortinValinta, null, Suunta.Ylos);
309            Keyboard.Listen(Key.Down, ButtonState.Pressed, KortinValinta, null, Suunta.Alas);
310            Keyboard.Listen(Key.Space, ButtonState.Pressed, KaannaKortti, null);
311            Keyboard.Listen(Key.Escape, ButtonState.Pressed, Lopeta, null);
312        }
313
314        void Lopeta()
315        {
316            Exit();
317        }
318
319        #region Liikkuminen
320        void KorostaKortti(Paikka korostettavaKortti)
321        {
322            korostettavaKortti = TarkistaKortinNro(korostettavaKortti);
323            highlighter.Position = new Vector(KortinX(korostettavaKortti.Sarake), KortinY(korostettavaKortti.Rivi));
324            Kortti.PuoliEsilla puoliesilla = kortit[korostettavaKortti.Rivi, korostettavaKortti.Sarake].KumpiPuoliEsilla();
325            korostettuKortti = korostettavaKortti;
326        }
327
328        /// <summary>
329        /// Aliohjelma pitää huolen, että valittu kortti on aina
330        /// rivi- ja sarakeindeksien sisäpuolella. Toisin sanoen
331        /// rivistä/sarakkeesta "yli" hypättäessä kursori palautuu
332        /// oikeaan paikkaan.
333        /// </summary>
334        /// <param name="kortinNro">Kortin rivi, sarake</param>
335        /// <returns>"Korjatut" koordinaatit</returns>
336        private Paikka TarkistaKortinNro(Paikka paikka)
337        {
338            // Viimeisen rivin jälkeen palataan ensimmäiselle riville
339            if (paikka.Rivi >= montakoRivia)
340                paikka.Rivi = 0;
341
342            // Viimeisen sarakkeen jälkeen palataan ensimmäiseen sarakkeeseen
343            if (paikka.Sarake >= montakoSaraketta)
344                paikka.Sarake = 0;
345
346            // Ensimmäisestä rivistä "taaksepäin" liikuttaessa
347            // hypätään viimeiselle riville
348            if (paikka.Rivi < 0)
349                paikka.Rivi = montakoRivia - 1;
350
351            // Ensimmäisestä sarakkeesta "taaksepäin" liikuttaessa
352            // hypätään viimeiseen sarakkeeseen
353            if (paikka.Sarake < 0)
354                paikka.Sarake = montakoSaraketta - 1;
355
356            // Mentiin pelipakan "tyhjälle alueelle"
357            if (kortit[paikka.Rivi, paikka.Sarake] == null)
358                paikka = TultiinNullViitteeseen(paikka);
359
360            return paikka;
361        }
362
363        private Paikka TultiinNullViitteeseen(Paikka kortinPaikka)
364        {
365            if (mihinSuuntaanMenossa == Suunta.Vasen)
366                return new Paikka(kortinPaikka.Rivi, (montakoKorttia % montakoSaraketta) - 1);
367            if (mihinSuuntaanMenossa == Suunta.Oikea)
368                return new Paikka(kortinPaikka.Rivi, 0);
369            if (mihinSuuntaanMenossa == Suunta.Ylos)
370                return new Paikka(montakoRivia - 2, kortinPaikka.Sarake);
371
372            // alas
373            return new Paikka(0, kortinPaikka.Sarake);
374        }
375
376        void KortinValinta(Suunta suunta)
377        {
378            mihinSuuntaanMenossa = suunta;
379            if (mihinSuuntaanMenossa == Suunta.Vasen)
380                KorostaKortti(new Paikka(korostettuKortti.Rivi, korostettuKortti.Sarake - 1));
381
382            if (mihinSuuntaanMenossa == Suunta.Oikea)
383                KorostaKortti(new Paikka(korostettuKortti.Rivi, korostettuKortti.Sarake + 1));
384
385            if (mihinSuuntaanMenossa == Suunta.Ylos)
386                KorostaKortti(new Paikka(korostettuKortti.Rivi - 1, korostettuKortti.Sarake));
387
388            if (mihinSuuntaanMenossa == Suunta.Alas)
389                KorostaKortti(new Paikka(korostettuKortti.Rivi + 1, korostettuKortti.Sarake));
390        }
391        #endregion
392
393        #region Kääntäminen ja parin löytyminen
394
395        public bool VoikoKorttiaKaantaa(Kortti kortti)
396        {
397            // Ei käännetä kahta kertaa samaa korttia
398            if (kaannetyt.Count == 0 || kortit[korostettuKortti.Rivi, korostettuKortti.Sarake] != kaannetyt[0])
399            {
400                // Jos kortti "on jo löydetty", niin sitä ei voi missään tapauksessa kääntää
401                bool onkoPoistettuPelista = kortit[korostettuKortti.Rivi, korostettuKortti.Sarake].PoistettuPelista;
402
403                if (!onkoPoistettuPelista)
404                {
405                    return true;
406                }
407            }
408            return false;
409        }
410
411        void KaannaKortti()
412        {
413            if (VoikoKorttiaKaantaa(kortit[korostettuKortti.Rivi, korostettuKortti.Sarake]))
414            {
415                kortit[korostettuKortti.Rivi, korostettuKortti.Sarake].Kaanna();
416                kaannetyt.Add(kortit[korostettuKortti.Rivi, korostettuKortti.Sarake]);
417
418                if (kaannetyt.Count == 2) // Tasan kaksi korttia käännetään yhdellä vuorolla
419                {
420                    if (kaannetyt[0].Tunniste == kaannetyt[1].Tunniste) // Käännetyt kortit muodostavat parin
421                    {
422                        foreach (Kortti kaannetty in kaannetyt)
423                        {
424                            RajaytaKortti(kaannetty);
425                            kaannetty.PoistettuPelista = true;
426                        }
427                        PariLoytyi();
428                    }
429                    else
430                    {
431                        // Jos kaksi korttia on käännetty niin ajastin lähtee käyntiin eikä sinä aikana voi kääntää kortteja
432                        Keyboard.Disable(Key.Space);
433                        piilotusAjastin.Start();
434                    }
435                }
436            }
437        }
438
439        void PiilotaKaannetyt(Timer t)
440        {
441            foreach (var item in kaannetyt)
442            {
443                item.Kaanna();
444            }
445            kaannetyt.Clear();
446            piilotusAjastin.Stop();
447            Keyboard.Enable(Key.Space);
448            VuoroVaihtuu();
449        }
450
451        public void PariLoytyi()
452        {
453            MediaPlayer.Play("tada");
454            kaannetyt.Clear();
455
456            if (vuorossaOlevaPelaaja.Equals(pelaaja1))
457            {
458                pelaajan1Pisteet.Value++;
459            }
460            else if (vuorossaOlevaPelaaja.Equals(pelaaja2))
461            {
462                pelaajan2Pisteet.Value++;
463            }
464
465            korttejaLoydetty.Value += 2;
466        }
467
468        /// <summary>
469        /// Näpsäkkä korttiin kohdistettu "räjähdys" tai mikä efekti lie.
470        /// </summary>
471        /// <param name="kaannetty">Kortti jonka päälle räjähdys tulee.</param>
472        public void RajaytaKortti(Kortti kortti)
473        {
474            Image i = kortti.KuvaPuoliTekstuuri;
475            ExplosionSystem e = new ExplosionSystem(i, 10);
476            e.MinLifetime = 0.3;
477            e.MaxLifetime = 1.5;
478            e.MinVelocity = 1;
479            e.MaxVelocity = 300;
480            e.MinScale = 0.01;
481            e.MaxScale = 0.05;
482            Add(e);
483            e.AddEffect(kortti.Position.X, kortti.Position.Y, 10);
484        }
485
486        public void VuoroVaihtuu()
487        {
488            if (vuorossaOlevaPelaaja.Equals(pelaaja1))
489            {
490                vuorossaOlevaPelaaja = pelaaja2;
491                highlighter.Image = LoadImage("highlight2");
492                vuoronaytto.Text = "Pelaaja 2";
493                return;
494            }
495
496            if (vuorossaOlevaPelaaja.Equals(pelaaja2))
497            {
498                vuorossaOlevaPelaaja = pelaaja1;
499                highlighter.Image = LoadImage("highlight1");
500                vuoronaytto.Text = "Pelaaja 1";
501                return;
502            }
503        }
504
505        #endregion
506
507        #region Kortit ruudulle
508
509        /// <summary>
510        /// Aliohjelma lisää halutun määrän kortteja
511        /// taulukkoon ja edelleen ruudulle.
512        /// </summary>
513        /// <param name="montakoKorttiaLisataan">Kuinka monta korttia taulukkoon (attribuutti) lisätään.</param>
514        void KortitRuudulle()
515        {
516            int montakoKorttiaLisatty = 0;
517
518            for (int r = 0; r < kortit.GetLength(0); r++) // Rivit
519            {
520                for (int s = 0; s < kortit.GetLength(1); s++) // Sarakkeet
521                {
522                    // Jos tarvittava määrä kortteja on lisätty,
523                    // laitetaan loppuihin taulukon alkioihin null-viite
524                    if (montakoKorttia == montakoKorttiaLisatty)
525                    {
526                        kortit[r, s] = null;
527                        continue;
528                    }
529
530                    kortit[r, s] = TeeKortti();
531                    kortit[r, s].KuvaPuoliTekstuuri = Image.FromFile(korttisarja + "/" + kortit[r, s].Tunniste.ToString() + ".jpg");
532                    Add(kortit[r, s]);
533
534                    kortit[r, s].X = KortinX(s);
535                    kortit[r, s].Y = KortinY(r);
536                    montakoKorttiaLisatty++;
537                }
538            }
539        }
540
541        public double KortinX(int sarake)
542        {
543            return (-(montakoSaraketta * (kortinLeveys + korttienVali)) / 2) + (sarake * (kortinLeveys + korttienVali)) + korttienVali;
544        }
545
546        public double KortinY(int rivi)
547        {
548            // Viimeinen termi tulee siitä että viimeisen kortin perässä ei tarvita välistystä
549            return ((montakoRivia) * (kortinKorkeus + korttienVali)) / 2 - rivi * (kortinKorkeus + korttienVali) - korttienVali;
550        }
551
552        public Kortti TeeKortti()
553        {
554            Image takaTekstuuri = LoadImage("taka");
555            int tunniste = AnnaTunniste();
556            return new Kortti(kortinLeveys, kortinKorkeus, false, takaTekstuuri, tunniste);
557        }
558
559        private int AnnaTunniste()
560        {
561            int tunniste;
562            while (true)
563            {
564                tunniste = RandomGen.NextInt(0, montakoKutakinKorttitunnusta.Length - 1);
565                if (montakoKutakinKorttitunnusta[tunniste] < 2)
566                {
567                    montakoKutakinKorttitunnusta[tunniste]++;
568                    break;
569                }
570            }
571            return tunniste;
572        }
573        #endregion
574    }
575}
Note: See TracBrowser for help on using the repository browser.