Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 8 - Programování jednoduchých Java GUI her - Časovač 2

V minulé lekci, Programování jednoduchých Java GUI her - Časovač, jsme si rozpohybovali objekt na JPanelu pomocí časovače a tím jsme si vytvořili animaci.

V tomto díle budeme pokračovat v tom, co jsme začali minule - pohyb objektů po JPanelu.

Vytvoříme program, ve kterém budeme pohybovat objektem (v tomto případě obdélníkem) pomocí 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) {

        }
    }
}
Pohyb pomocí klávesnice v Java Swing - Tvorba her v Java Swing
private final int SIRKA_OBDELNIKA = 80;
private final int VYSKA_OBDELNIKA = 50;

Deklarujeme dvě proměnné typu int a inicializujeme je na zadané hodnoty. Klíčové slovo final znamená, že tyto proměnné jsou konstanty (nebude se měnit jejich hodnota). Takovýmto způsobem deklarujeme proměnné, u kterých víme, že jejich hodnota je konečná.

Tento způsob deklarace je výhodný z toho důvodu, že v případě, že se v programu omylem pokusíme změnit hodnoty této proměnné, překladač nám to neumožní.

private int x, y;

X-ová a y-nová souřadnice levého horního rohu obdélníka.

private int smerX, smerY;

Proměnné uchovávající posun ve směru. Pokud jsou nula obdélník se nepohybuje.

private int rychlost;

Proměnná uchovávající rychlost, jakou se bude obdélník pohybovat.

this.obdelnik = new Rectangle(x, y, SIRKA_OBDELNIKA, VYSKA_OBDELNIKA);

Proměnná obdelnik je typu Rectangle. Do konstruktoru zadáváme souřadnice levého horního rohu (x, y), šířku a výšku obdélníka.

this.addKeyListener(new PosluchacKlavesnice());

JPanel (this) si registruje jako posluchače událostí KeyEvent objekt typu PosluchacKlaves­nice.

Jinak řečeno, objektu PosluchacKlaves­nice, který byl právě vytvořen pomocí new, se budou posílat události (zprávy) typu KeyEvent. Je to totéž, jako by jste napsali:

PosluchacKlavesnice posKla = new PosluchacKlavesnice();
this.addKeyListener(posKla);

Ušetří se tím ale trocha psaní.

Timer casovac = new Timer(10, new PosluchacCasovace());
casovac.start();

Nic nového, ale opakování je matka moudrosti. Vytvoříme nový Timer, který bude generovat události co deset milisekund a posluchačem těchto událostí bude právě vytvořený objekt typu PosluchacCasovace.

public void paintComponent(Graphics g) {
    super.paintComponent(g);

    g.setColor(Color.red);
    g.drawRect(x, y, SIRKA_OBDELNIKA, VYSKA_OBDELNIKA);
}

Vykreslí pozadí, nastaví barvu popředí na červenou a vykreslí obdélník (Rectangle). Obdélník rozpohybujeme tak, že mu budeme měnit souřadnice x a y a opětovně ho kreslit na JPanel.

x += smerX;
y += smerY;

V metodě move(), když je zavolána, se x a y změní podle hodnoty v proměnných smerX, smerY. Tyto dvě proměnné jsou v kostruktoru inicializovány na nulu, takže obdélník se nepohybuje. Pomocí změn těchto proměnných ovlivňujeme pohyb obdélníka. Měnit je budeme při stisku kláves.

Následně v metodě move() kontrolujeme, zda je obdélník (celá jeho plocha) viditelný. Možná vám není jasné, proč přičítáme ještě jedničku (x >= this.getWidth() - (SIRKA_OBDELNIKA + 1)). X-ová souřadnice začína nulou a při nastavení velikosti panelu na 400 bodů je viditelné x od 0 do 399. Výsledkem operace je 320 (x-ová souřadnice levého horního rohu obdélníka) a když 320 sečteme s 80 (šířkou obdélníka) dostaneme 400, což je pravý okraj obdélníka, který je však již není viditelný. Pokud to budete chtít zkusit a odmažete jedničku, přesto se obdélník může zobrazovat správně. Je to proto, že velikost nastavená metodou setPreferredSize() není zcela závazná a JPanel může mít velikost jinou. Aktuální velikost JPanelu získáte metodou 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 případě stisku klávesy na klávesnici je vygenerována událost KeyEvent, která je zaslána zaregistrovanému posluchači (je zavolána posluchačova metoda keyPressed() a jako parametr je jí předán objekt typu KeyEvent).

int klavesa = e.getKeyCode();
if (klavesa == KeyEvent.VK_LEFT) {
    smerX = -rychlost;
}

Získáme číslo reprezentující klávesu. Následně toto číslo porovnáváme s konstantou. Pokud se například proměnná klávesa rovná 37, jedná se o klávesu nenumerická šipka vlevo (37 je hodnota konstanty KeyEvent.VK_LEFT). V tomto případě proměnná smerX bude -rychlost.

Proměnná rychlost je dva, tím pádem při zavolání metody move(), které se děje při každém vygenerování událostí objektem Timer (dle našeho nastavení každých 10 milisekund), se bude hodnota souřadnice x snižovat o dva a obdélník se bude pohybovat doleva.

V metodě keyPressed(KeyEvent e) ošetřujeme stav, kdy je stisknuta nějaká z nenumerických šipek. Obdobné je to s metodou keyReleased(Ke­yEvent e). Pokud bychom tuto metodu nechali prázdnou, obdélník by se pohyboval i po puštění šipky.

//super.paintComponent(g);

Pokud jste to ještě nezkusili, tak zadokumentujte (nebo vymažte) volání rodičovské metody paintComponent. Tak nejlépe zjistíte, k čemu to vlastně je.

V příští lekci, Programování jednoduchých Java GUI her - Detekce kolizí, si ukážeme, jak detekovat kolize objektů pomocí třídy Rectangle a metody Intersect.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 330x (1.61 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

Předchozí článek
Programování jednoduchých Java GUI her - Časovač
Všechny články v sekci
Tvorba her v Java Swing
Přeskočit článek
(nedoporučujeme)
Programování jednoduchých Java GUI her - Detekce kolizí
Článek pro vás napsal vita
Avatar
Uživatelské hodnocení:
10 hlasů
vita
Aktivity