8. diel - Programovanie jednoduchých Java GUI hier - Časovač 2
V tomto diele budeme pokračovať v tom, čo sme začali minule - pohyb objektov po JPanelu.
Vytvoríme program, v ktorom budeme pohybovať objektom (v tomto prípade obdĺžnikom) pomocou klávesnice.
import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.JPanel; import javax.swing.Timer; public class MujPanel extends JPanel { private final int SIRKA_OBDELNIKA = 80; private final int VYSKA_OBDELNIKA = 50; private int x, y; private int smerX, smerY; private int rychlost; private Rectangle obdelnik; public MujPanel() { this.x = 0; this.y = 0; this.smerX = 0; this.smerY = 0; this.rychlost = 2; this.obdelnik = new Rectangle(x, y, SIRKA_OBDELNIKA, VYSKA_OBDELNIKA); this.setPreferredSize(new Dimension(400, 300)); this.setBackground(Color.blue); this.setFocusable(true); this.addKeyListener(new PosluchacKlavesnice()); Timer casovac = new Timer(10, new PosluchacCasovace()); casovac.start(); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.red); g.drawRect(x, y, SIRKA_OBDELNIKA, VYSKA_OBDELNIKA); } private void move() { x += smerX; y += smerY; if (x >= this.getWidth() - (SIRKA_OBDELNIKA + 1)) { x = this.getWidth() - (SIRKA_OBDELNIKA + 1); } if (x <= 0) { x = 0; } if (y >= this.getHeight() - (VYSKA_OBDELNIKA + 1)) { y = this.getHeight() - (VYSKA_OBDELNIKA + 1); } if (y <= 0) { y = 0; } } private class PosluchacCasovace implements ActionListener { @Override public void actionPerformed(ActionEvent e) { move(); repaint(); } } private class PosluchacKlavesnice implements KeyListener { @Override public void keyPressed(KeyEvent e) { int klavesa = e.getKeyCode(); if (klavesa == KeyEvent.VK_LEFT) { smerX = -rychlost; } else if (klavesa == KeyEvent.VK_UP) { smerY = -rychlost; } else if (klavesa == KeyEvent.VK_RIGHT) { smerX = rychlost; } else if (klavesa == KeyEvent.VK_DOWN) { smerY = rychlost; } } @Override public void keyReleased(KeyEvent e) { int klavesa = e.getKeyCode(); if (klavesa == KeyEvent.VK_LEFT) { smerX = 0; } else if (klavesa == KeyEvent.VK_UP) { smerY = 0; } else if (klavesa == KeyEvent.VK_RIGHT) { smerX = 0; } else if (klavesa == KeyEvent.VK_DOWN) { smerY = 0; } } @Override public void keyTyped(KeyEvent e) { } } }
private final int SIRKA_OBDELNIKA = 80; private final int VYSKA_OBDELNIKA = 50;
Deklarujeme dve premenné typu int a inicializujeme je na zadané hodnoty. Kľúčové slovo final znamená, že tieto premenné sú konštanty (nebude sa meniť ich hodnota). Takýmto spôsobom deklarujeme premenné, u ktorých vieme, že ich hodnota je konečná.
Tento spôsob deklarácie je výhodný z toho dôvodu, že v prípade, že sa v programe omylom pokúsime zmeniť hodnoty tejto premennej, prekladač nám to neumožní.
private int x, y;
X-ová a y-nová súradnice ľavého horného rohu obdĺžnika.
private int smerX, smerY;
Premenné uchovávajúci posun v smere. Ak sú nula obdĺžnik sa nepohybuje.
private int rychlost;
Premenná uchovávajúce rýchlosť, akou sa bude obdĺžnik pohybovať.
this.obdelnik = new Rectangle(x, y, SIRKA_OBDELNIKA, VYSKA_OBDELNIKA);
Premenná obdĺžnikov je typu Rectangle. Do konstruktoru zadávame súradnice ľavého horného rohu (x, y), šírku a výšku obdĺžnika.
this.addKeyListener(new PosluchacKlavesnice());
JPanel (this) si registruje ako poslucháča udalostí KeyEvent objekt typu PosluchacKlavesnice.
Inak povedané, objektu PosluchacKlavesnice, ktorý bol práve vytvorený pomocou new, sa budú posielať udalosti (správy) typu KeyEvent. Je to to isté, ako by ste napísali:
PosluchacKlavesnice posKla = new PosluchacKlavesnice(); this.addKeyListener(posKla);
Ušetrí sa tým ale trocha písania.
Timer casovac = new Timer(10, new PosluchacCasovace()); casovac.start();
Nič nové, ale opakovanie je matka múdrosti. Vytvoríme nový Timer, ktorý bude generovať udalosti čo desať milisekúnd a poslucháčom týchto udalostí bude práve vytvorený objekt typu PosluchacCasovace.
public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.red); g.drawRect(x, y, SIRKA_OBDELNIKA, VYSKA_OBDELNIKA); }
Vykreslenie pozadie, nastaví farbu popredia na červenú a vykreslí obdĺžnik (Rectangle). Obdĺžnik rozhýbe tak, že mu budeme meniť súradnice xaya opätovne ho kresliť na JPanel.
x += smerX; y += smerY;
V metóde move (), keď je zavolaná, sa xay zmení podľa hodnoty v premenných smerX, smer. Tieto dve premenné sú v kostruktoru inicializované na nulu, takže obdĺžnik sa nepohybuje. Pomocou zmien týchto premenných ovplyvňujeme pohyb obdĺžnika. Meniť ich budeme pri stlačení klávesov.
Následne v metóde move () kontrolujeme, či je obdĺžnik (celá jeho plocha) viditeľný. Možno vám nie je jasné, prečo pričítame ešte jedničku (x> = this.getWidth () - (SIRKA_OBDELNIKA + 1)). X-ová súradnice začína nulou a pri nastavení veľkosti panelu na 400 bodov je viditeľné x od 0 do 399. Výsledkom operácie je 320 (x-ová súradnice ľavého horného rohu obdĺžnika) a keď 320 sčítame s 80 (šírkou obdĺžnika) dostaneme 400, čo je pravý okraj obdĺžnika, ktorý je však už nie je viditeľný. Ak to budete chcieť skúsiť a odmazať jedničku, napriek tomu sa obdĺžnik môže zobrazovať správne. Je to preto, že veľkosť nastavená metódou setPreferredSize () nie je úplne záväzná a JPanel môže mať veľkosť inú. Aktuálnu veľkosť JPanelu získate metódou getWidth () a getHeight ().
public void keyPressed(KeyEvent e) { int klavesa = e.getKeyCode(); if (klavesa == KeyEvent.VK_LEFT) { smerX = -rychlost; } else if (klavesa == KeyEvent.VK_UP) { smerY = -rychlost; } else if (klavesa == KeyEvent.VK_RIGHT) { smerX = rychlost; } else if (klavesa == KeyEvent.VK_DOWN) { smerY = rychlost; } }
V prípade stlačenia klávesy na klávesnici je vygenerovaná udalosť KeyEvent, ktorá je zaslaná zaregistrovanému poslucháči (je zavolaná posluchačova metóda keyPressed () a ako parameter je ňou odovzdaný objekt typu KeyEvent).
int klavesa = e.getKeyCode(); if (klavesa == KeyEvent.VK_LEFT) { smerX = -rychlost; }
Získame číslo reprezentujúce kláves. Následne toto číslo porovnávame s konštantou. Ak sa napríklad premenná klávesa rovná 37, jedná sa o kláves nečíselný šípka vľavo (37 je hodnota konštanty KeyEvent.VK_LEFT). V tomto prípade premenná smerX bude -rýchlosť.
Premenná rýchlosť je dva, tým pádom pri zavolaní metódy move (), ktoré sa deje pri každom vygenerovaní udalostí objektom Timer (podľa nášho nastavenia každých 10 milisekúnd), sa bude hodnota súradnice x znižovať o dva a obdĺžnik sa bude pohybovať doľava.
V metóde keyPressed (KeyEvent e) ošetrujeme stav, kedy je stlačený nejaký z nenumerických šípok. Obdobné je to s metódou keyReleased (KeyEvent e). Ak by sme túto metódu nechali prázdnu, obdĺžnik by sa pohyboval aj po pustení šípky.
//super.paintComponent(g);
Ak ste to ešte neskúsili, tak Zdokumentujte (alebo vymažte) volanie rodičovskej metódy paintComponent. Tak najlepšie zistíte, k čomu to vlastne je.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 331x (1.61 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java