Nuorten koodauskerho 2016 - syksyn 4. kerran tehtävät

Tämän kerran tehtävät ovat extratehtäviä, eikä niistä saa pisteitä, mutta niiden teko on silti erittäin suositeltavaa.

Tällä kerralla on kaksi jouluteemaista tehtävää, joissa sovelletaan aikaisempien kertojen materiaalia ja lopusta löytyy tutoriaali, jossa tehdään Jypelillä lumisadetta.

Lumiukkotehtävä

Mallikuva lumiukosta
Mallikuva lumiukosta

Piirrä yllä olevan näköinen lumiukko. Pään pitää olla halkaisijaltaan tasan 32 yksikköä leveä. Vartanlon pitää olla 64 ja alaosan 128 yksikköä leveä.

Huom! Asetellessasi palloja, niiden X- ja Y- koordinaatit kuvastavat keskipisteitä, jotka on kuvaan piirretty punaisina pisteinä.

Jos haluat lisähaastetta, niin voit kokeilla tehdä aliohjelman, joka piirtää tietyn kokoisen pallon, ja sitten Begin-aliohjelmassa kutsua tätä aliohjelmaa kolme kertaa.

# kk4-lumiukko

Joulupukin matka

Joulupukki lähtee Korvatunturilta kohti Helsinkiä vakionopeudella 150 kilometriä tunnissa.

Kauanko Joulupukilla kestää saapua Helsinkiin?

Kaupunkien tarkat etäisyydet on laskettu etaisyydet nimiseen taulukkoon valmiiksi. Yllä olevassa kuvassa etäisyydet on pyöristetty kilometrin tarkkuuteen. Tehtävänäsi on laskea paljonko matkaa tulee yhteensä ja kauanko aikaa sen matkustamiseen menee Joulupukilta.

Korvatunturin ja Rovaniemen välisen tarkan etäisyyden saa näin:

etaisyydet[0]

Rovaniemen ja Kuusamon välisen saa näin:

etaisyydet[1]

Ja niin edespäin.

Vinkki: Silmukan käyttö tehtävän ratkaisussa on erittäin suositeltavaa.

# kk4-reitti

Lumisadetutoriaali

Tässä ohjeessa neuvotaan, miten Jypelillä voi tehdä lumisade-efektin. Valmis efekti näyttää tältä

Projektin aloittaminen

Aloitetaan luomalla uusi Fysiikkapeli-tyyppinen projekti.

Avaa Visual Studio tietokoneellesi ja valitse New Project. Valitse vasemmalta Jypeli-kategoria ja klikkaa yhden kerran Fysiikkapeli-projektimallia.
Huom! Älä tuplaklikkaa, koska muuten projektin nimeksi tulee automaattisesti Fysiikkapeli1 ja se tallentuu väärään paikkaan.

Vaihda projektin nimeksi Lumihiutaleita ja vaihda tallennushakemistoksi oma hakemistosi eli yliopiston tietokoneella esim. C:\MyTemp\JouniP\ (korvaa nimi omalla nimelläsi)
Huom! Peliä ei voi ajaa yliopiston koneella, jos se sijaitsee jossain muualla kuin MyTemp:ssä! Voit vaihtaa hakemistoa helposti klikkaamalla vieressä olevaa Browse...-painiketta.

Ruudun oikeassa laidassa on Solution Explorer -niminen ikkuna. Avaa siitä tiedosto Lumihiutaleita.cs muokattavaksi tuplaklikkaamalla sen nimeä.

Aliohjelma lumihiutaleen luomiseksi

Haluamme tehdä aliohjelman, joka luo pelimaailmaan yhden lumihiutaleen.

Pyyhi pois kommenttirivi:

// TODO: Kirjoita ohjelmakoodisi tähän

Kirjoita sen tilalle seuraava aliohjelmakutsu:

LuoLumihiutale();

Visual Studio valittaa Error List -ikkunassa sekä punaisella alleviivauksella, että sen nimistä aliohjelmaa kuin LuoLumihiutale ei ole olemassakaan. Tehdään seuraavaksi sellainen!

Etsi koodista Begin-aliohjelman lopettava aaltosulku }. Oikea kohta koodista näyttää suunnilleen tältä:

        PhoneBackButton.Listen(ConfirmExit, "Lopeta peli");
        Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
    }

Älä koske näihin riveihin, vaan kirjoita }-merkin alapuolelle seuraava aliohjelman esittely:

    public void LuoLumihiutale()
    {
        
    }

Huomaa, että aliohjelman esittelyrivin loppuun EI tule puolipistettä ; lainkaan, vaikka Visual Studio saattaakin sellaisen puutteesta vihjata, vaan heti seuraavalla rivillä on oltava aliohjelman aloittava {-sulku. Kun aaltosulut kirjoittaa paikalleen, koodi on jälleen toimivaa.

Lisää vasta tekemäsi aliohjelman aaltosulkujen { ja } väliin seuraavat koodirivit:

        PhysicsObject hiutale = new PhysicsObject(10.0, 10.0);
        Add(hiutale);

Kokeile kääntää ja ajaa ohjelma painamalla näppäimistöltä F5 tai klikkaamalla vihreää Start-nuolikuvaketta yläpalkista! Pois pääset painamalla Esc-näppäintä tai Alt+F4.

Nyt meillä on aliohjelma, joka osaa luoda lumihiutaleen! Se näyttää kyllä vielä kovin pikselimäiseltä laatikolta, mutta annetaan lumisade-efektimme aluksi ollakin sellainen.

Lisätään painovoima

Laatikkomainen lumihiutale ei näytä kovin lumimaiselta, jos se ei liiku lainkaan.

Lisätään seuraavaksi ohjelmaan painovoima.

Lisää Begin-aliohjelmaan aaltosulkujen väliin, esim. näppäinkuuntelijoiden jälkeen, mutta ennen lopettavaa }-aaltosulkua, seuraava rivi:

Gravity = new Vector(0.0, -200.0);

Tämä rivi saa kaikki ruudulle lisätyt fysiikkaoliot liikkumaan y-suunnassa -200 yksikön verran.

Kokeile ohjelmaa painamalla F5!

Hiutaleen heiluminen edestakaisin

Jotta palikkamme näyttäisi enemmän lumihiutaleelta, muokataan se heilumaan eli oskilloimaan edestakaisin vaakasuunnassa.

Lisää LuoLumihiutale-aliohjelman aaltosulkujen { ja } väliin ennen riviä Add(hiutale) seuraava rivi:

            hiutale.Oscillate(new Vector(1, 0), 50.0, 1.0);

Oscillate on jokaisella PhysicsObject-tyyppisellä oliolla oleva metodi (eli olion aliohjelma), joka ottaa vastaan vähintään kolme parametria: liikkeen suunnan, liikkeen suuruuden ja liikkeen nopeuden. Ensimmäinen parametreista new Vector(1, 0) kertoo, että halutaan liikkua x-suunnassa, mutta ei y-suunnassa ollenkaan. Vektorin pituudella (eli lukujen suuruudella)ei ole tässä merkitystä, ainoastaan suunnalla.

Hiutaleen elämän pituus

Ennen kuin lisäämme useampia lumihiutaleita, täytyy ottaa huomioon, että jokainen hiutale jatkaa matkaansa ruudun ulkopuolella. Jos hiutaleita tehtäisiin koko ajan lisää, kaikki vanhatkin hiutaleet putoaisivat yhä ruudun ulkopuolella ja jatkaisivat matkaansa ikuisuuksia! Se ei olisi kovin järkevää, koska mitä enemmän pelimaailmassa on olioita, sitä hitaammaksi peli muuttuu.

Korjataan tilanne lisäämällä LuoLumihiutale-aliohjelmaan seuraava rivi:

        hiutale.LifetimeLeft = new TimeSpan(0, 0, 2);

Nyt hiutale häviää 0 tunnin, 0 minuutin ja 2 sekunnin päästä pelimaailmasta!

Hiutaleen aloitussijainti järkevämmäksi

Hiutale lähtee liikkeelle pelimaailman keskipisteestä, origosta, koordinaateista (0, 0).

Haluaisimme, että voisimme vaihtaa sen paikan korkeammalle.

Tehdään aliohjelmaan LuoLumihiutale seuraava lisäys ennen kuin komennolla Add(hiutale); lisätään lumihiutaletta pelikentälle:

        Vector aloituspaikka = new Vector(0.0, 250.0);
        hiutale.Position = aloituspaikka;

Kokeile, miten ohjelma muuttuu painamalla F5!

Hiutaleen olemassaoloajan parantelu

Jos haluat, että hiutale elää hieman pidempään pelikentällä, voit pidentää aikaa kahdesta sekunnista pidemmäksi!

Useampia hiutaleita

Tehdään testin vuoksi peliin kaksi hiutaletta!

Lisää Begin-aliohjelmaan toinen kappale kutsuriviä:

    LuoLumihiutale();

Samanlaisia rivejä tulee siis olemaan kaksi peräkkäin! Toinen niistä oli jo olemassa:

    LuoLumihiutale();
    LuoLumihiutale();

Kokeile painamalla F5!

Huomaat, että näkyvissä on vain yksi lumihiutale. Se johtuu siitä, että molemmat hiutaleet ovat tasan samassa kohdassa!

Hiutaleen aloituspaikan hienosäätöä

Haluaisimme, että eri hiutaleet voisivat sijaita eri koordinaateissa. Lisää LuoLumihiutale-aliohjelman esittelyriville sulkujen sisään Vector aloituspaikka, jotta se otetaankin vastaan parametrina.

Etsi esittelyrivi:

    public void LuoLumihiutale()

Esittelyrivin pitäisi näyttää muutoksen jälkeen tältä:

    public void LuoLumihiutale(Vector aloituspaikka)

Pyyhi pois aliohjelman sisältä seuraava rivi, jotta aloituspaikka-nimistä muuttujaa ei olisi esiteltynä kahta kertaa:

            Vector aloituspaikka = new Vector(0.0, 250.0);

Ohjelma ei vielä ole käännettävissä, koska LuoLumihiutale-aliohjelmaa pitää kutsua niin, että sulkujen sisään antaa parametriksi sen koordinaatin, johon luotava lumihiutale halutaan tehdä.

Muokataan kutsurivejä. Etsi seuraavat kutsurivit:

    LuoLumihiutale();
    LuoLumihiutale();

Muuta ne seuraavanlaisiksi lisäämällä sulkujen sisään uudet sijainnit:

    LuoLumihiutale(new Vector(0, 250));
    LuoLumihiutale(new Vector(-100, 250));

Nyt toinen hiutaleista on x-suunnassa ruudun keskellä ja toinen siitä vasemmalla päin sadan koordinaattiyksikön päässä.

Kokeile painamalla F5!

Yläreunan koordinaatti ei ole välttämättä 250

Lukuarvo 250 ei välttämättä ole aivan kentän yläreunassa. Riippuu pelistä ja sen pelimaailman koosta, mikä milloinkin on yläreunan koordinaatti. Yläreunaan voidaan kuitenkin lukuarvosta riippumatta viitata näin: Level.Top

Vaihdetaan lukujen 250 tilalle Level.Top:

        LuoLumihiutale(0, Level.Top);
        LuoLumihiutale(-100, Level.Top);

Kameran zoomaus

Kentän yläreuna ei vieläkään välttämättä ole aivan ikkunan ylälaidassa. Zoomataan näkymää niin, että koko pelikenttä on kerralla näkyvissä: Lisää Begin-aliohjelmaan seuraava rivi:

        Camera.ZoomToLevel();

Lumihiutaleiden luominen sattumanvaraisiin paikkoihin

Tehdään uusi aliohjelma, joka tekee yhden lumihiutaleen sattumanvaraiseen aloituskoordinaattiin.

Lisätään ensin esittelyrivi aliohjelmalle. Haluamme aliohjelmalle nimen LuoSatunnainenHiutale, joten esittelyrivi ja tyhjä runko näyttävät seuraavalta:

    public void LuoSatunnainenHiutale()
    {
        
    }

Huom! Älä kirjoita aliohjelmaa vahingossa toisen aliohjelman sisälle! Oikea paikka on edellisen aliohjelman loppusulun } alapuolelle ennen seuraavan aliohjelman alkua tai koko ohjelman loppusulkua.

Koordinaatin arpominen

Arvotaan koordinaatit uusille lumihiutaleille Jypelistä löytyvän RandomGen-luokan avulla. Tehdään väliaikainen muuttuja satunnainenX, johon sijoitetaan arvottu luku.

        double satunnainenX = RandomGen.NextDouble(Level.Left, Level.Right);

Sen jälkeen käytetään arvottua koordinaattia hyväksi, kun luodaan uusi lumihiutale. Uuden lumihiutaleen luomiseksi oli jo olemassa kätevä aliohjelma LuoLumihiutale, joten hyödynnetään sitä! Sille piti viedä aloituspaikaksi yksi koordinaattivektori, joten luodaan ensin sellainen väliaikaiseen muuttujaan paikka ja viedään se sitten parametrina.

        Vector paikka = new Vector(satunnainenX, Level.Top);
        LuoLumihiutale(paikka);

Lopulta LuoSatunnainenHiutale näyttää tältä:

    public void LuoSatunnainenHiutale()
    {
        double satunnainenX = RandomGen.NextDouble(Level.Left, Level.Right);
        Vector paikka = new Vector(satunnainenX, Level.Top);
        LuoLumihiutale(paikka);
    }

Kun kokeilet ajaa ohjelmaa painamalla F5, huomaat, että hiutaleet ovat yhä samoissa aloituspaikoissa. Se johtuu siitä, että emme kutsuneet satunnaisia paikkoja tekevää aliohjelmaa lainkaan! Vaihda Begin-aliohjelmassa olevia kutsurivejä niin, että ohjelmassa ei kutsuta suoraan aliohjelmaa LuoLumihiutale, vaan aliohjelmaa LuoSatunnainenHiutale. Se ei tarvitse mitään parametreja.

Poista siis rivit

        LuoLumihiutale(new Vector(0, Level.Top));
        LuoLumihiutale(new Vector(-100, Level.Top));

Uudet kutsurivit näyttävät seuraavilta:

        LuoSatunnainenHiutale();
        LuoSatunnainenHiutale();

Kokeile, että muutoksesi toimii painamalla F5.

Jatkuvasti uusia hiutaleita

Lumisade-efekti ei olisi mitään, jos hiutaleita ei olisi enemmän ja jos niitä ei tulisi tasaisesti lisää.

Tehdään ajastin, joka luo tietyin väliajoin uuden satunnaisen lumihiutaleen.

Ota aiemmat kaksi riviä LuoSatunnainenHiutale(); pois pääohjelmasta, ja lisää niiden tilalle seuraavat rivit:

        Timer luontiajastin = new Timer();
        luontiajastin.Interval = 0.25;
        luontiajastin.Timeout += LuoSatunnainenHiutale;
        luontiajastin.Start();

Kokeile painamalla F5!

Kokonaisuus tässä vaiheessa

Lopputulos tässä vaiheessa näyttää suunnilleen tältä:

using System;
using System.Collections.Generic;
using Jypeli;
using Jypeli.Assets;
using Jypeli.Controls;
using Jypeli.Effects;
using Jypeli.Widgets;

public class Lumihiutaleita : PhysicsGame
{
    public override void Begin()
    {
        Timer luontiajastin = new Timer();
        luontiajastin.Interval = 0.25;
        luontiajastin.Timeout += LuoSatunnainenHiutale;
        luontiajastin.Start();

        Gravity = new Vector(0.0, -200.0);

        PhoneBackButton.Listen(ConfirmExit, "Lopeta peli");
        Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
        
        Camera.ZoomToLevel();
    }

    public void LuoSatunnainenHiutale()
    {
        double satunnainenX = RandomGen.NextDouble(Level.Left, Level.Right);
        Vector paikka = new Vector(satunnainenX, Level.Top);
        LuoLumihiutale(paikka);
    }

    public void LuoLumihiutale(Vector aloituspaikka)
    {
        PhysicsObject hiutale = new PhysicsObject(10, 10);
        hiutale.Oscillate(new Vector(1, 0), 50.0, 1.0);
        hiutale.Position = aloituspaikka;
        hiutale.LifetimeLeft = new TimeSpan(0, 0, 2);
        Add(hiutale);
    }

}

Hiutaleiden symmetrian rikkominen: heilumisen vaiheistus

Lumihiutale-efektin lumihiutaleet leijailevat kaikki niin, että ne lähtevät samaan suuntaan. Tasan samaan aikaan luodut lumihiutaleet näyttäisivät menevän täysin symmetrisesti, ja peräkkäinkin lisätyt hiutaleet ovat melko samanlaisia.

Korjataan Oscillate-metodille vietyjä parametreja niin, että lisätään neljäs vapaaehtoinen parametri, joka kertoo, mistä vaiheesta siniaaltoa heiluminen aloitetaan.

        hiutale.Oscillate(new Vector(1, 0), 50.0, 1.0, vaihe);

Vielä ei ole olemassa vaihe-nimistä muuttujaa, mutta esitellään sellainen LuoLumihiutale-aliohjelmalle vietävänä parametrina.

Etsi rivi:

    public void LuoLumihiutale(Vector aloituspaikka)

ja muokkaa sitä seuraavanlaiseksi:

    public void LuoLumihiutale(Vector aloituspaikka, double vaihe)

Jotta aliohjelman kutsuminen toimisi, on kutsuriville lisättävä vaiheen lukuarvo.

Vaihe voi olla mitä tahansa väliltä \(0.0 - 2\pi\).

Haluamme arpoa vaiheen satunnaisesti. Etsi LuoSatunnainenHiutale-aliohjelmasta kohta, jossa LuoLumihiutale-aliohjelmaa kutsuttiin, ja korjaa sitä. Lisätään luvun arpova rivi ja muokataan kutsuriviä.

Lisää virheellisenä näkyvän kutsurivin yläpuolelle seuraavanlainen arvontarivi:

double satunnainenVaihe = RandomGen.NextDouble(0.0, 2 * Math.PI);

Etsi kutsurivi:

LuoLumihiutale(paikka);

Muokkaa sitä niin, että lisäät sen toiseksi parametriksi satunnainenVaihe-muuttujan:

LuoLumihiutale(paikka, satunnainenVaihe);

Lopulta aliohjelmassa on siis rivit:

        public void LuoSatunnainenHiutale()
        {
            double satunnainenX = RandomGen.NextDouble(Level.Left, Level.Right);
            Vector paikka = new Vector(satunnainenX, Level.Top);
            
            double satunnainenVaihe = RandomGen.NextDouble(0.0, 2 * Math.PI);
            
            LuoLumihiutale(paikka, satunnainenVaihe);
        }
        

Viimeiset parantelut

Joskus kaksi lumihiutaletta saattaa törmätä toisiinsa ja ruveta pyörimään. Jos et halua, että laatikot pyörisivät, voit estää törmäysten vaikutukset näin:

hiutale.IgnoresCollisionResponse = true;

Lisää yllä oleva rivi aliohjelmaan LuoLumihiutale.

Voit myös vaihtaa värejä haluamiksesi. Jos haluat vaihtaa hiutaleen väriä joksikin muuksi kirkkaan valkoisesta, se onnistuu näin:

hiutale.Color = Color.Gray;

Gray:n tilalle voit valita minkä tahansa Jypelin tunteman värin.

Jos haluat vaihtaa pelissä oletuksena olevan vaaleansinisen taustan, kirjoita Begin-aliohjelmaan seuraavan kaltainen rivi:

Level.Background.Color = Color.DarkBlue;

Painovoima vaikuttaa kaikkiin hiutaleisiin niin, että niiden vauhti näyttäisi kiihtyvän melko paljon. Nopeutta saa hidastettua hieman näin:

hiutale.LinearDamping = 0.99;

Yllä oleva rivi lisätään LuoLumihiutale-aliohjelman sisälle. Lukuväli on 0-1. Kannattaa käyttää lähellä ykköstä olevia arvoja, esim 0.8 tai 0.99.

These are the current permissions for this document; please modify if needed. You can always modify these permissions from the manage page.