NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Diskuze: pomoc s rozhýbáním obrázku (2D transformace)

V předchozím kvízu, Online test znalostí Java, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
zuufku
Člen
Avatar
zuufku:10.8.2012 14:10

Zdravíčko,

dělám na jednom menším projektu (hře). Zasekl jsem se však u rozpohybování obrázku. Hotové mám pozadí a na něj jsem vykreslil panáčka (triviální). Teď bych už jen potřeboval panáčka přesunout z jednoho místa plynule na místo jiné. Nemohl by mi s tím prosím někdo z Vás pomoc?

Zatím mám v metodě paint pouze toto:

public void paint(Graphics g) {
     Graphics2D g2 = (Graphics2D) g;
     g2.drawImage(pozadi, 20, 20, this);
     g2.drawImage(panak, 457, 421, this);
}

Obrázky už jsem nahrál dříve.

 
Odpovědět
10.8.2012 14:10
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na zuufku
Fugiczek:12.8.2012 14:37

No já bych to vyřešil přes proměnnou delta a určení rychlosti panáčka.
Delta je doba která proběhla od poslední zobrazení snímku. Takže nejdřív bych si napsal metodu která bude vracet hodnotu delta. K tomu bude potřeba si někde deklarovat proměnnou která bude mít v sobě čas posledního snímku.
Takže někde si deklaruješ proměnou:

long lastFrame = System.getCurrentTime();

A pak si napišeš metodu která bude vracet deltu:

private int getDelta(){
                long time=System.getCurrentTime();
                int delta=(int)(time-lastFrame);
                lastFrame=time;

                return delta;
        }

Pak si někde stanovíš rychlost panáčka:

float velocity = 0.2f;

Dále bych doporučil si udělat pro panáčka objekt, kde bych dal informace o té rychlost, souřadnicích a jeho cíl v souřadnicích. Budu předpokládat že takovej objekt již je a má metody jako getVelocity(), get/set X(), get/setY() a souřadnice typu float tak jako rychlost.
Takže teď upravíme tu metodu paint:

public void paint(Graphics g) {
     Graphics2D g2 = (Graphics2D) g;
     g2.drawImage(pozadi, 20, 20, this);
     g2.drawImage(panak, Math.round(getX()), Math.round(getY()), this);
     updateLogic();
}

A teď metodu která bude počítat nové souřadnice:

private void updateLogic(){
int delta = getDelta();
panak.setX(panak.getX()+((float)delta*velocity));
panak.setY(panak.getY()+((float)delta*velocity));}

Samozřejmě updateLogic() se upraví tak aby postupně šel za danými souřadnice pomocí nějakého algoritmu. Pokud se bude panák pohybovat moc rychle stačí změnšit rychlost, nebo deltu vydělit třeba 1000 aby se čas převedl na sekundy. Snad tenhle vyčerpávající příspěvek bude k něčemu nápomocný :)

 
Nahoru Odpovědět
12.8.2012 14:37
Avatar
zuufku
Člen
Avatar
zuufku:12.8.2012 20:58

zdravíčko .. Tak už jsem to vyřešil trošku jinak přesto díky za odpověď. Jelikož mám dalších tisíc otázek, tak tady ještě nějaký vytasím. přes metodu

public void keyPressed(KeyEvent e)

vždy odchytím tlačítko a podle něj volím směr pohybu. Když chci ale odchytit dvě najednou (např. doprava+nahoru)? mám zvolit jinou metodu, nebo volit nějaké proměnné do kterých si dám požadované tlačítka a podle nich zvolím směr?

Dál jsem se chtěl zeptat, jak to chodí když chci ohraničit prostředí ( aby se mi panáček nedostal tam kde ho nevidím ). Mám to udělat stylem když je na xxx-tém pixelu, metoda jdi() nefunguje? ... nebo se to dělá jinak?

Za odpovědi/typy díky :)

 
Nahoru Odpovědět
12.8.2012 20:58
Avatar
Fugiczek
Tvůrce
Avatar
Fugiczek:12.8.2012 21:14

Takovej směr jsem zatím neřešil. Napadají mě dvě řešení. První že když se vyvolá metoda keyPressed tak se ten směr nastaví na true a když se vyvolá metoda keyReleased tak se nastaví zpět na false. Pak jen budeš ověřovat jestli jsou obě dvě proměnné true. Druhá možnost že si nastavíš proměnou typu float a tam budeš mít směr jako u hodin. 0-sever 0.125-severovýchod 0.25-vychod, ... No při stisknutí klávesy by se to přičítalo a odečítalo a cesta by se počítala přes uhel nebo nějak podobně.
K tomu druhému dotazu. Já si obvykle udělám mapu do textovýho souboru, 0-pruchozí 1-zeď. Udělám si to třeba ty čísla 20x20 a pak si propočítám podle herní plochy kolik zabírá místa jakoby jedno číslo. A pak si jen počítám jestli na tom místě není 1 :) Tvým stylem by to šlo udělat taky. Můj styl není nějak univerzální. Kdyby jsi chtěl udělat herní plochu která půjde ničit tak bych mapu nahrával jako obrázek a mapu postupně střelami "gumoval" zdi bych ověřoval metodou jakou jsi popisoval jestli je tam daná barva tak jdi :)

 
Nahoru Odpovědět
12.8.2012 21:14
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na zuufku
Fugiczek:12.8.2012 21:24

Ještě k těm aby se nedostal tam kde ho nevidíš tak prostě jen nedovolíš pohyb pokud jeho souřadnice nejsou menší než 0 a větší než velikost okna.
Mohlo by to vypadat nějak takhle:

if(panak.getX()>0 &&panak.getX()<getWidth()){
   if(panak.getY()>0 &&panak.getX()<getHeight()){
      //neco delej
   }
}

metody getWidth() a getHeight() jsou normálně u komponenty JFrame a možná i u JPanel ale si nejsem jistý.

 
Nahoru Odpovědět
12.8.2012 21:24
Avatar
zuufku
Člen
Avatar
zuufku:12.8.2012 22:36

Mohl by jsi sem hodit ukázku toho mapování do txt? Já abych to správně pochopil ... a ještě jestli neznáš nějaký tutoriály, nebo knížku kde se tyhle věci můžu naučit?

 
Nahoru Odpovědět
12.8.2012 22:36
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na zuufku
Fugiczek:12.8.2012 23:54

Já se vše učím z různých článků co najdu na netu v angličtině. Každý to dělá jinými způsoby a já si vyberu ten co se mi ke které hře hodí.
Tady ti postnu pár zdrojáků z jedné hry.
Toto je třída s mapou:

package objects;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

public class Map {

        private int[][]mapa;
        private int poradiMapy;

        public Map(){
                mapa=new int[21][21];
                poradiMapy=0;
        }

        /**
         *
         * @return <ul>
         * <li>0-když je vše v pořádku</li>
         * <li>-1-když mapa není k dispozici</li>
         * <li>-2-když nastane chyba při čtení</li>
         * </ul>
         */
        public short nactiMapu(){
                poradiMapy++;
                mapa=new int[21][21];
                try {
                        BufferedReader br=new BufferedReader(new InputStreamReader(new
                                        FileInputStream(poradiMapy + ".txt"), "UTF-8"));
                        String radka;
                        char[] radkaChar;
                        int radek=0;
                        while((radka=br.readLine())!=null){
                                radkaChar=new char[21];
                                radka.getChars(0, 21, radkaChar, 0);
                                for(int i=0;i<21;i++){
                                                mapa[radek][i]=Character.digit(radkaChar[i],10);
                                        if(!(mapa[radek][i]==0 || mapa[radek][i]==1)){
                                                br.close();
                                                prepis();
                                                return -2;
                                        }
                                }
                                radek++;
                        }
                        br.close();
                } catch (FileNotFoundException e) {
                        return -1;

                } catch (IOException e) {
                        prepis();
                        return -2;

                }
                return 0;
        }

        public int[][] getMap(){
                int [][] mapaCopy=new int[21][21];
                System.arraycopy(mapa, 0, mapaCopy, 0, 21);

                return mapaCopy;
        }

        public int getPoradiMapy(){
                return poradiMapy;
        }

        private void prepis(){
                mapa=new int[21][21];
                for(int[]a:mapa){
                        for(@SuppressWarnings("unused") int i:a){
                                i=0;
                        }
                }
        }
}

A tady je metoda ze jedné třídy, počítá se tu pohyb a cesta.

public void move(Map mapa)  throws ArrayIndexOutOfBoundsException{
                map=mapa.getMap();

                int probehlo=0;
                for(Point p:player){
                        if(p.isSelected() && (targetX!=0 || targetY!=0)){
                                if(targetX>p.getX() && map[(int)(p.getY())/20][(int)(p.getX()+p.getVelocity()+6)/20]!=1){
                                        p.setX(p.getX()+p.getVelocity());
                                }else if(targetX<p.getX() && map[(int)(p.getY())/20][(int)(p.getX()-p.getVelocity())/20]!=1){
                                        p.setX(p.getX()-p.getVelocity());
                                }else if(targetY>p.getY() && map[(int)(p.getY()+p.getVelocity()+6)/20][(int)(p.getX())/20]!=1){
                                        p.setY(p.getY()+p.getVelocity());
                                }else if(targetY<p.getY() && map[(int)(p.getY()-p.getVelocity())/20][(int)(p.getX())/20]!=1){
                                        p.setY(p.getY()-p.getVelocity());
                                }

                                if(p.getX()==targetX && p.getY()==targetY){
                                        p.setSelected(false);
                                }
                                probehlo++;
                        }else{
                                switch(rand.nextInt(4)){
                                case 0:
                                        if(p.getY()<widthWindow && map[(int)(p.getY()+p.getVelocity()+5)/20][(int)(p.getX())/20]!=1){
                                                p.setY(p.getY()+p.getVelocity());
                                        }
                                        break;
                                case 1:
                                        if(p.getX()<heightWindow && map[(int)(p.getY())/20][(int)(p.getX()+p.getVelocity()+5)/20]!=1){
                                                p.setX(p.getX()+p.getVelocity());
                                        }
                                        break;
                                case 2:
                                        if(p.getY()>0 && map[(int)(p.getY()-p.getVelocity())/20][(int)(p.getX())/20]!=1){
                                                p.setY(p.getY()-p.getVelocity());
                                        }
                                        break;
                                case 3:
                                        if(p.getX()>0 && map[(int)(p.getY())/20][(int)(p.getX()-p.getVelocity())/20]!=1){
                                                p.setX(p.getX()-p.getVelocity());
                                        }
                                        break;
                                default:
                                        try {
                                                throw new Exception("Random se zbláznil");
                                        } catch (Exception e) {
                                                e.printStackTrace();
                                        }
                                }
                        }
                }

                for(Point p:enemy){
                        switch(rand.nextInt(4)){
                        case 0:
                                if(p.getY()<widthWindow && map[(int)(p.getY()+p.getVelocity()+5)/20][(int)(p.getX())/20]!=1){
                                        p.setY(p.getY()+p.getVelocity());
                                }
                                break;
                        case 1:
                                if(p.getX()<heightWindow && map[(int)(p.getY())/20][(int)(p.getX()+p.getVelocity()+5)/20]!=1){
                                        p.setX(p.getX()+p.getVelocity());
                                }
                                break;
                        case 2:
                                if(p.getY()>0 && map[(int)(p.getY()-p.getVelocity())/20][(int)(p.getX())/20]!=1){
                                        p.setY(p.getY()-p.getVelocity());
                                }
                                break;
                        case 3:
                                if(p.getX()>0 && map[(int)(p.getY())/20][(int) (p.getX()-p.getVelocity())/20]!=1){
                                        p.setX(p.getX()-p.getVelocity());
                                }
                                break;
                        default:
                                try {
                                        throw new Exception("Random se zbláznil");
                                } catch (Exception e) {
                                        e.printStackTrace();
                                }
                        }
                }

                if(probehlo==0){
                        targetX=0;
                        targetY=0;
                }

        }

Tohle jsou zdrojaky z jedné hry kterou jsem samozřejmě nedokončil, takže ani ten pohyb není dokonalý ale snad z toho něco pochytíš. Čísla jako 5 a 6 se tam přičítají z důvodu velikosti toho objektu co se vykresluje. Pak to dělení 20 je abych se dostal do indexu těch polí a zjistil jesli v tom indexu je 0 nebo 1.

 
Nahoru Odpovědět
12.8.2012 23:54
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na zuufku
David Hartinger:13.8.2012 0:02

Můžeš se podívat na algoritmy pohybu:

Po přímce: http://www.itnetwork.cz/…yb-po-primce
V bludišti (vyhýbání se překážkám): http://www.itnetwork.cz/…y-v-bludisti

Nahoru Odpovědět
13.8.2012 0:02
New kid back on the block with a R.I.P
Avatar
zuufku
Člen
Avatar
zuufku:14.8.2012 1:05

opět musím poděkovat za odpovědi a nadhodit další dotaz. Řešili jste už někdy pohyb o určitý úhel? tzn. když mačkám nahoru jedu podle hlavy, když dám šipku doleva, objekt zatáčí o určitý kousek (úhel) doleva. Prostě jako v této hře :

http://achtungdiekurve.net/

Dík moc za pomoc :)

 
Nahoru Odpovědět
14.8.2012 1:05
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na zuufku
Fugiczek:14.8.2012 9:05

Tenhle pohyb jsem zatím neřešil ale bude mě to čekat teď v multiplayer hře kterou plánuji. Nemůžu ti poradit nic kontrétního, ale vím že se to dělá přes trigonometrii. Podívej se na toto: http://en.wikipedia.org/…/Unit_circle
Já to budu řešit stejně...

 
Nahoru Odpovědět
14.8.2012 9:05
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na zuufku
David Hartinger:14.8.2012 10:58

Přesně tak, nastuduj si goniometrické funkce ;-) Budeš mít uložený úhel, ten budeš šipkami zvyšovat nebo snižovat. Podle úhlu si vypočítáš další souřadnici.

Koukni na tohle, jistě si potom hravě napíšeš svůj kód: http://www.itnetwork.cz/…-po-kruznici

Nahoru Odpovědět
14.8.2012 10:58
New kid back on the block with a R.I.P
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na zuufku
David Hartinger:14.8.2012 11:05

Bude to něco jako (píšu z hlavy):

x += Math.Round(Math.Cos(uhel) * rychlost);
y += Math.Round(Math.Sin(uhel) * rychlost);
Nahoru Odpovědět
14.8.2012 11:05
New kid back on the block with a R.I.P
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na zuufku
Fugiczek:14.8.2012 14:21

No trošku bych to upravil na toto:

x+=Math.round(Math.cos(Math.toRadians(uhelVeStupnich))*(0.1*delta));
y+=Math.round(Math.sin(Math.toRadians(uhelVeStupnich))*(0.1*delta));

Mě osobně se líp dělá se stupni než s radiány.
0° - doprava
90° - dolu
180° - doleva
270° - nahoru
360° stejný jako 0°
Takhle ty směry platí jen když to přičítáš, u odečítání by to bylo naopak.
Udělal bych si jen metodu která ti ten uhel bude upravovat. Třeba nějak tak:

public void modifyAngle(int count){ //count musí být ve stupních
   if(angle+count>360){
      angle=+count-360;
   }else if(angle+count<0){
      angle=(angle+count)+360;
   }else{
      angle+=count;
   }
}

Když dáš count záporný úhel se bude odečítat. Jinak pokud se ti líbí víc radiány použij to co napsal David Hartinger.
U radiánů by to bylo:
PI*2 || 0 -> doprava
PI/2 ->dolu
PI -> doleva
PI+PI/2 -> nahoru
A na metoda na úpravu úhlu by se upravila z úhlů na radiány nějak takto:

public void modifyAngle(int count){ //count musí být v radiánech
   if(angle+count>(Math.PI*2)){
      angle=+count-(Math.PI*2);
   }else if(angle+count<0){
      angle=(angle+count)+(Math.PI*2);
   }else{
      angle+=count;
   }
}
 
Nahoru Odpovědět
14.8.2012 14:21
Avatar
Fugiczek
Tvůrce
Avatar
Fugiczek:14.8.2012 14:24

u té druhé metody musí být count float nebo double, to jsem se přepsal

 
Nahoru Odpovědět
14.8.2012 14:24
Avatar
zuufku
Člen
Avatar
zuufku:14.8.2012 22:29

Jo jo díky za odpovědi hned zítra se do toho pustím. Snad by to neměl být moc problém ... pak asi začnu řešit jak pootočit obrázek tak aby hlava byla furt směrem kterým jedu :)

 
Nahoru Odpovědět
14.8.2012 22:29
Avatar
Kit
Tvůrce
Avatar
Kit:14.8.2012 22:49

Místo výrazu

p.setX(p.getX()+p.getVelocity());

bych raději udělal

p.addX(p.getVelocity());

nebo rovnou

p.addVelocity(1,0);
p.addVelocity(0,-1);

apod.

Také je možné použít polární souřadnice

p.addVelocity(rychlost, kurs);

a v metodě addVelocity():

X+=rychlost*cos(kurs);
Y+=rychlost*sin(kurs);
Nahoru Odpovědět
14.8.2012 22:49
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
zuufku
Člen
Avatar
zuufku:16.8.2012 10:39

tak pohyb o úhly mám zdárně za sebou, teď bych potřeboval rotaci samotného objektu. tzn. když zahnu doleva o 15° aby se mi objekt o 15° natočil ... to znamená, že kdyby byl objekt šipka, tak ukazuje furt směrem kterým jedu ... neznáte prosím někdo princip řešení? :)

 
Nahoru Odpovědět
16.8.2012 10:39
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na zuufku
Fugiczek:16.8.2012 10:47

Pro obrázek:

AffineTransform affineTransform = new AffineTransform();
affineTransform.rotate(Math.toRadians(uhel_ve_stupnich));
g2.drawImage(image, affineTransform, null);

Pokud nevykresluješ obrázek tak:

g2.rotate(Math.toRadians(uhel_ve_stupnich));
 
Nahoru Odpovědět
16.8.2012 10:47
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na zuufku
Fugiczek:16.8.2012 11:14

Pro podrobnější informace o AffineTransform si můžeš přečíst v dokumentaci zde: http://docs.oracle.com/…ansform.html
Nastavování pozice pro vykreslování se dělá myslím takhle:

affineTransform.setToTranslation(x,y);
 
Nahoru Odpovědět
16.8.2012 11:14
Avatar
zuufku
Člen
Avatar
zuufku:16.8.2012 11:32

Ještě se tě zeptám, jak bys rozdělil ten kód? mám třídu Panacek(tam je obrázek a je tam naprogramován pohyb) ... a třídu Platno (tam je metoda paint() a pozadí).

 
Nahoru Odpovědět
16.8.2012 11:32
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na zuufku
Fugiczek:16.8.2012 12:10

Já si většinou dělám interface Drawable, který obsahuje metodu

public void draw(Graphics2D g2);

A pak ho implementuji do objektů který se mi vyklesujou. Takže přímo v objektu si napíšeš jak se ten tvůj panáček bude vykreslovat. Kód je pak přehlednější když zavolám na plátně pouze panak.draw(g2);
Místo paint() bych radši použival paintComponen­t(Graphics g); která je lepší a rychlejší.
Rozdělení kódu je otázkou vkusu. Já osobně bych to napsal úplně jinak, ignoroval metody paint() a paintComponent(), vytvořil si BufferStrategy(po­kud by bylo k dispozici BufferCapatabi­lities tak bych využíval i toho), pokud by to byl nějakej velkej projekt udělal bych si vykreslovaní a renderování přes VolatileImage.
O tom rozdělení kódy fakt nevím co bych ti k tomu řekl, akorát tak rozdělit a rozlišovat kód kde je herní logika a kde se jen vykresluje. V tvé třídě Platno by mělo být minimum počítání nějaké logiky, všechno by se mělo zpracovávat v jiných třídách. Měl by jsi tam měl jít prostě jen sestavení okna, nějakou smyčku na vykreslování, metodu na vykreslení, kde budeš vykreslovat to pozadi jedním řádkem a pak druhým řádkem budeš volat vykreslení panáčka a na nakonec nějaký listenery na myš/klávesnici (přes soukromou třídu která bude dědit od MouseInputAdapter nebo KeyAdapter, nebo používat implementaci těch tříd), ale to taky jednoduchý zpracování aby prostě nebylo v třídě která má za úkol zobrazovat a zachytávat různý vstupy moc počítání, aby to bylo přehledný.
Ale všechno co ti tu píšu každej si dělá po svým. Je jen na programátorovi jestli to bude psát "prasácky" nebo na úrovni s OOP.

 
Nahoru Odpovědět
16.8.2012 12:10
Avatar
zuufku
Člen
Avatar
zuufku:16.8.2012 12:17

jo jo díky moc za nákop .. OOP jsem samozřejmě měl, ale s grafikou teprve začínám a mám v tom docela bordel. Někde jsem dokonce četl (evidentně kravina) že veškerý vykreslování by se mělo dít jen v jedné třídě v metodě paint. Tak jsem se toho asi zbytečně snažil držet :)

 
Nahoru Odpovědět
16.8.2012 12:17
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na zuufku
Fugiczek:16.8.2012 12:42

Vykreslování hlavně u her bych doporučil dělat následovně:

1. Jak už jsem psal, ignorovat metody na překreslení

setIgnoreRepaint(true);

2. Vytvořit si bufferstrategy a uložit si to do nějaké proměnné

BufferStrategy bs = null; //deklarace někde na začátku třídy
...
createBufferStrategy(2); //vytvoření BS se 2 buffery (je to technika dvojího vykreslování)
bs=getBufferStrategy()

3. Udělat si svoji metodu na kreslení, třeba pod názvem updateGUI

public void updateGUI(){
Graphics2D g2 = (Graphics2D)bs.getDrawGraphics();
//tady různé vykreslování třeba to pozadí + panáček
g2.dispose();

bs.show(); //zobrazení
Toolkit.getDefaultToolkit().sync(); //užitečná funkce zvláště když děláš animace/hry
}
 
Nahoru Odpovědět
16.8.2012 12:42
Avatar
zuufku
Člen
Avatar
zuufku:16.8.2012 17:44

Tak rotace je funkční bohužel jen ke středu souřadnic [0,0] v levém horním rohu plátna. teď bych potřeboval přehodit střed okolo kterého panáček rotuje na roh panáčkova obrázku, aby se mi to točilo na místě.

Zatím sem vygooglil změnu měřítka následně.

AffineTransform af = new AffineTransform();
af.translate(x,y);
af.rotate(uhel)

Jenže se mi to ještě nepodařilo implementovat. Kde mám změnu měřítka provést? ve třídě panáček nebo plátno? ... Zkoušel jsem oboje a ani jedno mi nechodilo :(

 
Nahoru Odpovědět
16.8.2012 17:44
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na zuufku
Fugiczek:16.8.2012 18:15

Takhle to vykreslis doprostřed s úhlem otočení 45°

AffineTransform at = new AffineTransform();
                at.setToTranslation((getWidth()-i.getWidth(null))/2,(getHeight()-i.getHeight(null))/2);
                at.rotate(Math.toRadians(45),i.getWidth(null)/2,i.getHeight(null)/2);

                g2.drawImage(i, at, null);

Proměnná i je objekt typu Image. Metody getWidht() a getHeight() jsou metody z JFrame. Ty hodnoty si můžeš dát na plátně třeba jako public static final int HEIGHT/WIDTH a pak k nim pristupovat Platno.HEIGHT/WID­TH.
Tenhle kód jsem teď testoval na JFrame. První metoda setToTranslati­on() nastavíš pozici obrázku. Druhá metoda rotate() ti nastaví o kolik obrázek otočíš + si můžeš přidat bod na obrázku podle kterýho se to bude otáčet.

 
Nahoru Odpovědět
16.8.2012 18:15
Avatar
Kit
Tvůrce
Avatar
Odpovídá na zuufku
Kit:16.8.2012 18:38

Uvnitř objektu si udržuj souřadnice X a Y. K tomu Kurs a Rychlost. Když nebudeš měnit kurs ani rychlost, stačí zavolat

p.step()

Metoda step() provede výpočet

X += Math.Cos(Kurs) * Rychlost);
Y += Math.Sin(Kurs) * Rychlost);

K tomu si dopíšeš metody zmenaKursu() pro změnu směru a zmenaRychlosti() pro změnu rychlosti pohybu. Tyto metody se mohou volat na základě události od kurzorových šipek. Při malé rychlosti budeš zatáčet ostřeji. Může být i stanovena maximální rychlost (rychlost se ani při dalším požadavku nezvýší nad limit).

Pro vykreslení máš k dispozici vše co potřebuješ uvnitř objektu, stačí mu jen dopsat další metodu, abys to nemusel tahat přes nesmyslné gettery.

Nahoru Odpovědět
16.8.2012 18:38
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
zuufku
Člen
Avatar
zuufku:17.8.2012 16:33

Není nějaká metoda, která mi dá dohromady transformaci a pohyb? Myslím tím metody:

g2.drawImage(i, at, null);

a

g2.drawImage(i, i.x, i.y, null);

protože pohyb mi funguje rotace taky, ale nejde mi to dát dohromady (vykreslujou se mi dva obrázky).

 
Nahoru Odpovědět
17.8.2012 16:33
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na zuufku
Fugiczek:17.8.2012 17:08

Jak dohromady? Trochu specifikuj, poskytni nějaký zdrojový kód. Takhle se blbě radí.

 
Nahoru Odpovědět
17.8.2012 17:08
Avatar
zuufku
Člen
Avatar
zuufku:17.8.2012 17:55

ok tak mám metodu na rotování s panákem:

private void draw_rotace(Graphics2D g2){
        af.setToTranslation((getWidth()-panak.getWidth(null))/2,(getHeight()-panak.getHeight(null))/2);
        af.rotate(uhel,panak.getWidth(null)/2,panak.getHeight(null)/2);
        g2.setTransform(af);
        g2.drawImage(panak, af, null);
}

Tahle metoda zařídí rotaci o úhel.

pak mám druhou metodu na posunutí panáka:

private void draw_posun(Graphics2D g2) {
       g2.drawImage(panak, this.getX(), this.getY(),null);
}

(obě metody jsou ve třídě panák)

Jenže já oboje potřebuju napsat v jedné metodě, protože když je zavolám obě, tak se mi na plátno vykreslí dva panáci, jeden rotuje a druhej jede . Takže potřebuju nastavit rotaci a mít jen jednu metodu g2.drawImage() (pokud to teda takhle dobře chápu). A s tím si furt nemůžu poradit :)

 
Nahoru Odpovědět
17.8.2012 17:55
Avatar
Fugiczek
Tvůrce
Avatar
Odpovídá na zuufku
Fugiczek:17.8.2012 18:11

Kdyby jsi pořádně četl, tak jsem psal že pozice se nastavuje přes tuto metodu:

af.setToTranslation(x,y);
 
Nahoru Odpovědět
17.8.2012 18:11
Avatar
Fugiczek
Tvůrce
Avatar
Fugiczek:17.8.2012 18:18
public void draw(Graphics2D g2){
        af.setToTranslation(this.getX(),this.getY());
        af.rotate(uhel,panak.getWidth(null)/2,panak.getHeight(null)/2);
        g2.drawImage(panak, af, null);
}
 
Nahoru Odpovědět
17.8.2012 18:18
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 31 zpráv z 31.