Huom! Nämä wikisivut ovat osittain vielä työn alla, osa sisällöstä saattaa olla puutteellista. Ongelmakohtien viereen voit jättää kommentin, yliopiston käyttäjät myös pystyvät (ja saavat) muokata sivuja.

Jypelin käyttöohjeet » Ruutukentän luominen

Jypelissä on mahdollista luoda kenttä merkkijonotauluukoon, kuvatiedostoon tai tekstitiedostoon "piirretyn" mallin mukaisesti.

Tällöin puhutaan, että tehdään ns. ruutukenttä, sillä kuvatiedoston jokainen pikseli tai tekstitiedoston jokainen merkki asetetaan vastaamaan tietyn kokoista ruutua pelikentässä.

# stringlines

1. Kentän luominen merkkijonotaulukosta

Helpoin tapa luoda pelikenttä on tehdä se merkkijonotaulukosta.

private static readonly String[] lines = {
              "                        ",
...
              "                        ",
              "        =======         ",
              "        Y  Y  Y         ",
              "        X* X  X         ",
              "   *    X  X  X     *   ",
              "        X  X  X         ",
              "        X *X *X         ",
              };

Taulukkoon kuvataan itse valituilla kirjaimille mihin kohti kenttää halutaan mitäkin elementtejä.

Sitten lasketaan millaista leveyttä ja korkeutta kukin elementti edustaa.

Itse kentän kuvaus luodaan sitten tästä taulukosta:

TileMap tiles = TileMap.FromStringArray(lines);

Sitten kerrotaan mitä piirtometodia kutsutaan kunkin kirjaimen kohdalle. Metodille voidaan vielä lisäksi haluttu määrä lisäparametreja. Esimerkissä kullekin elementille on viety sen väri.

    tiles.SetTileMethod('X', LuoSeina, Color.Wheat);
    tiles.SetTileMethod('Y', LuoSeina, Color.Wheat);
    tiles.SetTileMethod('=', LuoKatto, Color.Red);
    tiles.SetTileMethod('/', LuoMaila, Color.Black);
    tiles.SetTileMethod('*', LuoVihollinen, Color.Pink);

Lopuksi pyydetään piirtämään kenttä kuvauksen perusteella:

tiles.Execute(tileWidth, tileHeight);

Kun Excecute-metodi löytää kentänkuvaustaulukosta jonkin kirjaimen, niin se kutsuu vastaavaa piirtometodia. Esimerkiksi

private void LuoSeina(Vector paikka, double leveys, double korkeus, Color vari)
{
    PhysicsObject seina = new PhysicsObject(leveys-1, korkeus-2);
    seina.Position = paikka;
    seina.Color = vari;
    seina.Tag = "rakenne";
    Add(seina);
}

Piirtometodille tulee parametrina tiles-olion kirjaimelle laskema paikka ja kirjainta vastaavan ruudun (tile) koko, johon elementti pitää piirtää.

Fysiikkamoottorin (Farsee) takia elementit pitää luoda hieman pienemmiksi kuin yhden ruudun koko, muuten elementit (oliot) työntävät toisiaan pois.

Aja alla oleva ohjelma, niin näet tuloksen. Voit myös muutella kentän asettelua ja Alusta-linkistä palata alkuperäiseen.

# angrylego1

Enemmän elävyyttä saada tietysti jos elementeille asetetaan kuvia tyyliin:

seina.Image = LoadImage("tiili");
# angrylego2

Mikäli peliin lisätään painovoima, tulee tällä tavalla piirretyssä kentässä ongelmia kun kappaleet eivät kannattele toisiaan.

    Gravity = new Vector(0, -500);
# angrylego3

Tähän auttaa hieman kun tehdään rakennelmasta sellainen, että ylimmät seinäelementit ovat muita leveämpiä ja näin kannattelevat kattoelementtejä:

private void LuoYlaSeina(Vector paikka, double leveys, double korkeus, Color vari)
{
    PhysicsObject seina = new PhysicsObject(leveys*1.8, korkeus-1);
    seina.Position = paikka;
    seina.Color = Color.Wheat;
    seina.Tag = "rakenne";
    seina.Image = LoadImage("tiili");
    Add(seina);
}
# angrylego4

