9. díl - Programování jednoduchých Java GUI her - Detekce kolizí

Java Tvorba her Programování jednoduchých Java GUI her - Detekce kolizí

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ě

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.


 

Stáhnout

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

 

  Aktivity (1)

Článek pro vás napsal vita
Avatar
vita

Jak se ti líbí článek?
Celkem (3 hlasů) :
55555


 



 

 

Komentáře

Avatar
Ondrca
Redaktor
Avatar
Ondrca:

Ahoj, mám něco podobnýho:

public void keyPressed(KeyEvent e) {
        int klavesa = e.getKeyCode();
        if (klavesa == KeyEvent.VK_LEFT) {
       smer.setText("left");
        } else if (klavesa == KeyEvent.VK_UP) {
smer.setText("up");
        } else if (klavesa == KeyEvent.VK_RIGHT) {
smer.setText("right");
        } else if (klavesa == KeyEvent.VK_DOWN) {
smer.setText("down");
        }
    }

mám to ve stejný třídě.
Poradíte mi prosím jak změnit text JLabel po stisknutí šipky na klávesnici, který mám nadefinovaný v hlavní třídě

public static void main(String[] args)
Editováno 28.9.2013 14:29
Odpovědět 28.9.2013 14:27
Zase jsem o něco chytřejší
Avatar
vita
Redaktor
Avatar
Odpovídá na Ondrca
vita:

Pokud má výše uvedený kód fungovat, tak smer je název proměnné typu JLabel, na které voláš její metodu setText(). V tom případě tento kód musí být umístěn ve třídě, která dědí z JPanelu a taktéž implementuje rozhraní KeyListener.

 
Odpovědět 8.10.2013 15:35
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.