[java 2d] langzaam verplaatsen

Pagina: 1
Acties:
  • 142 views sinds 30-01-2008
  • Reageer

  • intrix
  • Registratie: November 2002
  • Laatst online: 04-12-2023
Mensen ik ben nu al een week of wat bezig met de java2d api,
toch is er iets waar ik nou niet helemaal uit kom.

Als je in java een object bijvoorbeeld een rectangle wil tekenen,
dan zet je in je paint() methode -na Graphics naar een Graphics2d gecast
te hebben: g2d.fill(new Rectangle2D(*,*,*,*));

En dan wordt er netjes een vierkantje afgedrukt, wil je
dat vierkantje verplaatsen dan verander je een van de *-en en je
vierkant staat op een andere plaats. Nou zit ik dus met het volgende:

Ik wil nadat ik op een knop geklikt heb dat het vierkant 85 pixels omhoog
gaat. Nou geen probleem zou je denken zet een methode in je buttonHandler
die er voor zorgt dat als er op de knop gedrukt wordt de waarde van dat sterretje
verandert. Nou dat werkt ook wel. In MyCanvas zit een methode setPaint() en die
verandert die waarde, maar als je dus wilt dat het vierkant langzaam 85 pixels omhoog gaat, dan kom je in de problemen.

Ik heb het trouwens eerst het schokkend verversen weggehaal door de
update() er zo uit te laten zien:

Java:
1
2
3
4
    public void update(Graphics g)
    {
        paint(g);
    }


daarna dacht ik gewoon tegen de setpaint te zeggen

Java:
1
2
3
4
5
While(int t=0; t<85; t++)
{
    hoogte-=1;
    repaint();
}


maar hier trapt java niet helemaal in geloof ik, wat gebeurt er namelijk
repaint wordt pas na de while lus aangeroepen. Ik denk persoonlijk
dat die while lus te snel is voor de repaint() methode.
Maar ik zie geen andere oplossing, ik ben al een poosje bezig met het
boek java media api's cross-platform Imaging, Media and Visualization
maar ik heb na 4 hoofdstukken nog steeds niets kunnen vinden wat hier nou van toepassing zou kunnen zijn.

Heb ook al de halve java docs door geworsteld maar daar vindt ik toch ook niet wat ik zoek.

[ Voor 3% gewijzigd door intrix op 17-12-2003 14:37 ]

welcome my son, welcome to the machine


Verwijderd

intrix schreef op 17 december 2003 @ 14:36:
Ik wil nadat ik op een knop geklikt heb dat het vierkant 85 pixels omhoog
gaat. Nou geen probleem zou je denken zet een methode in je buttonHandler
die er voor zorgt dat als er op de knop gedrukt wordt de waarde van dat sterretje
verandert. Nou dat werkt ook wel. In MyCanvas zit een methode setPaint() en die
verandert die waarde, maar als je dus wilt dat het vierkant langzaam 85 pixels omhoog gaat, dan kom je in de problemen.
langzaam 85 pixels omhoog is dus geen 85 pixels omhoog maar het starten van een animatie die er uiteindelijk in resulteert dat het vierkant 85 pixels hoger staat.
Java:
1
2
3
4
5
While(int t=0; t<85; t++)
{
    hoogte-=1;
    repaint();
}


maar hier trapt java niet helemaal in geloof ik, wat gebeurt er namelijk
repaint wordt pas na de while lus aangeroepen. Ik denk persoonlijk
dat die while lus te snel is voor de repaint() methode.
Dit snap ik niet. Hoe kan een while lus nou "te snel" gaan voor repaint? Het is toch een methode die wordt aangeroepen? Die while lus gaat pas verder als repaint klaar is. Dat heeft verder niets met snel/langzaam te maken. Volgens mij lijkt het alleen alsof repaint pas na de while lus word aangeroepen. Waarom dit zo is? Geen idee :)

  • intrix
  • Registratie: November 2002
  • Laatst online: 04-12-2023
Verwijderd schreef op 17 december 2003 @ 14:46:
[...]


langzaam 85 pixels omhoog is dus geen 85 pixels omhoog maar het starten van een animatie die er uiteindelijk in resulteert dat het vierkant 85 pixels hoger staat.


[...]


Dit snap ik niet. Hoe kan een while lus nou "te snel" gaan voor repaint? Het is toch een methode die wordt aangeroepen? Die while lus gaat pas verder als repaint klaar is. Dat heeft verder niets met snel/langzaam te maken. Volgens mij lijkt het alleen alsof repaint pas na de while lus word aangeroepen. Waarom dit zo is? Geen idee :)
jij zegt dus een animatie starten .. maar hoe doe je dat dan?
daar kan ik dus niets over vinden in dat stomme boek :(

welcome my son, welcome to the machine


  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07-2025
nou die repaint zou best wel eens delayed kunnen gebeuren hoor. Niet dat ik daar 100% zeker van ben maar het kan dat de repaint in een andere event thread zit zodat je idd alleen 1 jump gaat zien. Heb je ergens geen "main loop"?

  • intrix
  • Registratie: November 2002
  • Laatst online: 04-12-2023
nou wilde ik hier iets zeggen maar dat kan ik nog even niet bewijzen,
en ik wil niets zeggen wat "dom" genoemd kan worden

[ Voor 85% gewijzigd door intrix op 17-12-2003 15:11 . Reden: eerst denken dan doen ]

welcome my son, welcome to the machine


  • KneoK
  • Registratie: December 2001
  • Laatst online: 27-05 12:52

KneoK

Not in a million lightyears

intrix schreef op 17 december 2003 @ 14:52:
[...]


jij zegt dus een animatie starten .. maar hoe doe je dat dan?
daar kan ik dus niets over vinden in dat stomme boek :(
Ik weet niet hoe het precies met Java zit, maar is het in eerste instantie niet beter om er een FOR loop van te maken ? Dus for(int t=0;t<85;t++){ bladiebla } ?

Of iets van:

Java:
1
2
3
4
while (int t < 85){
  t++;
  bladiebla
}


En dan weet ik (correct me if I'm wrong) van bijvoorbeeld Perl, dat deze de code binnen de FOR of WHILE loop uitvoert en het uiteindelijke resultaat op het scherm tovert als de gehele loop afgelopen is...
Het is dus niet zo dat bij elke verhoging van t ook automatisch het scherm update... Hij berekent het resultaat van de loop, en gooit aan het einde van de loop het resultaat op het scherm (wat dus resulteert in de kubus die 85 pixels is verschoven).
}

[ Voor 3% gewijzigd door KneoK op 17-12-2003 15:29 ]


Verwijderd

Even voor de duidelijkheid:

- Er wordt op een button gedrukt
- Er start een "animatie"
- Aan het einde van deze "animatie" is een vierkant 85 pixels omhoog gegaan.

Animatie is (in dit geval) een soepel bewegend vierkant.

Dit is wat je wil?

  • intrix
  • Registratie: November 2002
  • Laatst online: 04-12-2023
BioWEB schreef op 17 december 2003 @ 15:11:
[...]


Ik weet niet hoe het precies met Java zit, maar is het in eerste instantie niet beter om er een FOR loop van te maken ? Dus for(int t=0;t<85;t++){ bladiebla } ?
dat had er ook moeten staan dat heet dus slordigheidsfoutje :*) ;) :)
BioWEB schreef op 17 december 2003 @ 15:11:
[...]


En dan weet ik (correct me if I'm wrong) van bijvoorbeeld Perl, dat deze de code binnen de FOR of WHILE loop uitvoert en het uiteindelijke resultaat op het scherm tovert als de gehele loop afgelopen is...

Het is dus niet zo dat bij elke verhoging van t ook automatisch het scherm update... Hij berekent het resultaat van de loop, en gooit aan het einde van de loop het resultaat op het scherm (wat dus resulteert in de kubus die 85 pixels is verschoven).
}
dat is dus waar ik het over heb,
dat is wat er gebeurt, hij schuift niet elke keer op en met een
sleep(100) er tussen doet ie dat wel maar dat ziet er niet uit!

dus nu zit ik met een juistere formulering van het probleem namelijk hij
berekend het eindresultaat en update dan pas,
maar wat moet je daar aan doen?

welcome my son, welcome to the machine


  • intrix
  • Registratie: November 2002
  • Laatst online: 04-12-2023
Verwijderd schreef op 17 december 2003 @ 15:17:
Even voor de duidelijkheid:

- Er wordt op een button gedrukt
- Er start een "animatie"
- Aan het einde van deze "animatie" is een vierkant 85 pixels omhoog gegaan.

Animatie is (in dit geval) een soepel bewegend vierkant.

Dit is wat je wil?
ja dat is de bedoeling maar dat lukt dus niet met een while lus zoals ik
gedacht had dat te doen vanwege het feit dat java dus de eind berekening
doorvoert. (zie vorige reply)

welcome my son, welcome to the machine


  • MaxxRide
  • Registratie: April 2000
  • Laatst online: 09-01 10:13

MaxxRide

Surf's up

Probeer eens aan het einde van je while (na de repaint) een sleep ofzo te doen. Kun je kijken of de boel wel goed wordt berekend (lijkt me, heb al lang niet meer in JAVA gewerkt, maar zo kan het dacht ik wel in C of in Delphi).

If you are not wiping out you are nog pushing enough...


Verwijderd

Gegeven de info zou ik het gewoon zo doen (kan geen applets/grafische toeestanden in java dus dat is pseudo code):

Java:
1
2
3
4
5
6
BEGIN = VARIABELE_VAN_VIERKANT

for (int i = 0; i < GRENS; i += STAP_GROOTTE) {
    VARIABELE_VAN_VIERKANT = (BEGIN + i);     // moet hier wel te wijzgen zijn natuurlijk
     paint(g);      // of repaint, dat weet ik niet precies 
}


Waarbij GRENS is 85
STAP_GROOTTE is denk ik iets van 5 (ipv 1, 1 is een beetje weinig). Hangt er wel vanaf of je precies op 85 moet uitkomen of niet.
VARIABELE_VAN_VIERKANT is die variabele waarmee je die coordinaat verandert. Eventueel moeten dit er meerdere zijn dat weet ik niet.
En dan Painten maar.

Toch?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

Gebruik een aparte thread voor je animatie, zoals het hoort. En een repaint () is idd delayed, hij stuurt een request naar de teken-thread om opnieuw te tekenen, en dat kan dus nog wel even duren. Zolang er een repaint () is aangeroepen en er is nog niet opnieuw getekend, dan hebben volgende calls naar repaint () ook weinig nut.

Je kunt repaint ook aanroepen met parameters, en met bepaalde parameters kun je ervoor zorgen dat ie direct moet repainten. Ik weet niet precies uit mijn hoofd welke dat ook alweer was, maar dat kun je makkelijk vinden in de documentatie.

In die aparte thread kun je beter niet een simpel loopje gebruiken waarbij je de coordinaat steeds met 1 verandert, want dan is het heel erg cpu-snelheid afhankelijk. Wat je beter kunt doen is de tijd meten van elk loopje, en aan de hand daarvan je coordinaten aanpassen. Dus zeg dat je in 5 seconden 85 pixels moet bewegen, dan betekent dat 17 pixels per seconden, en als er 0.15 seconden verstreken zijn sinds de vorige keer dan moet er dus met 17*0.15 pixels worden bewogen (sla dit wel op in een float of double, anders krijg je afrondingsfouten).

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Oke er zijn een aantal dingen die fout gaan.
Ten eerste: De repaint method hertekend het scherm niet opnieuw. Het enige wat deze doet is in de GUI thread een paint request in de queue zetten. Dit garandeerd dus niet dat deze meteen uitgevoerd wordt.
Omdat het lusje zo snel uitgevoerd wordt is je positie al op zijn hoogste punt voordat het scherm opnieuw getekend wordt.

De tweede fout is dat je je Update functie overschreven hebt op de volgende manier

Java:
1
2
3
4
public void update( Graphics g )
{
    paint( g );
}

De update methode zorgt er normalitair voor dat je scherm weer helemaal leeg gemaakt wordt. Door dit niet te doen wordt alles wat jij op het scherm tekent bewaart.
Je moet het zo zien. De eerste keer teken je een vierkant op positie 100, 100. De tweede keer doe je dit op 100, 101 ( een pixel lager dus ). Het eerste vierkant staat er echter nog omdat het scherm niet gewist is. Dus krijg je gewoon een rechthoek wat 1 pixel breder is als je originele vierkant.
edit:

mischien eerst even refreshen voordat ik reageer :)

[ Voor 4% gewijzigd door Woy op 17-12-2003 16:18 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dat idd ook. Maar als je update niet override, of als je zelf eerst je Graphics leeg maakt met een clearRect () oid, dan krijg je idd zo'n knippereffect

Daarvoor kun je dubbel-buffering gebruiken. Dan teken je eerst op een in-memory Graphics, en daarna een drawImage op je control

Ik geloof dat dat ongeveer zo ging:

Java:
1
2
Image memImage = createImage (200, 200); // creëer een image van 200x200 pixels
Graphics memG = memImage.getGraphics (); // vraag het bijbehorende Graphics object op


Het tekenen doe je dan op de memG, en als je ermee klaar bent teken je de hele memImage op je control

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • intrix
  • Registratie: November 2002
  • Laatst online: 04-12-2023
.oisyn schreef op 17 december 2003 @ 16:34:
Dat idd ook. Maar als je update niet override, of als je zelf eerst je Graphics leeg maakt met een clearRect () oid, dan krijg je idd zo'n knippereffect

Daarvoor kun je dubbel-buffering gebruiken. Dan teken je eerst op een in-memory Graphics, en daarna een drawImage op je control

Ik geloof dat dat ongeveer zo ging:

Java:
1
2
Image memImage = createImage (200, 200); // creëer een image van 200x200 pixels
Graphics memG = memImage.getGraphics (); // vraag het bijbehorende Graphics object op


Het tekenen doe je dan op de memG, en als je ermee klaar bent teken je de hele memImage op je control
Dat van die update() daar zat ik dus mee dat knipperen ziet er niet uit,
elke keer weer die matrix die gevuld wordt op je scherm |:( .

maar goed even naar jouw reply;
je zegt dus een bufferedimage aanmaken, dat ken ik.
Maar wat doe je daar precies in,
je tekend telkens in dat bufferedimage een vierkant,
en verwijdert de vorige (denk ik te begrijpen) daarna moet de paint
thread weer geactiveerd worden door repaint aan te roepen,
alleen moet ik repaint dus een zooi parameters geven zodat ie hem gelijk
repaint. Dat van die apparte thread maken volg ik niet echt,
dat met die 17pix in zoveel sec enzo, nou is het laat dus misschien dat het
lichtje morgen ineens brand maar nu niet .. 8)7

in ieder geval alvast bedankt voor de hulp ben zo al een stuk wijzer geworden.

welcome my son, welcome to the machine


  • Scorpion
  • Registratie: April 2000
  • Laatst online: 18-01-2024

Scorpion

not to lame to read BitchX.doc

ook kun je de afstand natuurlijk berekenen aan de hand van de tijd, aangezien de animatie op een andere pc die sneller is eruit ziet alsof de sprite getransporteerd wordt ipv verplaatst.

code:
1
x += velX * deltaTime;


zoiets dus :)

[ Voor 36% gewijzigd door Scorpion op 20-12-2003 13:32 ]


  • intrix
  • Registratie: November 2002
  • Laatst online: 04-12-2023
Nou het klinkt allemaal heel leuk,
maar dat van die parameters mee geven aan repaint() :

public void repaint(long tm)

Repaints the component. If this component is a lightweight component, this results in a call to paint within tm milliseconds.

Dat werkt dus echt niet hoor! tenminste niet als ik het zo doe:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import java.applet.Applet;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.lang.StrictMath;
import java.util.*;

class MyCustomCanvas extends Canvas
{

    Rectangle2D kooi;
    float ylift, xcenter, ycenter;
    int t;
    
    public MyCustomCanvas()
    {
        ylift = 250;
        xcenter = 250;
        ycenter = 250;
    }
    
    public void setPaint(boolean direction)
    {
            for(int i=0 ; i<85 ; i++)   // dit gedeelte werkt dus echt niet!
            {
                ylift--;                            // was al iemand die zei dat 
                repaint(0);                    // for niet 85 keer doolopen wordt
            }                                       // maar gewoon de eind form. wordt door
    }                                               // berekend volgens mij klopt dat wel ja
    
    public void update(Graphics g)
    {
        paint(g);
    }
    
    public void paint(Graphics g)
    {

        Graphics2D g2d = (Graphics2D) g;
                    
        float srcalpha = 1- ((float)60/100);
        float dstalpha = 1- ((float)50/100);
        
        Shape dstRectangle = new Rectangle2D.Float(xcenter, ycenter -110, 80, 300);
        Shape srcRectangle1 = new Rectangle2D.Float(xcenter -110, ycenter, 300, 80);
        Shape srcRectangle2 = new Rectangle2D.Float(xcenter -110, ycenter -85, 300, 80);
        Shape srcRectangle3 = new Rectangle2D.Float(xcenter, ylift+85, 80, 80);
        
        BufferedImage bi = new BufferedImage(this.getSize().width, this.getSize().height, BufferedImage.TYPE_INT_ARGB);
        
        Graphics2D big = bi.createGraphics();
        
        big.setColor(new Color(1.f,0.f,0.f,dstalpha));
        big.fill(dstRectangle);
        
        big.setColor(Color.blue);
        big.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT,srcalpha));
        
        big.fill(srcRectangle1);
        big.fill(srcRectangle2);
        
        big.setColor(Color.black);
        big.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,srcalpha));        
        big.fill(srcRectangle3);
        
        g2d.drawImage(bi, null, 0, 0);      
      
    }


maar uiteraard zal hier de fout wel in zitten, iemand had al iets gezegd over
een aparte thread gebruiken ofzo maar begrijp nog steeds niet echt
hoe dat nou het soepelst zou lopen.

[ Voor 6% gewijzigd door intrix op 23-12-2003 15:48 ]

welcome my son, welcome to the machine


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ik denk dat je eerst je Update methode eens weg moet laten. Als je eerst het werkelijke probleem oplost kan je daarna gaan kijken hoe je het kan maken zonder dat het knippert.

Daarnaast zou je in je setPaint methode ( beetje onduidelijk naam vindt ik trouwens ) ongeveer de volgende code kunnen gebruiken.
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void setPaint()
{
    float deltaY = 0.01;//per milliseconde 0.01 pixel verschuiven
    int curTime = System.getMilliseconds();
    int newTime;
    int deltaTime;
    while( yPos < 100 )
    {
        newTime = System.getMilliseconds();
        deltaTime = newTime - curTime;
        curTime = newTime;
        yPos += deltaTime * deltaY;
        Repaint();
        try
        {
            Sleep( 50 );
        }
        catch( InterruptedException ex )
        {
             //Doe er wat mee
        }
    }
}

Het gaat er dus om dat een Repaint() niet meteen uit gevoerd wordt. Door op deze manier te werken ben je onafhankelijk van het teken proces en de snelheid van de processor de y positie aan het wijzigen. Deze code zal waarschijnlijk zo trouwens niet werken hoor want ik heb het uit mijn hoofd getypt en heb de getMilliseconds() even bedacht. Maar er bestaat wel zo'n methode maar daar moet je maar even naar zoeken.
En ik ga er hier trouwens van uit dat je yPositie een float is. Bij het tekenen moet je dit natuurlijk afronden naar een geheel getal.

[ Voor 14% gewijzigd door Woy op 23-12-2003 16:14 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • intrix
  • Registratie: November 2002
  • Laatst online: 04-12-2023
rwb schreef op 23 december 2003 @ 16:09:
Ik denk dat je eerst je Update methode eens weg moet laten. Als je eerst het werkelijke probleem oplost kan je daarna gaan kijken hoe je het kan maken zonder dat het knippert.

Daarnaast zou je in je setPaint methode ( beetje onduidelijk naam vindt ik trouwens ) ongeveer de volgende code kunnen gebruiken.
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void setPaint()
{
    float deltaY = 0.01;//per milliseconde 0.01 pixel verschuiven
    int curTime = System.getMilliseconds();
    int newTime;
    int deltaTime;
    while( yPos < 100 )
    {
        newTime = System.getMilliseconds();
        deltaTime = newTime - curTime;
        curTime = newTime;
        yPos += deltaTime * deltaY;
        Repaint();
        try
        {
            Sleep( 50 );
        }
        catch( InterruptedException ex )
        {
             //Doe er wat mee
        }
    }
}

Het gaat er dus om dat een Repaint() niet meteen uit gevoerd wordt. Door op deze manier te werken ben je onafhankelijk van het teken proces en de snelheid van de processor de y positie aan het wijzigen. Deze code zal waarschijnlijk zo trouwens niet werken hoor want ik heb het uit mijn hoofd getypt en heb de getMilliseconds() even bedacht. Maar er bestaat wel zo'n methode maar daar moet je maar even naar zoeken.
En ik ga er hier trouwens van uit dat je yPositie een float is. Bij het tekenen moet je dit natuurlijk afronden naar een geheel getal.
sorry voor de setPaint methode naam ;)
Ga even alles uitzoeken (hoe alle methodes heten en werken)
beetje jammer dat ik dit niet zelf had kunnen bedenken, nu ik het
zie denk ik uiteraard van ( .. jeweetwel .. ) maar goed heel erg bedankt!

welcome my son, welcome to the machine

Pagina: 1