2. Kentän tekeminen tekstitiedostosta

Aiempaa esimerkkiä mukaillen, kentän pohjana olevan tekstin voi myös halutessaan tallentaa erilliseen tekstitiedostoon, joka saadaan helposti ladattua pelin käynnistyessä.

2.1 1. Kenttätiedoston tekeminen ja muokkaaminen tekstieditorilla

Helpoin tapa on tehdä ruudukko erilliseen tekstitiedostoon, josta se sitten luetaan. Vaihtoehtoinen tapa on määrittää ruudut suoraan koodissa.

Tekeminen ja muokkaaminen onnistuu helpoiten Notepad++-ohjelmalla, mutta mikä tahansa tekstieditori (eli EI word!) käy.

Luo uusi tiedosto. Tekstitiedostoon voi nyt "piirtää" kirjoitusmerkeillä haluamansa kentän. Ruudukon leveydeksi tulee tiedoston pisimmän rivin pituus ja korkeudeksi tiedoston rivien määrä. Käytä tyhjien ruutujen merkitsemiseen välilyöntiä, älä käytä Tab-näppäintä.

Vinkki: Laita tyhjien merkkien näyttö:

  • View » Show Symbol » Show White Space and TAB

Vinkki: Kentän muokkaaminen voi olla helpompaa, kun painat Insert-näppäintä (tekstin korvaustila). Paina Insert-näppäintä uudelleen päästäksesi takaisiin normaaliin kirjoitustilaan.

Vinkki: Käytä merkkeinä pelkästään isoja ja pieniä kirjaimia sekä numeroita. Erikoismerkit (Esim £) eivät välttämättä toimi oikein.

Kun olet piirtänyt kentän, klikkaa tallennuskuvaketta, tai mene File » Save (Ctrl + S) ja anna tiedostolle nimeksi esimerkiksi "kentta1.txt" (ilman lainausmerkkejä), jos teit ensimmäisen kentän.

Kun kenttä on valmis, palaa Visual Studioon.

2.2 2. Kenttätiedoston lisääminen Visual Studioon

Kentän lataamiseksi lisätään kenttätiedosto content-kansioon. Katso tarkemmat ohjeet: Sisällön tuominen peliin

2.3 3. Ruutukartan luominen

Ruutukentän luomista varten tarvitsee koodissa luoda ruutukartta-olio (TileMap). Sopiva paikka ruutukartan luomiseksi on aliohjelma, joka luo kentän (esim. LuoKentta()).

Ruutukartta-olio luodaan seuraavasti (vaihda nimen kentta tilalle tiedosto, jonka liitit projektiin):

TileMap ruudut = TileMap.FromLevelAsset("kentta1");

2.4 4. Merkit / pikselit vastaamaan olioita

Tarkoitus on, että jokaista erilaista kirjoitusmerkkiä tai pikseliä vastaa joku tietynlainen olio. Jokainen käyttämäsi merkki tai pikseli liitetään sitä vastaavan olion luovaan aliohjelmaan seuraavalla tavalla:

Tekstitiedostolle:

ruudut.SetTileMethod('=', LuoPalikka);
ruudut.SetTileMethod('*', LuoTahti);

LuoPalikka sekä LuoTahti ovat joita kutsutaan jokaisen annetun merkin kohdalla, joita kenttätiedostosta löytyy. Tällaisessa aliohjelmassa voidaan esimerkiksi luoda uusi olio.

Nyt täytyy vielä kirjoittaa oliot luovat aliohjelmat. Esimerkiksi LuoPalikka voisi olla seuraavanlainen:

void LuoPalikka(Vector paikka, double leveys, double korkeus)
{
    PhysicsObject palikka = PhysicsObject.CreateStaticObject(leveys, korkeus);
    palikka.Position = paikka;
    palikka.Shape = Shape.Rectangle;
    palikka.Color = Color.Gray;
    Add(palikka);
}

Jos teet paljon samantyyppisiä elementtejä, jotka eroavat toisistaan vain vähän, esimerkiksi kuvan tai värin suhteen, voit antaa muuttuvat tiedot parametrina. Samoin voit toimia toki muidenkin ominaisuuksien kanssa. Alla esimerkki kahden eri värisen palikan tekemisestä samalla aliohjelmalla, sama toimii kuville kun pistät parametriksi Imagen.

public override void Begin()
{
    TileMap kentta = TileMap.FromLevelAsset("kentta1");
    kentta.SetTileMethod('$', LisaaTaso, Color.White);
    kentta.SetTileMethod('#', LisaaTaso, Color.Blue);
    kentta.Execute();
}

void LisaaTaso(Vector paikka, double leveys, double korkeus, Color vari)
{
    PhysicsObject taso = PhysicsObject.CreateStaticObject(leveys, korkeus);
    taso.Position = paikka;
    taso.Color = vari;
    Add(taso);
}

2.5 5. Kentän lisääminen peliin

Kun ruudut ovat taulukossa ja merkkien merkitys kerrottu, kentän voi vihdoin luoda peliin seuraavanlaisella komennolla:

ruudut.Execute(20, 20);

Tässä yhden ruudun kooksi tulisi (20, 20).

HUOM! Tämä komento muuttaa kentän kokoa! Jos siis lisäät kenttään reunoja tai zoomaat kameran näyttämään koko kentän, tee se vasta tämän jälkeen.

Toinen vaihtoehto on antaa kirjaston laskea edellämainitut attribuutit jolloin kentän koko ei muutu. Tällöin käytä komentoa:

ruudut.Execute();

2.6 6. Valmis esimerkki

Tässä eräs ratkaisu ruutukentän tekemiseen, kun kenttä on tehty erilliseen tekstitiedostoon nimeltä "kentta.txt":

public void LuoKentta()
{
    TileMap ruudut = TileMap.FromLevelAsset("kentta1");
    ruudut.SetTileMethod('P', LuoPelaaja);
    ruudut.SetTileMethod('#', LuoPalikka);
    ruudut.SetTileMethod('*', LuoTahti);
    ruudut.Execute(20, 20);
}

public void LuoPelaaja(Vector paikka, double leveys, double korkeus)
{
    pelaaja = new PlatformCharacter(10, 10);
    pelaaja.Position = paikka;
    AddCollisionHandler(pelaaja, "tahti", TormaaTahteen);
    Add(pelaaja);
}

public void LuoPalikka(Vector paikka, double leveys, double korkeus)
{
    PhysicsObject taso = PhysicsObject.CreateStaticObject(leveys, korkeus);
    taso.Position = paikka;
    taso.Image = tasonKuva;
    Add(taso);
}

public void LuoTahti(Vector paikka, double leveys, double korkeus)
{
    PhysicsObject tahti = new PhysicsObject(5, 5);
    tahti.IgnoresCollisionResponse = true;  
    tahti.Position = paikka;
    tahti.Image = tahdenKuva;
    tahti.Tag = "tahti";
    Add(tahti, 1);
}

3. Kentän tekeminen kuvatiedostosta

Kentän voi luoda kuvasta niin, että yksi kuvapiste eli pikseli vastaa yksittäistä oliota pelikentällä.

Eriväriset pikselit vastaavat siten eri olioita, joten vaikkapa mustat pikselit voivat olla seiniä, vihreät pelaajia ja keltaiset kerättäviä tähtiä. Värien merkityksen voi itse päättää.

3.1 1. Kentän piirtäminen Paint.NETillä

Mikroluokissa piirtämiseen on käytössä Paint.NET -niminen ohjelma. Voit piirtää ruutukentän muullakin ohjelmalla, tärkeintä on että kuvan yksittäisiä pisteitä eli pikseleitä pääsee muokkaamaan ja niiden väriarvot ovat helposti nähtävissä.

Avataan ensin Paint.NET Käynnistä-valikosta tai työpöydältä. Näkyville pitäisi tulla seuraavanlainen ikkuna:

