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í.
Avatar
David Hartinger
Vlastník
Avatar
David Hartinger:27.2.2013 11:43

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
You are the greatest project you will ever work on.
Avatar
Kit
Tvůrce
Avatar
Kit:27.2.2013 11:57

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 Hartinger
Vlastník
Avatar
Odpovídá na Kit
David Hartinger:27.2.2013 12:06

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
You are the greatest project you will ever work on.
Avatar
Kit
Tvůrce
Avatar
Odpovídá na David Hartinger
Kit:27.2.2013 12:30

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 Hartinger
Vlastník
Avatar
Odpovídá na Kit
David Hartinger:27.2.2013 12:34

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
You are the greatest project you will ever work on.
Avatar
Kit
Tvůrce
Avatar
Odpovídá na David Hartinger
Kit:27.2.2013 12:40

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
Tvůrce
Avatar
Odpovídá na David Hartinger
Kit:27.2.2013 12:46

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
Lukáš Hruda
Tvůrce
Avatar
Odpovídá na David Hartinger
Lukáš Hruda:27.2.2013 12:53

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 Hartinger
Vlastník
Avatar
Odpovídá na Kit
David Hartinger:27.2.2013 13:04

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
You are the greatest project you will ever work on.
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Lukáš Hruda
David Hartinger:27.2.2013 13:04

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
You are the greatest project you will ever work on.
Avatar
Lukáš Hruda
Tvůrce
Avatar
Odpovídá na David Hartinger
Lukáš Hruda:27.2.2013 13:12

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
Tvůrce
Avatar
Odpovídá na David Hartinger
Kit:27.2.2013 13:41

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:27.2.2013 13:54

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
https://www.facebook.com/peasantsandcastles/
Avatar
user
Tvůrce
Avatar
Odpovídá na David Hartinger
user:27.2.2013 15:09

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
Tvůrce
Avatar
Odpovídá na David Hartinger
Fugiczek:27.2.2013 15:58

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
Tvůrce
Avatar
Odpovídá na David Hartinger
Fugiczek:27.2.2013 16:23

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
27.2.2013 16:23
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Fugiczek
David Hartinger:27.2.2013 19:26

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
You are the greatest project you will ever work on.
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na David Hartinger
Fugiczek:27.2.2013 19:45

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
Lukáš Hruda
Tvůrce
Avatar
Odpovídá na David Hartinger
Lukáš Hruda:27.2.2013 19:50

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

 
Nahoru Odpovědět
27.2.2013 19:50
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Lukáš Hruda
David Hartinger:27.2.2013 19:55

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
You are the greatest project you will ever work on.
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Fugiczek
David Hartinger:27.2.2013 19:56

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
You are the greatest project you will ever work on.
Avatar
Lukáš Hruda
Tvůrce
Avatar
Odpovídá na David Hartinger
Lukáš Hruda:27.2.2013 20:04

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 Hartinger
Vlastník
Avatar
Odpovídá na Lukáš Hruda
David Hartinger:27.2.2013 20:08

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

Nahoru Odpovědět
27.2.2013 20:08
You are the greatest project you will ever work on.
Avatar
Lukáš Hruda
Tvůrce
Avatar
Odpovídá na David Hartinger
Lukáš Hruda:27.2.2013 20:17

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
Tvůrce
Avatar
Odpovídá na David Hartinger
Fugiczek:27.2.2013 20:20

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
27.2.2013 20:20
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Lukáš Hruda
David Hartinger:27.2.2013 20:24

Díky, zkusím :)

Nahoru Odpovědět
27.2.2013 20:24
You are the greatest project you will ever work on.
Avatar
Lukáš Hruda
Tvůrce
Avatar
Odpovídá na David Hartinger
Lukáš Hruda:27.2.2013 21:07

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:27.2.2013 21:16

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
https://www.facebook.com/peasantsandcastles/
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.