PELIOHJELMOINNIN ALKEET

Nyt olemme käsitelleet, joskin melko lyhyesti, ehtolauseet, toistolauseet ja funktiot. Seuraavaksi alamme koodaamaan pelejä Pygame-kirjastolla.

Ikkuna

Pygame on Python-kirjasto, jonka avulla teemme pelejä. Ikkuna on Pygame-pelin pohja: ilman ikkunaa ei voi olla peliä. Kaikki pelin elementit tullaan sijoittamaan ikkunaan. Luodaan ensin ikkuna Pygamella seuraavalla koodilla (kopioi koodi editoriisi ja aja se):

import pygame

naytto = pygame.display.set_mode((640, 400))
pygame.display.set_caption("Ensimmäinen peli")

def main():
    while True:
        tapahtuma = pygame.event.poll()
        if tapahtuma.type == pygame.QUIT:
            break

main()
Ohjelman tulisi luoda seuraavanlainen ikkuna:


Ikkunaohjelman rakenne

Nyt on aika katsoa tarkemmin ohjelman koodin rakennetta.

Ensimmäinen rivi tulee jokaisen ohjelmamme alkuun. Tämä rivi ottaa käyttöön peliohjelmointiin tarkoitetun pygame-kirjaston.

import pygame

Seuraava rivi luo ikkunan, jonka leveys on 640 pikseliä ja korkeus on 400 pikseliä:

naytto = pygame.display.set_mode((640, 400))

Seuraava rivi määrittää ikkunan otsikon:

pygame.display.set_caption("Ensimmäinen peli")

Tämän jälkeen määritellään pääohjelmafunktio. Funktiossa main on ohjelman pääsilmukka. Pääsilmukassa kuunnellaan käyttäjän tekemiä toimintoja, ja odotetaan niin kauan, kunnes syntyy tapahtuma pygame.QUIT. Tapahtuma pygame.QUIT syntyy esimerkiksi silloin, kun käyttäjä sulkee ohjelman painamalla ikkunan oikeassa ylänurkassa olevaa raksia. Lisäämme myöhemmin ohjelmaan lisää peliin liittyvää koodia.

def main():
    while True:
        tapahtuma = pygame.event.poll()
        if tapahtuma.type == pygame.QUIT:
            break

Tämän jälkeen, ohjelman "viimeisellä" rivillä, on komento main(), joka suorittaa main-funktiossa olevan koodin.

Piirtäminen

Värit

Tavallinen tapa ilmoittaa väri ohjelmoinnissa on käyttää RGB-merkintää. RGB tulee sanoista "red-green-blue" eli "punainen-vihreä-sininen". Sekoittamalla punaista, vihreää ja sinistä saadaan kaikki värit. Jokaisen värin osan määrä annetaan lukuna väliltä 0–255.

Esimerkkejä RGB-väreistä:

  • musta: (0, 0, 0)
  • valkoinen: (255, 255, 255)
  • punainen: (255, 0, 0)
  • vihreä: (0, 255, 0)
  • sininen: (0, 0, 255)
  • keltainen: (255, 255, 0)
  • tummanharmaa: (100, 100, 100)
  • vaaleanharmaa: (200, 200, 200)

Viiva

Seuraava koodi näyttää ikkunan, jossa on sininen viiva:

import pygame

naytto = pygame.display.set_mode((640, 400))
pygame.display.set_caption("Piirtäminen")

def main():
    while True:
        tapahtuma = pygame.event.poll()
        if tapahtuma.type == pygame.QUIT:
            break

        naytto.fill((0, 0, 0))
        pygame.draw.line(naytto, (0, 0, 255), (100, 50), (400, 370))
        pygame.display.flip()

main()

Huomaamme että ohjelmarunko on hyvin samanlainen kuin johdanto-osassa. Tässä olemme lisänneet pääsilmukkaan komennot naytto.fill, pygame.draw.line ja pygame.display.flip. Komento naytto.fill täyttää näytön mustalla värillä. Komento pygame.draw.line taas piirtää viivan, ja se saa parametreina seuraavanlaisia asioita:

pygame.draw.line(naytto, (red, green, blue), (alkux, alkuy), (loppux, loppuy))

