import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; import javax.swing.Timer; import javax.swing.JPanel; /** * Luokka Otokkapaneeli, joka periytyy luokasta JPanel. Luokka * piirtää ötökkäpaneelin taustan, lisää tarvittavan määrän ötököitä * ötökkälistaan ja piirtää ötökät paneeliin. Luokassa * toteutetaan ötököiden kuvien skaalaus Ötökkä-luokassa * määriteltyä skaalaussuhdetta käyttäen ja tarkistetaan alun * ötököiden sijoittelun päällekkäisyyttä jonkin verran. Luokka * käynnistää animaation ja pysäyttää sen. * * @author Karoliina Tiuraniemi * @version 1.0, 18.1.2009 * */ public class Otokkapaneeli extends JPanel { private static final long serialVersionUID = 1L; private Matikka matikka; private List otokkalista0; private List otokkalista1; private List otokkalista2; private List kuvat; private Ikkuna ikkuna; private int leveys; private int korkeus; private boolean liikkeella = false; private Timer ajastin; private int kuvaIndeksi; /** * Konstruktori, joka luo uuden ötökkäpaneelin ja tekee listan * valitulla tasolla tarvittavista animaation kuvista. * @param matikka Matikka * @param ikkuna Ikkuna * @param leveys * @param korkeus */ public Otokkapaneeli (Matikka matikka, Ikkuna ikkuna, int leveys, int korkeus){ super(); this.matikka = matikka; this.ikkuna = ikkuna; // varsinaisesti paneelin mittasuhteet määritellään Ikkunassa, // täällä arvot vain otetaan talteen. this.leveys = leveys; this.korkeus = korkeus; System.out.println("tehdään animaatiolista"); String nimi = "leppakerttu-"; if (this.ikkuna.annaPeli().annaTaso() == 2){ nimi = "koppakuoriainen-"; } this.kuvat = new ArrayList(); System.out.println("kuvalista luotu kuville " + nimi); int i = 1; while (new File("src/img/" + nimi + i + ".png").exists()){ try { // lisää kuvan i animaation listaan this.kuvat.add(ImageIO.read (new File("src/img/" + nimi + i + ".png"))); } catch (IOException ioe){ System.err.println("Kuvia ei löytynyt."); break; } i++; } System.out.println("Ötökkäpaneeli luotu"); } /** * Metodi, joka antaa Ikkunassa määritellyn leveyden ötökkäpaneelille. * Ei oikeaa leveyttä, koska lukua tarvitaan jo ennen kuin paneeli on luotu. * @return this.leveys */ public int annaLeveys(){ return this.leveys; } /** * Metodi, joka antaa Ikkunassa määritellyn korkeuden ötökkäpaneelille. * Ei oikeaa korkeutta, koska lukua tarvitaan jo ennen kuin * paneeli on luotu. * @return this.korkeus */ public int annaKorkeus(){ return this.korkeus; } /** * Metodi, joka antaa parametrina olevan numeron mukaisen * ötökkälistan. * @param listanNumero * @return this.otokkalista0 jos numero on 0, * this.otokkalista1 jos numero on 1 tai * this.otokkalista2 jos numero on 2. */ public List annaOtokkalista(int listanNumero){ if (listanNumero == 0){ return this.otokkalista0; } else if (listanNumero == 1){ return this.otokkalista1; } else if (listanNumero == 2){ return this.otokkalista2; } return null; } /** * Metodi, joka antaa Ötökkäpaneeliin liittyvän ikkunan. * @return this.ikkuna */ public Ikkuna annaIkkuna(){ return this.ikkuna; } /** * Metodi, joka aloittaa piirtämisen tekemällä ötökkälistat * ja kutsumalla sen jälkeen paintComponent-metodia. */ public void piirra(){ this.teeOtokkalistat(); repaint(); System.out.println("Ötökkäpaneeli piirretty"); } /** * Metodi, joka luo tason mukaan tarvittavat ötökkälistat */ public void teeOtokkalistat(){ // 1. tasolla käytetään listaa 0 if (this.ikkuna.annaPeli().annaTaso() == 1){ this.otokkalista0 = new ArrayList(); this.lisaaOtokka(this.otokkalista0, 0); } else if (this.ikkuna.annaPeli().annaTaso() == 2){ // 2. tasolla käytetään listaa 1 this.otokkalista1 = new ArrayList(); this.lisaaOtokka(this.otokkalista1, 1); // ja listaa 2 this.otokkalista2 = new ArrayList(); this.lisaaOtokka(this.otokkalista2, 2); } } /** * Metodi, joka lisää ötökän listaan, skaalaa tarvittaessa sen animaatioon * käyttämät kuvat ja tekee päällekkäisyystarkistukset. * * @param lista * @param listanNumero */ public void lisaaOtokka(List lista, int listanNumero){ int n = 0; // valitaan listan numeron mukainen ötököiden määrä int otokoidenMaara = this.matikka.annaTulos(); if (listanNumero == 1){ otokoidenMaara = this.matikka.annaLuku1(); } else if (listanNumero == 2){ otokoidenMaara = this.matikka.annaLuku2(); } // lisätään listaan otokoidenMaaran verran ötököitä while (n < otokoidenMaara){ Otokka otokka = new Otokka(this, listanNumero); lista.add(otokka); int taso = 2; if (listanNumero == 0){ taso = 1; } otokka.skaalausSuhde(taso, otokoidenMaara); /* tarkista, etteivät skaalatut ötökät mene kovin paljoa * päällekkäin. tässä tehdään tarkoituksella vain jonkin verran * päällekkäistarkistusta. kaikkia päällekkäisyyksiä ei voi poistaa * viiveen takia erityisesti silloin, kun ötököitä on paljon. */ int m = 0; while (m < n){ // tarkistetaan päällekkäisyyksiä listaan aikaisemmin // lisättyjen ötököiden kanssa Otokka toinenOtokka = lista.get(m); // tarkistetaan, ettei ötökkää piirretä minkään samaan listaan // aiemmin luodun ötökän päälle. while (otokka.annaNelio().intersects(toinenOtokka.annaNelio())){ // nyt menee päällekkäin, joten arvotaan uusi neliö otokka.arvoNelio(listanNumero); } m++; } n++; } } /** * Metodi, joka poistaa yksittäisen ötökän listasta * @param lista * @param otokka */ public void poistaOtokka(List lista, Otokka otokka){ lista.remove(otokka); } /** * Metodi, joka tyhjentää kaikki olemassaolevat ötökkälistat */ public void tyhjennaOtokkalistat(){ if (this.otokkalista0 != null){ this.otokkalista0.removeAll(this.otokkalista0); } if (this.otokkalista1 != null){ this.otokkalista1.removeAll(this.otokkalista1); } if (this.otokkalista2 != null){ this.otokkalista2.removeAll(this.otokkalista2); } } /** * Metodi, joka käynnistää animaation, vaihtaa liikkeellä- * attribuutin arvoksi true, luo uuden ajastimen kuvien vaihtoa * varten, käynnistää ajastimen ja kutsuu paintComponent()- * metodia. */ public void animaatio(){ System.out.println("Ötökkäpaneeli: animaatio"); this.liikkeella = true; this.ajastin = new Timer(50, new ActionListener(){ public void actionPerformed(ActionEvent arg0) { Otokkapaneeli.this.paivita(); Otokkapaneeli.this.repaint(); } }); if (!this.pysahdy()){ this.ajastin.start(); repaint(); } else if (this.pysahdy()){ this.ikkuna.uusiLasku(); } } /** * Metodi, joka pysäyttää animaation * @return true, jos taso on 1 ja ötökkälista0:n koko on 0 * tai jos taso on 2 ja ötökkälistojen 1 ja 2 koko on 0. * false, muulloin */ public boolean pysahdy(){ if (this.ikkuna.annaPeli().annaTaso() == 1 && this.otokkalista0.size() == 0){ this.ajastin.stop(); this.ikkuna.uusiLasku(); return true; } if (this.ikkuna.annaPeli().annaTaso() == 2 && this.otokkalista1.size() == 0 && this.otokkalista2.size() == 0){ this.ajastin.stop(); this.ikkuna.uusiLasku(); return true; } return false; } /** * Metodi, joka laittaa ötökät liikkeelle, tekee loopin animaatiota * varten, poistaa listalta ruudulta poistuneet ötökät ja pysäyttää * animaation kun ötökät ovat liikkuneet pois ruudulta. */ public void paivita(){ if (!this.pysahdy()){ int x = 0; while (x < 3){ // käydään läpi kaikki listat, tarkistetaan mitkä aktiivisia. List aktiivinenLista = this.annaOtokkalista(x); if (aktiivinenLista != null){ int n = 0; while (n < aktiivinenLista.size()){ Otokka otokka = aktiivinenLista.get(n); //laitetaan ötökät liikkeelle otokka.liiku(); // poistetaan listalta ruudusta poistuneet ötökät if (!otokka.nakyy() && aktiivinenLista.contains(otokka)){ if (x == 0) { this.poistaOtokka(this.otokkalista0, otokka); // kun ötökkälista on tyhjä, poistetaan // animaatiolistalta kuvat // ja pysäytetään animaatio. if (this.otokkalista0.size() == 0){ this.kuvat.clear(); this.pysahdy(); } } else if (x == 1) { this.poistaOtokka(this.otokkalista1, otokka); } else if (x ==2){ this.poistaOtokka(this.otokkalista2, otokka); // kun molemmat ötökkälistat ovat tyhjiä, // poistetaan animaatiolistalta // kuvat ja pysäytetään animaatio. if ( this.otokkalista1.size() == 0 && this.otokkalista2.size() == 0){ this.kuvat.clear(); this.pysahdy(); } this.poistaOtokka(aktiivinenLista, otokka); } } n++; } } x++; } // looppi animaatiota varten if (this.kuvat != null && this.kuvaIndeksi < (this.kuvat.size()-1)) { this.kuvaIndeksi++; } else { this.kuvaIndeksi = 0; } } } /** * Metodi, jonka sisään menee kaikki grafiikkakoodi. * @param g Graphics */ public void paintComponent(Graphics g) { // graphics olio tyyppimuunnetaan graphics 2D:ksi Graphics2D g2 = (Graphics2D) g; // määritellään oma väri g2.setPaint(Varit.VIHREA); // määritellään paneelin kokoinen neliö, jonka sisälle värjäys tulee int leveys = this.getWidth(); int korkeus = this.getHeight(); Rectangle r = new Rectangle(0,0,leveys,korkeus); // kutsutaan graphic-oliota, joka täyttää neliön. g2.fill(r); int x = 0; while (x < 3){ // käydään läpi kaikki mahdolliset ötökkälistat List aktiivinenLista = this.annaOtokkalista(x); // jos lista ei ole tyhjä if (aktiivinenLista != null){ int n = 0; // käydään läpi lista ja piirretään jokainen sen ötökkä. while (n < aktiivinenLista.size()){ Otokka otokka = aktiivinenLista.get(n); // haetaan ötökän oma kuva BufferedImage kuva = otokka.annaKuva(); int uusiLeveys = (int)(kuva.getWidth() * otokka.annaXSkaalaus()); int uusiKorkeus = (int)(kuva.getHeight() * otokka.annaYSkaalaus()); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); if (this.liikkeella){ // liikkeellä ollaan, joten käytetään kuvalistaa // indeksin kohdalta g2.drawImage(this.kuvat.get(this.kuvaIndeksi), otokka.annaX(), otokka.annaY(), uusiLeveys, uusiKorkeus, null); } else { // ei olla liikkeellä, joten kuva pysyy samana. g2.drawImage(kuva, otokka.annaX(), otokka.annaY(), uusiLeveys, uusiKorkeus, null); } n++; } } x++; } } }