Hem E-böcker Specialeffekter och spelutveckling i Java En konfigurerbar

Specialeffekter och spelutveckling i Java(TM) - En konfigurerbar och effektfull bildvisare (SlideShow)

av Anibal Wainstein

4.1.4 En konfigurerbar och effektfull bildvisare (SlideShow)

Även om AppletAnimator II kan användas för att visa bilder så är den inte särskilld imponerande. Här ska vi nu göra en mer animerad bildvisare som flyttar in en ny bild från ett slumpmässigt område. Äntligen kommer vi i kontakt med slumptal. Det finns en mycket användbar klass i Java som heter Math. Denna består mest av statiska metoder så du behöver inte göra ett Math-objekt för att kunna använda dessa utan de kan anropas direkt. En mycket viktig metod är random() metoden, som lämnar ett slumpvärde mellan 0 och 0.999999999... i form av ett flyttal (double). Genom att t.ex. multiplicera med tio så skulle du kunna få slumptal mellan 0 och 9. Observera att när man talkonverterar en double till integer så kommer talet att avrundas ner. Se på följande rad:

int slumpvarde = (int)(Math.random()*2.0);

Variabeln "slumpvarde" kommer att sättas till 0 eller 1. I bildvisaren kommer vi att använda oss av slumptal för att bestämma var en bild kommer ifrån. Vi kan faktiskt ta alla variabler och metoder i AppletAnimatorII appleten och använda dessa med bara en ändring i run() och paint() metoderna samt lägga till följande globala applet variabler precis under deklarationen av "currentimage" variabeln:

int nextimage = 0;
int nextimagexposition = 0;
int nextimageyposition = 0;

Dessa variabler bestämmer vilken bild som kommer att animeras in i appletskärmen och vad dess nuvarande position är. Paint() metoden kommer då att se ut så här:

public synchronized void paint(Graphics g)
{
    g.drawImage(images[currentimage],0,0,this);

    //följande bild ritas ovanpå den gamla bilden
    g.drawImage(images[nextimage]
        ,nextimagexposition,nextimageyposition,this);
}

Run() metoden blir dock lite mer komplicerad. Vi måste nu för första gången få reda på appletens dimensioner, ty den som kommer att återanvända appleten kommer troligtvis att ändra storlek. Det gör man med Applet metoden size(), som lämnar ett Dimension objekt. Med detta kan vi sedan få reda på appletens bredd och höjd med objektets variabler "width" och "height".

public void run()
{
    //vi tar reda på appletens dimension och
    //sparar det i variabeln d. Vi kan nu komma
    //åt appletens bredd och höjd genom att skriva
    //d.width resp. d.height
    Dimension d=size();

    //displacement variablerna specifierar
    //startkoordinaterna för bilden
    int displacementx=0;
    int displacementy=0;

    //pathsize kommer att användas för att veta
    //vilket avstånd som den nya bilden kommer
    //att flyttas
    int pathsize=0;

    //currentimage initieras så att den börjar med 
    //den första bilden, följt av nästa bild som blir
    //bild nummer två osv
    currentimage=0;
    nextimage=1;
    while (true)
    {
        //Vi räknar ut startpositionerna för bilderna, 
        //dvs varifrån bilderna ska komma från.
        int directionx=(int) (Math.random()*3.0)-1;
        int directiony=(int) (Math.random()*3.0)-1;

        //directionx och directiony kan komma
        //att få tre värden: -1, 0 och 1.
        //Det är inte kul om båda får värdet 0
        //samtidigt, så därför så ändrar vi på
        //directiony så att effekten blir lite
        //roligare
        if (directionx==0 && directiony==0) directiony=1;

        //variabeln pathsize sätts till bredden eller
        //höjden beroende på vilken som är lägst
        if (d.width<d.height) pathsize=d.width;
        else pathsize=d.height;

        //följande rad är skydd mot problemet
        //om användaren specifierar bara en enda
        //bild
        if (nextimage>maxitems-1) nextimage=0;

        //följande slinga tar hand om att uppdatera
        //skärmen under animeringen. Den kommer att
        //flytta bilden det antal ggr som specifieras
        //av pathsize, dvs kortsidan av appleten.
        for (int i=0; i<=pathsize; i++)
        {
            //bildpositionerna flyttas med
            //bråkdelen (i/pathsize).
            nextimagexposition=displacementx
                -directionx*(i*d.width)/pathsize;
            nextimageyposition=displacementy
                -directiony*(i*d.height)/pathsize;
            update(getGraphics());
            try {Thread.sleep(sleeptime);}
            catch(InterruptedException e) {}
        }
        //när flyttningen är klar så sätts currentimage
        //till den nya bilden
        currentimage=nextimage;

        //Vi ökar nextimage så att den
        //pekar på nästa bild, samtidigt så ser vi till
        //att nextimage inte överstiger arrayens index
        //utan att den tvingas börja om från början
        nextimage++;
        if (nextimage>maxitems-1) nextimage=0;
}

Appleten börjar med att placera en bild utom synhåll för åskådaren, dvs utanför appletskärmen. Sakta så flyttar den in bilden mot centrum, en pixel i taget. Ett problem som kan uppkomma här är om appleten är en rektangel och inte en kvadrat. Då måste appleten flytta bilden med olika horisontella och vertikala steg. Därför hämtar vi kortsidan på appletskärmen och for-slingan får räkna upp till den här sidans pixelantal (variabeln "pathsize"). Vi räknar upp ett procentuellt värde på hur mycket bilden skall röra sig (i/pathsize) och multiplicerar sedan med d.width eller d.height för att få den totala horisontella resp. vertikala sträckan som den har rört sig.

Problemet här är att eftersom vi håller på med integers så måste vi utföra divisionen sist och därför skriver vi ((i*d.width)/pathsize) istället. Annars så skulle (i/pathsize) alltid ge värdet noll eftersom värdet på "pathsize" är större än "i". Detta är viktigt, dividerar man ett mindre heltal med ett större så blir resultatet alltid noll.

Slutligen måste vi också multiplicera den här termen med "directionx" eller "directiony" så att bilden rör sig åt rätt håll. Till slut så drar vi av den här termen från "displacementx" resp. "displacementy" som är bildens startkoordinater.

Bilden visar hur bildvisaren fungerar. Den nya bilden "nextimage" kommer att flytta sig över den gamla bilden "currentimage".

Efter for-slingan så sätter vi den nya bilden till "currentimage" och ökar "nextimage". Om "nextimage" tidigare har pekat på sista bilden så sätter vi den till att peka på den första bilden istället (index noll). Resultatet blir att bilderna kommer att rotera runt. Den här raden måste kopieras till före for-slingan också i händelse att användaren av någon konstig anledning bara skulle vilja specifiera en enda bild. Detta måste göras för att slippa krascher. Nu kan du titta på resultatet genom att klicka här.

Nu blev du ganska besviken, va? All den här mödan bara för en flimrig applet! Problemet med appleten är att när första bilden har ritats ut i paint() metoden med drawImage() så uppdateras appletskärmen omedelbart. Den visar därför hela grundbilden innan den hinner rita över den med nästa bild. Vi måste alltså hitta ett sätt att förhindra att appletskärmen uppdateras mellan de två drawImage() anropen. Det är här dubbelbuffringstekniken kommer in och som vi kommer att diskutera i nästa delkapitel.


Nästa sida >>