From f4d6d2386f4193774e7eb78d30248694dfa4d48d Mon Sep 17 00:00:00 2001 From: anvasavi <anvasavi@jyu.fi> Date: Mon, 24 Mar 2025 14:12:41 +0200 Subject: [PATCH] =?UTF-8?q?Harjoitusty=C3=B6n=20vaihe:=20kentt=C3=A4,=20ol?= =?UTF-8?q?iot,=20painikkeet=20ja=20toiminnot=20luotu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Pallo TK/Pallo TK/Pallo_TK.cs | 405 ++++++++++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 Pallo TK/Pallo TK/Pallo_TK.cs diff --git a/Pallo TK/Pallo TK/Pallo_TK.cs b/Pallo TK/Pallo TK/Pallo_TK.cs new file mode 100644 index 0000000..548f4c8 --- /dev/null +++ b/Pallo TK/Pallo TK/Pallo_TK.cs @@ -0,0 +1,405 @@ +using System; +using System.Globalization; +using Jypeli; +using Jypeli.Controls; +using Jypeli.Widgets; + +public class Harjoitustyo : PhysicsGame +{ + private const double KENTAN_LEVEYS = 800; + private const double KENTAN_KORKEUS = 500; + private const double MAALIN_LEVEYS = 100; + private const double MAALIN_KORKEUS = 150; + private const double KESKIYMPYRAN_SADE = 50; + private const double VIIVAN_PAKSUUS = 5; + + private PhysicsObject pelaaja1; + private PhysicsObject pelaaja2; + private PhysicsObject pallo; + private PhysicsObject mv1; + private PhysicsObject mv2; + + private Label pelikello; + private Label pisteetPelaaja1; + private Label pisteetPelaaja2; + private Timer ajastin; + + private int pisteet1 = 0; + private int pisteet2 = 0; + + private PhysicsObject vasenMaalilinja; + private PhysicsObject oikeaMaalilinja; + + private PhysicsObject pallonHaltija = null; + + + public override void Begin() + { + MessageDisplay.Add("Peli alkaa!"); // Debug-viesti + LuoKentta(); + LuoPelaajat(); + mv1 = LuoMaalivahti(new Vector(-KENTAN_LEVEYS / 2 + 40, 0)); // Vasen mv + mv2 = LuoMaalivahti(new Vector(KENTAN_LEVEYS / 2 - 40, 0)); // Oikea mv + LuoPallo(); + LuoUI(); + AsetaNappaimet(); + AloitaAjastin(); + + // **Varmistetaan, että nämä lisätään vasta kun kaikki on luotu** + if (pallo != null && pelaaja1 != null && pelaaja2 != null) + { + AddCollisionHandler(pallo, vasenMaalilinja, TarkistaMaali); + AddCollisionHandler(pallo, oikeaMaalilinja, TarkistaMaali); + AddCollisionHandler(pallo, pelaaja1, PelaajaSaiPallon); + AddCollisionHandler(pallo, pelaaja2, PelaajaSaiPallon); + } + } + protected override void Update(Time time) + { + base.Update(time); + PaivitaPallonSijainti(); + } + + // Seuraavassa osiossa luodaan kenttä. + #region Luokenttä + private void LuoKentta() + { + Level.Size = new Vector(KENTAN_LEVEYS, KENTAN_KORKEUS); + Level.CreateBorders(); + Level.Background.Color = Color.LightGreen; + + vasenMaalilinja = new PhysicsObject(10, MAALIN_KORKEUS); + vasenMaalilinja.Position = new Vector(-KENTAN_LEVEYS / 2, 0); + vasenMaalilinja.Mass = Double.PositiveInfinity; + vasenMaalilinja.Color = Color.Gray; + + oikeaMaalilinja = new PhysicsObject(10, MAALIN_KORKEUS); + oikeaMaalilinja.Position = new Vector(KENTAN_LEVEYS / 2, 0); + oikeaMaalilinja.Mass = Double.PositiveInfinity; + oikeaMaalilinja.Color = Color.Gray; + + Camera.ZoomToLevel(); + LuoViiva(new Vector(0, 0), KENTAN_KORKEUS, true); + LuoKeskiympyra(Vector.Zero, KESKIYMPYRAN_SADE); + LuoRangaistusalueet(); + Add(oikeaMaalilinja); + Add(vasenMaalilinja); + } + private PhysicsObject LuoViiva(Vector paikka, double pituus, bool pysty) + { + double leveys = pysty ? VIIVAN_PAKSUUS : pituus; + double korkeus = pysty ? pituus : VIIVAN_PAKSUUS; + + PhysicsObject viiva = new PhysicsObject(leveys, korkeus); + viiva.Position = paikka; + viiva.Color = Color.White; + viiva.IgnoresCollisionResponse = true; + Add(viiva); + + return viiva; // Nyt viiva palautetaan, jotta sitä voidaan muokata myöhemmin. + } + private void LuoKeskiympyra(Vector paikka, double sade) + { + int viivojenMaara = 30; // Tarkkuus + double kulmaVäli = 360.0 / viivojenMaara; + double viivanPituus = 2 * Math.PI * sade / viivojenMaara; + + for (int i = 0; i < viivojenMaara; i++) + { + double kulmaAsteina = i * kulmaVäli; + Angle kulma = Angle.FromDegrees(kulmaAsteina); + + Vector alku = new Vector(paikka.X + Math.Cos(kulma.Radians) * sade, + paikka.Y + Math.Sin(kulma.Radians) * sade); + + // Luo viiva ja aseta sen kulma + PhysicsObject viiva = LuoViiva(alku, viivanPituus, false); + viiva.Angle = kulma + Angle.FromDegrees(90); // Käännetään 90 astetta, jotta se asettuu ympyrään + } + } + private void LuoRangaistusalueet() + { + double maalialueenLeveys = 80; + double maalialueenKorkeus = 200; + double rangaistusalueenLeveys = 200; + double rangaistusalueenKorkeus = 300; + + // **Vasemman puolen alueet + LuoLaatikko(new Vector(-KENTAN_LEVEYS / 2 + maalialueenLeveys / 2, 0), maalialueenLeveys, maalialueenKorkeus); + LuoLaatikko(new Vector(-KENTAN_LEVEYS / 2 + rangaistusalueenLeveys / 2, 0), rangaistusalueenLeveys, rangaistusalueenKorkeus); + + // **Oikean puolen alueet + LuoLaatikko(new Vector(KENTAN_LEVEYS / 2 - maalialueenLeveys / 2, 0), maalialueenLeveys, maalialueenKorkeus); + LuoLaatikko(new Vector(KENTAN_LEVEYS / 2 - rangaistusalueenLeveys / 2, 0), rangaistusalueenLeveys, rangaistusalueenKorkeus); + } + + private void LuoLaatikko(Vector paikka, double leveys, double korkeus) + { + // Läpinäkyvä täyttöalue + PhysicsObject tausta = new PhysicsObject(leveys, korkeus); + tausta.Position = paikka; + tausta.Color = Color.LightGreen; // Kentän taustaväri + tausta.IgnoresCollisionResponse = true; + Add(tausta); + + // Reunaviiva: ohut laatikko, jonka sisällä ei ole täyttöä + double reunapaksuus = 3; // Säädä tarvittaessa + + LuoViiva(new Vector(paikka.X, paikka.Y + korkeus / 2), leveys, false); // Yläreuna + LuoViiva(new Vector(paikka.X, paikka.Y - korkeus / 2), leveys, false); // Alareuna + LuoViiva(new Vector(paikka.X - leveys / 2, paikka.Y), korkeus, true); // Vasen reuna + LuoViiva(new Vector(paikka.X + leveys / 2, paikka.Y), korkeus, true); // Oikea reuna + } + #endregion + + // Seuraavassa osiossa luodaan oliot. + #region Oliot + + private void LuoPelaajat() + { + pelaaja1 = LuoPelaaja(new Vector(-150, 0), Color.Blue); + pelaaja2 = LuoPelaaja(new Vector(150, 0), Color.Red); + } + + private PhysicsObject LuoPelaaja(Vector paikka, Color vari) + { + PhysicsObject pelaaja = new PhysicsObject(30, 30); + pelaaja.Position = paikka; + pelaaja.Color = vari; + pelaaja.Shape = Shape.Circle; + pelaaja.Restitution = 0.5; + Add(pelaaja); + return pelaaja; + } + private PhysicsObject LuoMaalivahti(Vector paikka) + { + PhysicsObject mv = new PhysicsObject(40, 40); + mv.Position = paikka; + mv.Color = Color.Green; + mv.Shape = Shape.Circle; + mv.Restitution = 0.8; // Lisää palautus, jos pallo törmää siihen + mv.IgnoresCollisionResponse = false; // Tämä varmistaa, että maalivahti ei ohita törmäyksiä + mv.IgnoresGravity = true; // Maalivahti ei putoa alas + mv.CanRotate = false; + Add(mv); + + Timer.CreateAndStart(1.0, () => LiikutaMaalivahtia(mv)); + return mv; + } + + private void LuoPallo() + { + pallo = new PhysicsObject(20, 20); + pallo.Color = Color.Black; + pallo.Shape = Shape.Circle; + pallo.Restitution = 0.8; + Add(pallo); + } + + private void LuoUI() + { + pelikello = new Label(); + pelikello.Position = new Vector(0, Level.Top - 30); + pelikello.TextColor = Color.White; + Add(pelikello); + + pisteetPelaaja1 = new Label("Sininen: 0"); + pisteetPelaaja1.Position = new Vector(-300, Level.Top - 30); + pisteetPelaaja1.TextColor = Color.Blue; + Add(pisteetPelaaja1); + + pisteetPelaaja2 = new Label("Punainen: 0"); + pisteetPelaaja2.Position = new Vector(300, Level.Top - 30); + pisteetPelaaja2.TextColor = Color.Red; + Add(pisteetPelaaja2); + } + + #endregion + + // Seuraavassa osiossa luodaan toimintoja. + #region Toiminnot + private void TarkistaMaali(PhysicsObject pallo, PhysicsObject maali) + { + if (maali == vasenMaalilinja) + { + pisteet2++; + pisteetPelaaja2.Text = $"Punainen: {pisteet2}"; + } + else if (maali == oikeaMaalilinja) + { + pisteet1++; + pisteetPelaaja1.Text = $"Sininen: {pisteet1}"; + } + + ResetoiPeli(); + } + + private void ResetoiPeli() + { + pallo.Position = Vector.Zero; + pallo.Velocity = Vector.Zero; + pallo.AngularVelocity = 0; + + pelaaja1.Position = new Vector(-150, 0); + pelaaja2.Position = new Vector(150, 0); + } + + private void AloitaAjastin() + { + ajastin = new Timer(); + ajastin.Interval = 0.1; + ajastin.Timeout += PaivitaKello; + ajastin.Start(); + } + + private int peliaikaSekunteina = 0; + private void PaivitaKello() + { + peliaikaSekunteina += 2; + int minuutit = peliaikaSekunteina / 60; + int sekunnit = peliaikaSekunteina % 60; + pelikello.Text = $"Aika: {minuutit:00}:{sekunnit:00}"; + + if (minuutit >= 90) + { + ajastin.Stop(); + MessageDisplay.Add("Peli päättyi!"); + } + } + + private void Liikuta(PhysicsObject pelaaja, Vector suunta) + { + pelaaja.Push(suunta); + + } + + private void LiikutaMaalivahtia(PhysicsObject mv) + { + // Generoidaan satunnainen liike + double uusiY = mv.Position.Y + RandomGen.NextDouble(-50, 50); + double maxY = MAALIN_KORKEUS / 2; // Maalin yläraja + double minY = -MAALIN_KORKEUS / 2; // Maalin alaraja + // Varmistetaan, että maalivahti ei mene maalin rajojen yli + if (uusiY > maxY) uusiY = maxY; + if (uusiY < minY) uusiY = minY; + // Nopeutetaan liikettä kertoimella (esimerkiksi 3.0) + double liikenopeus = 2.0; + // Asetetaan maalivahdin nopeus liikkumiselle + mv.Velocity = new Vector(0, (uusiY - mv.Position.Y) * liikenopeus); + } + + //private void TorjuPallo(PhysicsObject mv, PhysicsObject pallo) + //{ + // Vector torjuntaSuunta = new Vector(RandomGen.NextDouble(-1, 1), RandomGen.NextDouble(-1, 1)).Normalize(); + // pallo.Hit(torjuntaSuunta * 200); // Torjunta työntää palloa satunnaiseen suuntaan + //} + + private void PelaajaSaiPallon(PhysicsObject pallo, PhysicsObject pelaaja) + { + if (pallonHaltija == null || pallonHaltija != pelaaja) + { + pallonHaltija = pelaaja; + pallo.Velocity = Vector.Zero; + pallo.IgnoresGravity = true; + pallo.IgnoresCollisionResponse = true; + + // Tarkistetaan kumpi pelaaja sai pallon ja asetetaan se hyökkäyssuuntaan + Vector suunta = (pelaaja == pelaaja1) ? new Vector(30, 0) : new Vector(-30, 0); + pallo.Position = pelaaja.Position + suunta; + } + } + private double hidastumisaika = 0; // Aika, joka on kulunut, kun pelaaja on pysähtymässä + private const double MAKSI_HIDASTUMIS_AIKA = 1.0; // Aika, jonka kuluessa pelaaja pysähtyy + private void Pysayta(PhysicsObject pelaaja) + { + // Jos pelaaja on jo pysähtymässä, lisää aikaa + if (hidastumisaika < MAKSI_HIDASTUMIS_AIKA) + { + hidastumisaika += 0.1; // Aika kulkee joka päivityksessä (voi säätää arvoa) + + // Vähennetään pelaajan nopeutta hitaasti + pelaaja.Velocity = new Vector(pelaaja.Velocity.X * (0.25), pelaaja.Velocity.Y * (0.25)); + } + else + { + // Kun aika on kulunut, pysäytämme pelaajan + pelaaja.Velocity = Vector.Zero; + } + } + + private void LaukaiseTaiTaklaa(PhysicsObject pelaaja) + { + if (pallonHaltija == pelaaja) + { + // Pelaaja laukoo pallon hyökkäyssuuntaan + pallo.IgnoresGravity = false; + pallo.IgnoresCollisionResponse = false; + + Vector hyokkayssuunta = (pelaaja == pelaaja1) ? new Vector(1, 0) : new Vector(-1, 0); + Vector palloSijainti = pallo.Position - pelaaja.Position; + Vector laukaisusuunta = palloSijainti.Normalize() + hyokkayssuunta; + + pallo.Hit(laukaisusuunta.Normalize() * 300); + + pallonHaltija = null; // Pelaaja menettää pallon hallinnan + } + else if (pallonHaltija != null && pallonHaltija != pelaaja) + { + // Pelaaja yrittää taklata pallollisen pelaajan + Vector taklausSuunta = (pallonHaltija.Position - pelaaja.Position).Normalize(); + pallonHaltija.Push(taklausSuunta * 1000); // Taklausvoima kasvaa + pallo.Hit(taklausSuunta * 300); // Pallo lentää pois hallinnasta + + pallonHaltija = null; // Pallollinen menettää pallon + pallo.IgnoresGravity = false; + pallo.IgnoresCollisionResponse = false; + } + } + private void PaivitaPallonSijainti() + { + if (pallo != null && pallonHaltija != null) + { + // Asetetaan pallo hyökkäyssuuntaan pelaajan mukaan + Vector suunta = (pallonHaltija == pelaaja1) ? new Vector(30, 0) : new Vector(-30, 0); + pallo.Position = pallonHaltija.Position + suunta; + pallo.Velocity = Vector.Zero; + } + } + #endregion + + // Painikkeet + #region Painikkeet + private void AsetaNappaimet() + { + Keyboard.Listen(Key.W, ButtonState.Down, Liikuta, "Pelaaja 1 ylös", pelaaja1, new Vector(0, 100)); + Keyboard.Listen(Key.S, ButtonState.Down, Liikuta, "Pelaaja 1 alas", pelaaja1, new Vector(0, -100)); + Keyboard.Listen(Key.A, ButtonState.Down, Liikuta, "Pelaaja 1 vasemmalle", pelaaja1, new Vector(-100, 0)); + Keyboard.Listen(Key.D, ButtonState.Down, Liikuta, "Pelaaja 1 oikealle", pelaaja1, new Vector(100, 0)); + Keyboard.Listen(Key.Space, ButtonState.Pressed, LaukaiseTaiTaklaa, "Pelaaja 1 laukoo/taklaa", pelaaja1); + + Keyboard.Listen(Key.Up, ButtonState.Down, Liikuta, "Pelaaja 2 ylös", pelaaja2, new Vector(0, 100)); + Keyboard.Listen(Key.Down, ButtonState.Down, Liikuta, "Pelaaja 2 alas", pelaaja2, new Vector(0, -100)); + Keyboard.Listen(Key.Left, ButtonState.Down, Liikuta, "Pelaaja 2 vasemmalle", pelaaja2, new Vector(-100, 0)); + Keyboard.Listen(Key.Right, ButtonState.Down, Liikuta, "Pelaaja 2 oikealle", pelaaja2, new Vector(100, 0)); + Keyboard.Listen(Key.Enter, ButtonState.Pressed, LaukaiseTaiTaklaa, "Pelaaja 2 laukoo/taklaa", pelaaja2); + + Keyboard.Listen(Key.W, ButtonState.Released, Pysayta, "Pysäyttää pelaajan", pelaaja1); + Keyboard.Listen(Key.S, ButtonState.Released, Pysayta, "Pysäyttää pelaajan", pelaaja1); + Keyboard.Listen(Key.A, ButtonState.Released, Pysayta, "Pysäyttää pelaajan", pelaaja1); + Keyboard.Listen(Key.D, ButtonState.Released, Pysayta, "Pysäyttää pelaajan", pelaaja1); + + Keyboard.Listen(Key.Up, ButtonState.Released, Pysayta, "Pysäyttää pelaajan", pelaaja2); + Keyboard.Listen(Key.Down, ButtonState.Released, Pysayta, "Pysäyttää pelaajan", pelaaja2); + Keyboard.Listen(Key.Left, ButtonState.Released, Pysayta, "Pysäyttää pelaajan", pelaaja2); + Keyboard.Listen(Key.Right, ButtonState.Released, Pysayta, "Pysäyttää pelaajan", pelaaja2); + Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli"); + } + + #endregion + + + + + +} + -- GitLab