using System; using System.Collections.Generic; using Jypeli; using Jypeli.Widgets; using Color = Jypeli.Color; namespace KelaCombatTesti; /// @author Sakari Hanki ja Salla Laine /// @version 28.03.2025 /// <summary> /// Pelissä tikkuhenkilö hakkaa kelabotteja pesismailalla /// </summary> public class KelaCombatTesti : PhysicsGame { private int _kenttanumero = 0; private string[] _kentat = {"kentta1", "kentta2"}; private Image[] _henkiloSaapastelu = LoadImages("kavely1", "kavely2"); private Image[] _paikallaanAnimaatio = LoadImages("kavely1"); private Image[] _putoamisAnimaatio = LoadImages("putoaminen1", "putoaminen2", "putoaminen3", "putoaminen4", "putoaminen5"); private Image[] _kelabottiKavely = LoadImages("Kelabotti", "Kelabotti2"); private SoundEffect _hyppyaani = LoadSoundEffect("Hyppyaani"); private SoundEffect _viinapulloaani = LoadSoundEffect("Viinapulloaani"); private SoundEffect _keladamageaani = LoadSoundEffect("Keladamageaani"); private SoundEffect _kavelyaani = LoadSoundEffect("Kavelyaani"); private SoundEffect _lyontiaani = LoadSoundEffect("Lyontiaani"); private Timer _ajastin = new Timer(); private PlatformCharacter _pelaaja; private PhysicsObject _pesismaila; private PhysicsObject _viinapullo; private PhysicsObject _kappale; private PhysicsObject _exit; private PhysicsObject _ansa; private PlatformCharacter _kelabotti; private Image _tiiliseinakuva = LoadImage("tiiliseina"); private Image _kelabottikuva = LoadImage("Kelabotti"); private Image _viinapullokuva = LoadImage("Viinapullo.png"); private Image _uloskaynti = LoadImage("Uloskaynti"); private Image _ansakuva = LoadImage("Tyohakemuskasa"); private List<PhysicsObject> _spawnipaikat = new List<PhysicsObject>(); // tässä listataan mahdolliset paikat, johon kelabotti voi spawnaa. Lista pitää sisällään spawnereita. //IntMeter edustaa muuttujia, jotka voivat kasvaa tai vähentyä tietyllä tavalla private IntMeter _pisteet; //pelaajan keräämät pisteet private DoubleMeter _pelaajanElamaaskuri; //pelaajan elämät //Label = tekstielementti, joka näytetään pelissä private Label _pisteNaytto; //pisteiden näyttäminen ruudulla /// <summary> /// Peli alkaa tästä /// </summary> public override void Begin() { LuoKentta(0); } /// <summary> /// Vasemmalle kävely /// </summary> /// <param name="vektori">suuntavektori</param> private void LiikuVasemmalle(Vector vektori) { _pelaaja.Walk(-120); } /// <summary> /// Vasemmalle kävedllessä kuuluva ääni /// </summary> /// <param name="vektori">suuntavektori</param> private void AaniVasemmalle(Vector vektori) { _kavelyaani.Play(); _ajastin.Interval = 0.5; // Äänen kesto _ajastin.Timeout += delegate { _kavelyaani.Play(); }; _ajastin.Start(); } /// <summary> /// Vasemmalle suuntautuvan äänen lopettaminen /// </summary> /// <param name="vektori">suuntavektori</param> private void LopetaAaniVasemmalle(Vector vektori) { if (_ajastin != null) // Tarkistetaan, onko ajastin luotu { _ajastin.Stop(); // Pysäytetään ajastin _kavelyaani.Stop(); // Lopetetaan äänen toisto } } /// <summary> /// Oikealle kävely /// </summary> /// <param name="vektori">suuntavektori</param> private void LiikuOikealle(Vector vektori) { _pelaaja.Walk(120); } /// <summary> /// Ääni oikealle liikkuessa /// </summary> /// <param name="vektori">suuntavektori</param> private void AaniOikealle(Vector vektori) { _kavelyaani.Play(); _ajastin.Interval = 0.5; // Äänen kesto _ajastin.Timeout += delegate { _kavelyaani.Play(); }; _ajastin.Start(); } /// <summary> /// Oikealle suuntautuvan äänen lopettaminen /// </summary> /// <param name="vektori">suuntavektori</param> private void LopetaAaniOikealle(Vector vektori) { if (_ajastin != null) // Tarkistetaan, onko ajastin luotu { _ajastin.Stop(); // Pysäytetään ajastin _kavelyaani.Stop(); // Lopetetaan äänen toisto } } /// <summary> /// Hyppääminen /// </summary> /// <param name="vektori">suuntavektori</param> private void Hyppaa(Vector vektori) { _hyppyaani.Play(); _pelaaja.Jump(900.0); } /// <summary> /// Tässä luodaan pelikenttä /// </summary> private void LuoKentta(int numero) { if (_kenttanumero == _kentat.Length) { Label valmistuminen = new Label(800, 60, "Toimeentulohakemus hyväkystty."); valmistuminen.Y = 140; valmistuminen.Font = new Font(60); valmistuminen.TextColor = Color.LimeGreen; Add(valmistuminen); } else { ClearAll(); for (int i = 0; i < 20; i++) { GameObject koriste = TeeKoriste(Level.BoundingRect); Add(koriste); } Level.Background.CreateGradient(Color.DarkGray, Color.Blue); Gravity = new Vector(0, -1100.0); // pelissä kentät luodaan piirtämällä pikseleitä. Pikselin väri kuvaa aina jotain tiettyä asiaa kentällä // ruutu = pikseli ColorTileMap ruudut = ColorTileMap.FromLevelAsset(_kentat[numero]); ruudut.SetTileMethod(Color.Lime, LuoPelaaja); //LIME pikseli on pelaaja, 0, 255, 0 ruudut.SetTileMethod(Color.Black, LuoTaso); //MUSTA on tiiliseinää ruudut.SetTileMethod(Color.Red, LuoKelabottiSpawni); //PUNAISEEN voi spawnaa vihu ruudut.SetTileMethod(Color.SkyBlue, LuoViinapullo); //VAALEANSNISET on pelaajaa parantavia viinapulloja 135, 206, 235 ruudut.SetTileMethod(Color.Wheat, LuoExit); // 245, 222, 179 ruudut.SetTileMethod(Color.Lavender, LuoAnsa); // 220 208 255 ruudut.Execute(80, 80); Timer.CreateAndStart(5.0, LuoKelabotti); LuoElamalaskuri(); LuoPistelaskuri(); Camera.Follow(_pelaaja); LisaaOhjaimet(); } } /// <summary> /// Aliohjelmassa lisätään ohjaimet /// </summary> private void LisaaOhjaimet() { Keyboard.Listen(Key.A, ButtonState.Pressed, AaniVasemmalle, null, new Vector()); Keyboard.Listen(Key.D, ButtonState.Pressed, AaniOikealle, null, new Vector()); Keyboard.Listen(Key.A, ButtonState.Released, LopetaAaniVasemmalle, null, new Vector()); Keyboard.Listen(Key.D, ButtonState.Released, LopetaAaniOikealle, null, new Vector()); Keyboard.Listen(Key.A, ButtonState.Down, LiikuVasemmalle, null, new Vector()); Keyboard.Listen(Key.D, ButtonState.Down, LiikuOikealle, null, new Vector()); Keyboard.Listen(Key.W, ButtonState.Pressed, Hyppaa, null, new Vector()); Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli"); Keyboard.Listen(Key.Space, ButtonState.Pressed, LuoPesismaila, "", new Vector(90, 10), _pelaaja); } /// <summary> /// aliohjelma luo tiili-palikoita, joista kenttä rakentuu /// </summary> /// <param name="paikka">palikan paikka</param> /// <param name="leveys">palikan korkeus</param> /// <param name="korkeus">palikan leveys</param> private void LuoTaso(Vector paikka, double leveys, double korkeus) { PhysicsObject taso = PhysicsObject.CreateStaticObject(leveys, korkeus); taso.Position = paikka; taso.CollisionIgnoreGroup = 2; taso.Color = Color.Gray; taso.Image = _tiiliseinakuva; taso.Tag = "taso"; Add(taso); } /// <summary> /// Aliohjelma, jossa luodaan seuraavaan kenttään vievä ovi /// </summary> /// <param name="paikka">oven paikka</param> /// <param name="x">oven leveys</param> /// <param name="y">oven korkeus</param> private void LuoExit(Vector paikka, double x, double y) { _exit = PhysicsObject.CreateStaticObject(100, 150); _exit.Position = paikka; _exit.CollisionIgnoreGroup = 2; _exit.Color = Color.HotPink; _exit.Tag = "exit"; _exit.Image = _uloskaynti; Add(_exit); } /// <summary> /// pelaajaa vahingoittavan ansan luova aliohjelma /// </summary> /// <param name="paikka">ansan paikka</param> /// <param name="x">ansan leveys</param> /// <param name="y">ansan korkeus</param> private void LuoAnsa(Vector paikka, double x, double y) { _ansa = PhysicsObject.CreateStaticObject(100, 150); _ansa.CollisionIgnoreGroup = 2; _ansa.Position = paikka; _ansa.Image = _ansakuva; _ansa.Tag = "ansa"; Add(_ansa); } /// <summary> /// Tekee kentälle koristeita /// </summary> /// <param name="kuuskulmio">mille alueelle koriste tehdään</param> /// <returns>koriste</returns> public static GameObject TeeKoriste(BoundingRectangle kuuskulmio) { GameObject koriste = new GameObject(400, 400, Shape.Hexagon); koriste.Position = RandomGen.NextVector(kuuskulmio); koriste.Color = Color.Rose; return koriste; } /// <summary> /// Aliohjelma luo pelaajaa parantavan viinapllon /// </summary> /// <param name="paikka">pullon paikka</param> /// <param name="x">pullon leveys</param> /// <param name="y">pullon korkeus</param> private void LuoViinapullo(Vector paikka, double x, double y) { _viinapullo = PhysicsObject.CreateStaticObject(50, 50); _viinapullo.Position = paikka; _viinapullo.Color = Color.White; _viinapullo.Tag = "Viinapullo"; _viinapullo.Image = _viinapullokuva; Add(_viinapullo); } /// <summary> /// Aliohjelma luo "haamupalikan" jonka sijaintiin kelabotti myöhemmin luodaan /// </summary> /// <param name="paikka">palikan paikka</param> /// <param name="leveys">palikan leveys</param> /// <param name="korkeus">palikan korkeus</param> private void LuoKelabottiSpawni(Vector paikka, double leveys, double korkeus) { PhysicsObject bottispawni = PhysicsObject.CreateStaticObject(leveys, korkeus); bottispawni.Position = paikka; bottispawni.IgnoresCollisionResponse = true; //BottiSpawni.CollisionIgnoreGroup = 3; bottispawni.IsVisible = false; bottispawni.IgnoresGravity = true; Add(bottispawni, -1); _spawnipaikat.Add(bottispawni); } /// <summary> /// Aliohjelma, jossa luodaan pelaaja /// </summary> /// <param name="paikka">pelaajan paikka</param> /// <param name="x">pelaajan x-koordinaatti</param> /// <param name="y">pelaajan y-koordinaatti</param> /// <returns>pelaaja</returns> private void LuoPelaaja(Vector paikka, double x, double y) { _pelaaja = new PlatformCharacter(50.0, 100.0); _pelaaja.Mass = 1.0; _pelaaja.Shape = Shape.Rectangle; _pelaaja.Color = Color.Black; _pelaaja.Position = paikka; _pelaaja.CollisionIgnoreGroup = 1; _pelaaja.AnimWalk = new Animation(_henkiloSaapastelu); _pelaaja.AnimIdle = new Animation(_paikallaanAnimaatio); _pelaaja.AnimWalk.FPS = 3; _pelaaja.AnimFall = new Animation(_putoamisAnimaatio); _pelaaja.AnimFall.FPS = 12; _pelaaja.LoopFallAnim = true; // Törmäyksen käsittelijä, mitä tapahtuu, kun pelaaja osuu kelabotiin //Siis pelaajan elämien väheneminen VahnigoitaPelaajaa-aliohjelman mukaisesti AddCollisionHandler(_pelaaja, "Kelabotti", VahingoitaPelaajaa); AddCollisionHandler(_pelaaja, "Viinapullo", ParannaPelaajaa); AddCollisionHandler(_pelaaja, "kappale", VahingoitaPelaajaa); AddCollisionHandler(_pelaaja, "exit", KentanVaihto); AddCollisionHandler(_pelaaja, "ansa", VahingoitaPelaajaa); Add(_pelaaja); } /// <summary> /// Aliohjelma, joka luo pelaajalle elämälaskurin ja sen nimen: "Mielenterveys" /// </summary> private void LuoElamalaskuri() { _pelaajanElamaaskuri = new DoubleMeter(100.0); _pelaajanElamaaskuri.MaxValue = 100; _pelaajanElamaaskuri.LowerLimit += ElamaLoppui; ProgressBar elamapalkki = new ProgressBar(150, 18); elamapalkki.X = Screen.Left + 110; elamapalkki.Y = Screen.Bottom + 50; elamapalkki.BindTo(_pelaajanElamaaskuri); elamapalkki.Color = Color.Red; elamapalkki.BarColor = Color.Green; elamapalkki.BorderColor = Color.Black; Label tekstikentta = new Label(200, 10, "Mielenterveys"); tekstikentta.X = Screen.Left + 100; tekstikentta.Y = Screen.Bottom + 70; tekstikentta.Font = new Font(20); Add(tekstikentta); Add(elamapalkki); } /// <summary> /// Aliohjelma, joka käsittelee pelaajan kuoleman ja ilmoittaa pelin loppumisen /// </summary> private void ElamaLoppui() { Label kuolema = new Label(800, 60, "Toimeentulohakemus hylätty."); kuolema.Y = 140; kuolema.Font = new Font(60); kuolema.TextColor = Color.Red; //Kuolema.Color = Color.Black; Add(kuolema); } /// <summary> /// Pesismailan luominen /// </summary> /// <param name="koko">Pesismailan koko</param> /// <param name="pelaaja">kohde, johon Pesismaila liitetään</param> private void LuoPesismaila(Vector koko, PlatformCharacter pelaaja) { _pesismaila = new PhysicsObject(koko.X, koko.Y); _pesismaila.Position = pelaaja.Position + new Vector(80*pelaaja.FacingDirection.GetVector().X, 10); _pesismaila.CollisionIgnoreGroup = 1; _pesismaila.Mass = 1; _pesismaila.Tag = "Pesismaila"; Add(_pesismaila); _pesismaila.LifetimeLeft = TimeSpan.FromSeconds(0.075); Sound lyontiaani2 = _lyontiaani.CreateSound(); lyontiaani2.Volume = 1; lyontiaani2.Play(); _pesismaila.IgnoresGravity = true; //PISTEET ei elämät AddCollisionHandler(_pesismaila, "Kelabotti", KunVihollinenTuhoutuu); } /// <summary> /// Tämä funktio luo Kelabotti-vihun ja sille annetaan pelaajan seuraamisaivot /// </summary> private void LuoKelabotti() { PhysicsObject spawni = _spawnipaikat[RandomGen.NextInt(_spawnipaikat.Count)]; _kelabotti = new PlatformCharacter(50.0, 100.0); _kelabotti.Color = Color.Orange; _kelabotti.Image = _kelabottikuva; _kelabotti.CollisionIgnoreGroup = 3; _kelabotti.Tag = "Kelabotti"; _kelabotti.Position = spawni.Position; _kelabotti.AnimWalk = new Animation(_kelabottiKavely); _kelabotti.AnimWalk.FPS = 3; Add(_kelabotti); FollowerBrain seuraajanAivot = new FollowerBrain(_pelaaja); seuraajanAivot.Speed = 100; _kelabotti.Brain = seuraajanAivot; Timer heittoajastin = new Timer(); heittoajastin.Interval = 2; heittoajastin.Timeout += delegate() { KelabotinAmmus(_kelabotti, "pelaaja"); }; heittoajastin.Start(); _kelabotti.Destroyed += heittoajastin.Stop; } /// <summary> /// Aliohjelma, jossa käsitellään Kelabotin heittämä ammus /// </summary> /// <param name="heittavaOlio">Kelabotti heittää ammuksen</param> /// <param name="kohdeolionTunniste">pelaajan tunniste</param> private void KelabotinAmmus(PhysicsObject heittavaOlio, string kohdeolionTunniste) { _kappale = new PhysicsObject(15, 15, Shape.Triangle); _kappale.Hit(new Vector(180*_pelaaja.FacingDirection.GetVector().X, 10)); _kappale.Position = heittavaOlio.Position; _kappale.CollisionIgnoreGroup = 3; _kappale.Color = Color.Silver; _kappale.Tag = "kappale"; _kappale.MaximumLifetime = TimeSpan.FromSeconds(1.5); Add(_kappale); } /// <summary> /// Tämä aliohjelma käsittlee sen, kun pelaaja osuu Kelabottiin /// </summary> /// <param name="pelaaja">pelaajahahmo</param> /// <param name="Kelabotti">pelin vihu; Kelabotti</param> private void VahingoitaPelaajaa(PhysicsObject pelaaja, PhysicsObject kappale) { int luku = RandomGen.NextInt(19, 34); _pelaajanElamaaskuri.Value = _pelaajanElamaaskuri - luku; // Vähentää pelaajan elämää satunnaisen määrän if (_pelaajanElamaaskuri.Value <= 0) //jos laskuri menee nollaan... { pelaaja.Destroy(); //...ja pelaaja tuhotaan //Pesismaila.Destroy();//...myös pesismaila } } /// <summary> /// Aliohjelma, joka parantaa pelaajan, kun tämä koskee viinapulloa /// </summary> /// <param name="pelaaja">kohde, joka parannetaan</param> /// <param name="Viinapullo">parantava esine</param> private void ParannaPelaajaa(PhysicsObject pelaaja, PhysicsObject viinapullo) { //Viinapullo.CollisionIgnoreGroup = 1; if (_pelaajanElamaaskuri.Value < 99) { //Viinapullo.CollisionIgnoreGroup = 0; _viinapulloaani.Play(); _pelaajanElamaaskuri.Value = _pelaajanElamaaskuri.Value + 20; _pisteet.Value += 20; viinapullo.Destroy(); } } /// <summary> /// Luo pistelaskurin pisteille, joita saa kun hakkaa kelabotteja /// </summary> private void LuoPistelaskuri() { Label opintoNopat = new Label(150, 50, "Opintonopat:"); opintoNopat.X = Screen.Left + 100; opintoNopat.Y = Screen.Bottom + 93; opintoNopat.Font = new Font(20); opintoNopat.TextColor = Color.Black; Add(opintoNopat); _pisteet = new IntMeter(0); // Aloitetaan nollasta _pisteNaytto = new Label(); _pisteNaytto.X = Screen.Left + 170; _pisteNaytto.Y = Screen.Bottom + 95; _pisteNaytto.TextColor = Color.OrangeRed; _pisteNaytto.Font = new Font(20); _pisteNaytto.BindTo(_pisteet); // Päivitetään teksti automaattisesti Add(_pisteNaytto); } /// <summary> /// Käsittelee kelabotin tuhoamisen ja antaa siitö pisteitä /// </summary> /// <param name="pelaaja">pelaajahahmo</param> /// <param name="kelabotti">pelin vihu; Kelabotti</param> private void KunVihollinenTuhoutuu(PhysicsObject pelaaja, PhysicsObject kelabotti) { _keladamageaani.Play(); _pisteet.Value += 100; // Lisää esim. 100 pistettä, kun botti tuhotaan kelabotti.Destroy(); // Poistaa botin näytöltä } /// <summary> /// Aliohjelma, jossa käsitellään kentän vaihto /// </summary> /// <param name="pelaaja">pelaaja</param> /// <param name="exit">esine, josta kenttä vaihtuu</param> private void KentanVaihto(PhysicsObject pelaaja, PhysicsObject exit) { if (_pisteet.Value >= 300) { _kenttanumero++; LuoKentta(_kenttanumero); } } }