Aikataulutus ja funktiot

Tähän mennessä ohjelmamme tekee asioita vain silloin, kun pelaaja painaa nappia. Peleissä kuitenkin tapahtuu usein asioita myös pelaajan tekemättä mitään, esimerkiksi pelaajaa saattaa jahdata vihollinen tai pelikentälle ilmestyy vähän väliä keräiltäviä aarteita.

Pygletin kello

Kun jokin tapahtuu omia aikojaan, tarvitsee ohjelman tietää milloin se tapahtuu. Tätä varten pygletistä löytyy clock, eli kello. Kellon kaikki komennot alkavat pyglet.clock.

Kelloa voi käyttää yleisesti ottaen kolmella tavalla:

  1. Kellolla voi aikatauluttaa, että jotain tehdään koko ajan.
  2. Kellolla voi aikatauluttaa, että jotain tehdään tietyn ajan välein, esimerkiksi kerran sekunnissa.
  3. Kellolla voi aikatauluttaa, että jotain tehdään vain kerran tietyn ajan kuluttua, esimerkiksi kolmen sekunnin päästä.

Näitä kellon käyttötapoja vastaavat komennot ovat:

  1. pyglet.clock.schedule(), mikä on englantia ja tarkoittaa pyglet.kello.aikatauluta()
  2. pyglet.clock.schedule_interval(), mikä on suomeksi pyglet.kello.aikatauluta_aikaväli()
  3. pyglet.clock.schedule_once(), mikä on suomeksi pyglet.kello.aikatauluta_kerran()

Komennon lopussa oleviin sulkuihin merkitään mitä aikataulutetaan. Puhutaankin siis seuraavaksi vielä nopeasti mitä nämä aikataulutettavat asiat ovat.

Funktio

Funktiot saattavat olla matematiikan tunnilta tuttuja, mutta ohjelmoinnista funktiot ovat hieman erilaisia. Yksinkertaisesti sanottuna funktio on aliohjelma, eli pieni ohjelma, jota voi käyttää jonkin muun isomman ohjelman sisällä. Olemme tähän mennessä itse asiassa jo käyttäneet funktioita: ikkunatapahtumat nimittäin määritellään funktioina! Pääohjelmamme on itse peli, ja se mitä näppäintä painaessa tehdään on oma pienempi ohjelmansa, jota pelimme käyttää.

Funktion kirjoittaminen aloitetaa sanalla def. Se on lyhenne englannin sanasta define eli määrittele. Sen jälkeen tulee funktion nimi ja sitten sulkuihin mitä arvoja funktiossa halutaan voida käyttää.

kuva funktion määrittelyn eri osista

Kaksoispisteen jälkeen kirjoitetaan mitä funktio tekee. Kaiken funktion koodin tulee olla sisennettyä eli:

def funktio():
    funktion sisältö tulee kirjoittaa näin
    myös uudessa rivissä on sisennys

Tämä on oikein 🠕

Tämä on väärin 🠗

def funktio():
funktion sisältöä ei voi kirjoittaa näin

Funktiot ovat ohjelmoinnin monikäyttöisimpiä työkaluja ja niitä voi hyödyntää paljon muussakin kuin ikkunatapahtumissa ja aikatauluttamisessa. Emme kuitenkaan tutustu funktioiden muihin käyttötarkoituksiin nyt.

Tehdään aikatauluttamalla diskopallo

Nyt voimme jatkaa viimekerran ohjelmaa. Ohjelmoidaan niin, että pallo vaihtaa yhden sekunnin välein väriään seuraavan kuvan mukaisesti, eli punaisesta vihreäksi, vihreästä siniseksi ja sinisestä takaisin punaiseksi.

Aloitetaan määrittelemällä funktio, joka muuttaa pallon väriä. Annetaan funktion nimeksi vaikkapa diskopallo. Aikataulutettavat funktiot tarvitsevat arvokseen ajan jolloin funktiota on viimeksi kutsuttu (käytetty). Tätä arvoa kutsutaan delta-ajaksi ja sitä usein merkitään dt.

Aloitetaan siis funktion kirjoittaminen näin: def diskopallo(dt):

Seuraavaksi mietitään mitä funktion pitää tehdä. Jos pallon väri on punainen, pitää väriksi vaihtaa vihreä. Toisaalta jos väri on vihreä, pitää väristä tulla sininen tai jos väri on sininen, tulee väriksi vaihtua taas punainen.

Lisäksi ohjelmassamme ympyrä voi olla myös valkoinen. Ohjelmoidaan siis, että jos väri on jotain muuta kuin kaavakuvassa, väriksi vaihdetaan aina punainen.

Kokonaisuudessaan funktio näyttää tältä ja se pitää lisätä loppuun ennen koodia pyglet.app.run():

def diskopallo(dt):
    if ympyrä.color == (255, 0, 0):
        ympyrä.color = 0, 255, 0
    elif ympyrä.color == (0, 255, 0):
        ympyrä.color = 0, 0, 255
    elif ympyrä.color == (0, 0, 255):
        ympyrä.color = 255, 0, 0
    else:
        ympyrä.color = 0, 255, 0

Huom! Ehtolauseet menevät värien pilkuista sekaisin, joten värit on laitettu sulkuihin ehtolauseissa.

Nyt kun meillä on funktio mitä aikatauluttaa, aikataulutetaan se!

Koska haluamme, että funktio tapahtuu kerran sekunnissa, käytämme komentoa pyglet.clock.schedule_interval(). Merkitään sulkuihin aikataulutettavan funktion nimi, pilkku ja pilkun jälkeen kuinka monen sekunnin välein haluamme, että funktio tehdään. Koko komento on siis:

pyglet.clock.schedule_interval(diskopallo, 1)

Lisätään komento ohjelmaamme funktion jälkeen, mutta ennen koodia pyglet.app.run().

Nyt meillä on diskopallo!

Koodi tähän mennessä

import pyglet

ikkuna = pyglet.window.Window(width = 800, height = 600)
ympyrä = pyglet.shapes.Circle(x = 400, y = 300, radius = 100)

@ikkuna.event
def on_draw():
	ikkuna.clear()
	ympyrä.draw()

@ikkuna.event
def on_key_press(merkki, muuntaja):
    if merkki == pyglet.window.key.P:
        ympyrä.color = 255, 0, 0
    else:
        ympyrä.color = 0, 0, 255

@ikkuna.event
def on_key_release(merkki, muuntaja):
	ympyrä.color = 255, 255, 255

def diskopallo(dt):
    if ympyrä.color == [255, 0, 0]:
        ympyrä.color = 0, 255, 0
    elif ympyrä.color == [0, 255, 0]:
        ympyrä.color = 0, 0, 255
    elif ympyrä.color == [0, 0, 255]:
        ympyrä.color = 255, 0, 0 
    else:
        ympyrä.color = 255, 0, 0

pyglet.clock.schedule_interval(diskopallo, 1)

pyglet.app.run()

Tehtävät

a) Tee ohjelma, jolla on ikkuna, jonka keskelle piirretään ympyrä.

b) Ohjelmoi ympyrä muuttumaan punaiseksi nappia painamalla. Ympyrän ei siis tarvitse muuttua takaisin valkoiseksi painamisen jälkeen.


Jatka edellisen tehtävän ohjelmaa.

a) Kirjoita funktio, joka vaihtaa ympyrän väriä sekunnin välein alla olevan kuvan mukaan.

<img src=kuvat/diskopallo.png height=”400”>

b) Muuta koodia niin, että väri vaihtuukin kolmen sekunnin välein.

c) Muuta koodia niin, että väri vaihtuukin kahdesti sekunnissa.


Jatka edellisen tehtävän ohjelmaa.

a) Alla on funktio, joka siirtää ympyrän vasempaan alareunaan. Kirjoita tai kopioi se ohjelmaasi.

def alakulmaan(dt):
    ympyrä.x = 0
    ympyrä.y = 0

b) Aikatauluta funktio tapahtumaan kahden sekunnin kuluttua ohjelman käynnistämisestä.


Aloita uusi ohjelma.

a) Tee ohjelma, jolla on ikkuna, jonka keskelle piirretään ympyrä.

b) Kirjoita tai kopioi alla oleva funktio ohjelmaasi.

def siirtyminen(dt):
    if ympyrä.x == 50:
        ympyrä.x = 200
    else:
        ympyrä.x = 50

c) Aikatauluta funktio tapahtumaan kahden sekunnin välein.


Aloita uusi ohjelma.

a) Tee ohjelma, jolla on ikkuna, jonka keskelle piirretään ympyrä.

b) Alla on funktio, joka muuttaa ympyrää. Kirjoita tai kopioi se ohjelmaasi.

def värimuunnos(dt):
    if ympyrä.color[0] > 25:
        ympyrä.color = ympyrä.color[0] - 25, 255, 255

c) Aikatauluta funktio tapahtumaan viisi kertaa sekunnissa (0.2 sekunnin välein).

d) Mitä tapahtuu?


  1. (Haastavampi tehtävä)

Jatka edellistä tehtävää.

Ympyrän väri koostuu kolmesta numerosta: punaisen, vihreän ja sinisen määrästä. ympyrä.color[0] tarkoittaa värin ensimmäistä numeroa, ympyrä.color[1] tarkoittaa värin toista numeroa ja ympyrä.color[2] tarkoittaa kolmatta numeroa.

Edellisen tehtävän funktio onkin siis kutakuinkin näin:

määritele värimuunnos(delta-aika):
    jos ympyrän värin ensimmäinen luku on isompi kuin 25:
        vähennetään ympyrän ensimmäisestä numerosta 25. Muut numerot ovat 255.

c) Muokkaa funktiota niin, että värin ensimmäistä numeroa muutetaan vähemmän.

b) Muokkaa funktiota niin, että siinä muutetaankin ainoastaan värin toista numeroa.

c) Muuta funktiota niin, että siinä muutetaan toista ja kolmatta numeroa.


  1. (Haastavampi tehtävä)

Aloita uusi ohjelma.

Ympyrällä on muitakin ominaisuuksia kuin väri ja sijainti. Yksi näistä on ympyrän säde. Ympyrän säde on tallennettuna muuttujaan ympyrä.radius. Radius on englantia ja tarkoittaa sädettä.

<img src=kuvat/säde.png height=”400”>

a) Tee ohjelma, jolla on ikkuna, johon piirretään ympyrä.

b) Koodi ympyrä.radius = ympyrä.radius + 1 suurentaa säteen kokoa yhdellä. Kirjoita funktio, joka suurentaa säteen kokoa viidellä.

c) Aikatauluta tämä funktio tapahtumaan puolen sekunnin välein. Mitä ohjelma tekee?


  1. (Haastavampi tehtävä)

Jatka edellisen tehtävän ohjelmaa.

a) Muokataan koodia niin, että säteellä on jokin maksimikoko. Muokkaa funktiota siis niin, että kokoa suurennetaan vain jos säteen koko on pienempi kuin 300.

Vinkki! x < 7 testaa onko x pienempi kuin seitsemän.

b) Muokkaa ohjelmaa niin, että muussa tapauksessa säteen kooksi asetetaan 10.