Diskuze: Arkanoid - odraz míčku od cihel

Java Java Arkanoid - odraz míčku od cihel

Avatar
David Čápka
Tým ITnetwork
Avatar
David Čápka:

Ahoj,
mám jednoduchý arkanoid v Javě (viz obrázek) a nějak jsem se zasekl na odrazu míčku od cihliček.

Hlavní třída hry vypadá takto:

public class HerniPlatno extends JPanel {

    int x = 200;
    int y = 300;
    Timer casovac;
    int smerX = -1;
    int smerY = -1;
    int rychlost = 5;
    int palkaX = 200;
    int palkaSmerX = 0;
    int palkaRychlost = 4;
    boolean[][] cihly = new boolean[10][4];
    int score = 0;
    int zivoty = 3;


    public HerniPlatno() {
        Dimension d = new Dimension(400, 400);
        setPreferredSize(d);

        for (int j = 0; j < 4; j++) {
            for (int i = 0; i < 10; i++) {
                cihly[i][j] = true;
            }
        }

        casovac = new Timer(25, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                x += smerX * rychlost;
                y += smerY * rychlost;
                palkaX += palkaSmerX * palkaRychlost;

                if (x < 0) {
                    smerX = 1;
                }
                if (x > 400) {
                    smerX = -1;
                }
                if (y < 0) {
                    smerY = 1;
                }
                if (y > 400) {
                    JOptionPane.showMessageDialog(null, "Ztratil si zivot!");
                    spadlo();
                }
                if ((y > 380) && (x > palkaX - 50) && (x < palkaX + 50)) {
                    smerY = -1;
                }

                for (int j = 0; j < 4; j++) {
                    for (int i = 0; i < 10; i++) {
                        if((cihly[i][j]) && (y > (j * 20 + 50))&&(y<(j*20+50+19))&&(x>(i*30+50))&&(x<(i*30+50+29))){
                            cihly[i][j] = false;
                            score +=1;

                            smerY *= -1;
                        }
                    }
                }

                repaint();
            }
        });
        casovac.start();
    }

    public int getSmerPalky() {
        return palkaSmerX;
    }

    public void setSmerPalky(int smer) {
        palkaSmerX = smer;
    }
    public void restartuj(){
       score = 0;
       zivoty = 3;
       JOptionPane.showMessageDialog(null, "Nova hra!");
    }

    public void spadlo(){
        zivoty -=1;
        if(zivoty == 0){
            restartuj();
        }
        x = 200;
        y = 300;
        smerX = 1;
        smerY = 1;
        palkaX = 300;
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillOval(x - 5, y - 5, 10, 10);
        g.fillRect(palkaX - 50, 380, 100, 10);
        g.drawString("Skore: " + score, 10, 10);
        g.drawString("zivoty: " + zivoty, 10, 25);

        for (int j = 0; j < 4; j++) {
            for (int i = 0; i < 10; i++) {
                if (cihly[i][j]){
                g.fillRect(i * 30 + 50, j * 20 + 50, 29, 19);
            }
            }
        }

    }
}

Míček má 2 směry (vertikální a horizontální, majím hodnotu -1 nebo 1). Dále má souřadnice X a Y. Cihličky jsou realizovány jako 2D pole booleanů. Hlavní loop hry obstarává timer.

Kód testu zda míček koliduje s cihličkou je tento:

for (int j = 0; j < 4; j++) {
  for (int i = 0; i < 10; i++) {
    if((cihly[i][j]) && (y > (j * 20 + 50))&&(y<(j*20+50+19))&&(x>(i*30+50))&&(x<(i*30+50+29))){
      cihly[i][j] = false;
      score +=1;

      smerY *= -1;
    }
  }
}

Zatím tam mám pouze prohození vertikálního směru, což však nefunguje korektně, potřeboval bych měnit směr podle toho z jaké strany míček na cihlu uhodil. Jde to nějak jednoduše?

Případně projekt v NetBeans: https://dl.dropbox.com/…Arcanoid.zip

Díky za nápady.

Odpovědět 27.2.2013 11:43
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Kit:

