Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Java: Pehmeä skrollaus

Sivun loppuun

Mobel [14.06.2007 20:30:30]

#

Ongelmana on tilepohjaisen taustan skrollaaminen. Olen onnistunut tilen liikuttelussa yksi kerrallaan, mutta taustan liikuttelu sulavasti(pikselitasolla) tuottaa ongelmia.

Piirrän tilet ruudulle taulukosta näin:

for(y = 0; y < näkymäKorkeus; y++)for(x = 0; x < näkymäLeveys; x++){ //käydään koko taulukko läpi

   for(int i = 0; i < 100; i++){ //katsotaan mitä lukuja taulukossa on
      if(karttaTaulukko[x+kamerax][y+kameray]==i){
      kuva=getImage(getCodeBase(), "tile"+i+".png"); //ladataan png-kuva
      puskuri.drawImage(kuva, x*tilex+murtoX, y*tiley+murtoY, tilex, tiley, this); //piirretään kuva paikalleen
      }
   }
}

Taustan skrollaaminen onnistuuu lisäämällä tai vähentämällä murtoX/murtoY-muuttujaa ja kun muuttuja on yhtä suuri kuintilen leveys/korkeus se nollataan ja lisätään kamerax/kameray :tä. Kuitenkin liikuttaessa vasemmalle taustaan jää valkoinen kohta, sillä piirtoa ei aloiteta yhtä tileä kauempaa. Miten saan piirrettyä taustan yhtä tileä kauempaa vasemmalle mentäessä(oiekallehan tuo onnistuu lisäämällä kamerax:ää yhdellä)?

Käytän seuraavanlaista silmukkaa oikealle liikkumiseen:

for(murtoX=0; murtoX>-64; murtoX--){
   murtoX=0;
   kamerax++;
   repaint();
   odota(65);
}


public void odota(int aika) {
   try { //ohjelma odottaa hetken
      Thread.sleep(aika);
   }catch (InterruptedException e) {}
}

Mistä johtuu, että kun liikun oikealle ruutu on valkoinen silmukan suorittamiseen asti?

Kiitokset jo etukäteen vastauksista!

Lahha [15.06.2007 15:28:42]

#

Tuossa minun funktioni C++:lla SDL:ää ja omaa tile-engineäni käyttäen.

void PiirraKentta(TileSet *tileset, SDL_Surface *naytto, Alue *kentta, Pelaaja *pelaaja, System *sysdata)
{
	int start_x=sysdata->res_w/2-pelaaja->x, start_y=sysdata->res_h/2-pelaaja->y, x=0, y=0;

	while(x < kentta->leveys)
	{
		while(y < kentta->korkeus)
		{
			tileset->DrawTile(kentta->HaeKohta(x, y), naytto, start_x+x*tileset->GetSize(), start_y+y*tileset->GetSize(), false);
			y++;
		}
		y=0;
		x++;
	}

}

Tuo piirtää koko kartan joten ei aivan hyvä isoilla kartoilla. Minulla oli versio joka piirtää vain näkyvän osan mutta se oli semmonen tile kerrallaan mallinen.

tsuriga [15.06.2007 16:49:10]

#

Kyse oli varmaankin Javasta, vaikka eihän sitä tosiaan mainittu.

Mobel [15.06.2007 17:52:34]

#

Tosiaan Javastahan oli kyse, mutta kiitos kuitenkin.

Mobel [16.06.2007 15:16:27]

#

Taisimpa vähän hätiköidä tuon kysymyksen kanssa. Tietysti tuo onnistuu muuttamalla aloituskoordinaatteja -1:ksi(tässä tapauksessa x ja y).

for(y = -1; y < näkymäKorkeus; y++)for(x = -1; x < näkymäLeveys; x++){ //käydään koko taulukko läpi nyt -1:stä näkymäLeveys+1:een asti

   for(int i = 0; i < 100; i++){ //katsotaan mitä lukuja taulukossa on
      if(karttaTaulukko[x+kamerax][y+kameray]==i){
      kuva=getImage(getCodeBase(), "tile"+i+".png"); //ladataan png-kuva
      puskuri.drawImage(kuva, x*tilex+murtoX, y*tiley+murtoY, tilex, tiley, this); //piirretään kuva paikalleen
      }
   }
}

Mutta silti tuo toinen ongelma vaivaa. Eli miksi ruutu pysyy silmukan ajan valkoisena ja piirtyy vasta sitten kun silmukka on valmis?

for(murtoX=0; murtoX>-64; murtoX--){
   murtoX=0;
   kamerax++;
   repaint();
   odota(65);
}


public void odota(int aika) {
   try { //ohjelma odottaa hetken
      Thread.sleep(aika);
   }catch (InterruptedException e) {}
}

kayttaja-2499 [17.06.2007 00:42:45]

#

Ensiksi kysyisin että oletko varma että silmukka päättyy joskus? Jos murtoX:n arvo on aina 0 se on aina arvoa -64 suurempi.

Ruudun valkoisuus voi johtua jostain muusta, mitä et tässä esitä.

Mobel [18.06.2007 18:55:04]

#

On tietysti mahdollista, että virhe johtuu muusta kuin tuosta hidasteesta, mutta jos muutan koodia niin, että aina hiiren klikkauksella ukko liikkuu esim. oikealle yhden pikselin koodi toimii oikein. Vain silloin kun kutsun hidastetta ruutu pysyy valkoisena.

Tein tällaisen pikkuohjelman samasta ongelmasta:

import java.applet. *;
import java.awt. *;
import java.awt.event. *;

public class Testi extends Applet implements KeyListener{

