Kirjautuminen

Haku

Tehtävät

Keskustelu: Yleinen keskustelu: Isometrinen maailman toteutus

Daih [12.05.2009 21:46:12]

#

Eli itseäni kiehtoisi tehdä isometrinen pelimaailma, sillä osaan jo 2d ohjelmoinnin aika hyvin ja tämä ei kuulemma eroa siitä paljoakaan tai ainakin paljon vähemmän, kuin 3d. Eli miten tällainen luodaan, jos esim. tile olisi 32*32 pikselin kokoinen?

Tässä myös on ongelmana se, että en tiedä mistä löytäisin tietoa, miten tällainen luodaan. Ohjeen ei tarvitse olla millään tietyllä ohjelmointikielellä, kunhan se vain on helposti sovellettavissa c++:aan. Eli pseudokoodia haen tästä asiasta. Myös tällaisen pelimaailman piirtämisestä olisi hyvä saada tietoa, sekä miten korkeusvaihtelu luotaisiin, eli miten tällainen tilen asettelu tapahtuu. Toivottavasti ei ole liian monimutkaisesti kysytty asia.

Metabolix [12.05.2009 22:16:40]

#

Usein isometrinen maailma ei eroa toteutuksellisesti lainkaan ylhäältä kuvattavasta, paitsi että korkeammalla olevia asioita piirretään myös ruudulla hieman ylemmäs. Tällöin näennäiset korkeuserot toteutetaan täysin graafisesti.

Esimerkki: Käytävä kulkee ruudulla ylävasemmalle. Käytävällä on portaat ylös, jolloin käytävä kulkee ruudulla tässä kohti jyrkemmin ylöspäin. Jos korkeuserot olisi toteutettu pelimoottoriin, hahmon naaman ei pitäisi portaissakaan kääntyä, koska hahmon varsinaisen kulkusuunnan ei pitäisi portaiden vuoksi muuttua, vaikka se liikkuukin myös hieman ylemmäs ruudulla. Kun korkeuseroja ei ole toteutettu, huomataan, että hahmo kääntyykin tässä kulkemaan pystysuorempaan, aivan kuin portaita ei oikeasti olisikaan vaan käytävä todella tekisi mutkan ja portaat olisi vain maalattu lattiaan. Niinhän ne usein onkin. (Esimerkiksi Diablo II käyttää tätä menetelmää. Kapeissa portaissa hahmo kulkee joskus tiheää siksakkia eikä lopputulos näytä kovin hyvältä. Toisaalta kapeita portaita esiintyy hyvin harvoin.)

Tämä kikka helpottaa toteutusta huimasti, koska kaikki liikkuminen voidaan toteuttaa tuttuun 2d-tapaan.

Joissain peleissä toteutus ei kuitenkaan ole tällainen ainakaan kaikilta osin; esimerkiksi Baldur's Gate II sisältää kohtia, joissa kaksi hahmoa piirtyy samaan kohti, vaikka ne ovat eri paikoissa (esim. linnan muurilla ja muurin takana pihalla). Tällöin toteutuskin on vastaavasti mutkikkaampi ja tarvitaan jokin mekanismi korkeuden tunnistamiseen. Silti tämänkin voi toteuttaa niin, että 2d-logiikka riittää. 3d-logiikkaa tarvitaan vasta, jos hahmo voi liikkua korkeussuunnassa mielivaltaisessa paikassa.

Näiden jutteluiden päätteeksi: Mikä oikeastaan on ongelmasi? Oletko yrittänyt tehdä jotain, oletko kohdannut jonkin ylitsepääsemättömän ongelman? Oletko vain todennut, "hui, isometrinen peli, enpä tiedäkään tästä mitään", vai oletko ehkä pohtinut asioita itse?

os [12.05.2009 22:43:11]

#

Tilepohjaisen "suoraan ylhäältä" kuvatun kaksiulotteisen maailman pitäisi muuttua "isometriseksi" suhteellisen helposti ainoastaan piirtofunktiota ja tietysti grafiikoita muuttamalla. Tilet ja niissä olevat objektit on vain pirrettävä oikeassa järjestyksessä vähän eri tavoin laskettuihin paikkoihin ruudulla.

Ensin sinun on päätettävä, mistä vinkkelistä haluat maailmaasi kuvattavan. Voit päättää suoraan koordinaatiston kantavektorit esimerkiksi:

- kuljettaessa yksi tile oikealle siirrytään 20 pikseliä oikealle ja 5 alaspäin: saadaan kantavektori a = (20, 5).

- kuljettaessa yksi tile alaspäin siirrytään 15 pikseliä alaspäin ja 4 pikseliä vasemmalle: saadaan toinen kantavektori b = (-4, 15).

Nyt voit laskea jokaisen tilen (x, y) pikselikoordinaatit: (px, py) = x a + y b. Tiedät myös, minkä muotoisen suunnikkaan jokaisen tilen pohja muodostaa ja tämän tiedon pohjalta voit piirtää grafiikat. Grafiikoiden on oltava maskattuja kuvia, jotta ne voivat mennä asianmukaisella tavalla päällekkäin. Tämän saat aikaiseksi piirtämällä tilet ja niissä olevat objektit oikeassa järjestyksessä, tässä esimerkkitapauksessa tilet vaikka rivi kerrallaan (0,0), (1,0), ... (m,0), (0,1), (1,1)... Lasket siis vain tässä järjestyksessä pikselikoordinaatit jokaiselle (näkyvälle) tilelle ja blittaat näitä tilejä ja niissä olevia objekteja (joiden koordinaatteja ja järjestystä voi vielä joutua hienosäätämään samalla logiikalla) vastaavat kuvat. Kannattaa ajatella laskevansa koordinaatteja esimerkiksi tietylle tilen pohjan kulmalle tai objektin pohjan keskipisteelle ja huolehtia, että blitattavan bittikarttakuvan vastaava kohta todella osuu juuri näihin pikselikoordinaatteihin. Kuvassa olevan elementin "korkeuden" voi muuten valita mielivaltaisesti. Jos kenttään haluaa lisää samanlaisten tilejen muodostamia kerroksia, onnistuu tämä lisäämällä vielä yksi kantavektori, joka vastaa siirtymää yhtä kerrosta ylemmäs ja piirtämällä samassa (x,y)-ruudussa päällekkäin olevat tilet ruuduittain alimmasta lähtien.

Daih [13.05.2009 18:45:50]

#

Tilen kokona on nyt (50,50), eli
Liikuttaessa oikealle tulee a = (25,25)
liikuttaessa alas taasen tulee b = (-25,25)

Oman pähkäilyni täältä löytyvän oppaan avulla ja os:in apujen kanssa seuraavanlainen, jos tarkoituksena olisi sijoittaa tile, joka on taulukossa kohta (4,2) kartalle:

(Px,Py) = xa+yb = 4 * (25i + 25j) + 2 * (-25i + 25j) = 100i + 100j + (-50i) +50j = 50i + 150j

Eli ymmärsin asian oikein, joten nyt uskon onnistuvani tämän projektini tekemisessä ja sekoitan vasta korkeuselementin mukaan myöhemmin, kunhan ensinnä saan tasamaalle tarkoitetun moottorin toimimaan oikein.

pipo [14.05.2009 01:45:24]

#

Moro Daih. Jäi joskus kesken tämmönen tilesysteemi.Tässä on maastokanvaasi ja näytössä näkyvä näkymäkanvaasi erikseen, koska piti muistaakseni tehdä näkymästä skrollattava. Sillain että maastokanvaasi liikkuisi tilen tai puoli tileä kerrallaan, ja näkymäkanvaasi liikkuisi pikseleitä kerrallaan.

Liikkumisen voi tehdä tohon vaikka siten, että muuttaa origon koordinaatteja painettaessa nuolta, ja täyttää koko näkymän tämän jälkeen. Esim jos painaa oikealle niin (maasto.x += 1).

Mun käsittääkseni isometrisen maailman piirtäminen eroaa ylhäältä kuvatusta ton Metabolixin kertoman korkeuseron lisäksi vain siten, että tilet pitää piirtää järjestyksessä kauimmista lähimpiin (riippumatta korkeuseroista tai siitä minkä kokoisen alueen tile peittää). Ja ihan niinkun 2Deessäkin, tilet voi olla eri kokoisia, esim puu pitäisi piirtää vähän ylempään koordinaattiin kuin nurmikko sen vieressä. 2Deessä vaan puun korkeudella ei ole merkitystä piirtämisen kannalta.

Jos teet korkeuseroja, niin käytä ihmeessä heksoja. Parilla lisäkulmalla saa paljon uskottavamman/luonnollisemman näköisiä muotoja maastoon. Nää tämmöset on ihan kauheen rumia.

Mm. näistä löydät suht. selkokielistä tietoa: Gamedev, Amit Patelin sivusto.

# -*- coding: cp1252 -*-
# salmiakkitile.py
import pygame
from pygame.locals import *

class Tile:
    def __init__(self):
        self.leveys, self.korkeus = 64, 32
        self.kuva = pygame.image.load('tile.png')
        self.kuva.set_colorkey(self.kuva.get_at((0,0)), RLEACCEL)
        self.fontti = pygame.font.Font(pygame.font.get_default_font(),12)

class Maasto:
    def __init__(self, Tile):
        self.tile = Tile
        self.n = 10 # näkymän leveys tileinä
        self.leveys, self.korkeus = self.n*self.tile.leveys, 2*self.n*self.tile.korkeus
        self.nakyma = pygame.Surface((self.leveys,self.korkeus))
        self.x = -39 # origon tilekoordinaatit
        self.y = 4

    def tayta(self):
        '''Piirtää kaikki näkymän tilet.'''
        for ty in range(self.n*2):
            for tx in range(self.n):
                self.piirra(tx, ty)

    def piirra(self, tx, ty):
        '''Piirtää tilen tx, ty.
        Näkymän vasemmassa yläkulmassa aina 0,0'''
        x, y = self.pikseli(tx, ty)
        self.nakyma.blit(self.tile.kuva, (x, y))
        koordinaatit = self.tile.fontti.render('%d,%d' %(tx+self.x, ty+self.y), 0, (0,0,0))
        koord_xy = koordinaatit.get_rect()
        koord_xy.center = (x+(self.tile.leveys/2), y+(self.tile.korkeus/2))
        self.nakyma.blit(koordinaatit, koord_xy)

    def pikseli(self, tx, ty):
        '''Palauttaa tilen tx,ty pikselikoordinaatit.'''
        return tx*self.tile.leveys+(ty&1)*self.tile.leveys/2, ty*self.tile.korkeus/2

class Gui:
    def __init__(self, Tile, Maasto):
        self.tile = Tile
        self.maasto = Maasto
        self.leveys = self.maasto.leveys
        self.korkeus = self.maasto.korkeus
        self.ikkuna = pygame.display.set_mode((self.leveys, self.korkeus),1)
        self.tile.kuva.convert()
        self.x, self.y = 0, 0
        self.maasto.tayta()
        self.paivita()

    def paivita(self):
        self.syote()
        self.ikkuna.blit(self.maasto.nakyma, (0,0), (self.x, self.y, self.leveys, self.korkeus))
        pygame.display.flip()

    def syote(self):
        self.nappaimisto()
        #self.hiiri()

    def nappaimisto(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.lopeta()
            if event.type is pygame.KEYDOWN :
                nappain = pygame.key.name(event.key)
                if nappain == 'q':
                    self.lopeta()
                else: print nappain

    def lopeta(self):
        pygame.display.quit()
        raise SystemExit()

def paaohjelma():
    pygame.init()
    pygame.display.init()
    fps = pygame.time.Clock()
    tile = Tile()
    maasto = Maasto(tile)
    gui = Gui(tile, maasto)
    print 'maastokanvaasin mitat:',maasto.leveys, maasto.korkeus
    print 'guin  kanvaasin mitat:',gui.leveys, gui.korkeus
    while True:
        gui.paivita()
        fps.tick(10)
paaohjelma()

Tile

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta