Programmering

Animation i Java-applets

Denne artikel beskriver, hvordan du implementerer animation ved hjælp af Java applet API. Den beskriver almindeligt anvendte teknikker og giver et simpelt eksempel for at illustrere hver teknik.

Grundlæggende animationsteknikker

Mange former for animation er mulige i Java. Fælles for dem alle er, at de skaber en slags bevægelse på skærmen ved at tegne successive rammer med en relativt høj hastighed (normalt ca. 10-20 gange pr. Sekund).

Vi starter med at oprette en simpel skabelon-applet til at lave animationer og langsomt uddybe den, indtil vi når frem til en ret komplet applet.

Brug af en tråd

For at opdatere skærmen flere gange pr. Sekund skal du oprette en ny Java-tråd, der indeholder en animationssløjfe. Animationssløjfen er ansvarlig for at holde styr på den aktuelle ramme og til at anmode om periodiske skærmopdateringer. For at implementere en tråd skal du enten oprette en underklasse af Tråd eller overholde Kan køres interface.

En almindelig fejl er at sætte animationssløjfen i maling() metode til en applet. Hvis du gør det, vil det have mærkelige bivirkninger, fordi det holder hoved AWT-tråden, som er ansvarlig for al tegning og håndtering af begivenheder.

Som et eksempel har jeg skrevet en lille skabelon-applet, kaldet Example1Applet, der illustrerer den generelle oversigt over en animations-applet. Eksempel1Applet viser, hvordan du opretter en tråd og kalder genmaling () metode med faste intervaller. Antallet af billeder pr. Sekund specificeres ved at sende en appletparameter. Her er et eksempel på, hvad du vil lægge i dit HTML-dokument:

Her er eksempel1applet.

Bemærk:

Denne applet tegner faktisk ikke noget på skærmen endnu. Tegning til skærmen forklares senere. Bemærk også, at appleten ødelægger sin animationstråd, når brugeren forlader siden (hvilket resulterer i appletens hold op() metode kaldes). Dette sikrer, at appleten ikke spilder CPU-tid, mens dens side ikke er synlig.

Holder en konstant billedhastighed

I eksemplet ovenfor sover applet simpelthen i en fast periode mellem rammer. Dette har den ulempe, at du nogle gange venter for længe. For at få 10 billeder pr. Sekund skal du ikke vente 100 millisekunder mellem rammer, fordi du mister noget tid ved bare at køre tråden.

Den følgende applet, Example2Applet, viser, hvordan man holder bedre tid. Det beregner simpelthen den korrekte forsinkelse mellem billeder ved at holde styr på starttiden. Det beregner den estimerede krævede forsinkelse mellem rammer baseret på det aktuelle tidspunkt.

Her er eksempel2applet.

Maling af hver ramme

Det, der er tilbage, er at male hver ramme. I de foregående eksempler kalder vi genmaling () for hver ramme, som forårsager appletens maling() metode, der skal kaldes. Example3Applet har en maling() metode, der trækker nummeret på den aktuelle ramme til skærmen.

Her er eksempel3Applet i aktion efterfulgt af en kodeliste.

Bemærk:

Hvis du angiver, at billedhastigheden er meget høj (f.eks. 100 billeder pr. Sekund), bliver løb() metode kalder genmaling () 100 gange i sekundet. Dette vil dog ikke altid resultere i 100 opkald til maling() pr. sekund, fordi når du udsteder anmodning om maling for hurtigt, kollapses de til en enkelt skærmopdatering. Derfor holder vi styr på det aktuelle billednummer i løb() metode snarere end i maling() metode.

Genererer grafik

Lad os nu animere noget, der er lidt sværere at tegne. Example4Applet tegner en kombination af sinusbølger. For hver x-koordinat trækker den en kort lodret linje. Alle disse linjer danner sammen en simpel graf, der ændres for hver ramme. Desværre vil du opdage, at denne tilgang forårsager en masse blink. Vi forklarer årsagen til blinket og nogle retsmidler i det næste afsnit.

Her er eksempel4applet i aktion, efterfulgt af en kodeliste.

Undgå overdreven blinkning

Det blinkende, du ser i eksempel 4Applet, har to årsager: at male hver ramme tager for lang tid (på grund af den mængde beregning, der kræves under genmaling), og hele baggrunden ryddes før maling() Hedder. Mens beregningen af ​​den næste ramme foregår, ser brugeren baggrunden for animationen.

Denne korte tid mellem rydningen af ​​baggrunden og maleriet af sinusbølgen ses som en flash. På nogle platforme som pc'en blinker mere tydeligt, end det er på X Windows. Årsagen er, at X Windows-grafikken er bufret, hvilket gør flashen lidt kortere.

Du kan reducere blinkende kraftigt ved hjælp af to enkle tricks: implementering af opdater () metode og brug af dobbelt buffering (undertiden kendt som ved hjælp af en backbuffer).

Tilsidesættelse af opdateringsmetoden ()

Når AWT modtager en anmodning om genmaling af en applet, kalder den appletens opdater () metode. Som standard er opdater () metode rydder applets baggrund og kalder derefter maling() metode. Ved at tilsidesætte opdater () metode til at inkludere tegningskoden, der plejede at være i maling() metode, undgår vi at rydde applets hele område med hver genmaling.

Nu hvor baggrunden ikke længere ryddes automatisk, er vi nødt til at gøre det selv i opdater () metode. Vi kan nu slette hver lodrette linje i grafen individuelt, før vi tegner den nye linje, hvilket eliminerer blinket helt. Denne effekt vises i eksempel 5Applet.

Her er eksempel5applet i aktion efterfulgt af en kodeliste.

Bemærk:

Når du tilsidesætter opdater () metode, skal du stadig implementere maling(). Dette skyldes, at maling() metode kaldes direkte af AWT-tegnesystemet, når der opstår "skade" på applets tegneområde - for eksempel når et vindue, der tilslører en del af applets tegningsområde, fjernes fra skærmen. Dit maling() implementering kan simpelthen ringe opdater ().

Dobbelt buffering

En anden måde at reducere blinket mellem rammer på er at bruge dobbeltbuffering. Denne teknik bruges i mange animationsapplets.

Det generelle princip er, at du opretter et offscreen-billede, du tegner en ramme ind i billedet, og derefter slår du hele billedet på skærmen med et opkald til drawImage (). Fordelen er, at det meste af tegningen udføres uden for skærmen. Det endelige maleri af offscreen-billedet på skærmen er normalt meget mere effektivt end at male rammen direkte på skærmen.

Sinusbølgeapplet med dobbeltbuffering vises i eksempel6applet. Du vil se, at animationen er ret glat, og at du ikke har brug for nogen specielle tricks, når du tegner rammen. Den eneste ulempe er, at du skal allokere et offscreen-billede, der er lige så stort som tegneområdet. Hvis tegneområdet er meget stort, kan det kræve en hel del hukommelse.

Her er eksempel6applet i aktion efterfulgt af en kodeliste.

Bemærk:

Når du bruger dobbelt buffering, skal du tilsidesætte opdater () metode, da du ikke ønsker, at applets baggrund skal ryddes, inden du maler rammen. (Du rydder baggrunden selv ved at tegne til offscreen-billedet.)

Brug af billeder

Nu omskriver vi paintFrame () metode med en metode, der animerer nogle billeder. Dette tilføjer nogle mindre komplikationer til problemet. Billederne er ret store, og de indlæses trinvist. Det kan tage lang tid, før billederne tegnes fuldt ud, især når du indlæser dem over en langsom forbindelse. Dette er grunden til, at drawImage () metoden tager et fjerde argument, et ImageObserver-objekt. Billedobservatøren er et objekt, der meddeles, når flere af billeddataene er ankommet. For at få billederne bruger vi getImage () metode.

Flytning af et billede over skærmen

Denne første billed-animerende applet, Example7Applet, bruger følgende to billeder:

world.gif: car.gif:

Verdensbilledet bruges som baggrund, og billedet tegnes to gange ovenpå det, hvilket skaber en animation af to biler, der kører rundt i hele verden.

Her er eksempel 7Applet i aktion efterfulgt af en kodeliste.

Visning af en sekvens af billeder

Example8Applet viser, hvordan du opretter en animation ved hjælp af separate billeder til hver ramme. Her er de 10 rammer, der bruges:

T1.gif: T2.gif: T3.gif: T4.gif: T5.gif:

T6.gif:

T7.gif:

T8.gif:

T9.gif:

T10.gif:

Vi bruger stadig dobbeltbuffering for at fjerne blink. Årsagen er, at hvert billede, vi gengiver, er delvist gennemsigtigt, og vi skal derfor slette hver ramme, inden vi tegner det næste. Dette ville medføre blinkende uden dobbeltbuffering.

Her er eksempel8applet i aktion efterfulgt af en kodeliste.

Bemærk:

Når du viser sekvenser af billeder, skal du være forsigtig med at justere billederne korrekt. Den nemmeste måde er at sikre, at billederne alle har samme størrelse og kan tegnes i samme position. Hvis det ikke er tilfældet, bliver din applet nødt til at tegne hver ramme med forskellig forskydning.

Brug af MediaTracker for at undgå trinvis visning

Når et Java-program indlæser et billede, kan det vise billedet, før billedet er helt indlæst. Brugeren ser, at billedet først gengives ufuldstændigt og derefter trinvis mere og mere fuldstændigt, når billedet indlæses. Denne inkrementelle skærm giver brugeren feedback (forbedrer den opfattede ydeevne) og lader programmet let udføre andre opgaver, mens billedet indlæses.

Hvad animation angår, kan trinvis billedvisning være nyttigt for baggrundsbilleder, men det kan være meget distraherende, når det bruges til de animerede billeder. Det er derfor undertiden ønskeligt at vente, indtil hele animationen er indlæst, før den vises.

Du kan bruge Jim Graham's MediaTracker klasse for at spore download af billeder og forsinke animationsvisningen, indtil hele billedsættet er fuldt downloadet. Eksempel9Applet viser, hvordan du bruger MediaTracker klasse for at downloade billeder til den bølgende Duke-animation.

Her er eksempel 9Applet i aktion efterfulgt af en kodeliste.

Tilføjer lyd

Det er let at tilføje lyd til en animation. Du kan bruge getAudioClip () metode til at få et AudioClip-objekt. Senere kan du afspille klippet enten som en kontinuerlig sløjfe eller som en enkelt lyd. Eksempel 10Applet viser, hvordan man spiller en kontinuerlig baggrundslyd såvel som en gentagen lyd under animationen.

Her er eksempel10Applet i aktion, efterfulgt af en kodeliste.

Bemærk:

Når du afspiller en kontinuerlig lyd, skal du huske at stoppe den, når brugeren forlader siden (dvs. gør det i din applet hold op() metode).

En anden note:

Kontinuerlig lyd kan være meget irriterende. Det er en god ide at give brugeren en måde at slukke for lyden uden at forlade siden. Du kan give en knap eller bare slukke for lyden, når brugeren klikker i appleten.

Tips til hurtigere indlæsning af billeder

En animation, der bruger mange billeder, tager lang tid at downloade. Dette skyldes hovedsageligt, at der oprettes en ny HTTP-forbindelse til hver billedfil, og det kan tage flere sekunder at oprette forbindelse, selv når der er masser af båndbredde.

I dette afsnit fortæller vi dig om to billedformater, som din applet kan bruge til at downloade billeder hurtigere.

Brug af en billedstrimmel

Du kan forbedre downloadets ydeevne ved at bruge et enkelt billede, der indeholder flere animationsrammer. Du kan gengive en enkelt ramme ud af billedet ved hjælp af clipRect () operatør. Nedenfor er et eksempel på en billedstrimmel, der bruges i UnderConstruction-appleten.

Applet skaber en boreeffekt ved ikke at slette de tidligere rammer. Baggrunden ryddes kun så ofte.

Her er UnderConstruction i aktion med et link til kildekoden.

Inter-frame kompression ved hjælp af Flic

Hvis du virkelig vil forbedre downloadydelsen for en animation, der består af flere rammer, skal du bruge en eller anden form for komprimering mellem rammer.

Animationsværktøjer

I øjeblikket (januar 1996) er der få værktøjer til rådighed, der hjælper dig med at oprette Java-drevne animationer. Det bedste værktøj, jeg kunne finde, er DimensionX's The Easy Animator (TEA) (tidligere kendt som JAM). Det giver dig mulighed for at oprette animationer interaktivt. Vi vil gerne opfordre udviklere til at skrive flere værktøjer til oprettelse af animationer i Java.

Hvis du har et par færdige billeder til visning, kan du bruge applet Animator. Animator har mange parametre, der giver dig mulighed for at specificere kontinuerlige lyde, rammespecifikke lyde, individuel ramtiming og positioner, et startbillede, rammebestilling osv.

Du skal også tjekke siden Gamelan Animation for at finde mange applets, der bruger animation.

Konklusion

Jeg håber, at denne artikel hjælper appletudviklere med at skrive flere og bedre animationsapplets. Jeg håber også, at bedre værktøjer snart bliver tilgængelige.

Arthur van Hoff var indtil for nylig senioringeniør hos Sun Microsystems og har været involveret i udviklingen af ​​Java-sproget siden 1993. Han er forfatter til den første Java-kompilator skrevet udelukkende på Java. Han forlod for nylig Sun for at danne et nyt firma sammen med Sami Shaio, Kim Polese og Jonathan Payne. Det nye firma vil fokusere på at opbygge Java-applikationer. Kathy Walrath er teknisk forfatter hos Sun Microsystems. Hun har været en del af Java-teamet siden 1993. I øjeblikket arbejder hun sammen med Mary Campione om The Java Tutorial: Object-Oriented Programming for the Internet, en appletforbedret tutorial til at lære Java-sproget, applet-programmering og Java GUI-programmering. . Udover at være tilgængelig online, offentliggøres Java Tutorial også i sommer som en del af Addison-Wesley Java Series.

Denne historie "Animation in Java applets" blev oprindeligt udgivet af JavaWorld.