	/**
	 *
	 */
	private static final long serialVersionUID = 1L;

	String napit=""; //mitä namiskoja on paineltu
	int x=50, y=50; //laatikon koordinaatit

	//kaksoispuskuroinnille
	Dimension mitat; //appletin mitat
	Graphics puskuri; //toinen piirtopinta
	Image offScreen; //ja uusi kuva



	public void init(){

		addKeyListener(this); //lisätään näppäimistön kuuntelija

		mitat=getSize(); //haetaan appletin koko
		offScreen=createImage(mitat.width, mitat.height); //luodaan samankokoinen uusi kuva
		puskuri=offScreen.getGraphics(); //vedetään sille vielä piirtopintakin
	}



	public void paint(Graphics pixeli){

		puskuri.clearRect(0, 0, mitat.width, mitat.height); //pyyhitään puskuri

		puskuri.drawRect(x, y, 50, 50); //piirretään neliö puskuriin


		pixeli.drawImage(offScreen, 0, 0, this); //piirretään offScreen-kuva näkyvälle piirtopinnalle
	}

	public void update(Graphics pixeli){ //ylikirjoitetaan tämä ettei kutsuta update()-metodia
		paint(pixeli);
	}

	public void keyPressed(KeyEvent nappi){

		napit= KeyEvent.getKeyText(nappi.getKeyCode()); //otetaan näppäimen "nimi" ylös

	    if (napit.equals("Right")) if ( x < 200 ){ //jos painettiin oikeaa nuolta niin siirrytään silmukkaan
	    	for(int kieppi=0;kieppi<64;kieppi++){ //pyöritetään looppia kunnes on liikuttu 65 pikseliä
	    		x++; //liikutetaan laatikkoa
	    		odota(65); //odotetaan 65ms
	    		repaint(); //päivitetään näyttö
	    	}
	    }

	}

	public void keyReleased(KeyEvent nappi){} //turhat pakolliset metodit
	public void keyTyped(KeyEvent nappi){}



	public void odota(int aika) { //hidaste
		try {
			Thread.sleep(aika);
		}catch (InterruptedException e) {}
	 }
}

Kiitoksia jälleen kaikille aikaansa tähän ongelmaan tuhlanneille!

kayttaja-2499 [19.06.2007 18:00:21]

#

Kuuntelioiden (listener) säikeen (thread) käyttäminen isoihin operaatioihin ei ole välttämättä hyvä asia.

Mitä jos tekisit oman säikeen ns. pelisilmukalle ja lisäisit painetut näppäimet vaikka HashSet:iin keyPressed-metodissa ja poistaisit ne sieltä keyReleased-metodissa.

Pelisilmukassa käsiteltäisiin ensin pelimaailman muutokset, missä tallennettuja näppäimenpainalluksia käytetään hyväksi, ja tämän jälkeen kutsutaan ruudunpäivitystä. Samalla voisi mitata ruudunpäivityksen käyttämän ajan ja käyttää tätä aikaa hyväksi pelimaailman muuttamisessa. Näin saataisiin muutokset riippumaan ajasta.

Mobel [19.06.2007 18:43:38]

#

Koska en ole paljoakaan säikeiden kanssa pelannut, ja tämä on ensimmäinen hieman isompi projekti, olisi hienoa jos voisit(tai kuka vaan joka viitsii) kirjoittaa kayttaja-2499:n mainitsemat ominaisuudet(tai edes osan niistä) tuohon yllä olevaan esimerkkiin(tai aivan uuteen). Tiedän, että tämä on melko paljon pyydetty, mutta se auttaisi suuresti.
Kaikki tieto ja muu info aiheesta on tervetullutta.

Jos jolla kulla on aikaa ja viitseliäistyyttä arvostaisin sitä suuresti! ^^

kayttaja-2499 [19.06.2007 23:53:09]

#

Tässä hieman esimerkkiä:

public class Testi extends Applet implements KeyListener, Runnable {
  private HashSet<Integer> nappaimet = new HashSet<Integer>();

  public Testi() {
    addKeyListener(this);
    new Thread(this).start();
  }

  public void run() {
    long alkuaika = System.currentTimeMillis();
    long loppuaika;
    long kesto = 0;
    double x = 0;
    double nopeus = 5 / 1000; // 5 yksikköä / sekunnissa

    while(true) {

      /* Maailman muuttaminen */
      if(nappaimet.contains(KeyEvent.VK_RIGHT)) {
        x += nopeus * kesto;
      }

      repaint();

      loppuaika = System.currentTimeMillis();
      kesto = loppuaika - alkuaika; // Kesto millisekunteina
      alkuaika = loppuaika;
    }
  }

  public void keyPressed(KeyEvent e) {
    nappaimet.add(e.getKeyCode());
  }

  public void keyReleased(KeyEvent e) {
    nappaimet.remove(e.getKeyCode());
  }

  public void keyTyped(KeyEvent e) {}
}

Koodasin suoraan textareaan joten en takaa että koodi toimii. Mutta kaipa tästä jotain vinkkekä saa.

Mobel [20.06.2007 23:03:17]

#

Erittäin suuret kiitokset!

Tuosta oli suuri apu ja sain ohjelmani toimimaan juuri niin, kuin halusin. HashSet-ratkaisu osoittautui toimivaksi ja säikeiden käyttökin alkaa pikkuhiljaa luonnistua.
Erittäin mahtavaa, että jaksoit auttaa minut alkuun!

PS. Pyrin taas vähän aikaa olemaan häiriköimättä foorumeilla(ainakin tämän osion kohdalla). ^^


Sivun alkuun

Vastaus

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

Tietoa sivustosta