Pirmojo „Android“ žaidimo rašymas naudojant „Corona SDK“

Autorius: Randy Alexander
Kūrybos Data: 1 Balandis 2021
Atnaujinimo Data: 26 Birželio Birželio Mėn 2024
Anonim
Pirmojo „Android“ žaidimo rašymas naudojant „Corona SDK“ - Programos
Pirmojo „Android“ žaidimo rašymas naudojant „Corona SDK“ - Programos

Turinys


Populiariausia „Google Play“ parduotuvės kategorija visada buvo žaidimai. Nors mes visi tikriausiai naudojame tokias svarbiausias produktyvumo programas kaip žiniatinklio naršyklė, el. Pašto klientas ir momentinių pranešimų programa, žaidimai vis dar išlieka svarbi mobiliųjų įrenginių dalis. Taigi nenuostabu, kad daugelis žmonių, kurie nori išmokti kurti „Android“, nori pradėti nuo žaidimo. Be to, būkime nuoširdūs, rašyti žaidimą yra daug smagiau, nei kurti produktyvumo programą!

Oficiali „Android“ kalba yra „Java“, o oficialioji kūrimo aplinka - „Android Studio“. Jei norite pažvelgti į „Java“, aš siūlau mūsų „Java“ pagrindų vadovėlį, o jei norite išmokti rašyti programą naudodamiesi „Android Studio“, tada siūlau susipažinti su mūsų mokymo programa, kaip rašyti pirmąją „Android“ programą. Tačiau „Java“ ir „Android“ studija nėra vieninteliai „Android“ kūrimo būdai. Galimų kalbų ir SDK apžvalgą galite rasti mūsų vadove: Noriu sukurti „Android Apps“ - kokias kalbas turėčiau išmokti?


Vienas iš SDK, paminėtų programavimo kalbų vadove, yra „Corona“, trečiosios šalies SDK, pirmiausia skirtas žaidimams rašyti. Vietoj „Java“ „Corona“ naudoja „Lua“ - greitą scenarijų kalbą, kurią lengva išmokti, tačiau galinga. Tačiau „Corona“ nėra vienintelis mobiliųjų žaidimų SDK, kuris naudoja „Lua“, kiti gerai žinomi pavyzdžiai yra „Cocos2d-X“, „Marmalade“ ir „Gideros“.

Atsisiųskite ir įdiekite

Norėdami pradėti naudoti „Corona“, turėsite atsisiųsti ir įdiegti SDK. Eikite į „Corona“ svetainę ir paspauskite atsisiuntimo mygtuką. Norėdami atsisiųsti rinkinį, turėsite sukurti paskyrą (kuri yra nemokama). Jei norite sukurti faktinį .apk failą, o ne tik paleisti savo programą emuliatoriuje, turėsite įdiegti „Java 7“, tačiau jums nereikės įdiegti „Android SDK“. Norėdami įdiegti „Java 7“ plėtros rinkinį, eikite į „Oracle“ svetainę, ieškokite skyriaus „Java SE plėtros rinkinys 7u79“ ir atsisiųskite savo kompiuterio versiją.


Įdiegę „Corona“, turite ją suaktyvinti. Tai yra vienkartinis procesas, kuris yra nemokamas. Paleiskite „Corona“ treniruoklį ir sutikite su licencija. Įveskite el. Pašto adresą ir slaptažodį, kuriuos naudojote atsisiuntimui, ir spustelėkite Prisijungti.

Projekto pradžia

Iš „Corona Simulator“ spustelėkite „Naujas projektas“. Laukelyje „Programos pavadinimas:“ įveskite savo programos pavadinimą ir palikite numatytuosius nustatymus likusiems nustatymams. Spustelėkite „Gerai“.

Dabar pasirodys trys langai. Pirmieji du yra „Corona Simulator“ ir „Corona Simular Output“. „Corona“ taip pat atidarys failų naršyklės langą, kuriame bus rodomi jūsų projekto failai.

Didžioji dalis projektų katalogo failų (iš jų 23) yra skirti programos piktogramai! Šiuo metu mums svarbiausia byla main.lua, nes čia parašysime savo programos kodą.

Įvadas į Lua

Prieš pradėdami rašyti kodą, turime pasidaryti apžvalgą apie Lua. „Lua“ vertėjas (atsiminkite, kad tai yra scenarijų kalba, o ne sudaryta kalba) galimas „Windows“, „OS X“ ir „Linux“. Tačiau jis yra įmontuotas Koronoje, todėl šiuo metu jums nereikia nieko papildomai įdiegti. Lengviausias būdas žaisti su „Lua“ yra naudoti internetinį tiesioginį demonstracinį filmą.

Internete galite rasti daug gerų vadovėlių apie „Lua“ ir turėtumėte peržvelgti „Lua Reference Guide“, „Programming in Lua“, „The.Lua.Tutorial“ ir „Tutorials Point Lua Tutorial“.

Čia yra nedidelė „Lua“ programa, kuri parodys keletą pagrindinių „Lua“ funkcijų:

vietinė funkcija „doubleIt“ (x) grąžina x * 2 galą i = 1,10,1 padaryti x = doubleIt (i), jei (x == 10), tada spausdinti („dešimt“) dar spausdinti („doubleIt (i)“) pabaigos pabaiga

Aukščiau pateiktas kodas parodo tris svarbius „Lua“ konstruktus: funkcijas, kilpas ir if teiginius. Funkcija „doubleIt“ () yra labai paprasta, ji tiesiog dvigubai viršija parametrą x.

Pagrindinis kodas yra a dėl kilpa nuo 1 iki 10. Tai skambina „doubleIt“ () už kiekvieną pakartojimą. Jei grąžinimo vertė yra 10 (t. Y. Kada i yra 5), ​​tada kodas atspausdinamas „dešimt“, priešingu atveju jis tiesiog išspausdina rezultatą „doubleIt“ ().

Jei turite kodavimo patirties, pavyzdžio kodą turėtų būti pakankamai lengva sekti. Jei norite išmokti pagrindinio programavimo, tada siūlau naudoti kai kuriuos iš aukščiau nurodytų šaltinių, kad galėtumėte patobulinti savo įgūdžius.

Žaidimo rašymas

Rašyti pagrindines programas Koronoje yra paprasta. Jums reikia rūpintis tik viena byla, main.lua, ir leisk Koronai atlikti visus sunkumus. Žaidimas, kurį rašysime, yra paprastas žaidimas „čiaupas“. Ekrano apačioje pritrūks balionas ar bomba. Jei žaidėjas baksnoja į balioną, kuriame surinko tašką, bakstelėjo į bombą, rezultatas bus padalintas iš 2 kaip baudos. Norėdami parašyti kodą, kurį turite redaguoti main.lua. Tai galite padaryti bet kuriame teksto rengyklėje.

„Corona SDK“ turi įmontuotą 2D fizikos variklį, kuris labai palengvina žaidimų kūrimą. Pirmasis žaidimo rašymo žingsnis yra fizikos variklio paleidimas:

vietinė fizika = reikalauti („fizika“) physics.start ()

Kodas yra gana savaime suprantamas. Modulio fizika įkeliama ir inicijuojama, ji priskiriama kintamajam fizika. Norėdami įjungti variklįfizika.start () vadinamas.

Toliau mes sukursime keletą naudingų kintamųjų, kurie bus naudingi ne tik šiam paprastam žaidimui, bet ir sudėtingesniems žaidimams. pusėW ir pusėH išlaikykite pusės ekrano pločio ir pusės ekrano aukščio vertes:

halfW = display.contentWidth * 0.5 halfH = display.contentHeight * 0.5

ekranas objektas yra iš anksto apibrėžtas objektas, kurį „Corona“ suteikia visuotinai prieinamai.

Dabar yra pirmas žingsnis, dėl kurio kažkas įvyksta ekrane:

vietinis „bkg = display.newImage“ („night_sky.png“, halfW, halfH)

Kaip ir tokios savybės kaip turinysAukštis ir turinio plotis, ekranas objektas taip pat turi daug naudingų funkcijų. newImage () funkcija nuskaito vaizdo failą (šiuo atveju .png) ir rodo jį ekrane. Ekrano objektai pateikiami sluoksniais, taigi, kadangi tai yra pirmasis vaizdas, kurį pateikiame ekrane, tada jis visada bus fonas (nebent kodas aiškiai ką nors daro tam pakeisti). Parametrai pusėW ir pusėH liepkite Corona pastatyti atvaizdą viduryje.

Šiuo metu galite paleisti kodą emuliatoriuje ir pamatyti fono paveikslėlį. Jei įrašysite failą, emuliatorius pastebės, kad failas pasikeitė, ir pasiūlys iš naujo paleisti. Jei taip neatsitiks, naudokite Failas-> Paleisti iš naujo.

Kadangi vartotojas surinks taškus už bakstelėjimą ant balionų, turime inicijuoti balų kintamąjį ir ekraną atvaizduoti:

rezultatas = 0 scoreText = display.newText (rezultatas, pusėW, 10)

Rezultatas bus laikomas įsivaizduojamai pavadintame kintamajame rezultatas,ir „scoreText“ yra objektas, kuris rodo rezultatą. Kaip newImage (), newText () įdėkite ką nors į ekraną, šiuo atveju - tekstą. Nuo „scoreText“ yra visuotinis kintamasis, tada tekstą galime pakeisti bet kurioje vietoje. Bet mes prie to greitai pateksime.

Galite iš naujo paleisti emuliatorių ir ekrano viršuje pamatyti 0 rezultatų rodymą.

Kairė: tik fonas. Dešinė: fonas ir rezultatas.

Dabar ateina kažkas šiek tiek sudėtingesnio, bet nesijaudinkite, paaiškinsiu tai eilute po eilutės:

vietinė funkcija balloonTouched (įvykis), jei (event.phase == "prasidėjo"), tada Runtime: removeEventListener ("enterFrame", event.self) event.target:removeSelf () score = score + 1 scoreText.text = score end end

Aukščiau pateiktas kodas nusako funkciją, vadinamą balloonTouched () kuris bus vadinamas kaskart bakstelint oro balioną. Mes dar nesakėme „Corona“ skambinti šia funkcija kiekvieną kartą, kai tik paliečiamas balionas, tai ateis vėliau, bet kai tai padarysime, funkcija paskambins.

Bakstelėjimo arba lietimo įvykiai turi kelis etapus, iš kurių keli yra skirti vilkimui palaikyti. Vartotojas užsideda pirštą ant objekto, tai yra „pradžios“ etapas. Jei jie slenka pirštu bet kuria kryptimi, tai yra „perkelta“ fazė. Kai vartotojas pakelia pirštą nuo ekrano, tai yra „baigta“ fazė.

Pirmoji eilutė balloonTouched () patikrinimai, ar mes esame „pradžios“ etape. Mes norime pašalinti balioną ir padidinti rezultatą, kai tik įmanoma. Jei funkcija dar kartą iškviečiama kitoms fazėms, tokioms kaip „baigta“, tada funkcija nieko nedaro.

Vidujejei teiginys yra keturios kodo eilutės. Pakalbėkime apie du paskutinius pirmuosius, nes jie yra paprastesni.rezultatas = rezultatas + 1 tiesiog padidinkite rezultatą vienu irscoreText.text = rezultatas keičia balo tekstą ekrane, kad jis atspindėtų naują rezultatą. Prisimeni, kaip aš tai pasakiau„scoreText“ buvo globalus ir buvo prieinamas bet kur, ką mes čia darome.

Dabar pirmos dvi eilutės. Kai balionas ar bomba nukrenta ekrano apačioje, jis vis dar egzistuoja programos atmintyje, tiesiog negalite jo pamatyti. Tobulėjant žaidimui, šių ne ekrane rodomų objektų skaičius nuolat didės. Todėl turime turėti mechanizmą, kuris pašalintų objektus, kai jie yra nepastebimi. Mes tai darome atlikdami funkciją, vadinamąišoriniame ekrane, apie kuriuos dar nerašėme. Ši funkcija bus vadinama vieną kartą per kadrą žaidimo metu. Kai balionas bus bakstelėtas, turime jį ištrinti ir pašalinti skambutį, kuris patikrina, ar balionas nepatenka į ekraną.

Linijaevent.target:removeSelf () ištrina balioną. Kai įvyksta lietimas, vienas iš klausytojo funkcijos parametrų yraįvykis parametras. Tai nurodo įvykio funkciją ir tipo įvykius, pvz.renginys.fazė. Čia taip pat nurodoma, kuris balionas buvo bakstelėtas,renginys.target. Pašalinti save () funkcija daro tai, ką sako, daro, ištrina objektą (šiuo atveju balioną).

Prieš tai esanti eilutė pašalina „pradinio kadro“ klausytoją, tai yra funkcija, vadinama kiekvienu kadru, kad būtų galima pamatyti, ar balionas nenukrito nuo ekrano apačios. Pažvelgsime į tai išsamiau, kai ateisime parašytiišoriniame ekrane klausytojo funkcija.

Taigi, norėčiau pakartoti.balloonTouched ()patikrina, ar tai yra lietimo sekos pradžia. Tada pašalinamas „pradinio kadro“ klausytojas - funkcija, kuri vadinama kiekvienu kadru, kad pamatytų, ar balionas nenukrito nuo ekrano apačios. Tada jis ištrina balioną, padidina rezultatą ir parodo naują rezultatą.

Tai buvo balionai, dabar mums reikia kažko panašaus į bombas:

vietinė funkcija „bombTouched“ (įvykis), jei („event.phase ==„ prasidėjo “), tada Runtime: removeEventListener („ enterFrame “, event.self) event.target:removeSelf () score = math.floor (score * 0.5) scoreText.text = rezultatas pabaigos pabaiga

Kaip matote, kodas yra labai panašus, išskyrus tai, kad užuot didinant balą, rezultatas dauginamas iš 0,5 (t. Y. Dalijamas iš 2). matematikos grindys () funkcija suapvalina rezultatą iki artimiausio sveikojo skaičiaus. Taigi, jei žaidėjas turėtų 3 balus ir bakstelėtų bombą, tada naujas rezultatas būtų 1, o ne 1,5.

Aš paminėjau išorinis ekranas () funkcija anksčiau. Ši funkcija bus vadinama kiekvienu kadru, kad būtų patikrinta, ar objektas nedingo ekrane. Štai kodas:

vietinės funkcijos išorinis ekranas („self“, įvykis), jei (self.y == nulis), tada grįžkite į pabaigą, jei (self.y> display.contentHeight + 50), tada Runtime: removeEventListener („enterFrame“, self) self: removeSelf () end end

Skaičiuojant yra situacija, vadinama lenktynių būkle. Čia atsitiks du dalykai, bet vienas gali atsitikti pirmas, o kartais kitas įvykti pirmas. Tai yra varžybos. Kai kurios lenktynių sąlygos yra nematytos, nes atrodo, kad vienas dalykas įvyksta pirmiausia, bet per tą dieną, esant tinkamoms sąlygoms, jie gali sukelti įdomių klaidų, o pirmiausia įvyksta kitas dalykas, o tada sistema sugenda!

Šiame nesudėtingame žaidime yra lenktynių sąlygos, nes du dalykai gali nutikti labai arti vienas kito: bakstelėjus balioną ir išorinis ekranas () iškviečiama funkcija, kad pamatytumėte, ar balionas nenukrito nuo ekrano. Rezultatas yra tai, kad kodas, skirtas ištrinti balioną, gali būti iškviestas, tada - išorinis ekranas () funkcija vadinama (tai vyksta 30 kartų per sekundę). Norėdami apeiti šią keistą įvykių seką, išorinis ekranas () funkcija turi patikrinti, ar y objekto vertė yra nulis (negalioja) arba ne. Jei tai yra nulis tada tai reiškia, kad objektas jau buvo ištrintas, taigi judėkite toliau - tai nėra mūsų ieškomi droidai.

Jei objektas vis dar žaidžiamas, patikrinkite jo vietą, jei jis nutolo 50 taškų nuo ekrano, tada ištrinkite jį ir pašalinkite klausytoją, kad išorinis ekranas () funkcija nebus pakartotinai iškviesta į šį objektą. Kodas tuo įsitikintiišorinis ekranas () vadinamas kiekvienu kadru, yra kito kodo skyriaus dalis.

Visa šio žaidimo prielaida yra ta, kad nauji balionai ar bombos ir toliau kris į ekraną. Todėl mums reikia funkcijos, kuri sukurs arba naują balioną, arba naują bombą:

vietinė funkcija addNewBalloonOrBomb () vietinė startX = math.random (display.contentWidth * 0,1, display.contentWidth * 0,9) if (math.random (1,5) == 1) then - BOMB! vietinė bomba = display.newImage („bomb.png“, startX, -300) physics.addBody (bomba) bomb.enterFrame = offscreen Runtime: addEventListener („enterFrame“, bomb) bomba: addEventListener („touch“, bombTouched) kita - Balioninis vietinis balionas = ekranas.naujas vaizdas („red_balloon.png“, „startX“, -300) „physics.addBody“ (balionas) balloon.enterFrame = išorinis ekrano vykdymo laikas: „addEventListener“ („enterFrame“, balionas) balionas: „addEventListener“ („touch“, balloonTouched) pabaigos pabaiga

Pirmoji funkcijos eilutė nusprendžia, iš kur oro balionas nukris x lėktuvas. Jei balionas ar bomba visada nukrito viduryje, tai nebus labai įdomu! TaigistartX yra atsitiktinis skaičius nuo 10 iki 90 procentų ekrano pločio.

Kitas atsitiktinis skaičius yra pasirinktas nuo 1 iki 5.Jei skaičius yra 1, bomba bus numesta. Jei jis bus 2, 3, 4 ar 5, tada balionas bus numestas. Tai reiškia, kad bombos bus numestos maždaug 20 procentų laiko.

Bombos ir baliono kodas yra gana panašūs. Pirmiausia vaizdas (bomba arba balionas) rodomas naudojantnewImage(). Jos x pozicija tokiastartX o jos y padėtis nustatyta –300, t.y., ekrano viršuje. Priežastis ta, kad mes norime, kad objektas nukristų iš ekrano srities į matomą sritį, o paskui iš apačios. Kadangi mes naudojame 2D fizikos variklį, verta duoti šiek tiek pradinio objekto atstumą, kad jis galėtų nukristi, kad jis galėtų įgyti tam tikrą greitį.

Kvietimas įphysics.addBody () nufotografuoja newImage () ir paverčia jį daiktu fizikos variklyje. Tai labai galinga. Bet kokį vaizdų failą galima padaryti kūnu, kuris reaguoja į sunkumą ir susidūrimus tiesiog paskambinęsfizika.addBody ().

Paskutinės trys bombos ar baliono kodo eilutės nustato klausytojus. Nustatymas„EnterFrame“ nuosavybė nurodo „Corona“, kuri funkcija skambinti kiekvienam kadrui ir skambučiuiKlaida: addEventListener () nustato jį. Galiausiai skambutis įbalionas: addEventListener () „Corona“ nurodo, kuri funkcija skambinti, jei liečiama bomba ar balionas.

Dabar žaidimas yra beveik baigtas. Mums tereikia dar dviejų kodo eilučių:

„addNewBalloonOrBomb () timer.performWithDelay“ (500, „addNewBalloonOrBomb“, 0)

Pirmoji eilutė leidžia tiesiogiai nukviesti bombą ar balionąaddNewBalloonOrBomb (). Antroje eilutėje nustatomas laikmatis, kuris paskambinsaddNewBalloonOrBomb () kas pusę sekundės (500 milisekundžių). Tai reiškia, kad naujas balionas ar bomba kris kas pusę sekundės.

Dabar galite paleisti žaidimą emuliatoriuje.

Čia yra visas main.lua sąrašas, visą šio žaidimo projekto kodą galite rasti čia, „GitHub“.

-------------------------------------------------- --------------------------------------- - - krintantis oro baliono ir bombos žaidimas - Parašė Gary Simsas - ------------------------------------------- ---------------------------------------------- - Pradėkite fizikos variklis vietinė fizika = reikalaujama („fizika“) physics.start () - apskaičiuokite pusę ekrano pločio ir aukščio pusė = ekranas.turinio plotis * 0,5 pusėH = ekranas.sukuriamasis aukštis * 0,5 - nustatykite vietinį fono ekraną bkg = ekranas.naujiena („night_sky.png“, halfW, halfH) - Taškų balas = 0 scoreText = display.newText (balas, halfW, 10) - Skambinamas, kai žaidėjas baksnoja balioną - Padidinkite rezultatą 1 vietine funkcija balloonTouched ( įvykis), jei (event.phase == „prasidėjo“), tada Runtime: removeEventListener („enterFrame“, event.self) event.target:removeSelf () score = score + 1 scoreText.text = score end end - Call, kai bombą baksnoja žaidėjas - Pusė rezultato kaip baudos vietos funkcija bombTouched (event) if (event.phase == „prasidėjo“), tada Runtime: removeEventListener („enterFrame“, event.self) event.target:removeSelf () score = math.floor (score * 0,5) scoreText.text = score end end - ištrinkite objektus, kurie nukrito nuo ekrano apačioje vietinė funkcija (ekranas, įvykis), jei (self.y == nulis), tada grįžkite atgal, jei (self.y> display.contentHeight + 50), tada Runtime: removeEventListener („enterFrame“, self) self: removeSelf () pabaigos pabaiga - pridėkite naują krintančio oro baliono ar bombos vietinę funkciją „addNewBalloonOrBomb“) - „red_ballon.png“ ir „bomb.png“ galite rasti „GitHub“ repo vietiniame startX = math.random (display.contentWidth * 0,1, display.contentWidth * 0,9) if (math.random (1,5) == 1) tada - BOMB! vietinė bomba = display.newImage („bomb.png“, startX, -300) physics.addBody (bomba) bomb.enterFrame = offscreen Runtime: addEventListener („enterFrame“, bomb) bomba: addEventListener („touch“, bombTouched) kita - Balioninis vietinis balionas = ekranas.naujas vaizdas („red_balloon.png“, „startX“, -300) „physics.addBody“ (balionas) balloon.enterFrame = išorinis ekrano vykdymo laikas: „addEventListener“ („enterFrame“, balionas) balionas: „addEventListener“ („touch“, balloonTouched) end end - pridėti naują balioną ar bombą dabar addNewBalloonOrBomb () - Laikykite vis pridedant naują balioną ar bombą kas 0,5 sekundės timer.performWithDelay (500, addNewBalloonOrBomb, 0)

Tolesni žingsniai

Kitas žingsnis - žaisti žaidimą realiame „Android“ įrenginyje. Norėdami sukurti .apk failą, spustelėkite Failas-> Sukurti „Android“ ... ir užpildykite laukus. Rezultatas bus .apk failas, kurį galėsite nukopijuoti į savo įrenginį ir įdiegti. Turėsite įsitikinti, kad sukonfigūravote savo įrenginį, kad būtų galima įdiegti programą iš nežinomų šaltinių. „Amazon“ turi keletą geros informacijos apie tai, nes taip pat turite nustatyti, kad įdiegtumėte „Amazon Appstore“. „Corona“ taip pat turi vadovą, kaip pasirašyti, kurti ir išbandyti savo programą „Android“ įrenginiuose.

Sėkmingai įdiegus žaidimą jūsų įrenginyje, reikia patobulinti žaidimą. Pvz., Kodėl gi nepabandžius pridėti „pop“ ar „sprogimo“ garsų, kai baksteli balionas ar bomba. „Corona“ turi tam skirtą API:media.playEventSound ().

Arba kodėl nepabandžius pridėti trečiojo tipo objektų, tarkime, kad didelis padidinimas padidina dabartinį partitūrą, ar kaip būtų su tam tikra fonine muzika?

Apvyniokite

Žaidimų rašymas su „Corona“ yra gana tiesus, nes SDK tvarko tokius dalykus kaip „OpenGL“ ir apima įmontuotą 2D fizikos variklį. Taip pat „Lua“ lengva išmokti ir ji neturėtų būti sunku tiems, kurie turi bent minimalią programavimo patirtį. „Coronalabs“ svetainėje yra daugybė dokumentų, įskaitant daugybę vadovų ir vadovėlių.

Mažiau nei 100 kodo eilučių turime veikiantį žaidimą. Gerai, kad laimėti neteks jokių prizų, tačiau tai rodo „Corona SDK“ galią ir lankstumą.

„Huawei Watch GT“ dabar galima įsigyti JAV už 200 USD

Lewis Jackson

Birželio Birželio Mėn 2024

Jau praėjo keli mėneiai, kai „Huawei“ pakelbė „Watch GT“, tačiau JAV žmonė dabar gali paiimti naujauią bendrovė išmanųjį laikrodį, kad galėtų umokėti po centą po du Benjaminu....

Atnaujinima, 2019 m. Vaario 19 d. (01:55 val. ET): Jei praleidote galimybę iš ankto užiakyti žaidimų telefoną „Nubia Red Magic Mar Mar“, dabar galite užiakyti įrenginį tieiai iš „Nubia“. Kaino praided...

Žiūrėkite