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