Innholdsfortegnelse:

Interessant programmeringsveiledning for designer-Få bildet ditt til å løpe (første del): 16 trinn
Interessant programmeringsveiledning for designer-Få bildet ditt til å løpe (første del): 16 trinn

Video: Interessant programmeringsveiledning for designer-Få bildet ditt til å løpe (første del): 16 trinn

Video: Interessant programmeringsveiledning for designer-Få bildet ditt til å løpe (første del): 16 trinn
Video: ЛЮБОВЬ С ДОСТАВКОЙ НА ДОМ (2020). Романтическая комедия. Хит 2024, Juli
Anonim
Interessant programmeringsveiledning for designer-få bildet ditt til å løpe (del én)
Interessant programmeringsveiledning for designer-få bildet ditt til å løpe (del én)

Løpe! Løpe! Løpe!

Programmering er ikke så vanskelig. Nøkkelpunktet er å finne rytmen din og gjøre det en etter en.

Før jeg leser dette kapitlet, håper jeg at du allerede har vært kjent med den grunnleggende funksjonstegningsmetoden, eller at du vil føle deg svimmel og forvirret av to store hodefunksjoner: oppsett og tegning.

Siden vi ønsker å lage bevegelig grafikk, må vi vite hvordan animasjon produseres.

Bildet ovenfor virker ganske attraktivt og avslører visuelt implementeringsprinsippet for animasjon.

Animasjon er magi. Det er en magi om visuell juks. Men i denne informasjonen eksploderte, video flom alder, har vi allerede vært vant til det. Få mennesker vil bli overrasket over at det er en fantastisk ting å kunne se animasjonen.

Samme prinsipp kan brukes på tegne -animasjon med program. Vi må vurdere hvordan vi tegner forskjellig grafikk i hver ramme, og programmet vil automatisk bla sider mens vi supplerer en fullført animasjon i hodet. I det følgende kapitlet vil vi snakke om hvordan du realiserer grunnleggende grafisk bevegelse. Før det må vi vite litt grunnleggende kunnskap om variabler.

Trinn 1: Variabel

Variabel er beholderen for data. Den kan brukes gjentatte ganger i et program.

For eksempel:

[cceN_cpp theme = "dawn"] størrelse (500, 500); ellips (100, 250, 50, 50); ellips (200, 250, 50, 50); ellipse (300, 250, 50, 50); ellips (400, 250, 50, 50);

[/cceN_cpp]

Denne delen av koden har ikke brukt noen variabler. Det tegner fire sirkler i skjermen. Vi kan finne at de har samme bredde og høyde. Nå som det er det samme, for å minimere gjentatt datainngang, kan vi definere et tegn for å representere det. Dette tegnet er variabelt.

Her er koden etter å ha lagt til en variabel:

[cceN_cpp theme = "dawn"] størrelse (500, 500); int a = 50; ellips (100, 250, a, a); ellips (200, 250, a, a); ellips (300, 250, a, a); ellips (400, 250, a, a);

[/cceN_cpp]

Vi får et helt samme resultat!

Siden vi har definert variabel a, kan vi enkelt endre parametere. Hvis vi endrer a = 50 til a = 100, vil alle sirkelenes bredde og høyde bli 100 jevnt. Så vi trenger ikke å endre parametere en etter en. Variabel er virkelig en god oppfinnelse.

Trinn 2: Opprettelse av variabel

Før vi bruker variabelen, må vi uttale oss og angi datatypen.

int i;

i = 50;

Den første setningen i koden har gitt en uttalelse for en variabel i. int er et symbol som hovedsakelig brukes til å deklarere variabel. Når du erklærer det, vil det spare et rom i datamaskinminnet, som tilsvarer å generere en "boks", spesielt brukt til å gjenopprette heltallsdata. Den andre setningen står for at oppgave 50 skal implementeres med variabel i. Etter implementeringen av denne setningen, vil data bli lagret i variabelen i stabilt. Eller du kan være latere å kombinere de to ovennevnte setningene til ett og fullføre oppgaven mens du kommer med uttalelser.

int i = 50;

Det er relativt gratis å navngi en variabel. Men noen ganger må vi ta hensyn til noe.

Trinn 3: Navngi regulering av variabel

• Det må være en kombinasjon av alfabet og understreking. Det kan være et symbol eller et ord.

• Skille mellom store og små bokstaver. Navn og navn kan stå for forskjellige variabler.

• Prøv å navngi det så enkelt som mulig, slik at du kan forstå det ved ett blikk. Det innledende tegnet må være et alfabet i stedet for et tall eller et spesialtegn.

• Ingen stikkord som int, float

Det følgende er noen feil uttalelser.

int $ a;

int 89b;

Her er de riktige utsagnene:

int r;

int super_24;

int openTheDoor;

Trinn 4: Variabel type

Bortsett fra å deklarere heltall data, kan vi deklarere for desimal data (også kalt flytende data) med nøkkelord float.

flyte b = 0,5

Vi må huske hva slags datatype vi brukte for uttalelsen vår. Hvis vi har brukt nøkkelordet int, kan sistnevnte oppgave ikke skrive i = 0.5 eller noe sånt, eller programmet blir feil. Men hvis vi skriver motsatt, er det greit. For eksempel er float i = 5 riktig grammatikk, men programmet vil gjenkjenne det som desimaltall.

Noen av variablene er allerede definert av systemet. Vi trenger ikke å erklære dem selv. Akkurat som den tidligere refererte "bredden, høyden", vil den automatisk få bredden og høyden på dataskjermen. Så høy frekvens i bruk at designeren definerer det direkte som en standardvariabel for å gjøre det mer praktisk for oss å bruke.

Trinn 5: Operatør

Følgende er behandlingsoperatører:

+ pluss

- minus

* multiplisere

dele opp

% Modul for resten

Du må være kjent med alle disse operatørene bortsett fra %. Det virker ganske rart fordi resultatet er resten. 9%3 er 0. Mens 9%5 er 4.

Operatører kan brukes blant oppgaver og variabler.

[cceN_cpp theme = "dawn"] int a = 1; // erklære heltallsvariabel a, oppgave er 1. int b = 2; // Deklarer heltallsvariabel b, oppgaven er 2. int c; // Deklarere heltallsvariabel c. c = a + b; // Pluss to oppgaver og tilordne resultatet til c. trykk (c); // Utgangsvariabel c.

[/cceN_cpp]

Trinn 6: Driftsresultat:

Utgangsresultatet vises ikke på vinduet, men i konsollen nederst.

Skrivemetoden til den fjerde linjen ser ganske merkelig ut. Men det er et vanlig format som ofte brukes under datamaskinoppgave. Venstre side av like symbol bør være den siste tildelte variabelen, mens høyre side skal være operasjonsprosess.

Utskriftsfunksjonen på den femte linjen kan skrive ut variabler i konsollen, som ofte brukes til å teste tilstanden til datautgang.

Trinn 7: Driftsregulering

Et plagsomt punkt i prosessering er at vi må klargjøre typen variabel. Vi må være spesielt oppmerksom på prosessen med flytende tall og heltallstype.

skrive ut (6 /5); // resultat 1

Drift mellom heltall vil ha et nytt heltall. 6 delt på 5 er 1,2. Men resultatet fra programmet er 1. Dette er i strid med vår intuisjon. Programmet vil ikke håndtere runde, men slette tallet bak desimaltegnet.

print (6.0 / 5.0); // resultat 1.2

Drift mellom flytende punkter vil resultere i et nytt flytpunktnummer. Hvis det faktiske resultatet er 1,2, blir programmets utgangsresultat det samme.

utskrift (6 / 5.0); // resultat 1.2

utskrift (6,0 / 5); // resultat 1.2

Til slutt er det en blanding av heltall og flytende tall. Det endelige utgangsresultatet vil være 1,2.

• Egentlig må du huske på at målet med denne forskriftsdesignen er å ikke miste nøyaktigheten av data. Så hvis ett element er et flytende tall, blir resultatet også flytende punktnummer.

Trinn 8: Oppsettfunksjon og tegnefunksjon

Tidligere har vi snakket om en bunke med jordingskunnskap. Nå kommer vi endelig for å spille noe interessant. Funksjonsoppsett og tegning tilsvarer hovedfunksjonene i behandlingen. Disse to funksjonene er veldig spesielle. Det kan kontrollere prosedyren for programmet. Forholdsvis komplisert program vil inneholde disse to funksjonene fordi de er grunnrammen for programmet. Format:

ugyldig oppsett () {

}

ugyldig trekning () {

}

Den spesielle bruken gjør deres påkallingsformat annerledes enn de andre funksjonene. Vi må legge til "void" før funksjonsnavn, som står for ingen "returnert verdi". Bak funksjonsnavnet må vi legge til parenteser og seler.

[cceN_cpp theme = "dawn"] ugyldig oppsett () {print (1); } void draw () {print (2); } [/cceN_cpp]

La oss se på et eksempel:

Når du trykker på betjeningsknappen, sender konsollen først "1" og deretter konstant "2" til du har trykket ned stoppknappen eller lukket vinduet.

Kode i parentes i oppsettfunksjonen vil bli implementert bare én gang. Mens kode innen funksjonstegning stadig vil kjøre i omløp (standardimplementering 60 ganger/sekund).

På grunn av dette tegnet brukes oppsettet vanligvis til å initialisere miljøegenskaper, for eksempel bredden og høyden på skjermen, bakgrunnsfarge og alle typer variabeltildeling. Selv om vi ofte plasserer tegnefunksjoner i funksjonstegning for å generere kontinuerlig endret grafikk.

Trinn 9: Sirkel i horisontal bevegelse

Med funksjonstegning kan vi begynne å lage animasjonene våre. Metoden for å skrive animasjonseffekt ved prosessering er ganske "vanskelig". Den har ingen eksisterende kommando. For eksempel, angi en viss form for å gjøre krøllete.

Vi må definere disse detaljene selv. Du må fortelle programmet hva slags grafikk hver ramme definitivt trenger.

Skriv følgende kode inn i den (la oss begynne å gjøre det med hendene):

[cceN_cpp theme = "dawn"] int x; int y; ugyldig oppsett () {størrelse (300, 300); x = 0; y = høyde/2; } void draw () {bakgrunn (234, 113, 107); noStroke (); ellips (x, y, 50, 50); x = x+1; }

[/cceN_cpp]

Denne delen av koden viser en bevegelsessirkel. Den tidligere deklarerte variabelen x, y brukes til å lagre koordinatposisjonen. Dens oppgaver kjøres i funksjonsoppsett. Nøkkelen er følgende i funksjonstegning:

x = x + 1

Ikke se på det som en matematisk ligning, ellers blir det veldig rart. Her er "=" et symbol for tildeling. Det representerer å plassere de riktige tallene i den venstre variabelen. Anta at x er 50, når koden er i gang, tilsvarer høyre side av "=" 50+1, dvs. 51. Det endelige resultatet vil bli tilordnet variabel x. Så verdien av x blir 51.

Følg prosedyren i programmet, hver gang funksjonstegning fungerer for en gangs skyld, vil verdien av x øke 1. Så hver gang vi tegner, vil sirkelen bevege seg en pikselretning horisontalt til høyre, sammenlignet med den tidligere rammen. Derfor blir grafikken bevegelig.

• For å få koden til å oppnå bedre lesbarhet, må vi spare et bestemt rom før hver kodelinje i seler. Og den skal være så justert som mulig. Trykk TAB eller flere mellomrom, det kan trekke seg tilbake.

• Symbolet for tomrom og linjeskift i programmet påvirker ikke programmet. Så det er ok hvis vi skriver en mer eller mindre.

Her er en annen enklere måte å uttrykke det på. For å få variabel sirkel til å øke 1 automatisk, må vi skrive den for å være følgende format.

sirkel = sirkel +1

Ganske upraktisk! Hvis navnet på variabelen er lengre, må vi skrive flere ord. Så våre late forgjengere tenker ut en idé som denne.

sirkel ++

Er det ikke veldig enkelt? Det betyr å øke 1 automatisk. I likhet med det er det - -, som betyr å redusere 1 automatisk.

Men hvis vi håper at mengden automatisk økning er et annet tall som 2, må vi prøve et annet uttrykk.

sirkel += 2

Dette tilsvarer

sirkel = sirkel + 2

På samme måte er det - =, /=, *=.

Trinn 10: Bevegelsesretning

Hvilken retning grafikken beveger seg avhenger av hvordan du endrer koordinaten din. Hvis den endres til y = y + 1, vil sirkelen bevege seg nedover. Hvis både x og y øker 1, beveger sirkelen seg nedover til høyre nederst. Hvis vi skriver at det er et minus -symbol, vil det bevege seg i motsatt retning.