Parametrit ovat arvoja, joita komennoille voidaan antaa. Yllä olevalle pygame.draw.line-komennolla annetaan parametrina naytto, johon viiva piirretään, piirrettävän viivan väri punaisen, sinisen ja vihreän yhdistelmänä, viivan alkupisteen x- ja y-koordinaatit, sekä viivan loppupisteen x- ja y-koordinaatit.

Näiden lisäksi tarvitaan komento pygame.display.flip, joka näyttää juuri piirretyt asiat näytöllä.

Ohjelman suoritus näyttää seuraavalta:




Tehtävä 1: Rasti

Tee ohjelma joka piirtää seuraavanlaisen kuvion. Väreinä siis sininen ja vihreä.


Laatikko

Seuraava koodi näyttää ikkunan, jossa on punainen laatikko:

import pygame

naytto = pygame.display.set_mode((640, 400))
pygame.display.set_caption("Piirtäminen")

def main():
    while True:
        tapahtuma = pygame.event.poll()
        if tapahtuma.type == pygame.QUIT:
            break

        naytto.fill((0, 0, 0))
        pygame.draw.rect(naytto, (255, 0, 0), (100, 50, 150, 200))
        pygame.display.flip()

main()
 

Tässä komento pygame.draw.rect piirtää laatikon. Komennon käyttötapa on seuraava:

 pygame.draw.rect(naytto, (red, green, blue), (alkux, alkuy, leveys, korkeus))
 

Ohjelman suoritus näyttää seuraavalta:



Ympyrä

Seuraava koodi näyttää ikkunan, jossa on keltainen ympyrä:

import pygame

naytto = pygame.display.set_mode((640, 400))
pygame.display.set_caption("Piirtäminen")

def main():
    while True:
        tapahtuma = pygame.event.poll()
        if tapahtuma.type == pygame.QUIT:
            break

        naytto.fill((0, 0, 0))
        pygame.draw.circle(naytto, (255, 255, 0), (350, 150), 40)
        pygame.display.flip()

main()

Tässä komento pygame.draw.circle piirtää ympyrän. Komennon käyttötapa on seuraava:

pygame.draw.circle(naytto, (red, green, blue), (keski-x, keski-y), säde)

Ohjelman suoritus näyttää seuraavalta:



Kuvan piirtäminen

Seuraava koodi näyttää ikkunan, jossa on Scratchista tuttu kissa (kuva Wikimedia Commons). Kuva on cat.png -tiedostossa, ja kuvatiedosto on ja tulee olla samassa kansiossa kooditiedoston kanssa. Vain siten koodi löytää kuvatiedoston.

import pygame

naytto = pygame.display.set_mode((640, 400))
pygame.display.set_caption("Piirtäminen")
x = 100
y = 200

def main():
    while True:
        tapahtuma = pygame.event.poll()
        if tapahtuma.type == pygame.QUIT:
            break

        naytto.fill((0, 0, 0))
        kuva = pygame.image.load("cat.png").convert()
        naytto.blit(kuva, (x, y))
        pygame.display.flip()

main()

Lopputulos näyttää tältä:


Tehtävä 2: Oma pelihahmo

Piirrä oma pelihahmo ja sijoita se ruudulle kohtaan x = 400, y = 400. Käytä hieman aikaa hahmon piirtämiseen, sillä tulet tarvitsemaan hahmoa myöhemmin peliohjelmointia harjoitellessa.

Tehtävä 3: Kuvan piirtävä funktio

Tee funktio piirraKuva, joka ottaa parametrina kuvatiedoston nimen merkkijonona, x-koordinaatin sekä y-koordinaatin, ja piirtää kuvan annettujen tietojen mukaan.

Tehtävä 4: Hahmo satunnaiseen sijaintiin

Tee ohjelma, joka sijoittaa hahmon satunnaiseen sijaintiin kentälle piirtämälläsi kuvalla. Ohjelman tulee käyttää edellisen tehtävän piirraKuva -funktiota. Laske hahmon sijainti uudelleen jokaisella while True -silmukan suorituskerralla. Lopputuloksesta huomaat kuinka näyttää siltä että hahmo "liikkuu" paikasta toiseen.

Koodin jäsentäminen

piirraKuva -funktio ei vielä riitä, että voisimme siirtyä seuraavaan vaiheeseen eli kontrollien ottamiseen mukaan peliimme. Jäsennellään nyt koodia niin, että piirtäminen ja kontrollit tapahtuvat kokonaan eri funktioissa. Kopioi allaoleva koodi itsellesi seuraavan vaiheen pohjaksi, mutta vaihda kuvatiedostonimen tilalle oman hahmosi tiedostonimi. piirtaminen -funktio ottaa parametrina muuttujat naytto ja hahmot. hahmot taas on lista, joka sisältää listan ["cat.png", 100, 100, True]. Listan ensimmäinen alkio on kuvatiedoston nimi, toinen alkio x-koordinaatti ja kolmas alkio y-koordinaatti. Neljännen alkion on tarkoitus olla aina joko True tai False sen mukaan, piirretäänkö hahmo vai ei.

piirtaminen -funktiossa käydään läpi jokainen hahmot -listan lista. Tässä tapauksessa for hahmo in hahmot - silmukan sisällölle tulee vain yksi toistokerta koska hahmot -lista sisältää vain yhden hahmon. Mikäli hahmolistan neljäs alkio on True, hahmo piirretään.

kontrolli -funktiota kutsutaan pelin pääsilmukassa eli while True -lohkossa, mutta tällä hetkellä
tulostaa vain "Kontrolli".

import pygame

naytto = pygame.display.set_mode((640, 400))
pygame.display.set_caption("Piirtäminen")


def piirraKuva(kuvatiedosto, x, y):
    naytto.blit(kuvatiedosto, (x, y))

def piirtaminen(naytto, hahmot):
    naytto.fill((0, 0, 0))
    for hahmo in hahmot:
        if hahmo[3] == True:
            kuva = pygame.image.load(hahmo[0]).convert()
            naytto.blit(kuva, (hahmo[1], hahmo[2]))
    pygame.display.flip()

def kontrolli(hahmot, tapahtuma):
    print("Kontrolli")

def main():
    kissahahmo = ["cat.png", 100, 100, True]
    hahmot = [kissahahmo]
    while True:
        tapahtuma = pygame.event.poll()
        if tapahtuma.type == pygame.QUIT:
            break
        kontrolli(hahmot, tapahtuma)
        piirtaminen(naytto, hahmot)


main()

Kontrolli

Muistat ehkä Scratchista kontrollit. Seuraavassa muistutus:



Seuraavaksi toteutamme toiminnallisuuden, jolla pelihahmo ilmestyy näytölle vasta kun painetaan välilyöntiä. Kopioi seuraava koodi, mutta lue se tarkasti, sillä seuraavassa tehtävässä sinulla pitää olla ymmärrystä mitä kontrollikoodi tekee.

import pygame

naytto = pygame.display.set_mode((640, 400))
pygame.display.set_caption("Piirtäminen")


def piirraKuva(kuvatiedosto, x, y):
    naytto.blit(kuvatiedosto, (x, y))

def piirtaminen(naytto, hahmot):
    naytto.fill((0, 0, 0))
    for hahmo in hahmot:
        if hahmo[3] == True:
            kuva = pygame.image.load(hahmo[0]).convert()
            naytto.blit(kuva, (hahmo[1], hahmo[2]))
    pygame.display.flip()

def kontrolli(hahmot, tapahtuma):
    if tapahtuma.type == pygame.KEYDOWN:
        if tapahtuma.key == pygame.K_SPACE:
            hahmot[0][3] = True

def main():
    kissahahmo = ["cat.png", 100, 100, False]
    hahmot = [kissahahmo]
    while True:
        tapahtuma = pygame.event.poll()
        if tapahtuma.type == pygame.QUIT:
            break
        kontrolli(hahmot, tapahtuma)
        piirtaminen(naytto, hahmot)


main()

Tehtävä 5: Kaksi hahmoa

Piirrä toinen hahmo ja lisää sen piirtäminen haluamaasi sijaintiin koodiisi. Ohjelman tulee toimia niin, että alussa näyttö on musta, ja kun painetaan välilyöntiä niin molemmat hahmot ilmestyvät näytölle.

Vinkkejä: Sinun täytyy ensin muokata main -funktion hahmot -listaa siten että se sisältää myös toiselle hahmolle oman listaelementin. Jos et ole varma mitä hahmot -listasi sisältää ohjelman suorituksessa, kannattaa esimerkiksi tulostaa se print(hahmot) -koodilla ennen pelin pääsilmukkaa eli while True -toistolausetta. Kun hahmot-listalla on oikea sisältö, myös kontrolli -funktio vaatii muokkausta siten että kaikkien hahmot-listan listaelementtien viimeinen arvo asetetaan True:ksi.

Erilaisia näppäimiä

Pysähdytään tutkimaan riviä

 if tapahtuma.key == pygame.K_SPACE 

tapahtuma.key kertoo, mitä näppäintä käyttäjä painoi. pygame.K_SPACE taas on välilyöntinäppäimen koodi. Ehto siis tarkistaa, onko käyttäjän painama näppäin välilyöntinäppäin. Seuraavassa taulukossa on koodeja yleisimmille pelien kontrolleihin tarvittaville näppäimille.
Pygame-koodi näppäin
K_SPACE välilyönti
K_RIGHT oikea nuolinäppäin
K_LEFT vasen nuolinäppäin
K_DOWN alaspäin -nuolinäppäin
K_UP ylöspäin -nuolinäppäin
K_ESCAPE esc
K_0 Numeronäppäin 0. Muut numeronäppäinkoodit ovat samaa muotoa K_numero, eli esimerkiksi K_5.
K_a Kirjainnäppäin a. Muut kirjainnäppäinkoodit ovat samaamuotoa K_kirjain, eli esimerkiksi K_b.

Tehtävä 6: Päähahmo liikkumaan nuolinäppäimillä

Tästä lähtien pelisi päähahmo, tai päähenkilö, on hahmot -listan ensimmäinen hahmo. Tehtävänäsi on toteuttaa tälle hahmolle nuolinäppäimillä liikkuminen. Se toteutetaan niin, että kontrolli -funktioon lisätään ehtoja eri näppäimille. Seuraavassa koodissa kontrolli -funktioon on lisätty elif -lohko, jossa otetaan hahmot-listasta ensimmäinen alkio ja tallennetaan se muuttujaan päähahmo . Päähahmon x-koordinaattia kasvatetaan 10:llä.

Toteuta kontrolli -funktioosi muut elif-lohkot muille nuolinäppäimille ja testaa että ohjelmasi toimii. Vinkki: Hahmo liikkuu oikealle, kun x-koordinaatti kasvaa. Hahmo liikkuu alaspäin, kun y-koordinaatti kasvaa.

def kontrolli(hahmot, tapahtuma):
    if tapahtuma.type == pygame.KEYDOWN:
        if tapahtuma.key == pygame.K_SPACE:
            for hahmo in hahmot:
                hahmo[3] = True
        elif tapahtuma.key == pygame.K_RIGHT:
            päähahmo = hahmot[0]
            päähahmo[1] += 10

Tehtävä 7: Hahmon liikkumisen rajaus näytölle

Kokeile liikuttaa hahmoa ikkunan rajojen yli pois näkyvistä. Ei ole hyvä että hahmo voi liikkua ikkunan rajojen ulkopuolelle, joten tehtävänä on nyt koodata tarkistukset, joiden avulla ei ole mahdollista että hahmo liikkuu ikkunan ulkopuolelle.

Vinkki: Tarvitset tarkistuksissa sekä koko näytön pituutta sekä leveyttä. Kuvan sijainti määrittyy Pygamessa kuvan vasemman yläkulman mukaan. Siispä tulet huomaamaan, että jos esimerkiksi pienimpänä mahdollisena x-koordinaattina 0 ja suurimpana mahdollisena x-koordinaattina 640 (eli näytön leveys), vasemmalle mentäessä hahmo pysähtyy näkyviin näytölle ja oikealle mennessä se menee näytön yli ja pysähtyy vasta ikkunan ulkopuolelle. Tämä ei kuitenkaan haittaa kunhan hahmo pysähtyy. Muista käyttää x-koordinaattien tarkistuksessa näytön leveyttä ja y-koordinaattien tarkistuksessa näytön korkeutta.