Valitse File-valikosta New... luodaksesi uuden kuvan. Avautuvaan ikkunaan kirjoita kentälle haluttu koko Width- ja Height-kohtiin.

HUOM. Kentän koko on olioina, ei pikseleinä, joten vältä 80x80 suurempia kuvakokoja!

Kuvan zoomaustasoa voi säätää painamalla Ctrl pohjaan ja käyttämällä hiiren rullaa tai + ja - -näppäimiä.

Poista vielä valkoinen tausta valitsemalla kaikki (Ctrl+A) ja painamalla Delete-näppäintä. Nyt kuvan pitäisi näyttää tältä:

Tallenna kuva pelin Content-hakemistoon.

Kuva pitää tallentaa png-muodossa, jotta läpinäkyvyys säilyy ja jotta kuvaan ei tule pakkausartifakteja. (Ks. myös Miten teen kuvaan läpinäkyviä osia.)

Nyt voit aloittaa kentän piirtämisen. Valmis kenttä voi näyttää vaikkapa tältä:

Voit itse päättää, mitä oliota mikäkin väri vastaa. Esimerkiksi mustat pikselit voivat olla seiniä, vihreät pelaajia, keltaiset kerättäviä tähtiä ja punaiset vihollisia.

3.2 2. Kenttätiedoston lisääminen Visual Studioon

Kentän lataamiseksi kuvasta lisätään kenttätiedosto content-kansioon. Katso tarkemmat ohjeet TIMistä: ​https://tim.jyu.fi/view/kurssit/tie/ohj1/tyokalut/sisallon-tuominen-peliin

3.3 3. Kentän luominen Visual Studioon lisätystä kuvatiedostosta

Kun kuva on liitetty Content-kansioon, voimme ottaa sen käyttöön koodissa.

Sopiva paikka kentän luomiseksi on aliohjelma, joka luo kentän (esim. LuoKentta).

Kentän luomisen vaiheet:

  • Luodaan uusi ColorTileMap nimeltä ruudut, johon kuvatiedosto luetaan.

  • Kerrotaan ColorTileMapille mitä aliohjelmaa kutsutaan, kun tietyn värinen pikseli tulee vastaan kuvatiedostossa. (Ja toteutetaan tarvittavat aliohjelmat.)

    • Aliohjelmassa luodaan olio, sijoitetaan se oikeaan paikkaan ja lisätään peliin
    • Aliohjelmille tulee parametrina vektori, joka kertoo olion paikan pelikentällä.
    • Lisäksi parametreina tulevat yhdelle pikselille varatun ruudun leveys ja korkeus pelikentällä.
    • Listan väreistä ja nimet Paint.netin väreille näet allaolevasta kuvasta.

Lista paint.NETin valmiista väreistä.

  • Luodaan kenttä Execute-komennolla. Parametreina annetaan yhden pikselin leveys ja korkeus pelikentällä.

Esimerkki:

Onko näistä Jypeli/paint.net -väreistä olemassa parempaa kuvaa, jossa olisi esim. isompi laatikko jokaista väriä(pelkän tekstin sijasta), niin omaan kenttään olisi helpompi poimia tietty väri? Nyt kun nuo tekstit ovat ohuita ja joutuu zoomaa lähelle, on aika vaikea poimia juuri se oikea pikseli sille tietylle värille. Tuntuu myös ettei kaikki värit ole ihan oikealla nimellä, koska monet näistä ei vaan toimi omassa kentässä.

Värit on tarkoitus poimia Paint.NETin omasta värivalikosta. Tuota kuvaa voisi kyllä kuitenkin parantaa.

19 Oct 22 (edited 21 Oct 22)
void LuoKentta()
{
  //1. Luetaan kuva uuteen ColorTileMappiin.
  ColorTileMap ruudut = ColorTileMap.FromLevelAsset("kentta1");
  
  //2. Kerrotaan mitä aliohjelmaa kutsutaan, kun tietyn värinen pikseli tulee vastaan kuvatiedostossa.
  ruudut.SetTileMethod(Color.Green,  LuoPelaaja);
  ruudut.SetTileMethod(Color.Black,  LuoTaso);
  ruudut.SetTileMethod(Color.Yellow, LuoTahti);
  
  //3. Execute luo kentän
  //   Parametreina leveys ja korkeus
  ruudut.Execute(20, 20);
}

void LuoPelaaja(Vector paikka, double leveys, double korkeus)
{
  pelaaja = new PlatformCharacter(10, 10);
  pelaaja.Position = paikka;
  AddCollisionHandler(pelaaja, "tahti", TormaaTahteen);
  Add(pelaaja);
}

void LuoTaso(Vector paikka, double leveys, double korkeus)
{
  PhysicsObject taso = PhysicsObject.CreateStaticObject(leveys, korkeus);
  taso.Position = paikka;
  taso.Image = tasonKuva;
  taso.CollisionIgnoreGroup = 1;
  Add(taso);
}

void LuoTahti(Vector paikka, double leveys, double korkeus)
{
  PhysicsObject tahti = new PhysicsObject(5, 5);
  tahti.IgnoresCollisionResponse = true;  
  tahti.Position = paikka;
  tahti.Image = tahdenKuva;
  tahti.Tag = "tahti";
  Add(tahti, 1);
}

HUOM! Execute-komento muuttaa kentän kokoa! Jos siis lisäät kenttään reunoja tai zoomaat kameran näyttämään koko kentän, tee se vasta tämän jälkeen.

Vinkki: Mikäli teet kentän, jossa on paljon samoja staattisia olioita (maasto, seinät, jne.), lisää seuraava rivi olion luovaan aliohjelmaan:

    palikka.CollisionIgnoreGroup = 1;

Tämän rivin vaikutus on se, että kaikki oliot, joilla on sama CollisionIgnoreGroup eivät törmää keskenään. Pelissä vierekkäiset tasot törmäilevät muuten huomaamattamme keskenään, ja näiden törmäysten käsittely syö tietokoneen laskentatehoa.

4. Tekstuurin lisääminen

Ruutukentän luomille olioille halutaan usein asettaa jokin kuva eli tekstuuri. Koska samaa kuvaa käytetään monta kertaa, se kannattaa ladata muuttujaan pelin alussa. Sitten samaa kuvaa voi helposti käyttää samanlaisia olioita luovassa aliohjelmassa.

Piirrä tekstuuri kuvankäsittelyohjelmalla ja katso sitten ohjeet sisällön tuomisesta projektiin.

Kun kuva on olemassa ja tuotu projektiin sitä voidaan käyttää seuraavasti:

Ladataan kuva muuttujaan luokan alussa:

using System;
using Jypeli;

public class Peli : PhysicsGame
{
    Image palikanKuva = LoadImage("palikka");

    public override void Begin()
    {
        //...

Asetetaan ladattu kuva olioille:

void LuoPalikka(Vector paikka, double leveys, double korkeus)
{
    PhysicsObject palikka = PhysicsObject.CreateStaticObject(leveys, korkeus);
    palikka.Position = paikka;
    palikka.Image = palikanKuva;
    Add(palikka);
}

5. Optimointi (jos peli on hidas)

Jos kenttä on iso ja siinä on paljon staattisia olioita kuten seiniä vierekkäin, sitä voidaan nopeuttaa antamalla Jypelin yhdistellä vierekkäisiä olioita. Tämä onnistuu kirjoittamalla ruutukentän luontiin ennen Execute-riviä

kentta.Optimize(Color.Black);

tai tekstikentälle

kentta.Optimize('x');

Huom. älä käytä esim. kerättäville esineille, pelaajille tai muille joiden lukumäärällä on merkitystä

On myös tärkeää huomioida, että tämä muuttaa kappaleiden kokoa yhdistämällä vierekkäin olevia samanlaisia kappaleita yhdeksi. Eli jos jonkin kappaleen fyysiset mitat ovat tärkeät, tämä voi tuottaa ongelmia (esimerkiksi tekstuurien venymisen suhteen).

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