Arcade-pelien ohjelmointi
Pythonilla ja Pygamella

Chapter 16: Ruudukko pelialueena

16.1 Johdanto

Video: Array Backed Grid

Miinaharava, risti-nolla ja monet seikkailupelit tallentavat pelidataa ruudukkoon. Seuraavassa esimerkissä on risti-nolla pelin pelialusta:

 OO
 X 
X  

...jossa voitaisiin esittää tyhjiä ruutuja ja merkittyjä ruutuja O'a ja X'ä tällä tavalla:

022
010
100

Tätä ruudukkoa voidaan ohjelmoinnissa kutsua kaksiulotteiseksi taulukoksi tai matriisiksi. Taulukon lukuarvot esittävät sitä, mitä kussakin pelilaudan ruudussa pitäisi esittää. Ensimmäisessä esimerkissä, 0 vastaa pelaamatonta pelilaudan ruutua, 1 esittää X, ja luku 2 esittää O.

fig.minesweeper
Figure 16.1: Minesweeper game, showing the backing grid of numbers

Kuvassa 16.1 on esimerkki klassisesta miinaharavapelistä. Esimerrkikuvaan on lisätty myös kaksiulotteinen taulukkoesitys oikealle puolelle, jossa näkyy pelialueen tilanne numeroesityksenä.

Luku 10 esittää miinaa, luku 0 on klikkaamaton ruutu, luku 9 esittää miinoista vapaata aluetta ja luvut 1 - 8 esittävät ympärillä olevissa kahdeksassa ruudussa olevien miinojen määrän. Ruudussa esitetään luku vain, jos pelaaja klikkaa ruutua.

Miinaharavassa on oikeastaan kaksi taulukkoa. Toinen on pelinäkymänä toimiva taulukko ja toinen erillinen taulukko on peliktilannetta kuvaaville numeroille, jossa on mm. pelaajan merkitsemät “liput” miinojen merkkinä.

Klassisissa seikkailupeleissä pelialue luodaan 'tiilikuviolla'. Pelialue voi olla valtavan kokoinen taulukko, jossa jokainen kuvion paikka ja maaston tyyppi on taulukoitu numerona. Maaston tyyppejä on erilaisia; hiekkaa, savea, mutaa, tie, polku, vihreää tai ruskeaa ruohoa jne. Ohjelma Tiled Qt on esitetty kuvassa 16.2 tekee helpottaa tällaisten pelialueiden ja taulukoiden tekemistä.

fig.qt_tiled
Figure 16.2: Using Qt Tiles to create an adventure map

Seikkailupeleissä käytetään samanlaista taulukointitekniikkaa kuin miinaharavapelissäkin. Yksi taulukko (tai taulukkotaso) esittää liikkumisessa käytettävää maastoa, jossa voidaan vaikkapa kävellä. Toinen taulukko voisi esittää taasen niitä kohtia, joissa ei voida liikkua; esim. seinät, puut jne. Jokin taulukkotaso vois sisältää vaaralliset asiat kuten laavaa, pohjattomat kuopat, suon silmäkkeet. Yhteen taulukkoon voidaan laittaa poimittavat objektit ja siirreltävät esineet ja yhdessä taulukossa on aloitustilanteessa olevat monsterit.

Tällaisten 'mappien' lataaminen Python-ohjelmaan on mahdollista, mutta tämän tarkempi eisttäminen ei ole tämän materiaalin tehtävä. Miten 'mapit' saadaan ladattua, voit selvittää tarkemmin esim. tästä projektista PyTMX, josta löytyy mappeihin tarvittavaa koodia.

16.2 Sovellus

Taulukoinnin teoriaa on tullut nyt paljon, joten on aika koodata käytännössä jotain havainnollistavaa. Tässä esimerkissä teemme ruudukon, jossa on valkoisia ja vihreitä ruutuja. Ruudun väri saadaan muutettua vihreäksi klikkaamalla hiirellä. Tämä on ensimmäinen vaihe miinaharava-tyyppisen pelin tekemisessä. Toinen esimerkki voisi olla laivan upotuspeli.

Lataa tästä esimerkkikoodi. Tästä löytyy Pygame-template koodipohja:
ProgramArcadeGames.com/python_examples/f.php?file=pygame_base_template.py

Voit aloittaa tyhjällä Pygame-templatetiedostolla ja seuraamalla alla olevia ohjeita, voit koodata ohjelman itse. Lopullinen ohjelma löytyy tämän kappaleen lopusta, mutta älä ohita tärkeitä opittavia asioita ja kopioi valmista ohjelmaa! Kopioida osaa jokainen, mutta tällaista ohjelmaa ei kaikki osaa tehdä. Nyt on hyvä tilaisuus opetella tämä.

16.2.1 Ruudukon piirtäminen

  1. Aseta peli-ikkunan kooksi 255x255 pikseliä.
  2. Luo muuttujat width, height, ja margin. Aseta muuttujien width ja height arvoksi 20. Tämä asettaa kunkin ruudun koon. Aseta margin muuttujan arvoksi 5, joka määrää ruutujen välissä olevan tilan ja ikkunan reunojen paksuuden. Luo nämä muuttujat ennen ohjelman pääsilmukkaa.
  3. Piirrä valkoinen ruutu vasempaan yläkulmaan ja käytä annettuja arvoja height ja width, jotka edellä määritettiin. (Voit tietenkin asettaa värimäärityksen joksikin muuksi kuin valkoiseksi.) Tähän mennessä tehdyn ohjelman pitäisi näyttää tämän kuvan mukaiselta 16.3.
    step_03
    Figure 16.3: Step 3
  4. Käytä for silmukkaa 10 ruudun piirtämiseen riville. Käytä muuttujan nimenä column for-silmukassa. Lopputulos näyttää yhdeltä pitkältä laatikolta, kunnes teemme ruutujen väliin marginaalit. Katso kuvaa 16.4.
    step_04
    Figure 16.4: Step 4
  5. Säädetään piirtämistä asettamalla ruutujen väliin tyhjää margin muuttujalla. Nyt peli-ikkunan pitäisi näyttää tämän kuvan mukaiselta 16.5.
    step_05
    Figure 16.5: Step 5
  6. Lisää marginaali jokaisen suorakulmion väliin ennen piirtämistä. Tällä tavalla saadaan pikkuruudut näkymään ikkunan reunasta reunaan. Katso kuvaa 16.6.
    step_06
    Figure 16.6: Step 6
  7. Lisää toinen for silmukka, jolla saadaan tehtyä ruudut riveittäin. Muuttuja tähän for silmukkaan nimetään row nimiseksi. Nyt saamme aikaiseksi täyden matriisin ruutuja. Katso kuva 16.7.
    step_07
    Figure 16.7: Step 7

    16.2.2 Matriisin täyttö

  8. Seuraavaksi teemme kaksiulotteisen taulukon. Valitettavasti Python ei ole kaikista helpoin kieli kaksiulotteisen taulukon käsittelyyn. Pythonille löytyy ladattavia kirjastotiedostoja, joissa on käsittelyä helpottavia toimintoja. Tässä esimerkissä emme kuitenkaan käytä näitä. Voit luoda kaksiulotteisen taulukon seuraavan koodiesimerkin avulla:
    # --- Create grid of numbers
    # Create an empty list
    grid = []
    # Loop for each row
    for row in range(10):
        # For each row, create a list that will
        # represent an entire row
        grid.append([])
        # Loop for each column
        for column in range(10):
            # Add a the number zero to the current row
            grid[row].append(0)
    

    Lyhyemmin saman voisi tehdä alla olevalla yhden rivin koodilla. Tätä ei selitetä tarkemmin:

    grid = [[0 for x in range(10)] for y in range(10)]
    

    Käytä toista näistä kahdesta koodista luodaksesi peliruudukko. Sijoita koodi ennen pääohjelmasilmukkaa.

  9. Asetetaan taulukon yhteen soluun malliksi luku 1.

    Kaksiulotteisessa taulukossa taulukon indeksointi esitetään niin, että ensimmäinen indeksi osoittaa rivin ja toinen indeksi osoittaa sarakkeen. Tämä 'rivi-ensin' esitystapa on käytössä useimmissa ohjelmointikielissä. Poikkeuksina mainittakoon Fortran ja MATLAB, joissa käytetään 'sarake-ensin' esitystapaa.

    # Set row 1, column 5 to zero
    grid[1][5] = 1
    

    Aseta tämä koodi ennen pääohjelmasilmukkaa.

  10. Aseta ruudun väri käyttämällä muuttujaa nimeltään color. Sijoita muuttuja siihen kohtaan koodia, jossa suorakulmiot piirretään. Ennen suorakulmioiden piirtämistä määritä colormuuttuja ja anna sille arvoksi WHITE.
  11. Asetetaan ruudukolle taustaväri ja tämän asetuksen lisäksi color muuttujan jälkeen lisätään if lause. If-lauseessa tutkitaan ruudukon grid[row][column] indekseissä olevien solujen arvot. Jos ruudukon solun arvo on 1, vaihdetaan ruudun väri vihreäksi. Ruudukossa pitäisi siis olla nyt yksi vihreä ruutu. Katso kuva 16.8.
    step_11
    Figure 16.8: Step 11
  12. Tulosta näytölle “click”, jos käyttäjä klikkaa hiirellä ruudukkoan ruutua. Katso
    bitmapped_graphics.py esimerkistä, miten saat tutkittua hiiren klikkauksen.
  13. Tulosta hiiren koordinaatit kun käyttäjä klikkaa hiirellä.
    Katso move_mouse.py tiedostosta malli siitä, miten hiiren sijainti saadaan luettua. Katso kuva 16.9.
    step_13
    Figure 16.9: Step 13
  14. Muunna hiiren koordinaatit ruudukon koordinaateiksi ja tulosta siis ruudukon koordinaatit. Muista tässä käyttää 'width' ja 'height' arvoja ruudukon paikkatietona ja huomio myös 'margin'. Lopulliset arvot on vielä muutettava kokonaisluvuiksi. Tämä voidaan tehdä joko käyttämällä int tai käyttämällä kokonaislukujakoa // normaalin jakolaskuoperaattorin / sijasta. Katso kuva 16.10.
    step_14
    Figure 16.10: Step 14
  15. Vaihda se ruudukon ruudun väri vihreäksi, jota käyttäjä klikkasi. Katso kuva 16.11.
    step_15
    Figure 16.11: Step 15

16.2.3 Lopullinen ohjelma

"""
 Example program to show using an array to back a grid on-screen.

 Sample Python/Pygame Programs
 Simpson College Computer Science
 http://programarcadegames.com/
 http://simpson.edu/computer-science/

 Explanation video: http://youtu.be/mdTeqiWyFnc
"""
import pygame

# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

# This sets the WIDTH and HEIGHT of each grid location
WIDTH = 20
HEIGHT = 20

# This sets the margin between each cell
MARGIN = 5

# Create a 2 dimensional array. A two dimensional
# array is simply a list of lists.
grid = []
for row in range(10):
    # Add an empty array that will hold each cell
    # in this row
    grid.append([])
    for column in range(10):
        grid[row].append(0)  # Append a cell

# Set row 1, cell 5 to one. (Remember rows and
# column numbers start at zero.)
grid[1][5] = 1

# Initialize pygame
pygame.init()

# Set the HEIGHT and WIDTH of the screen
WINDOW_SIZE = [255, 255]
screen = pygame.display.set_mode(WINDOW_SIZE)

# Set title of screen
pygame.display.set_caption("Array Backed Grid")

# Loop until the user clicks the close button.
done = False

# Used to manage how fast the screen updates
clock = pygame.time.Clock()

# -------- Main Program Loop -----------
while not done:
    for event in pygame.event.get():  # User did something
        if event.type == pygame.QUIT:  # If user clicked close
            done = True  # Flag that we are done so we exit this loop
        elif event.type == pygame.MOUSEBUTTONDOWN:
            # User clicks the mouse. Get the position
            pos = pygame.mouse.get_pos()
            # Change the x/y screen coordinates to grid coordinates
            column = pos[0] // (WIDTH + MARGIN)
            row = pos[1] // (HEIGHT + MARGIN)
            # Set that location to one
            grid[row][column] = 1
            print("Click ", pos, "Grid coordinates: ", row, column)

    # Set the screen background
    screen.fill(BLACK)

    # Draw the grid
    for row in range(10):
        for column in range(10):
            color = WHITE
            if grid[row][column] == 1:
                color = GREEN
            pygame.draw.rect(screen,
                             color,
                             [(MARGIN + WIDTH) * column + MARGIN,
                              (MARGIN + HEIGHT) * row + MARGIN,
                              WIDTH,
                              HEIGHT])

    # Limit to 60 frames per second
    clock.tick(60)

    # Go ahead and update the screen with what we've drawn.
    pygame.display.flip()

# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit()

ja aloita sitten tekemään omaa peliohjelmaasi!

16.2.4 Multiple Choice Quiz

Klikkaa tästä monivalintatehtävään.

16.2.5 Short Answer Worksheet

Klikkaa tästä kappaleen kertaustehtäviin.


You are not logged in. Log in here and track your progress.