Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Java: (java) Esimerkkejä tuplapuskuroinnista ja säikeistä kaivataan

Sivun loppuun

Paulus M [01.03.2005 20:38:35]

#

koodi vinkki, joissa kaksoisbufferointi on mahdollisimman yksinkertaisesti esitetty, siis vaikka pallo kulkee laidasta laitaan(ei mielellään Aplettia).
Olisin kiitollinen, jos joku (esim. Sami) jaksaisi koodata tällaisen ja olisi kirjoittanut vielä niitä kommentteja käskyihin ynnä muuhun. Niitä aiempia koodivinkkejä on vähän vaikeampi hahmottaa, koska lauseiden kommentit perustuu lähinnä sisältöön, eikä Java käskyjen toimintaan...toki on hyvä, että sisältö kerrotaan huolella, mutta ois kiva, jos myös näiden käskyjen toimintaa selitettäisiin vähän.

Toinen koodivinkki olisi hyvä säikeiden toiminnasta. Ja mieluusti tästäkin pelkistetty ja yksinkertainen kommenttien kera, niin että niitä olisi helpompi lukea.


Kiitos etukäteen, jos joku vaan jaksaa koodata.

Sami [02.03.2005 01:49:45]

#

Kaksoispuskurointi on melko yksinkertaista toteuttaa. Käytännössä se menee niin, että ylikirjoitat update-metodin ja et suoritakaan piirtämistä suoraan piirtopinnalle, vaan piirrät ensin puskuriin ja lopuksi piirrät drawImagella puskurissa olevan kuvan näytölle. Appletin tai minkä tahansa muun piirtopinnan kaksoispuskurointi käy käytännössä täsmälleen samalla tavalla.

Koodina kaksoispuskurointi näyttää suunnilleen tältä:

import java.awt.*;

public class Buffer extends Frame {
	int x, y;

	public Buffer() {
		// Ei mitään sen kummempaa, kuin että asetetaan ikkunan koko ja ikkuna näkyväksi
		this.setSize(500, 500);
		this.setVisible(true);

		// Silmukka jossa liikutetaan palloa vasemmalta oikealle ja joka kierros piirretään pallo uudestaan
		y = 250;
		for (x = 0; x < 500; x += 5) {
			repaint();
		}

		System.exit(0);
	}


	public void paint (Graphics g) {
		int width = this.getWidth();
		int height = this.getHeight();

		// Pitäisi varmaan osata selittää järkevästi, mitä seuraavilla kahdella rivillä tehdään, mutta kun ei vaan osaa...
		// Ensiksi kuitenkin luodaan uusi kuva puskuriksi (bufferImage)
		Image bufferImage = createImage(width, height);
		// Ja sitten luodaan uusi piirtopinta (buffer), joka piirtää bufferImageen
		Graphics buffer = bufferImage.getGraphics();

		//Kaikki piirtäminen tapahtuu g:n sijaan bufferiin
		buffer.setColor(Color.GREEN);
		buffer.fillOval(x-25, y-25, 50, 50);

		// Lopuksi vain piirretään puskurikuva g:hen.
		g.drawImage(bufferImage, 0, 0, this);
	}

	// Ylikirjoitetaan update-metodi siten, että se ei tyhjääkään piirtopintaa ennen uuden kuvan piirtämistä
	public void update(Graphics g) {
		paint(g);
	}

	public static void main(String[] args) {
		Buffer baa = new Buffer();
	}
}

Koodi ja kommentit on tehty keskellä yötä, joten siinä saattaa olla jotain hullua, mutta ainakin se kääntyi ja näytti toimivan ihan oikein :)

tsuriga [02.03.2005 02:48:30]

#

Haulla löytyy, https://www.ohjelmointiputka.net/koodivinkit/24347-java-kaksoispuskurointi

Paulus M [02.03.2005 09:45:42]

#

Kiitoksia Sami erittäin selkeästä esimerksitä:)

Paulus M [02.03.2005 16:28:54]

#

esimerkki toimii täydellisesti, mutta viive vaan on unohtunut.
Laitoin sinne väliin omanlaisen viiveen:

for (int viive = 0; viive < 10000000; ++viive){}

mutta ei toi näytä olevan kauheen tehokas javassa, vai onko. Onko muita tapoja laittaa viivettä?

Sami [02.03.2005 21:12:50]

#

Thread.sleep(long time); (+ try-catch)

Enkä varsinaisesti unohtanut sitä viivettä, sillä ainakin itselläni kuvan piirtäminen puskurista näytölle vie sen verran pitkän ajan, että se riittää viiveeksi.

Paulus M [03.03.2005 21:54:59]

#

Vielä ois yks juttu:
Tiedätkö mistä johtuu se, että pallo liikkuu pätkittäin vasemmalta oikealle, eikä sulavasti. Kuinka sen voisi korjata?

tsuriga [03.03.2005 21:59:38]

#

Laita pienempi horisontaalinen muutos kerralla, ja säilyttääksesi saman muutosnopeuden, pienennä nukkumisaikaa.

Sami [03.03.2005 22:04:56]

#

Paulus M:

        for (x = 0; x < 500; x += 5) {
            repaint();
        }

-->

        for (x = 0; x < 500; x += 1) {
            repaint();
        }

Paulus M [06.03.2005 09:54:32]

#

ei se silti vielä lopeta kokonaan tökkimistä. Luin yhdestä kirjasta jossa sanottiin, että javassa pitäisi käyttää säikeitä animaatioita tehdessä, varsinkin jos käytetään takaisin kutsuttavia funktioita?

FooBat [07.03.2005 00:29:57]

#

Tökkiminen varmaan johtuu siitä, että repaint ei tarkoita sitä, että siinä kohtaa piirretään kuva uudestaan. Se tarkoittaa ainoastaan, että käyttöliittymä tulisi piirtää uudestaan kun siihen seuraavan kerran tulee tilaisuus. Tästä syystä x todennäköisesti kasvaa ruutujen välillä paljon enemmän kuin yhden askeleen. Nykiminen riippuu sitten siitä kuinka monta kertaa tuo silmukka ehtii pyöri ennen kuin tulee käyttöliittymää päivittävän threadin vuoro.

Nykimisen saanee pois, jos piirtosimukassa suhteuttaa liikkeen aikaan tai lisää pienen viiveen (Thread.sleep(20)) tuohon for silmukkaan.

Paulus M [07.03.2005 11:31:16]

#

lainaus:

Tökkiminen varmaan johtuu siitä, että repaint ei tarkoita sitä, että siinä kohtaa piirretään kuva uudestaan. Se tarkoittaa ainoastaan, että käyttöliittymä tulisi piirtää uudestaan kun siihen seuraavan kerran tulee tilaisuus.

Miten tämän repaint() funktion saisi sitten piirtämään kuvan uudestaan?


En sitten tiedä, mikä on nykymisen ja tökkimisen ero, mutta kyllä laiton tuohon väliin ton Thead.sleep:in, koska ilman sitä ikkuna ei ole kun sadasosan sekunnin päällä.

FooBat [07.03.2005 20:02:39]

#

lainaus:

Miten tämän repaint() funktion saisi sitten piirtämään kuvan uudestaan?

Periaatteessa piirtäminen suoraan onnistuisi kutsumalla

paint(getGraphics())

Mutta tätä ei kyllä yleensä suositella.

lainaus:

En sitten tiedä, mikä on nykymisen ja tökkimisen ero, mutta kyllä laiton tuohon väliin ton Thead.sleep:in, koska ilman sitä ikkuna ei ole kun sadasosan sekunnin päällä.

Tulinpahan nyt oikeasti testanneeksi sitä koodia, ja näköjään virtuaalikone ajaa täydellisen garbage collectionin joka kuvan jälkeen (Tämän näkee käynnistämällä ohjelma "java -verbose:gc Buffer"). Se pieni Nykiminen johtuu luultavasti tuosta. Tämä puolestaan johtuu siitä, että tuossa jatkuvasti varataan uudestaan tuo muistipuskuri. Siirrä bufferedImagen luonti pois paint-metodista sisäiseksi muuttujaksi niin pitäisi helpottaa.

Paulus M [08.03.2005 21:37:47]

#

Tota, mitkäköhän se mahtaisi käytännössä tarkoittaa. Jos jaksat kertoo, niin mitä mun pitäis kirjoittaa lisä koodia ja minkä tilalle? En oikeen saanut itse toimimaan, kun sen verran vähän ole javaa käyttänyt.

Metabolix [08.03.2005 23:34:58]

#

Käytät varmaan tuota Samin koodia? Tee siis näin:
Ota nämä pois:

// Ensiksi kuitenkin luodaan uusi kuva puskuriksi (bufferImage)
Image bufferImage = createImage(width, height);
// Ja sitten luodaan uusi piirtopinta (buffer), joka piirtää bufferImageen
Graphics buffer = bufferImage.getGraphics();

Ja laita ne luokan alkuun:

public class Buffer extends Frame {
    int x, y;
    Image bufferImage; // Tähän ...
    Graphics buffer; // ... ja tähän ...

    public Buffer() {
        // ... ja tänne (kun en ole varma, saako näitä laittaa aiemmin):
        bufferImage = createImage(width, height);  // Muista laittaa koko näihin.
        buffer = bufferImage.getGraphics();

Kaikki muu koodi pysyy paikallaan. Varmaan tuonne paint-metodin alkuun tarvitaan jonkinlainen tyhjennys bufferille? En tiedä, en osaa Javaa. Joku buffer.clear() varmaan. Johonkin resize-metodiin pitää laittaa bufferin uudelleenluonti, että koko on oikea.

Paulus M [10.03.2005 14:27:30]

#

Okka...kiitti


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta