175 14 1MB
Swedish Pages [101] Year 2014
Till denna bok medföljer ett antal övningsfiler som du laddar ner från vår webbplats www.docendo.se: 1. Starta webbläsaren, skriv www.docendo.se i adressfältet och tryck på Retur. 2. Skriv artikelnumret, 1260, i sökrutan och klicka på Sök. 3. Klicka på titeln Programmering Java Fördjupning. 4. Klicka på filen 1260.zip högst upp på sidan. 5. Klicka på Spara, välj var du vill spara filen, exempelvis på skrivbordet, och klicka på Spara. 6. När filen har hämtats stänger du dialogrutan och avslutar webbläsaren. 7. Om du har valt att spara filen på skrivbordet visas den som en ikon med namnet 1260. Dubbelklicka på ikonen för att packa upp filerna till lämplig mapp på din hårddisk.
Copyright © Docendo AB Detta verk är skyddat av upphovsrättslagen. Kopiering, utöver lärares rätt att kopiera för undervisningsbruk enligt BONUS-avtal är förbjuden. BONUS-avtal tecknas mellan upphovsrättsorganisationer och huvudman för utbildningsanordnare, exempelvis kommuner/universitet. Våra böcker och tillhörande produkter är noggrant kontrollerade, men det är ändå möjligt att fel kan förekomma. Vi tar gärna emot förbättringsförslag. Produkt- och producentnamnen som används i boken är ägarens varumärken eller registrerade varumärken. ISBN: 978-91-7531-021-3 Artikelnummer: 1260E Författare: Jonas Byström Redaktör: Iréne Friberg Omslag: Malina Andrén Bild på omslaget ©iStock
1
Repetition och lite nytt
I detta kapitel A-kursen repeteras här i komprimerad form i sina huvuddrag. Du förutsätts förstå grundläggande Java samt kunna hantera någon utvecklingsmiljö för Java, till exempel NetBeans.
Programexekvering Ett program exekveras ”uppifrån och ner”. Centralprocessorn (CPU:n) läser och utför maskinkoden instruktion för instruktion, på samma sätt som Java-VM (Virtual Machine) läser och utför bytekod. Java-VM ger dessutom utvecklaren en ”sandlåda” att jobba i.
Loop Somliga instruktioner används för att flytta programexekveringen. Dessa instruktioner säger alltså åt Java-VM att läsa och utföra programkod på ett nytt ställe — vilket kan användas för att skapa loopar (även kallade slingor). En loop är när en viss del av koden utförs flera gånger; loopen utförs till dess ett visst uttryck är falskt. Start
Ja
Har du roligt? Nej Sov på saken!
Detta är ett exempel på en loop. Loopen utförs så länge uttrycket ”Har du roligt?” = ”Ja” är sant. Dock tröttnar ju alla någon gång, vilket leder till att uttrycket ”Har du roligt” = ”Ja” blir falskt. Detta i sin tur innebär att exekveringen går vidare till ”Sov på saken!”. Loopar används till att utföra samma operationer flera gånger, ofta en gång per dataelement. Till exempel är en loop ett idealiskt hjälpmedel för att söka igenom en lista.
5
1 Repetition och lite nytt
Källkod Källkod är den text du skriver in i din utvecklingsmiljö. Efter att du programmerat färdigt låter du en kompilator översätta Java-källkoden till bytekod som kan köras av Java-VM:en. Källkoden för större projekt organiseras i flera källkodsfiler. Filtillägget .java används för källkod, och de filerna innehåller klasser, metoder, interface eller variabler För att kunna skapa objekt av andra klasser så måste filen importeras. Detta gör du med import mitt_paket.MinKlass.
Verktyg I detta material har vi valt utvecklings-verktyget NetBeans IDE 7.2 (NetBeans) som exempel. Bilder, exempel och instruktioner i detta kapitel visar NetBeans. Om du arbetar i en annan version eller någon annan utvecklingsmiljö kan du ändå känna igen dig och göra övningarna. I NetBeans kan du lätt få hjälp om nyckelord och metoder genom att ställa markören i det ord du undrar över och sedan trycka Alt+F1. Prova gärna detta, till exempel med metoden System.out.println. I hjälpen kan du se vad den gör (Prints a String and then terminate the line) och se vad den har för parametrar, returvärde och andra relevanta fakta.
Säkerhetskopiera Börja med att kopiera övningsfilerna som medföljer materialet. Det bästa är om du hela tiden arbetar med lokala kopior. Lägg exempelvis källkoden någonstans under Mina dokument; lämpligt är kanske den mapp som skapas automatiskt av NetBeans vid installationen, mappen NetBeansProjects, om det är lämpligt för dig skapar du också en ny mapp kallad Java B till vilken du kopierar övningsfilerna.
Öppna, kompilera, kör och stäng Du ska nu öppna ett färdigt projekt för att direkt komma in i arbetsgången igen. Du ska börja med att starta utvecklingsverktyget. 1. Klicka på knappen Start, välj Alla Program, NetBeans, välj NetBeans IDE 7.2. När programmet startar kan det se ut som i följande bild.
6
1 Repetition och lite nytt
2. I menyn väljer du File, Open, Project... 3. Klicka på Phantom och klicka sedan på knappen Open Project. 4. Kompilera med F11. 5. Kör programmet med F6. En meddelanderuta visas:
6. Avsluta programmet genom att stänga meddelanderutan. 7. Avsluta NetBeans med File, Exit. Om det är några oklarheter så kan du alltid gå tillbaka till ”På rätt kurs: Java Programmering A” för att repetera; där finner du många och utförliga instruktioner för hur du ska gå tillväga vid hanteringen av NetBeans.
7
1 Repetition och lite nytt
Auto-importera Om du någon gång skriver in funktionalitet som du inte ännu har importerat så kommer du att få kompileringsfel. I stället för att manuellt skriva in ditt importuttryck högst uppe i Java-filen så kan du alltid trycka Ctrl+Shift+I för att lägga till import-uttrycket automatiskt. Detta är extremt användbart, lär dig detta utantill!
Programexempel Data och variabler Variabler är till för att lagra data i. Heltalsvariabler kan endast lagra heltal, flyttalsvariabler klarar tal i potensform. Heltalsvariablerna heter byte, short, int och long för 8-, 16-, 32- respektive 64-bitars heltal. Flyttalsvariablerna heter float och double. En array (eller ett fält) med variabler är när flera variabler ”ligger på rad” i minnet. En array med char kan omtolkas som en sträng, där varje enskilt tecken motsvarar en bokstav. En sträng deklareras med texten omgiven av citationstecken, till exempel ”Derivatan av en kvot är inte ofta konstigare än personen som deriverar”. Tilldelning till variabler anges med =, till exempel int x = 7;. Vid jämförelse används , =, == och !=, som exempel returnerar x < 5 sant om x är mindre än 5, falskt om x är större än eller lika med 5. Enkla, ”atomära”, datatyper som heltal och flyttal kopieras, medan mer komplex data refereras i stället. Referenser används alltså till att referera till data eller objekt. Mer repetition om referenser senare i materialet. För addition av variabler används operatorn +, subtraktion har operatorn –, multiplikation använder *, / används för division och % för modulus. Variabler kan deklareras antingen som medlemmar eller som lokala i en metod. Medlemsvariabler deklareras utanför alla metoder, och kan användas av alla metoder. Lokala variabler deklareras inuti en metod och kan bara användas i just den metoden. Så många variabler som möjligt ska vara lokala för att programmet ska bli lättläsligt och lätt att avlusa. För att skapa objekt används class, alternativt enum. enum används för att skapa representationer av olika status, till exempel LEFT, RIGHT, MIDDLE.
Några nyckelord
Nyckelordet if används för att villkorligt utföra ett antal satser. Nyckelorden do, while och for används alla för loopar.
8
1 Repetition och lite nytt
int x; for (x=1; x data[j+1]) { int temp = data[j]; data[j] = data[j+1]; data[j+1] = temp; } } } }
Uttrycket i if-satsen på raden under kommentaren avgör om listan kommer att sorteras i stigande eller fallande ordning. I detta fall byter elementen plats om värdet i elementet j är större än värdet i elementet j+1, vilket medför att listan kommer att sorteras i stigande ordning med minsta värdet först. Om ett - och cd LoadImage C:\JavaB\Kod\LoadImage>_
3. Starta programmet genom att ange något som kallas ”classpath”, det används som en sökväg för att hitta alla filer som laddas. Skriv in följande (på en rad): java -cp ”build/classes;../Sdb/dist/Sdb.jar” loadimage/ LoadImage
Sdb.jar är en arkivfil som innehåller Java-klasserna för att öppna fönster, och så vidare. På samma sätt måste du göra med ditt program för att kunna använda dig av sdb-paketet.
56
9
Java Generics
Inbyggda listor i Java Den funktionalitet du tidigare utvecklat med sortering, listor och hashtabeller finns inbyggd i Java. För att underlätta för användaren så kan man använda vilka klasser som helst, så att man slipper specialanpassa algoritmer eller datastrukturer för speciella ändamål. För att använda en inbyggd lista av strängar så gör man så här: List minLista = new ArrayList();
Notera att ArrayList ärver av List. För att lägga till och ta bort element så gör man så här: minLista.add(”En liten text”); minLista.add(”... och en till”); minLista.remove(1); // Ta bort andra elementet. String s = minLista.get(0); // Hämtar första.
Detta kallas Java Generics och förenklar storeligen användningen av listor, som synes, samt förbättrar prestanda avsevärt. Sortering är också enkelt på dylika listor: Collections.sort(minLista);
Även hashtabeller finns färdigt att använda: HashSet minHashTabell; minHashTabell = new HashSet(); minHashTabell.put(”Första”, 1); minHashTabell.put(”Andra”, 2); // Hämta ett elementet med angiven nyckel: Integer i = minHashTabell.get(”Första”);
Du behöver inte kunna detaljerna utantill för att klara av materialet, men det kan vara bra att känna till eftersom det senare kommer att komma exempel som innehåller Java Generics.
57
9 Java Generics
Övningsuppgifter Övning 9.1
Skapa en lista för att stoppa in heltal i. Man kan inte använda atomära typer i Generics, men det finns en klass som heter Integer...
Övning 9.2
Se om du kan använda klassen HashMap för att stoppa in värdet Göteborg med heltalsnyckeln 31, Stockholm med nyckeln 8 och Malmö med nyckeln 40. Du behöver ange två klasser för att definiera en instans av HashMap.
58
10
Praktisk programmering – TCP/IP och trådar
I detta kapitel Praktisk programmering mot TCP/IP ger några handfasta exempel på hur du kan använda färdig teknik för att göra din applikation mer intressant. Användning av TCP/IP är mycket vanligt i programvaruindustrin, vilket gör det så mycket mer attraktivt att lära sig. Kommunikation mellan datorer sker oftast med protokollet TCP/IP. Det är detta protokoll som används när du surfar, laddar hem filer, läser e-post, chattar, spelar multiplayer-spel, lyssnar på musik över nätet, et cetera. Den största programmeringsstandarden för att, med TCP/IP, koppla upp, skicka och ta emot data och koppla ner heter BSD Sockets. (Berkley Software Distribution Sockets är en standard från Berkley Unix.) Överhuvudtaget har denna standard bevarats förhållandevis väl, även på Microsofts plattformar. I Java medföljer ett antal klasser för att ytterligare förenkla kommunikationen via sockets, som du nu kommer lära dig använda. Du kommer även att beröra trådar i detta kapitel. Det är ett avancerat koncept som du kan använda för att exekvera flera saker samtidigt i ditt program.
Sockets Sockets fungerar ungefär som att öppna, läsa, skriva och stänga en fil. Dock brukar man säga koppla upp, läsa, skriva respektive koppla ner när det gäller nätverksanslutningar i stället för filer.
Telefonera och ringa upp En vanlig och mycket god analogi med sockets är den gamla hederliga telefonen. För att kunna ringa så måste du installera din telefon. I Java gör man det med följande konstruktor: Socket(String host, int port)
Socket använder det underliggande protokollet TCP, om du vill använda till exempel UDP så finns andra klasser för det. Hur gör man då för att koppla upp sig? Socket socket = new Socket(”google.com”, 80);
Den sista parametern är portnummret (till exempel port 80 för webservrar).
59
10 Praktisk programmering – TCP/IP och trådar
Du kan även ange en IP-adress direkt. IP-adresser består av ett tal på formen a.b.c.d där a, b, c och d är heltal mellan 0 och 255. Dessutom åtföljs alla TCP/IP-adresser av ett portnummer mellan 0 och 65535. Att man använder olika portnummer gör att man kan ha flera parallella uppkopplingar (surfa, e-post, chatt, och så vidare) på en dator, trots att man bara har ett IP-nummer. IP-nummer och TCP-port skrivs ofta ihop, så här: 1.2.3.4:56789; vilket alltså blir IP-adress 1.2.3.4 och TCP-portnummer 56789. För att lägga på telefonluren när du är klar så använder du funktionen close. socket.close();
Prata
Använd klassen PrintWriter för att skicka data: PrintWriter out = new PrintWriter( socket.getOutputStream(), true); out.prinln(”Hej från mig!”);
PrintWriter funkar på samma sätt som System.out, som du är van att skriva ut text med.
Lyssna
Om du vill ta emot data via en socket så använder du BufferedReader på samma sätt som för en fil. InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader reader = new BufferedReader(isr); String line = reader.readLine(); System.out.prinln(line);
Vänta på samtal Om du vill att programmet ska vänta på att någon kopplar upp sig mot det (serverapplikation) så använder du klassen ServerSocket: ServerSocket serverSocket = new ServerSocket(12345); Socket clientSocket = server.accept();
Här lyssnar servern på porten 12345; detta motsvaras ungefär av att lyssna till en specifik telefon. När sedan någon kopplar upp sig är det bara att använda clientSocket som tidigare för att skicka och ta emot.
60
10 Praktisk programmering – TCP/IP och trådar
Om chattprogram Ett chattprogram är egentligen två olika program: ett klientprogram och ett serverprogram. För att du ska få någon slags meningsfull kommunikation så är det ju fördelaktigt om flera klienter kan koppla upp sig mot samma server – så kul är det ju inte att chatta med sig själv!
Server-/klientmodell Servern kommer att ha en lista med alla som är uppkopplade. Klienten skickar textdata som servern tar emot. Servern skickar den sedan vidare till alla uppkopplade klienter. I följande bild visas ett nätverksdiagram över flödet med fyra uppkopplade klienter:
Klient3
Klient1
2 2
1
Klient2
Server
2
2
Klient4
Klient1 skickar här ett meddelande (1) till Server. Server tar emot meddelandet, lägger på namnet ”Klient1: ” i början på meddelandet och skickar ut det till alla klienter (2).
Ett exempel förenklar: om Arne, Berit och Caesar är anslutna till en server och Arne skickar strängen ”Hejsan tjejen och killen!” till servern så ska alltså servern skicka ”Arne: Hejsan tjejen och killen!” till alla anslutna klienter, det vill säga till Arne, Berit och Caesar. När klienten tar emot ett meddelande från servern så ska det bara skrivas ut i klartext på skärmen. Programmet kommer att bli så enkelt som möjligt, ingen säkerhet mot flooding eller liknande DoS-attacker, ingen funktionalitet för kick eller ban (längre fram ges en förklaring till uttrycken). Dessa förslag på utökningar blir en extrauppgift för den engagerade. Uttrycken flooding, DoS-attacker, kick och ban är engelska. De används ofta i samband med nätverksprogrammering.
61
10 Praktisk programmering – TCP/IP och trådar
Flooding (översvämning) betyder att någon illvillig person skickar massor av nonsensdata till en annan dator. Denna dator får problem eftersom den inte hinner med att ta emot all inkommande data på ett korrekt vis. DoS står för Denial of Service. Ta flooding mot en chattserver som exempel. Säg att det finns 100 anslutna klienter till chattservern. En av dessa klienter har skapat en egen klientapplikation som skickar massor av textmeddelanden till servern som servern i sin tur försöker skicka vidare till alla anslutna klienter. Detta leder till två problem: 1) alla klienter får skräptext som de inte vill läsa och 2) servern måste skicka ut 100 gånger mer data än vad den hemmagjorda klientapplikationen skickar in. Man kan lätt inse att chattservern snart går på knäna i ett dylikt scenario. Kick kan vara ett kommando som serveroperatören använder sig av för att sparka ut oönskade klienter från servern. Det enda som sker är egentligen att klienten kopplas från. Ban (på svenska ungefär ”bannlysa”) används ofta också som ett kommando av serveroperatören. En bannlysning fungerar helt enkelt så att klienten kastas ut (kick) och sedan sätts en begränsad eller obegränsad tid till dess att klienten får tillstånd att logga in igen. En bannlysning kan ske antingen på IP-adressen eller på användarkontot (om sådant finns). Idén är helt enkelt att användaren ska få lite tid att tänka över sina onda handlingar innan tillfälle ges att utöva dem igen...
Kort om trådar Trådar är ett avancerat begrepp som har med parallellprogrammering att göra. Parallellprogrammering innebär att man låter datorn utföra två uppgifter simultant. Detta är egentligen inget konstigt – du använder det varje gång du har två program igång samtidigt. En tråd är en exekverande enhet inom ett program. Till exempel är det en tråd som börjar exekvera i main varje gång du startar ett program. Skillnaden mellan att ha flera trådar i ett program och att ha flera program igång samtidigt är dock väsentlig: operativsystemet ser till att individuella program fungerar, medan du själv får se till att det fungerar när du programmerar för flera trådar inom ett program. Utan att förklara på djupet kan sägas att ett program, som exempelvis chattservern som du snart ska programmera, behöver flera trådar eftersom programmet behöver göra flera saker samtidigt. Chattservern måste dels vänta på klienter som vill ansluta och dels ”lyssna” efter data från varje enskild klient.
62
10 Praktisk programmering – TCP/IP och trådar
Dessutom måste chattservern vänta på inmatad data från serveroperatören. Även klienten måste ha flera trådar: en för att vänta på data från servern och en för att ta emot tangentbordsdata från användaren. För att skapa en tråd så kan du ärva en Java klass Thread. När du anropar metoden start på en instans av Thread så börjar tråden exekvera i metoden run (ungefär som ett program börjar exekvera i main): class MyThread extends Thread { public void run() { System.out.println(”Jag kör i en annan tråd!”); } }; MyThread myThread = new MyThread(); myThread.start();
Analysfas Du får först några basala förutsättningar för chattservern och chattklienten.
Vad ska chattservern göra? I stora drag ska chattservern göra följande: 1. Öppna en socket för att kunna lyssna på anslutande chattklienter. 2. Starta en tråd som väntar på att chattklienter ska ansluta. 3. När en klient ansluter ska chattservern starta en tråd för att lyssna på data som klienten skickar. Klienten ska få ett hälsningsmeddelande direkt vid inloggningen. Alla andra klienter ska få ett meddelande om den nytillkomna klientens närvaro. 4. Vänta på att serveroperatören skriver in någon text.
Vad ska chattklienten göra? 1. Fråga vilket ”nick” användaren vill ha, det vill säga inloggningsnamnet. 2. Fråga vilken server (IP-adress) klienten ska ansluta till. 3. Ansluta till chattservern. Skicka inloggningsdata, som bara är namnet på användaren. 4. Starta en tråd som väntar på data från chattservern. 5. Vänta på att användaren matar in text. 6. Koppla ner.
63
10 Praktisk programmering – TCP/IP och trådar
Designfas Vilka funktioner behöver servern? 1. Öppna socket och knyta den till den lokala IP-adressen. 2. Vänta på anslutningar från klienter. 3. Lägga till en användare när en klient loggar in. 4. Vänta på data från de inloggade klienterna. 5. Skicka ett meddelande till en klient. 6. Skicka ett meddelande till alla inloggade klienter. 7. Ta bort användare när en klient loggar ut. 8. Hantera text som serveroperatören skriver in. 9. Koppla ner.
Vilka funktioner behöver klienten? 1. Öppna socket. 2. Vänta på indata från servern. 3. Ansluta till servern. Skicka användarnamn. 4. Hantera text som användaren matar in. 5. Koppla ner.
Gemensamma funktioner? I normala fall hade man lagt gemensam funktionalitet i en eller flera gemensamma projekt eller en eller flera gemensamma .java-filer, men vi bryr oss inte om det här eftersom det blir så lite kod.
Hantera text? Texten som matas in är ibland ett chattmeddelande och ibland ett kommando. Kommandon i chattklienter (till exempel för IRC) brukar inledas med ett snedstreck.
64
10 Praktisk programmering – TCP/IP och trådar
Hejsan alla! gunnar_gren: Hejsan alla! /bye
Den första raden är inmatningen från ett meddelande (1). Meddelandet skickas till servern. Servern lägger på användarnamn och bildar ett nytt meddelande (2). Meddelandet (2) är det som skrivits ut på rad två. På den sista raden står ett kommando: /bye. Denna typ av kommando är lämpligt att använda för att avsluta.
Vilka kommandon? I detta exempel så kommer du bara att implementera ett enda kommando: /quit – för att avsluta applikationen. Dock kan man lätt tänka sig en hel uppsjö med kommandon. Vissa kommandon bör av säkerhetsskäl bara finnas på servern. Du kan även lägga in synonymer, det vill säga flera kommandon som gör samma sak för att det ska vara lättare att gissa. Några få exempel på kommandon: /disconnect, /connect, /help, /?, /private, /info, /name, /bye, /quit, /exit, /kick-user, /kick-ip, /ban-user, /ban-ip.
Vilken data behöver servern? Detta syftar alltså till medlemsvariablerna. 1. En klass för en användare. 2. En socket för att lyssna efter klientuppkopplingar på.
Vilken data behöver klienten? Med andra ord, vilka medlemsvariabler behöver klienten? 1. En socket för att koppla upp sig mot servern med. 2. En PrintWriter för att skicka text med.
3. En BufferedReader för att läsa text med.
Övrig data Lägg gärna alla strängar som konstanter.
65
10 Praktisk programmering – TCP/IP och trådar
Hur fungerar uppkopplingen och login?
Direkt efter att klienten lyckats med sitt anrop till konstruktorn Socket, det vill säga uppkopplingen gick bra, så ska klienten skicka en sträng med sitt användarnamn i. Så här ser ett tidsschema ut ur serverns perspektiv: Anslutande klient
Server
Redan anslutna klienter
Öppna socket Vänta på att användare ska koppla upp connect() Initiera ett användarobjekt Skicka användarnamn Lägg till namnet i användarobjektet Skicka välkomstmeddelande Skicka information om inloggning Tid
Implementationsfas Det kan tänkas att du vill lägga till fler funktioner än de som är listade ovan för att göra koden bättre och mer överblickbar. Du kommer bara att implementera klienten; den är enklast. Om du vill implementera servern också så får du självfallet det, dock får du ingen annan hjälp än den färdiga källoden till chattservern: SdbChatServer.
Implementera funktioner för chattklienten 1. Skapa ett nytt projekt som du kallar för ChatClient. 2. Namnge och skriv in definitionerna för medlemsvariablerna och prototyperna för metoderna. 3. Sätt ut kommentarer i main som talar om i vilken ordning du ska göra anropen till de olika metoderna. 4. Börja med det du är säker på: skriv färdigt en metod i taget. De enklaste metoderna är de som kopplar upp en socket och skickar användarnamn, respektive den som kopplar ner en socket.
66
10 Praktisk programmering – TCP/IP och trådar
5. Implementera sedan metoden för att hantera användardata. Använd funktionerna Sdb.in.readLine och String.equals för att låta användaren mata in data och för att jämföra strängarna med till exempel kommandot /quit. 6. Implementera sist funktionen för att koppla upp sig och skicka användarnamn. Jämför med tidigare information i kapitlet och försök att på egen hand finna ut hur du ska skriva. 7. Om du kör fast och absolut inte kan komma på hur du ska lösa problemet så kan du alltid tjyvkika på den färdiga chattklienten SdbChatClient. När du är färdig med klienten går du över till testfasen.
Testfas 1. Öppna projektet SdbChatServer. Kompilera och kör. 2. Starta din chattklient. 3. Ange ditt användarnamn. 4. Ange vilken adress servern har som du ska ansluta till. Servern skriver ut nätverksnamn och IP-adress i slutet av andra raden när den startar. Titta på den och skriv av. Fungerade det? Jag hoppas verkligen det! I så fall tycker jag att du ska skicka ut din chattklient till dina klasskompisar tillsammans med din IP-adress och ha sedan chattservern igång så att du kan testa att chatta via din alldeles egna klient! Glöm inte heller att skicka med instruktioner för hur man startar klienten!
67
10 Praktisk programmering – TCP/IP och trådar
Övningsuppgifter Övning 10.1
Verifiera att du förstått allting i kapitlet. Gå igenom det som var svårt några gånger extra.
Övning 10.2
Gör en egen chattserver som är kompatibel med chattklienten i kapitlet.
Övning 10.3
Kan du kombinera dessa kunskaper i TCP/IP med någon annan slags applikation? Kanske ett spel? Eller kanske för att skicka krypterade meddelanden till kompisar? Om du kombinerar nätverksprogrammering med dina nyvunna kunskaper i bildhantering från tidigare kapitel så kan du skapa enkla ritprogram där flera användare kan rita samtidigt på olika datorer. Eller så kan du göra ett program där flera personer kan skapa ett bildkollage tillsammans. Fantasin är det enda som sätter gränsen för vad du kan komma på för applikationer. Gör en valfri applikation som inkluderar TCP/IP. (Svar saknas i facit.)
68
11
Praktisk programmering – läsa andras kod
I detta kapitel Syftet med det här kapitlet är att lära dig läsa och modifiera existerande och mer avancerad kod. Som programmerare i ett projekt med flera deltagare så råkar man betydligt oftare ut för att läsa och modifiera andras kod (eller gammal kod man glömt bort hur den funkar) än att faktiskt skriva egen. Som en bonus handlar det om 3D-rendering i OpenGL, vilket många som nyss börjat med programmering är nyfikna på. OpenGL stöds i många plattformar, om man kan Java kan man även skriva program för Android-enheter, men det är inte heller allt för svårt att gå vidare till C++ och skriva OpenGL-program till både Mac och iPhone/iPad. I kapitlet ges inga förklaringar till OpenGLs funktionalitet – det är bortom målen i kursen. Men det torde inte hindra den entusiastiske från att hitta goda möjligheter för egen innovation.
Överblick När du öppnar en Java-fil som du inte skrivit själv så börja alltid med att skaffa dig en överblick i hela filen. Ett vanligt nybörjarfel är att stirra sig blind på detaljerna så att man har svårt att skaffa sig en helheltsbild. Det är väsentligt att man skaffar sig en helhetsbild av koden man ska ändra i innan man skrider till verket. Annars är risken stor att man missuppfattar övergripande mål med koden man ändrar i. Och om man missförstår syftet bakom en viss algoritm, så är det lätt hänt att man i sina ändringar tillför buggar. Koden du kommer läsa i detta kapitel innehåller vissa syntaktiska (”Java-grammatiska”) formuleringar som du inte tidigare stött på. Som nybörjare är det bara att vänja sig! Eftersom du har som mål att förstå programmet på hög nivå, så måste du försöka att bortse från alla detaljer du inte förstår. Gå in med inställningen att du i varje läge bara ska försöka förstå tillräckligt för komma vidare. Bli inte missmodig om du känner dig ”vilsen”; det gör alla programmerare ibland. Efter bara några minuter kommer du att finna att du har en övergripande uppfattning om programmet, och då vet du bättre var du ska sätta in dina stötar.
69
11 Praktisk programmering – läsa andras kod
Hugg in Kika i katalogen Duck/. Öppna projektet och rota runt lite. Försök bilda dig en övergripande uppfattning om vad det är för ett program. Du väljer själv hur du skaffar dig den uppfattningen; om du tycker det är svårt får du lite vägledning direkt. 1. Testkör. Ingenting är så talande som att provköra en kodsnutt som du ska sätta dig in i. 2. Kolla snabbt igenom samtliga .java-filer. 3. Hitta till konstruktorn. I huvudmetoderna av koden du ska granska hittar du oftast de stora penseldragen i vad den ursprungliga programmeraren tänkt. 4. Om koden du läser är väldigt omfattande så brukar huvudmetoderna innehålla en väldigt hög och abstrakt nivå på anropen. Om mängden kod däremot är liten så kommer du finna högnivåanrop blandat med anrop på en lägre nivå. Eftersom ditt mål är att skaffa dig en överblick så måste du försöka sila bort lågnivåanropen när du läser igenom koden. Kodmängden i det här programmet är att anse som väldigt liten. Du kommer därför se, och förhoppningsvis ignorera, en hel del lågnivåanrop. Till exempel är alla anrop som börjar på gl.gl, lågnivåanrop direkt till OpenGL; dem är det alltså bäst att ignorera tills vidare. 5. Skriv ner pseudokod för programmet i en textredigerare. På så sätt är det enkelt för dig att utöka pseudokoden i takt med att du förstår mer om vad som görs. Din första pseudokodsnutt för programmet Duck bör innehålla ungefär 10–20 rader för huvudfunktionerna i konstruktorn och renderingsmetoden. Nu har du antagligen redan en ganska god bild av vad programmet gör, ungefär hur många rader (relevant) kod som ingår i programmet och ungefärligen hur programmet är uppbyggt med initiering och huvudloop. Nu när du förstår helheten på den här nivån, så är du redo för att tackla lite detaljer runt implementationen. Vissa av uppgifterna i det här kapitlet kan tyckas svåra, eftersom du inte är fullt införstådd med alla detaljer än, men de visar på din förmåga att lösa problem även om du bara känner till koden på en abstrakt nivå. Som programmerare är det oftast mycket viktigare att snabbt ta itu med problemlösning än att på förhand förstå samtliga detaljer kring ett problem.
70
11 Praktisk programmering – läsa andras kod
Övningsuppgifter Övning 11.1
Beskriv kort vad programmet Duck gör.
Övning 11.2
Hur många rader relevant kod anser du ingår i projektet? Motivera.
Övning 11.3
Beskriv huvudfunktionerna i konstruktorn och metoden render med pseudokod på en övergripande nivå.
Övning 11.4
Tror du att 3D-modellen som visas i programmet rör sig med samma hastighet på en snabb och en långsam dator? Motivera.
Övning 11.5
3D-modellen ritas ut som trianglar. Hur många trianglar består den av? Hur räknar man ut det, och i vilken fil ska man titta?
Övning 11.6
Hur modifierar du programmet så att både modellen och bakgrunden rör sig tio gånger snabbare?
Återställ programmet i sin ursprungliga hastighet när du är klar.
Övning 11.7
Modifiera programmet så att endast bakgrunden (inte modellen) rör sig tio gånger snabbare.
Övning 11.8
Hitta var bakgrundsfärgerna sätts. Vilken funktion är det som sätter dem?
Övning 11.9
När du tittar i funktionen i 11.8 så ser du i vilken ordning hörnpunkterna beskrivs för OpenGL. I vilken ordning vill OpenGL ha en hörnpunkt – först färg, sedan position eller först position, sedan färg?
Övning 11.10
Kika vidare i funktionen i 11.8. I den funktionen ritas bakgrunden ut som en rektangel. Det är vad gl.glBegin(GL.GL_QUADS); betyder. I vilken ordning sätts positionerna på de fyra hörnpunkterna på bakgrundsrektangeln ut?
71
11 Praktisk programmering – läsa andras kod
Övning 11.11
Vi kollar ytterligare i funktionen från 11.8. De funktioner som anropas för att ställa in bakgrundsfärgerna anger RGB (rött, grönt, blått) i intervallet [0, 1] där 0 och mindre betyder ingen färg och 1 och högre betyder maximal färgstyrka. Du är van med RGB sedan tidigare, skillnaden här är att intervallet beskrivs av ett flyttal mellan 0 och 1 i stället för ett heltal mellan 0 och 255.
Du kan se i koden att färgernas värden sätts med hjälp av trigonometriska funktioner.
Ändra så att alla färgerna ritas ut i gråskala, fast med samma intensitet som respektive trigonometrisk funktion ger. I den andra hörnpunkten (som har två anrop till trigonometriska funktioner) väljer du den intensiteten som den första trigonometriska funktionen returnerar.
Hur ser den resulterande koden mellan gl.glBegin och gl.glEnd ut?
Övning 11.12
Börja med att kommentera bort anropen från metoden render till DrawWireFrame.
Programmet är redan förberett för att få ankan att simma som fisken i vattnet, men det är inte färdigställt än. Kan du komma på hur du får ankan att simma som en ål?
Ledtråd: den ena parametern heter wobble och reglerar hur ”sladdrig” ankan ska vara. Ett lagom värde för en riktigt sladdrig anka är 0.5. Den andra parametern heter angle och gör sig bäst om man matar den med ett värde som successivt ökar typ fem gånger så snabbt som rotationsvinkeln som räknas ut varje loop.
72
12
Nyckelord i Java
Standardiserade nyckelord abstract
goto
this
assert
if
throw
boolean
implements
throws
break
import
transient
byte
instanceof
true
case
int
try
catch
interface
void
char
long
volatile
class
native
while
const
new
continue
null
default
package
do
private
double
protected
else
public
enum
return
extends
short
false
static
final
strictfp
finally
super
float
switch
for
synchronized
73
12 Nyckelord i Java
De vanligaste nyckelorden Här hittar du de vanligaste nyckelorden i Java. För varje nyckelord finns beskrivning, syntax och exempel. A Nyckelord
abstract
Beskrivning
Används på klasser eller metoder för att ange att en implementation ska ligga i en ärvd klass.
Syntax
abstract deklaration
Exempel
abstract class MyClass { abstract void myMethod(); }
B Nyckelord
bool
Beskrivning
Variabeltyp som kan anta två värden: sant och falskt.
Syntax
bool deklaration;
Exempel
bool is_active = false;
Nyckelord
break
Beskrivning
Bryter den innersta loopen.
Syntax
break;
Exempel
while (true) { break; }
C Nyckelord
case
Beskrivning
Ett av flera möjliga utfall i en switch-sats. Måste alltid följas av ett konstant heltal och ett kolon.
Syntax
case konstant_heltal:
74
12 Nyckelord i Java
Exempel
switch (x) { case 3: System.out.print(”Tre!”); break; }
Nyckelord
catch
Beskrivning
Fångar ett undantag.
Syntax
catch (undantag) {}
Exempel
try { ... } catch (Exception ex) { ex.printStackTrace(); }
Nyckelord
char
Beskrivning
Variabeltyp för tecken.
Syntax
char deklaration;
Exempel
char ch = '#';
Nyckelord
class
Beskrivning
Definierar en klass.
Syntax
class Deklaration {}
Exempel
class MyClass { }
Nyckelord
continue
Beskrivning
Fortsätter med nästa steg i en loop.
Syntax
continue;
Exempel
while (true) { continue; }
75
12 Nyckelord i Java
D Nyckelord
default
Beskrivning
Nyckelordet default används endast i switch-satser. Exekveringen kommer till default-alternativet om inget case-alternativ matchar.
Syntax
default:
Exempel
switch (x) { case 0: System.out.print(”Noll”); break; case 1: System.out.print(”Ett!”); break; default: System.out.print(”Fel”); break; }
Nyckelord
do
Beskrivning
Loop som testar villkoret på sista raden. Det innebär att loopen alltid kommer att köras minst en gång. Loopen kommer att exekveras till dess att villkoret är falskt.
Syntax
do { } while (villkor);
Exempel
do { } while (true);
Nyckelord
double
Beskrivning
Variabeltyp för flyttal. 15 signifikanta siffor.
Syntax
double deklaration;
Exempel
double d = 3.1415;
E Nyckelord
else
Beskrivning
Används enbart efter en if-sats. Exekveringen kommer till elsesatsen om inte villkoret i if-satsen är sant.
Syntax
if (villkor) { } else { }
76
12 Nyckelord i Java
Exempel
int x = ...; if (x == 1) { System.out.println(”Ett!”); } else { System.out.println(”Inte ett!”); }
F Nyckelord
false
Beskrivning
false är det ena av de två värdena som variabeltypen bool kan anta. true är det andra.
Syntax
false
Exempel
bool b = false;
Nyckelord
final
Beskrivning
final anger att en klass, metod eller variabel inte kan ändras. En klass kan inte ärvas, en metod kan inte överlagras, en variabel kan inte tilldelas mer än en gång. Variabler kan även användas i nästlade, anonyma klasser.
Syntax
final deklaration
Exempel
final class MyClass { final int x = 7; final void myMethod() { } }
Nyckelord
finally
Beskrivning
finally används tillsammans med try för att hantera oväntade händelser som till exempel när en metod avslutas under en pågående initiering av resurser.
Syntax
finally {}
Exempel
try { ... } catch (Exception ex) { } finally { // Denna kod kommer tt köras, oavsett // vad som händer ovan. }
77
12 Nyckelord i Java
Nyckelord
float
Beskrivning
Variabeltyp för flyttal. 7 signifikanta siffor.
Syntax
float deklaration;
Exempel
float f = 3.1415f;
Nyckelord
for
Beskrivning
En villkorlig loop. Loopen kommer att exekveras till dess att villkoret är falskt.
Syntax
for (uttryck; villkor; uttryck) { }
Exempel
for (int x = 0; x < 3; ++x) { System.out.println(x); }
I Nyckelord
if
Beskrivning
Exekverar villkorliga satser. Innehållet i if-satsen kommer att exekveras om villkoret är sant. if-satsen kan kombineras med en else-sats.
Syntax
if (villkor) { satser; }
Exempel
int x = ...; if (x == 3) { System.out.println(x); }
Nyckelord
implements
Beskrivning
Följs av interface som en klassen implementerar.
Syntax
implents interface
Exempel
class MyClass implements MyInterface { }
78
12 Nyckelord i Java
Nyckelord
import
Beskrivning
Importerar en klass, alla klasser i ett paket eller en statiska medlemmar i en klass.
Syntax
import KlassEllerPaket; static import statiskMetod;
Exempel
import import static static
Nyckelord
int
Beskrivning
Variabeltyp för heltal.
Syntax
int deklaration;
Exempel
int i = -385;
Nyckelord
interface
Beskrivning
Definierar ett interface, en uppsättning odefinierade metoder.
Syntax
interface Deklaration {}
Exempel
public interface MyInterface { void myMethod(); }
java.awt.*; sdb.Sdb; import sdb.Sdb.createConsole; import Math.*;
L Nyckelord
long
Beskrivning
Variabeltyp för heltal.
Syntax
int deklaration;
Exempel
int l = -287;
79
12 Nyckelord i Java
M Nyckelord
main
Beskrivning
Inget nyckelord, men bör inte användas till andra deklarationer än huvudfunktionen.
Syntax
main
Exempel
public static void main(String[] argv) {}
N Nyckelord
new
Beskrivning
Allokerar en ny instans av en klass eller en ny array.
Syntax
new deklaration;
Exempel
new MyClass(); new int[128];
Nyckelord
null
Beskrivning
En referens är null när den inte refererar någon instans.
Syntax
null;
Exempel
String s = null;
P Nyckelord
package
Beskrivning
Talar om vilket paket man är i, högst uppe i källkodsfilen.
Syntax
package deklaration;
Exempel
package game;
Nyckelord
private
Beskrivning
Anger att en klass, en metod eller en variabel bara är tillgänglig från alla den klasssen den definieras i.
80
12 Nyckelord i Java
Syntax
private deklaration
Exempel
private int x;
Nyckelord
protected
Beskrivning
Anger att en klass, en metod eller en variabel är tillgänglig från andra klassser som ärver eller som ligger i samma paket. Om inget anges blir det automatiskt protected i klasser.
Syntax
protected deklaration
Exempel
protected class MyClass { protected void myMethod(); }
Nyckelord
public
Beskrivning
Anger att en klass, en metod eller en variabel är tillgänglig från alla andra klassser. Om inget anges blir det automatiskt public i interface.
Syntax
public deklaration
Exempel
public class MyClass { public void myMethod(); }
R Nyckelord
return
Beskrivning
Returnerar från en metod. Om metoden ska returnera ett värde så ska return ta värdet som parameter. Om det är en void-funktion så ska return inte ta någon parameter
Syntax
return ;
Exempel
void x() { return; } int y() { return 4; }
81
12 Nyckelord i Java
S Nyckelord
short
Beskrivning
Variabeltyp för heltal.
Syntax
short deklaration;
Exempel
short i = -292;
Nyckelord
static
Beskrivning
Gör en metod, medlemsvariabel eller inre klass frikopplad från instansen.
Syntax
static deklaration
Exempel
class Abc { static String def = ”GHI”; static void jkl() {} } System.out.println(Abc.def); Abc.jkl();
Nyckelord
switch
Beskrivning
Villkorlig exekvering av olika satser beroende på heltalsuttrycket. Används tillsammans med nyckelorden case default.
Syntax
switch (heltalsuttryck) { case x: ... case y: ... case z: ... default: ... }
Exempel
int x = ...; switch (x) { case 10: case 91: case 99: default: }
System.out.print(”tio”); System.out.print(”nittioett”); System.out.print(”nittionio”); System.out.print(”annat tal”);
82
12 Nyckelord i Java
T Nyckelord
this
Beskrivning
this refererar till instansen i nuvarande klass.
Syntax
this
Exempel
class MyClass { int x; MyClass() { this.x = 7 } }
Nyckelord
true
Beskrivning
true är det ena av de två värdena som variabeltypen bool kan anta. false är det andra.
Syntax
true
Exempel
bool b = true;
Nyckelord
try
Beskrivning
Kontrollerar ett block där ett eller flera undantag kan ske.
Syntax
try {} catch (undantag) {}
Exempel
try { new File(”.”).canonicalPath(); } catch (Exception ex) { }
U Nyckelord
unsigned
Beskrivning
Anger att en heltalsvariabel enbart ska kunna anta positivia värden.
Syntax
unsigned heltalsdeklaration;
Exempel
unsigned char x = 3;
83
12 Nyckelord i Java
V Nyckelord
void
Beskrivning
void anger att en metod inte ska returnera något värde.
Syntax
void metoddeklaration
Exempel
void setPixel(int x, int y) { }
W Nyckelord
while
Beskrivning
En villkorlig loop. Loopen kommer att exekveras till dess att villkoret är falskt.
Syntax
while (villkor) { }
Exempel
int x = 0; while (x < 3) { System.out.println(x); ++x; }
84
13
Teckentabell
Tecken
ASCII-värde
Namnkod
Funktion
\0
0
NUL
Slut på sträng
\x1
1
SOH
\x2
2
STX
\x3
3
ETX
\x4
4
EOT
\x5
5
ENQ
\x6
6
ACK
\a
7
BEL
Avger en ton
\b
8
BS
Backsteg
\t
9
HT
Tabb
\n
10
LF
Radmatning
\v
11
VT
Vertikal tabb
\f
12
FF
Sidmatning
\r
13
CR
Vagnretur
\xE
14
SO
\xF
15
SI
\x10
16
DLE
\x11
17
DC1
\x12
18
DC2
\x13
19
DC3
\x14
20
DC4
\x15
21
NAK
\x16
22
SYN
\x17
23
ETB
\x18
24
CAN
\x19
25
EM
\x1A
26
SUB
85
13 Teckentabell
Tecken
ASCII-värde
Namnkod
\x1B
27
ESC
\x1C
28
FS
\x1D
29
GS
\x1E
30
RS
\1F
31
US
32
SP
!
33
"
34
#
35
$
36
%
37
&
38
'
39
(
40
)
41
*
42
+
43
,
44
-
45
.
46
/
47
0
48
1
49
2
50
3
51
4
52
5
53
6
54
7
55
Funktion
Mellanslag
86
13 Teckentabell
Tecken
ASCII-värde
8
56
9
57
:
58
;
59
62
?
63
@
64
A
65
B
66
C
67
D
68
E
69
F
70
G
71
H
72
I
73
J
74
K
75
L
76
M
77
N
78
O
79
P
80
Q
81
R
82
S
83
T
84
Namnkod
Funktion
87
13 Teckentabell
Tecken
ASCII-värde
U
85
V
86
W
87
X
88
Y
89
Z
90
[
91
\
92
]
93
^
94
_
95
`
96
a
97
b
98
c
99
d
100
e
101
f
102
g
103
h
104
i
105
j
106
k
107
l
108
m
109
n
110
o
111
p
112
q
113
Namnkod
Funktion
88
13 Teckentabell
Tecken
ASCII-värde
r
114
s
115
t
116
u
117
v
118
w
119
x
120
y
121
z
122
{
123
|
124
}
125
~
126
\x7F
127
Namnkod
Funktion
DEL
89
13 Teckentabell
90
14
Facit
1.1 Java-VM:en exekverar bytekod (1:or och 0:or), instruktion för instruktion. Instruktionerna läses in och utföres ”uppifrån och ner” (det vill säga från lägre till högre adresser), dock finns det instruktioner som kan få Java-VM:en att ”hoppa” till en annan adress för att fortsätta programexekveringen där.
1.2 Man trycker Ctrl+Shift+I!
1.3 En loop är en konstruktion som gör att man kan genomföra samma bearbetning flera gånger utan att behöva skriva källkoden flera gånger. Ofta använder man en loop för att bearbeta olika data i, men med en och samma funktion. Till exempel skulle en loop lämpa sig idealiskt för att söka igenom telefonkatalogen: varje dataelement har ju samma format (namn och telefonnummer), men data skiljer sig åt (alla har inte samma namn eller telefonnummer).
1.4 .java. Filer med ändelsen .java innehåller programkoden som ska översättas till bytekod.
1.5
byte, short, int, long, float, double, bool, char, enum.
De fyra första typerna är heltal. De två nästkommande är flyttal. Näst kommer en så kallad boolesk variabel som endast kan anta värdena true och false. char används för tecken. Typen enum är till för uppräkningar, men kan även användas ungefär som en klass.
1.6
short x;
1.7
+, –, *, / och %. Dessutom +=, –=, *=, /=, %=, ++ och ––. Det finns även fler operatorer, men de har du inte gått igenom än. Några av dessa används för binär aritmetik. De är: >>, midValue; ++top) ; for (; stars[bottom].z < midValue; --bottom) ; if (top first) { sortStars(stars, first, bottom); sortStars(stars, top, last); } }
6.1 –
6.2
System.arrayCopy (används för att kopiera arrayer), String.equals och String.valueOf, PrintWriter.println och så vidare.
7.1 Se exempelprojektet SdbSearchPerformanceTest.
97
14 Facit
7.2
SearchPerformanceTest() { int nameCount = 30; // Nollställ hashtabellen och listan. testHashTable = new ListItem[256]; for (int a = 0; a < 256; ++a) { testHashTable[a] = null; } testList = null; // Lägg in data. for (int i = 0; i < nameCount; ++i) { hashAddNode(testHashTable, Names.names[i][0], Names.names[i][1]); testList = listAddNode(testList, Names.names[i][0], Names.names[i][1]); } // Sök efter data i hashtabellen. long Time1 = System.nanoTime(); for (int i = 0; i < nameCount; ++i) { hashAddNode(testHashTable, Names.names[i][0], Names.names[i][1]); } for (int i = 0; i < nameCount; ++i) { hashFindNode(testHashTable, Names.names[i][0], Names.names[i][1]); } long Time2 = System.nanoTime(); System.out.println(”Hash time: ” + (Time2-Time1)); // Sök efter long Time3 = for (int i = testList =
}
data i listan. System.nanoTime(); 0; i < nameCount; ++i) { listAddNode(testList, Names.names[i][0], Names.names[i][1]);
} for (int i = 0; i < nameCount; ++i) { listFindNode(testList, Names.names[i][0], Names.names[i][1]); } long Time4 = System.nanoTime(); System.out.println(”List time: ” + (Time4-Time3));
Resultatet för få namn (= b.height) { y2 = b.height-1; } int i = imageOffset + 3*x + 3*(b.width)*(b.height-1-y2);
Resultatet blir en något svängigare bild.
99
14 Facit
9.1
List list = new ArrayList();
9.2
HashMap numberLookup = new HashMap(); numberLookup.put(31, ”Göteborg”); numberLookup.put(8, ”Stockholm”); numberLookup.put(40, ”Malmö”);
10.1 –
10.2 Se källkoden i SdbChatServer.
10.3 –
11.1 Programmet ritar ut en roterande anka. I bakgrunden varierar en färggradient; varje hörn på skärmen har en egen pulserande nyans av rött, grönt, gult, blått och svart.
100
14 Facit
11.2 Ungefär 200 rader. Det är egentligen bara filerna Duck.java, Render.java som innehåller algoritmer som vi är intresserade av att titta på och ändra i. Filen DuckMesh.java innehåller bara data – nämligen hörnpunkter och trianglar för ankan. Den behöver vi bara kolla på en gång för att inse att den inte innehåller några algoritmer, och helt ointressant för manuell redigering. Filen SdbGl.java innehåller bara sådant som vi varken vill eller behöver tänka på (öppna fönster, sköta basala inställningar, och så vidare).
11.3
Öppna ett OpenGL-fönster. Räkna ut normalerna till hörnpunkterna på modellen. Lagra start-tiden. [HuvudLoop] vinkel = tid (i sekunder) sedan start Alla dessa är beroende av vinkel med skalfaktor: Rita bakgrunden. Rotera modell och ljuskälla. Rita modellen med fyllda trianglar. Rita modellen med ofyllda trianglar. Gå till [HuvudLoop]!
11.4 Ja. Orsaken är att den absoluta ”vinkel” som används för bakgrunden och modellen är tidbaserad (sekunder sedan programmet startade) och inte baserad på något annat, tidigare tillstånd. Tiden går lika fort för alla datorer, oavsett hur snabba de är.
11.5 Filen DuckMesh.java innehåller vad vi vill veta. Den första arrayen, DuckMesh.vertices, listar hörnpunkterna i trianglarna på ankan. Den andra arrayen, triangles, listar trianglarna som ankan består av. En triangel definieras som index på de tre ingående hörnpunkterna. Antalet definierade rader i DuckMesh.triangles är lika med antalet trianglar. Det antalet är 564.
101
14 Facit
11.6 Ändra raden float angle = elapsedTime;
till
float angle = elapsedTime * 10;
11.7 Ändra raden Render.drawBackground(angle / 25);
till
Render.drawBackground(angle * 10 / 25);
11.8
De anges i funktionen Render.drawBackground.
11.9 Först färg, sedan position. (Positionen anges sist för varje hörnpunkt i OpenGL.)
11.10 Hörnpunkterna sätts ut i följande ordning: övre vänstra, nedre vänstra, nedre högra, övre högra. Moturs, således.
11.11
gl.glBegin(GL.GL_QUADS); double d = Math.sin(a * 2); gl.glColor3d(d, d, d); gl.glVertex2d(-1.0, 1.0); d = Math.cos(a * 3); gl.glColor3d(d, d, d); gl.glVertex2d(-1.0, -1.0); d = Math.sin(a * 7) * Math.cos(a); gl.glColor3d(d, d, d); gl.glVertex2d(1.0, -1.0); d = Math.sin(a * 11 + 1); gl.glColor3d(d, d, d); gl.glVertex2d(1.0, 1.0); gl.glEnd();
102
14 Facit
11.12 Ändra anropet Render.drawMesh(DuckMesh.vertices, duckMeshNormals, DuckMesh.triangles, 0, 0);
till
Render.drawMesh(DuckMesh.vertices, duckMeshNormals, DuckMesh.triangles, 0.5f, angle * 5);
De två sista parametrarna är valfria; det kan du se på funktionsprototypen.
103