Rozděl tu podmínku, kterou máš uvnitř dvojitého testovacího cyklu, na dvě. Jednu pro x a druhou pro y.

Nahoru Odpovědět 27.2.2013 11:57
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

Nevím jak to myslíš? Dvě pod sebe nebo do sebe?

for (int j = 0; j < 4; j++) {
        for (int i = 0; i < 10; i++) {
                if((cihly[i][j]))
                {
                        if ((y > (j * 20 + 50))&&(y<(j*20+50+19)))
                        {

                        }
                        if ((x>(i*30+50))&&(x<(i*30+50+29)))
                        {

                        }
                }
        }
}
Nahoru Odpovědět 27.2.2013 12:06
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Přesně tak. Nezkoumal jsem to úplně do detailů, ale takto by to mohlo fungovat:

if ((y > (j * 20 + 50)) && (y < (j * 20 + 50 + 19))) {
    cihly[i][j] = false;
    score += 1;
    smerY *= -1;
} else if ((x > (i * 30 + 50)) && (x < (i * 30 + 50 + 29))) {
    cihly[i][j] = false;
    score += 1;
    smerX *= -1;
}
Editováno 27.2.2013 12:31
Nahoru Odpovědět 27.2.2013 12:30
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

Takhle to vymaže cihlu i v případě, že s ní míček nekoliduje, stačí, když je na stejné úrovni X nebo Y.

Nahoru Odpovědět 27.2.2013 12:34
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Aha, to jsem nedomyslel. Budou se tedy ty podmínky muset patřičně rozšířit, ale konstrukce ifu zůstane stejná.

Nahoru Odpovědět 27.2.2013 12:40
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Zkus si představit, že míček je v bodě [0, 0] a narazí do něj cihla. Pak už jen uděláš transformaci souřadnic.

Nahoru Odpovědět 27.2.2013 12:46
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Odpovídá na David Čápka
Lukáš Hruda (Luckin):

Udělej si na okraji cihly jakousi zeď, třeba 5 pixelů tlustou, pro každou stranu jednu. Pak podle toho od který zdi se míček odrazí poznáš jak má změnit směr.

pro levou stranu:
ball.x, ball.y - souřadnice středu míčku
radius - poloměr míčku
block.x, block.y - souřadnice levého horního rohu cihly
block.sizeY - výška cihly

if(ball.x + radius >= block.x && ball.x + radius < block.x + 5 && ball.y + radius >= block.y && ball.y - radius <= block.y + block.sizeY)
{
  //odraz
}

Jenom nesmí bejt rychlost míčku větši než tloušťka tý zdi.
Mě tohle fungovalo, jenom sem ještě musel definovat náraz do rohů, což u mě nebyl problém, protože sem tam dělal různý úhly.

 
Nahoru Odpovědět 27.2.2013 12:53
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

To mi moc nejde :`

Ale napadlo mě kontrolovat 4 body míčky v jeho "rozích", když ho vezmu jako čtverec. To by mělo fungovat. Ten který bude první kolidovat určí směr odrazu.

Nahoru Odpovědět 27.2.2013 13:04
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Lukáš Hruda (Luckin)
David Čápka:

Já bych to chtěl nějak jednodušeji, ale koukám, že ta hra není tak jednoduchá, jak jsem myslel. Jak vůbec počítáš ty úhly?

Nahoru Odpovědět 27.2.2013 13:04
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Odpovídá na David Čápka
Lukáš Hruda (Luckin):

Přes goniometrický funkce. U míčku mam x,y,rychlost a úhel a při každym pohybu spočítam: x += cos(úhel) * rychlost, y -= sin(úhel) * rychlost. U y je - kvůli převrácenej ose y. Při odrazu pak jenom úhel obrátim správnym směrem, a při odrazu od rohu nastavim úhel na +- 45 stupňů správnym směrem.

EDIT: Při odrazu od desky je úhel tim menší na danou stranu, čím je odraz blíž k okraji desky, pokud spadne na prostředek, odrazí se pod úhlem 90 stupňů.

Editováno 27.2.2013 13:13
 
Nahoru Odpovědět 27.2.2013 13:12
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

A co kdybys to zjednodušil na kolizi obdélníků?

Pokud bys chtěl ošetřit i ty úhly, tak by to samozřejmě nestačilo, ale v tom případě ani nebude stačit pohyb ve čtyřech směrech.

Nahoru Odpovědět 27.2.2013 13:41
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Luboš Běhounek (Satik):

Nebo můžeš kolize řešit per-pixel, pak podle kolidujícího pixelu i lehce určíš, jak se má míček odrazit.

Nahoru Odpovědět 27.2.2013 13:54
:)
Avatar
user
Redaktor
Avatar
Odpovídá na David Čápka
user:

Rád bych pomohl, zkušenosti mám ale jen s XNA, v jave nedělám a nevím jaké tam máš možnosti oproti např. matematickým pomocným třídám v XNA aj... Zítra bych měl nahrát svoji hru do soutěže. To by ti mohlo pomoci, všechno je tam řešené.

Doporučil bych si ale udělat nějakou širší objektovou strukturu, vše pak bude srozumitelnější, zas tak jednoduché to asi opravdu nebude...

Editováno 27.2.2013 15:12
 
Nahoru Odpovědět 27.2.2013 15:09
Avatar
Fugiczek
Redaktor
Avatar
Odpovídá na David Čápka
Fugiczek:

Pocitat 4 rohy je pekne, ale nebude to presny. Udelej si cihle jako novou tridu, ktera bude dedit po Rectangle. Umozni ti to dalsi vyvoj kdy si budes moct dat ruzne druhy cihel a vyresi se ti tim problem s kolizi, protoze Rectangle obsahuje metodu intersects. Pro mene presnejsi a rychlejsi vypocet muzes udelat pro kulicku okraje z Rectanglu a to budes davat jako parametr do te metody. Pokud by jsi to chtel vice presneji tak to bude o neco pomalejsi, vytvoris si okraje pomoci tridy Ellipse2D a instanci pouzijes jako parametr na vytvoreni instance tridy Area ktera ma metodu intersects s rectanglem.

 
Nahoru Odpovědět 27.2.2013 15:58
Avatar
Fugiczek
Redaktor
Avatar
Odpovídá na David Čápka
Fugiczek:

No koukl jsem se ted na kod a doufam ze prijmes mensi objektivni kritiku :-) No doufam ze to nehodlas pouzit jako ukazku nekde, protoze struktura OOP zadna (trida pojmenovana HerniPlatno a mas tam prakticky vsechno). Vykreslujes na JPanel ktery je na kresleni nevhodny (pouziva se Canvas :-) ), navic pouzivas pasivni renderovani (to znamena ze volas jen metodu repaint a prepisujes metody na kresleni komponenty) a jeste k tomu volas puvodni metodu paint, ta se nevola pokud nemas na Conteineru nejaky komponenty. Dale proc pouzivas Timer? Nejaky padny duvod proc ho pouzivat? Na herni smycky je naprosto nevhodnej, delaji se pres vlakna, vetsinou jedno kde se volaji metody na render a aktualizovani herni logiky.

 
Nahoru Odpovědět  +1 27.2.2013 16:23
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Fugiczek
David Čápka:

V mnoha věcech máš samozřejmě pravdu, ale je to dělané jako jednoduchá ukázka nějakého realtimového vykreslování ve Swingu, proto tam nejsou vlákna atd., určitě to není brané jako vážný pokus o hru :)

Nahoru Odpovědět 27.2.2013 19:26
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Fugiczek
Redaktor
Avatar
Odpovídá na David Čápka
Fugiczek:

Uprimne je mi jedno jestli se tu nauci spatne nebo dobre praktiky. Jen jsem ti to chtel dat vedet. Jinak swing celkove neni vhodny na kresleni, v nem se spis vylepsovali vlastnosti komponent, jejich moznosti, vzhled a na vykon se nehledelo. Skoro vsechny tridy z AWT byly predelany do Swingu, ale Canvas jako jeden z mala ne, protoze je dost dobry. Takovych navodu na realtimove vykreslovani podobne tomu tvemu je hodne, proste se soustredili jen na jednoduchost a aby to bylo kratke a nikoho neodradilo. Je to fajn nic na to nenamitam, jsem rad kdyz to dela blbe a pak mu muzu vysvetlit proc to ma blbe, akorat kdyz pak podle toho chce udelat nekdo vetsi hru tak se pak divi proc ma maly vykon, pritom duvod je tak prosty, spatne zvoleni trid.

 
Nahoru Odpovědět 27.2.2013 19:45
Avatar
Odpovídá na David Čápka
Lukáš Hruda (Luckin):

Pro jednoduchou ukázku sis vybral docela složitou hru :D

 
Nahoru Odpovědět 27.2.2013 19:50
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Lukáš Hruda (Luckin)
David Čápka:

No až na ten pitomý odraz je to dost jednoduché, vždyť to má pár řádků :)

Nahoru Odpovědět 27.2.2013 19:55
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Fugiczek
David Čápka:

Ano, dělá to tak hodně lidí a neříkal bych, že je to špatně, je to prostě nejjednodušší cesta jak něco takového udělat. Pokud vím, dal jsi sem i ukázky jak to udělat lépe, rád to u toho zmíním.

Nahoru Odpovědět 27.2.2013 19:56
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Odpovídá na David Čápka
Lukáš Hruda (Luckin):

Pochopil jsem, že posouváš míček vždy jenom o jeden pixel, v tom případě můžeš udělat něco takovýho.

for (int j = 0; j < 4; j++) {
       for (int i = 0; i < 10; i++) {
               if((cihly[i][j]))
               {
                       int blockPosY = j * 20 + 50;
                       int blockPosX = i * 30 + 50;
                       int blockSizeY = 19;
                       int blockSizeX = 29;

                       if(x == blockPosX && y >= blockPosY && y <= blockPosY + blockSizeY) {/*kod*/}  //zleva
                       else if(x == blockPosX + blockSizeX && y >= blockPosY && y <= blockPosY + blockSizeY) {/*kod*/} //zprava
                       else if(y == blockPosY && x >= blockPosX && x <= blockPosX + blockSizeX) {/*kod*/} //zhora
                       else if(y == blockPosY + blockSizeY && x >= blockPosX && x <= blockPosX + blockSizeX) {/*kod*/} //zdola
               }
       }
}
 
Nahoru Odpovědět 27.2.2013 20:04
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Lukáš Hruda (Luckin)
David Čápka:

Ne, je tam rychlost, ta se násobí směrem.

Nahoru Odpovědět 27.2.2013 20:08
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Odpovídá na David Čápka
Lukáš Hruda (Luckin):

V tom případě můžeš takhle kontrolovat kolizi pro jednotlivý pixely v míčku jestli alespoň jeden z nich je na tý čáře.

 
Nahoru Odpovědět 27.2.2013 20:17
Avatar
Fugiczek
Redaktor
Avatar
Odpovídá na David Čápka
Fugiczek:

Spatne to neni pokud to funguje :-) Pokud neco neplanuju zverejnit nebo je to fakt mala hra tak taky plytvam vykonem kde se da :-D Klidne se tam zmin, bude lepsi kdyz budou vedet ze to jde i vykoneji. :-)

 
Nahoru Odpovědět  +1 27.2.2013 20:20
Avatar
David Čápka
Tým ITnetwork
Avatar
Nahoru Odpovědět 27.2.2013 20:24
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Odpovídá na David Čápka
Lukáš Hruda (Luckin):

Nezapomeň ošetřit rohy, jinak se ti může míček při názaru do dvou stran najedou odrazit uplně jinak než by měl. :D

 
Nahoru Odpovědět 27.2.2013 21:07
Avatar
Luboš Běhounek (Satik):

Pokud tedy půjdeš do těch per-pixel kolizí, tak se ty odrazy dají řešit třeba tak, že každý pixel má uloženou svojí normálu, aby jsi věděl, jak se má odraz od toho pixelu provést.

Nahoru Odpovědět 27.2.2013 21:16
:)
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 28 zpráv z 28.