Hem E-böcker Specialeffekter och spelutveckling i Java Dubbelbuffring  

Specialeffekter och spelutveckling i Java(TM) - Dubbelbuffring 

av Anibal Wainstein

4.2 Dubbelbuffring 

Dubbelbuffring är en teknik som har använts i nästan alla programmeringsspråk av spelutvecklare och specialeffektsprogrammerare. När man ritar linjer, rektanglar, texter och bilder direkt på skärmen så kan man i princip se när varje objekt ritas ut. Detta är inte önskvärt om man bara vill att åskådaren ska se slutresultatet, och som vi har sett med textscroller och slideshow exemplen så kan detta leda till flimmer. För att undvika detta så ritar man först i en buffert (därav namnet "dubbelbuffring"). Bufferten kan vara en bild som man ritar på i minnet och visar inte upp den för åskådaren förrän den är färdig. I Java gör man detta genom att skapa en bild som är lika stor som appleten och sedan hämtar man ett Graphics-objekt som är kopplad till denna. När man har ritat klart så anropar man paint() metoden som ritar ut buffertbilden på skärmen.

4.2.1 SlideShow II, nu utan flimmer

För att dubbelbuffra slideshow appleten i förra avsnittet så måste vi först deklarera en global Image variabel och en Graphics variabel som vi initierar i init() metoden. Lägg till följande variabler till de globala appletvariablerna (lägg in dem under deklarationen för variabeln "nextimagepositiony"):

Image bufferimage;
Graphics bufferg;

//"delay" får användas istället för sleeptime för att
//fördröja varje animering. "sleeptime kommer att användas
//för att lägga en konfigurerbar fördröjning mellan varje
//bild istället.
int delay=0;

När vi ändå är på gång att ändra i appleten så kan vi passa på att lägga till en ny parameter "delay". Denna kommer att användas i stället för "sleeptime" som fördröjning i animationen. Variabeln "sleeptime" kommer att användas som fördröjning mellan varje bild i stället. Nu kommer änvändaren av denna applet att kunna lägga in en fördröjning innan nästa bild rullar in. För att skapa bufferten så skriver vi följande rader och lägger in dem sist i init() metoden:

//Hämta storleken för appleten
Dimension d=size();

//createImage() skapar en tom bild
//som är lika stor som appletskärmen
bufferimage=createImage(d.width,d.height);

//bufferg kopplas nu till bufferbilden
bufferg=bufferimage.getGraphics();
delay=getIntegerParameter("delay",10);

Det enda vi behöver göra nu är att se till att de två bilderna ritas ut i bufferten först och inte direkt på skärmen. Detta görs i paint() metoden:

public synchronized void paint(Graphics g)
{
    //först kontrollerar vi att bufferg
    //är initierat, det är inte alltid säkert
    //att den är det.
    if (bufferg!=null)
    {
        //vi ritar de två bilderna i bufferten först
        bufferg.drawImage(images[currentimage],0,0,this);
        bufferg.drawImage(images[nextimage]
             ,nextimagexposition,nextimageyposition,this);

        //nu ritar vi ut bufferten i appletskärmen
        g.drawImage(bufferimage,0,0,this);
    }
}

Det finns lite ändringar att göra i run() metoden också, nu när vi har ändrat på parametrarna:

public void run()
{
    Dimension d=size();
    int displacementx=0;
    int displacementy=0;
    int pathsize=0;
    currentimage=0;
    nextimage=1;
    while (true)
    {
        int directionx=(int) (Math.random()*3.0)-1;
        int directiony=(int) (Math.random()*3.0)-1;
        if (directionx==0 && directiony==0) directiony=1;
        if (d.width<d.height) pathsize=d.width;
        else pathsize=d.height;
        displacementx=directionx*d.width;
        displacementy=directiony*d.height;
        if (nextimage>maxitems-1) nextimage=0;
        for (int i=0; i<=pathsize; i++)
        {
            nextimagexposition=displacementx
                -directionx*(i*d.width)/pathsize;
            nextimageyposition=displacementy
                -directiony*(i*d.height)/pathsize;
            update(getGraphics());

            //nu är det "delay" som är fördröjningen
            //i for-slingan.
            try {Thread.sleep(delay);}
            catch(InterruptedException e) {}
        }
        //"sleeptime" används utanför slingan
        try {Thread.sleep(sleeptime);}
        catch(InterruptedException e) {}
        currentimage=nextimage;
        nextimage++;
        if (nextimage>maxitems-1) nextimage=0;
    }
}

Vi lägger upp en ny fördröjning utanför for-slingan och använder "sleeptime" variabeln där istället. Nu kan appletanvändaren specifiera en fördröjning innan nästa bild börjar rulla in. Nu borde appleten vara helt färdig. Glöm nu inte att lägga in parametern "delay" och sätta denna till 20. Ändra om sleeptime till 1000 millisekunder eller mer. Klicka här för att titta på den. Visst är den vacker?

 


Nästa sida >>