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 9 - Programování jednoduchých Java GUI her - Detekce kolizí

V předchozí lekci, Programování jednoduchých Java GUI her - Časovač 2, jsme pokračovali v pohybu objektů po JPanelu.

V následujících dvou dílech si ukážeme, jak detekovat kolize objektů.

Detekce kolizí

V předchozí kapitole jsme vytvořili obdélník, který se při stisku šipek pohyboval po panelu. Všechen tento kód jsme nacpali do třídy, která vytvářela panel a začalo to být trošku nepřehledné.

Vezmeme tedy předchozí příklad a trošku ho upravíme. Nejdříve vytvoříme třídu představující obdélník (chytače), potom třídu s panelem a nakonec třídu s hlavním oknem.

Detekce kolizí v Javě - Tvorba her v Java Swing

Třída představující náš obdélník.

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class Chytac implements KeyListener {

    private Color barva = Color.white;
    private final int SIRKA = 50;
    private final int VYSKA = 10;
    private int x, y, smerX, smerY, rychlost;
    private MujPanel panel;

    public Chytac(MujPanel panel) {

        this.rychlost = 3;
        this.panel = panel;
        this.x = (panel.getSIRKA_PANELU() - SIRKA) / 2;
        this.y = (panel.getVYSKA_PANELU() - VYSKA) / 2;
    }

    public void vykresliSe(Graphics g) {
        g.setColor(barva);
        g.drawRect(x, y, SIRKA, VYSKA);
    }

    public void move() {
        x += smerX;
        y += smerY;

        if (x >= panel.getSIRKA_PANELU() - (SIRKA + 1)) {
            x = panel.getSIRKA_PANELU() - (SIRKA + 1);
        }
        if (x <= 0) {
            x = 0;
        }
        if (y >= panel.getVYSKA_PANELU() - (VYSKA + 1)) {
            y = panel.getVYSKA_PANELU() - (VYSKA + 1);
        }
        if (y <= 0) {
            y = 0;
        }
    }

    @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) {
    }
}

 

public class Chytac implements KeyListener

Třída implementuje rozhraní KeyListener, což znamená, že má schopnost reagovat na události generované stiskem kláves. Nemusíme tedy vytvářet speciální třídu posluchače klávesnice, ale jako posluchače zaregistrujeme objekt typu Chytac.

private MujPanel panel;

Do této proměnné uložíme odkaz na panel, ve kterém byl vytvořen Chytac. Budeme tak mít přístup k metodám objektu MujPanel (například metody getSIRKA_PANELU() a getVYSKA_PANELU() pro zjištění rozměrů panelu).

this.x = (panel.getSIRKA_PANELU() - SIRKA) / 2;
this.y = (panel.getVYSKA_PANELU() - VYSKA) / 2;

Zde pozor. Chceme umístit Chytace od středu panelu. Chytac se ale vykreslí na souřadnice x = 0, y = 0. Jak je toto možné?

Sice jsme nastavili preferovanou velikost JPanelu, ale panel ještě nebyl vytvořen, proto je jeho šířka a výška nula. Výše uvedeným kódem Chytac dokonce prvotně umístíme mimo panel (0 - SIRKA, 0 - VYSKA), ale protože je každý cyklus volána metoda chytac.move() (v MujPanel.java), pozice je upravena na [0, 0]. Prozatím to takto necháme.

public void vykresliSe(Graphics g) {
    g.setColor(barva);
    g.drawRect(x, y, SIRKA, VYSKA);
}

Tato metoda dostane jako parametr grafický kontext (grafický kontext si můžete představit jako podložku, která se postupně předává kreslícím metodám, každá metoda na ni nakreslí to svoje - předává se plocha panelu a na ni se postupně kreslí) a vykreslí objekt Chytac na souřadnice x, y.

Metody public void move(), public void keyPressed(KeyEvent e) a public void keyReleased(Ke­yEvent e) jsou nám již známy z předchozích příkladů. Metodu public void keyTyped(KeyEvent e) nebudeme používat.

Třída s hlavním panelem.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;

public class MujPanel extends JPanel {

    private Chytac chytac;

    public MujPanel() {

        this.chytac = new Chytac(this);

        this.setPreferredSize(new Dimension(400, 300));
        this.setBackground(Color.black);
        this.addKeyListener(chytac);
        this.setFocusable(true);

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

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

        chytac.vykresliSe(g);
    }

    private class PosluchacCasovace implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {

            chytac.move();
            repaint();
        }
    }

    public int getSIRKA_PANELU() {
        return this.getWidth();
    }

    public int getVYSKA_PANELU() {
        return this.getHeight();
    }
}

 

this.chytac = new Chytac(this);

Vytvoříme nový objekt typu Chytac a odkaz na něj uložíme do privátní proměnné chytac, kterou jsme deklarovali dříve.

this.addKeyListener(chytac);

Zprávy budou zasílány objektu typu Chytac. Je to logické, protože Chytac reaguje na klávesové šipky.

this.setFocusable(true);

Nezapomeňte na zaměření (focus) panelu. Bez něj by nám ovládání z klávesnice nefungovalo.

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

    chytac.vykresliSe(g);
}

Vykreslí pozadí a zavolá kreslící metodu Chytace, které předá grafický kontext (plochu na kreslení).

private class PosluchacCasovace implements ActionListener {

    public void actionPerformed(ActionEvent e) {

        chytac.move();
        repaint();
    }
}

V případě vygenerování události ActionEvent objektem Timer (jako posluchac je zaregistrován objekt typu PosluchacCasovace) je zavolána metoda actionPerformed(Ac­tionEvent e). Dle nastavení Timeru v tomto programu, je tato metoda volána přibližně každých deset milisekund. Tato metoda následně volá metodu move() objektu Chytac, která (v případě že je stisknuta klávesa nenumerická šipka) provede změnu souřadnic Chytace. Pak je volána metoda repaint(), která volá metodu paintComponent(). Díky tomu se plocha panelu překresluje (každých deset milisekund).

public int getSIRKA_PANELU() {
    return SIRKA_PANELU;
}

public int getVYSKA_PANELU() {
    return VYSKA_PANELU;
}

Přidali jsme dvě metody, které vrací rozměr panelu.

Třída vytvářející hlavní okno a obsahující metodu main (vstupní bod programu)

import javax.swing.JFrame;

public class DetekceKolizi extends JFrame {

    public DetekceKolizi() {
        this.setTitle("Detekce kolizí");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        MujPanel panel = new MujPanel();
        this.add(panel);

        this.pack();
        this.setResizable(false);
    }

    public static void main(String[] args) {
        new DetekceKolizi().setVisible(true);
    }
}

Poslední důležitou věc, kterou si ještě musíme ukázat, je jak zjistit srážku objektů (detekovat kolize). Srážka objektů je situace, kdy se jeden objekt protne s druhým. V našem programu chceme tuto srážku zjistit v případě, že objekt Chytac narazí do objektu Ctverec. Jak Chytac tak Ctverec jsou obdélníky (čtverec je obdélník se stejnou délkou stran) a určitě bychom si mohli napsat metodu, která by zjišťovala, kdy došlo k protnutí obdélníků. Java ale tuto práci udělala za nás a nabízí nám hotovou metodu. Je to metoda intersects objektu Rectangle. Abychom ji mohli použít, potřebujeme dva objekty Rectangle, které porovnáme a zjistíme, zda se překrývají. Pokračování v dalším díle.

V příštím díle, Programování jednoduchých Java GUI her - Detekce kolizí 2, si dokončíme 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 313x (2.06 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

Předchozí článek
Programování jednoduchých Java GUI her - Časovač 2
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í 2
Článek pro vás napsal vita
Avatar
Uživatelské hodnocení:
13 hlasů
vita
Aktivity