[cceN_cpp theme = "dawn"] int x, y; // Kan deklarere flere variabler samtidig, bruk komma for å skille. ugyldig oppsett () {størrelse (300, 300); x = 0; y = 0; } void draw () {bakgrunn (234, 113, 107); noStroke (); ellipse (x, y, 50, 50); x ++; y ++; }

[/cceN_cpp]

Bevegelseshastighet

Husker du standard 60 bilder per sekund i funksjonstegning? I henhold til denne hastigheten vil sirkelen ovenfor bevege seg 60 piksler per sekund til høyre.

Hvis vi ønsker å endre den grafiske bevegelseshastigheten, er det to metoder: Den ene er å øke x -verdien hver gang siden den skal endres.

x = x + 10

Den har forbedret hastigheten 10 ganger sammenlignet med den opprinnelige!

Den andre metoden er å endre frekvensen for oppdatering av lerretet. frameRate ()

Denne funksjonen kan endre lerretets kringkastingsfrekvens. Skriv frameRate (10) i funksjonsoppsettet, det endrer de originale 60 bildene per sekund til 10 bilder per sekund. Hastigheten reduseres 6 ganger enn før.

Trinn 11: Oversett bakgrunn

Alle de foregående eksemplene skriver bakgrunn til funksjonstegning. Har du noen gang tenkt på å skrive det inn i funksjonsoppsett? Vil det ha noen forskjeller? La oss nå oppdatere eksemplet på horisontal bevegelse.

[cceN_cpp theme = "dawn"] int x, y; ugyldig oppsett () {størrelse (300, 300); bakgrunn (234, 113, 107); x = 0; y = høyde/2; } void draw () {noStroke (); ellips (x, y, 50, 50); x += 1; } [/cceN_cpp]

Hva har skjedd? Kanskje den ikke kan forstå årsaken til produksjonen av problemet ordentlig. Slett funksjon noStroke, legg til slag igjen, og se bevegelsesbanen til sirkelen.

Åh, det er på grunn av den tidligere opprettede sirkelen ikke har blitt slettet! Fordi funksjonsoppsettet fungerer bare en gang, hvis vi skriver bakgrunn over det, vil det fylle bakgrunnen for bare en gang, og sistnevnte vil det ikke ha noen effekt lenger. Funksjonsbakgrunn er som malerbøtteverktøy. Når den er brukt, vil den dekke alt innhold på lerretet i stedet for å angi bare en bakgrunnsfarge. Vi skriver det før funksjonstegning, slik at den tidligere rammen blir dekket hver gang vi lager et nytt mønster. Derfor kan sirkelen gå som vi forventet. Bortsett fra å huske bruken av hver funksjon, må vi tenke på posisjonen til koden. Mye tid, den oppadgående eller nedadgående linjen for kodeaen og for å skrive den innenfor eller utenfor en avstiver, vil det skape ganske forskjellige effekter. Koderetningen er todimensjonal. Hvis det vises en feil, må vi kalibrere i denne to dimensjonen.

• Denne ikke gjentatte tegnemetoden kan skape en helt spesiell effekt hvis den brukes riktig. Du kan kopiere følgende kode og prøve.

[cceN_cpp theme = "dawn"] ugyldig oppsett () {størrelse (400, 400); } void draw () {ellipse (width/2-mouseX, height/2-mouseX, mouseY, mouseY); ellipse (bredde/2-mouseX, høyde/2+mouseX, mouseY, mouseY); ellipse (bredde/2+mouseX, høyde/2-mouseX, mouseY, mouseY); ellipse (bredde/2+mouseX, høyde/2+mouseX, mouseY, mouseY); } [/cceN_cpp]

Her har vi brukt den magiske variabelen mouseX og mouseY. Sist vil vi snakke om det i detalj.

Trinn 12: Ristesirkel

Hva om jeg vil gjøre sirkelbevegelsesretningen uregelmessig? Med funksjon tilfeldig smart, kan du også innse denne effekten. Tilfeldig er en ofte brukt funksjon. Den kan brukes til å generere tilfeldig funksjon. Det er som en sporløs ånd. Når den er relatert til variabler, kan du ikke forestille deg hva som blir neste.

Kall format:

tilfeldig (høy)

Høy representerer den tilfeldige øvre grensen, og standardgrensen for bunn er 0. For eksempel tilfeldig (10). Det vil produsere et tall fra 0 til 10 tilfeldig (0 er inkludert, men 10 er ikke inkludert).

tilfeldig (lav, høy)

Hvis vi setter to parametere, vil den gå tilbake til den tilfeldige verdien mellom dem. For eksempel tilfeldig (5, 10). Det vil produsere et tall fra 5 til 10 tilfeldig (5 er inkludert, men 10 er ikke inkludert).

Eksempel:

[cceN_cpp theme = "dawn"] float x;

x = tilfeldig (50, 100);

skrive ut (x); [/cceN_cpp]

Hver gang vi kjører programmet, sender konsollen forskjellige verdier.

• Merk: Verdier opprettet av tilfeldig funksjon tilhører typen flytende punkt (desimaltallstype). Hvis vi vil tilordne en verdi til en heltallsvariabel, må vi transformere den gjennom funksjon int (). Transformasjonen følger ikke runden, men sletter desimaldelen direkte. Dermed har utgangen av int (random (5)) bare 5 muligheter: 0, 1, 2, 3, 4.

Etter at vi har blitt kjent med bruken av tilfeldig funksjon, kan vi komme direkte inn i saken nedenfor.

[cceN_cpp theme = "dawn"] int x, y; ugyldig oppsett () {størrelse (300, 300); x = bredde/2; y = høyde/2; } void draw () {bakgrunn (234, 113, 107); noStroke (); x += int (tilfeldig (-5, 5)); y += int (tilfeldig (-5, 5)); ellips (x, y, 50, 50); }

[/cceN_cpp]

De tidligere lagt til koordinatverdiene er faste. Bare hvis vi øker en tilfeldig verdi, vil sirkelen bevege seg i en ubestemt retning. Med det større tilfeldige området, rister det oftere. Siden verdiendringen mellom rammene hoppes, vil bevegelsen ikke være jevn lenger. Mens den tidligere rammen er på (150, 150), vil den sistnevnte rammen bevege seg til posisjonen (170, 170) innenfor et glimt.

Trinn 13: Migreringskrets

Migrasjonskrets

Vil det skape jevn bevegelse? Funksjonsstøy kan hjelpe oss. Den har bedre rytme enn standard tilfeldig. Og tilfeldig genererte tilfeldige tall er kontinuerlig.

Kall format:

støy (t)

Funksjonsstøy kan ikke definere utgangsområdet. Programmet definerer at det bare kan generere flytende tall fra 0 til 1, og fast inngang kan bare ha fast utgang.

[cceN_cpp theme = "dawn"] float x = noise (5); flyte y = støy (5); utskrift (x, y); [/cceN_cpp]

Fordi de ovennevnte inndataparametrene er 5, så utgangsresultatene er de samme. Så hvordan endrer jeg resultatet? Svaret er å endre inngangsparametrene dynamisk. Egentlig kan vi betrakte støy som et ubegrenset talespor, inngangsparametrene er akkurat som "nåtiden". Hvis parameterinngangen er kontinuerlig, vil utgangen også være kontinuerlig.

[cceN_cpp theme = "dawn"] float x, y; ugyldig oppsett () {størrelse (700, 100); x = 0; bakgrunn (0); } ugyldig tegning () {x += 1; y = støy (frameCount/100,0)*100; noStroke (); ellipse (x, y, 2, 2); }

[/cceN_cpp]

I dette tilfellet tegner vi endringsbanen til Y slik at vi kan forstå funksjonsstøy bedre.

• Blant den vil variabel frameCount få den nåværende rammen. Forskjellig fra bredden, høyden i forrige, er den stabil uten endringer. Dessuten begynner den å øke fra 0. Hvis vi forstår det med vår første animerte grafikk, viser den siden vi har vendt oss til (snarere til tidsoppfattelsen i programmet).

• frameCount er en heltallsvariabel. Delt med en annen heltallsvariabel, vil programmet som standard behandle resultatet som et heltall. For å forbedre resultatets nøyaktighet må vi endre 100 til 100,0. Delt med et flytende tall, får vi også et flytende punktnummer.

• For å endre Y -akselen fra 0 til 100, må vi multiplisere resultatet av støy med 100. Dermed kan vi kontrollere det tilfeldige verdiområdet.

Noen av dere som er flinke til å tenke, kan spørre "hvorfor må vi dele frameCountby 100? Er det ikke greit å skrive frameCount direkte?" Selvfølgelig kan du! Men her, for bedre å vise egenskapene til funksjonsstøy, senker vi "kringkastingshastigheten". Eksemplet nedenfor viser endringer i utgangsverdien under forskjellig endringshastighet.

[cceN_cpp theme = "dawn"] float x, y1, y2, y3, y4, y5; ugyldig oppsett () {størrelse (700, 500); x = 0; bakgrunn (0); } ugyldig tegning () {x += 1; y1 = støy (frameCount)*100; y2 = støy (frameCount/10,0)*100; y3 = støy (frameCount/100,0)*100; y4 = støy (frameCount/1000.0)*100; y5 = støy (frameCount/10000.0)*100; noStroke (); ellips (x, y1, 2, 2); ellips (x, y2+100, 2, 2); ellipse (x, y3+200, 2, 2); ellipse (x, y4+300, 2, 2); ellipse (x, y5+400, 2, 2); slag (80); linje (0, 100, bredde, 100); linje (0, 200, bredde, 200); linje (0, 300, bredde, 300); linje (0, 400, bredde, 400); }

[/cceN_cpp]

Du kan betrakte de endrede parametrene i funksjonsstøy som en fremdriftslinje. Endre parameteren er som om vi flytter fremdriftslinjen. Så når det endrede omfanget av dette "stemmesporet" er større, vil de kontinuerlige egenskapene til utgangsverdien foran og bak være svakere. (Vi kan forestille oss hva som vil skje hvis vi sender et musikkstykke eller en video med 2 ganger hastighet, 5 ganger hastighet, 20 ganger hastighet). Når omfanget er større enn en viss verdi, har det ingen stor forskjell å fungere tilfeldig ved verdiskapning.

Hvis du kan forstå alle eksemplene ovenfor, vil du føle at ingenting kan være lettere å tegne en migrerende sirkel. Du kan også forstå de interne prinsippene.

[cceN_cpp theme = "dawn"] float x, y; ugyldig oppsett () {størrelse (300, 300); x = 0; } void draw () {bakgrunn (234, 113, 107); x = støy (frameCount/100,0 + 100)*300; y = støy (frameCount/100,0)*300; noStroke (); ellips (x, y, 50, 50); }

[/cceN_cpp]

Nå er bevegelsen mer interessant akkurat som en roterende gyro.

• Grunnen til at variabel x innenfor funksjonsstøy må pluss 100 er fordi for å skille dem på en avstand. Hvis parametrene til xy innenfor funksjonsstøy er like eller ganske nære, vil endringen av x, y -koordinaten nærme seg det samme. Dette er for å få bevegelsen til å bli mye mer tilfeldig.

Trinn 14: Sirkel flyttet av mus

Deretter kommer vi endelig til to variabler jeg liker best: mouseX og mouseY. Ved første øyekast av de to forestillingene glitrer øynene mine av lys. Fordi det er den mest direkte måten å samhandle med grafikk. Vi kan lage mange interessante programmer med det.

Saken er ganske enkel:

[cceN_cpp theme = "dawn"] int x, y; ugyldig oppsett () {størrelse (300, 300); x = 0; y = 0; } void draw () {bakgrunn (234, 113, 107); noStroke (); x = musX; y = musY; ellips (x, y, 50, 50); }

[/cceN_cpp]

mouseX kan skaffe x -koordinat for musen, mens mouseY kan få y -koordinat.

• La oss prøve å endre positivt og negativt symbol, eller bytte mouseX og mouseY.

Trinn 15: Slutt

Fra disse kjente kommandoene kan du kanskje utføre bevegelse av grafikk. Med innholdet i det siste kapitlet, bruk fantasien din riktig, du kan lage mange interessante animerte effekter.

I vårt neste kapittel kan vi se flere mange eksempler. Samtidig vil vi bruke matematiske funksjoner og kombinere det med grafisk bevegelse.

Denne artikkelen kommer fra designeren Wenzy.

Trinn 16: Relative avlesninger:

Interessant programmeringsveiledning for designer-behandling av første berøring

Interessant programmeringsveiledning for designer-Lag ditt første behandlingsprogram

Denne artikkelen er fra:

Hvis du trenger hjelp, kan du kontakte: [email protected].

Anbefalt: