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 » Miten lisään ohjaimet peliin

Peli voi ottaa vastaan näppäimistön ja hiiren ohjausta. Ohjainten liikettä “kuunnellaan” ja voidaankin määrittää erikseen mitä mistäkin tapahtuu. Ohjaimelle on tehty oma Listen-aliohjelma jolla kuuntelun asettaminen onnistuu.

Esimerkki näppäimistön kuuntelusta:

Keyboard.Listen(Key.Left, ButtonState.Down, LiikutaPelaajaaVasemmalle, "Pelaaja liikkuu vasemmalle");
  • Kun vasen (Key.Left) näppäin on painettuna alhaalla (ButtonState.Down), niin liikutetaan pelaajaa suorittamalla metodi LiikutaPelaajaaVasemmalle. Viimeisenä parametrina on ohjeteksti.

1. Yleisesti

Jokainen Listen-kutsu on muodoltaan samanlainen riippumatta siitä mitä ohjainta kuunnellaan.

Ensimmäinen parametri kertoo mitä näppäintä kuunnellaan, esimerkiksi:

  • Näppäimistö: Key.Up
  • Hiiri: MouseButton.Left

Visual Studion kirjoitusapu auttaa löytämään mitä erilaisia näppäinvaihtoehtoja kullakin ohjaimella on.

Toinen parametri määrittää minkälaisia näppäinten tapahtumia halutaan kuunnella ja sillä on neljä mahdollista arvoa:

  • ButtonState.Released: Näppäin on juuri vapautettu
  • ButtonState.Pressed: Näppäin on juuri painettu alas
  • ButtonState.Up: Näppäin on ylhäällä (vapautettuna)
  • ButtonState.Down: Näppäin on alaspainettuna

Kolmas parametri kertoo mitä tehdään, kun näppäin sitten on painettuna. Tähän tulee tapahtuman käsittelijä, eli sen aliohjelman nimi, jonka suoritukseen haluamme siirtyä näppäimen tapahtuman sattuessa.

Neljäs parametri on ohjeteksti, joka voidaan näyttää pelaajalle pelin alussa. Tässä tarvitsee vain kertoa mitä tapahtuu kun näppäintä painetaan. Ohjetekstin tyyppi on string eli merkkijono. Jos ohjetta ei halua tai tarvitse laittaa, neljännen parametrin arvoksi voi antaa null jolloin se jää tyhjäksi.

Parametrejä voi antaa enemmänkin sen mukaan mitä pelissä tarvitsee. Omat (eli valinnaiset) parametrit laitetaan edellä mainittujen pakollisten parametrien jälkeen ja ne viedään automaattisesti Listen-kutsussa annetulle käsittelijälle. (Esimerkki valinnaisten parametrien käytöstä.)

1.1 Lopetuspainike ja näppäinohjepainike

Pelin lopettamiselle ja näppäinohjeen näyttämiselle ruudulla on Jypelissä olemassa valmiit aliohjelmat. Ne voidaan asettaa näppäimiin seuraavasti:

Keyboard.Listen(Key.Escape, ButtonState.Pressed, Exit, "Poistu");
Keyboard.Listen(Key.F1, ButtonState.Pressed, ShowControlHelp, "Näytä ohjeet");

Tässä näppäimistön Esc-painike lopettaa pelin ja F1-painike näyttää ohjeet.

ShowControlHelp näyttää peliruudulla pelissä käytetyt näppäimet ja niille asetetut ohjetekstit. Ohjeteksti on Listen-kutsun neljäntenä parametrina annettu merkkijono.

2. Näppäimistö

Tässä esimerkissä asetetaan näppäimistön nuolinäppäimet liikuttamaan pelaajaa. Viimeinen parametri (vektori) on ns. valinnainen parametri:

public override void Begin()
{
    pelaaja1 = new PhysicsObject(40, 40);
    Add(pelaaja1);
  
    Keyboard.Listen(Key.Left, ButtonState.Down, LiikutaPelaajaa, null, new Vector(-1000, 0));
    Keyboard.Listen(Key.Right, ButtonState.Down, LiikutaPelaajaa, null, new Vector(1000, 0));
    Keyboard.Listen(Key.Up, ButtonState.Down, LiikutaPelaajaa, null, new Vector(0, 1000));
    Keyboard.Listen(Key.Down, ButtonState.Down, LiikutaPelaajaa, null, new Vector(0, -1000));
}

void LiikutaPelaajaa(Vector vektori)
{
    pelaaja1.Push(vektori);
}

Listen-aliohjelmassa pystyy antamaan omia parametreja, kuten tässä on annettu vektori. Käsittelijä LiikutaPelaajaa ottaa vastaan vastaavan parametrin.

Ohjetekstin arvo on null eli tyhjä.

3. Peliohjain

Sama esimerkki kahden pelaajan versiona peliohjaimia käyttäen:

PhysicsObject pelaaja1;
PhysicsObject pelaaja2;

public override void Begin()
{
    pelaaja1 = new PhysicsObject(40, 40);
    Add(pelaaja1);
    pelaaja2 = new PhysicsObject(40, 40);
    Add(pelaaja2);
  
    ControllerOne.Listen(Button.DPadLeft, ButtonState.Down, LiikutaPelaajaa, 
                        null, new Vector(-1000, 0), pelaaja1);
    ControllerOne.Listen(Button.DPadRight, ButtonState.Down, LiikutaPelaajaa, 
                        null, new Vector(1000, 0), pelaaja1);
    ControllerOne.Listen(Button.DPadUp, ButtonState.Down, LiikutaPelaajaa, 
                        null, new Vector(0, 1000), pelaaja1);
    ControllerOne.Listen(Button.DPadDown, ButtonState.Down, LiikutaPelaajaa, 
                        null, new Vector(0, -1000 ), pelaaja1);
  
    ControllerTwo.Listen(Button.DPadLeft, ButtonState.Down, LiikutaPelaajaa, 
                        null, new Vector(-1000, 0), pelaaja2);
    ControllerTwo.Listen(Button.DPadRight, ButtonState.Down, LiikutaPelaajaa, 
                        null, new Vector(1000, 0), pelaaja2);
    ControllerTwo.Listen(Button.DPadUp, ButtonState.Down, LiikutaPelaajaa, 
                        null, new Vector(0, 1000), pelaaja2);
    ControllerTwo.Listen(Button.DPadDown, ButtonState.Down, LiikutaPelaajaa, 
                        null, new Vector(0, -1000), pelaaja2);
}

void LiikutaPelaajaa(Vector vektori, PhysicsObject pelaaja)
{
    pelaaja.Push(vektori);
}

Tässä esimerkissä käsittelijälle LiikutaPelaajaa annettiin parametrina vielä se pejaaja, jota liikutetaan.

3.1 Tatti

Jos halutaan kuunnella ohjaimen tattien liikettä, käytetään ListenAnalog-kutsua.

ControllerOne.ListenAnalog(AnalogControl.LeftStick, 0.1, LiikutaPelaajaa, 
                            "Liikuta pelaajaa tattia pyörittämällä.");

Kuunnellaan vasenta tattia (AnalogControl.LeftStick). Luku 0.1 kuvaa sitä, miten herkästä liikkeestä tattia kuunteleva aliohjelma suoritetaan. Kuuntelua käsittelee aliohjelma LiikutaPelaajaa.

Nyt sitten LiikutaPelaajaa-aliohjelman tulee ottaa vastaan seuraavanlainen parametri:

void LiikutaPelaajaa(AnalogState tatinTila)
{

}

Tatin asento saadaan selville parametrina vastaan otettavasta AnalogState-tyyppisestä muuttujasta:

void LiikutaPelaajaa(AnalogState tatinTila)
{
    Vector tatinAsento = tatinTila.StateVector;
}

StateVector antaa siis vektorin, joka kertoo mihin suuntaan tatti osoittaa. Vektorin X ja Y -koordinaattien arvot ovat molemmat väliltä miinus yhdestä yhteen (-1 - 1) tatin suunnasta riippuen. Tämän vektorin avulla voidaan esimerkiksi kertoa pelaajalle mihin suuntaan sen kuuluu liikkua.

yksikkoympyra

Tatin asennon tietyllä hetkellä saa selville myös ilman jatkuvaa tatin kuuntelua kirjoittamalla:

Vector tatinAsento = ControllerOne.LeftThumbDirection;

Tämä palauttaa samoin vektorin tatin sen hetkisestä asennosta (X ja Y väliltä -1, 1).

3.2 Liipasin

Liipasinten kuuntelu toimii lähes samalla tavalla kuin tattien kuuntelu. Käytetään ListenAnalog-kutsua:

ControllerOne.ListenAnalog(AnalogControl.RightTrigger, 0.1, KaasutaAutolla, 
                           "Käytä oikeaa liipasinta kaasupolkimen tavoin.");

Kuunnellaan oikeaa liipasinta (AnalogControl.RightTrigger). Luku 0.1 kuvaa sitä, miten herkästä liikkeestä liipasinta kuunteleva aliohjelma suoritetaan. Kuuntelua käsittelee aliohjelma KaasutaAutolla.

Liipasimen kuuntelusta vastaavan aliohjelman, tässä KaasutaAutolla, tulee olla seuraavanlainen:

void KaasutaAutolla(AnalogState liipasimenTila)
{
    
}

Aliohjelman täytyy ottaa vastaan AnalogState-tyyppinen parametri. Parametrista saadaan selville liipasimen asento:

void LiikutaPelaajaa(AnalogState liipasimenTila)
{
    double liipasimenAsento = liipasimenTila.State;
}

State antaa desimaaliluvun väliltä 0 - 1. 0 tarkoittaa, että liipasinta ei paineta yhtään. Vastaavasti 1 tarkoittaa, että liipasin on painettu aivan pohjaan saakka.

Liipasimen tila tietyllä hetkellä saadaan tarvittaessa selville myös ilman jatkuvaa liipasimen kuuntelua kirjoittamalla:

double vasemmanLiipasimenTila = ControllerOne.LeftTriggerState;

Tässä esimerkissä otetaan ykkösohjaimen vasemman liipasimen tila tietyltä hetkeltä. Arvot ovat jälleen väliltä 0 - 1.

3.3 Useampi ohjainvaihtoehto

Jos pelissä pelaajalla voi olla ohjain lisättynä ja samaan aikaan näppäimistö käytössä ja näppäimistö kuuntelee näppäinten ylhäällä oloa, kannattaa asettaa vain joko näppäimelle tai ohjaimelle kuuntelijat.

if (ControllerOne.IsConnected)
{
    ControllerOne.Listen(Button.DPadLeft,  ButtonState.Down, LiikutaPelaajaa, 
                         null, new Vector( -1000, 0 ), pelaaja1);
}
else
{
    Keyboard.Listen(Key.Left, ButtonState.Down, LiikutaPelaajaa, 
                   "Liikuttaa pelaajaa", new Vector(-1000, 0), pelaaja1);
}

4. Hiiri

4.1 Näppäimet

Hiiren näppäimiä voi kuunnella aivan samaan tapaan kuin näppäimistön.

Mouse.Listen(MouseButton.Left, ButtonState.Pressed, Ammu, "Ammu aseella.");

Tässä esimerkissä painettaessa hiiren vasenta näppäintä kutsutaan Ammu-nimistä aliohjelmaa. Tuo aliohjelma pitää tietenkin erikseen tehdä:

void Ammu()
{
    // Kirjoita tähän Ammu()-aliohjelman koodi.
}

4.2 Hiiren liike

Hiirellä ohjauksessa on kuitenkin usein oleellista tietää jotain kursorin sijainnista. Hiiren kursori ei ole oletuksenä näkyvä peliruudulla, mutta sen saa halutessaan helposti näkyviin, kun kirjoittaa koodiin seuraavan rivin vaikkapa kentän luomisen yhteydessä:

Mouse.IsCursorVisible = true;

Hiiren paikan ruudulla saadaan vektorina kirjoittamalla:

Vector paikkaRuudulla = Mouse.PositionOnScreen;

Tämä kertoo kursorin paikan näyttökoordinaateissa, ts. origo keskellä. Y-akseli kasvaa ylöspäin.

Hiiren paikan pelimaailmassa (peli- ja fysiikkaolioiden koordinaatistossa) voi saada kirjoittamalla

Vector paikkaKentalla = Mouse.PositionOnWorld;

Tämä kertoo kursorin paikan maailmankoordinaateissa. Origo on keskellä ja Y-akseli kasvaa ylöspäin.

Hiiren liikettä voidaan kuunnella aliohjelmalla Mouse.ListenMovement. Sille annetaan parametrina kuuntelun herkkyyttä kuvaava double, käsittelijä sekä ohjeteksti. Näiden lisäksi voidaan antaa myös omia parametreja. Esimerkki hiiren kuuntelusta:

PhysicsObject pallo;

public override void Begin()
{
    pallo = new PhysicsObject(30.0, 30.0, Shape.Circle);
    Add(pallo);
    Mouse.IsCursorVisible = true;
    Mouse.ListenMovement(0.1, KuunteleLiiketta, null);
}

void KuunteleLiiketta()
{        
    pallo.X = Mouse.PositionOnWorld.X;
    pallo.Y = Mouse.PositionOnWorld.Y;

    Vector hiirenLiike = Mouse.MovementOnWorld; // tai Mouse.MovementOnScreen
    // tähän hiiren liikevektorin hyödyntäminen
}

Tässä esimerkissä luomamme fysiikkaolio nimeltä pallo seuraa hiiren kursoria. Käsittelijää kutsutaan aina kun hiirtä liikuttaa.

ListenMovement:in parametreissa herkkyys tarkoittaa sitä, miten pieni hiiren liike aiheuttaa tapahtuman.

Hiiren liikkeestä saa tietoa Mouse-luokan metodeilla. Esimerkiksi MovementOnWorld ja MovementOnScreen antavat hiiren liikevektorin, joka kertoo mihin suuntaan ja miten voimakkaasti kursori on liikkunut (hiiren ollessa paikoillaan se on nollavektori!).

4.3 Hiiren kuunteleminen vain tietyille peliolioille

Jos hiiren painalluksia halutaan kuunnella vain tietyn peliolion (tai fysiikkaolion) kohdalla, voidaan käyttää apuna Mouse.ListenOn-aliohjelmaa:

Mouse.ListenOn(pallo, MouseButton.Left, ButtonState.Down, TuhoaPallo, null, pallo);

Parametrina annetaan se olio, jonka päällä hiiren painalluksia halutaan kuunnella. Seuraavat parametrit ovat kuin normaalissa Listen-kutsussa, ja viimeiseksi voidaan antaa käsittelijän parametrina saama olio. Käsittelijää TuhoaPallo kutsutaan tässä esimerkissä silloin, kun hiiren kursori on pallo-nimisen olion päällä ja hiiren vasen nappi on painettuna pohjaan. Käsittelijä olisi nyt seuraavan esimerkin mukainen:

void TuhoaPallo(PhysicsObject klikattuPallo)
{
    klikattuPallo.Destroy();
}

Hiirellä on olemassa myös esimerkiksi seuraavanlainen metodi:

PhysicsObject kappale = new PhysicsObject(50.0, 50.0);
bool onkoPaalla = Mouse.IsCursorOn(kappale);

Mouse.IsCursorOn palauttaa totuusarvon true tai false riippuen siitä, onko kursori sille annetun olion (peli-, fysiikka- tai näyttöolion) päällä.

5. Puhelimen kiihtyvyysanturi

Kiihtyvyysanturin kuunteleminen tapahtuu samaan tapaan kuin muillakin ohjaimilla.

5.1 Kallistus

Kiihtyvyysanturia voi kuunnella tietyn suunnan suhteen:

Accelerometer.Listen(AccelerometerDirection.Left, 
                     AccelerometerSensitivity.High, 
                     TeeJotain, "Tekee jotain");

void TeeJotain()
{
    // jotain...
}

On olemassa myös versio johon ei tarvitse antaa parametrinä herkkyyttä, tällöin käytetään oletusherkkyyttä.

Accelerometer.Listen(AccelerometerDirection.Any, TeeJotain, "Tekee jotain");
Accelerometer.ListenAnalog(TeeJotainMuuta, "Tekee jotain muuta");

Oletusherkkyyden vakioarvot ovat

  • DefaultSensitivity = 0.2 (High) DefaultAnalogSensitivity = 0.01 (Realtime)

Oletusherkkyyden arvoa voi muuttaa seuraavasti:

// Suunnat
Accelerometer.SetDefaultSensitivity(AccelerometerSensitivity.Realtime);
// Tai
Accelerometer.SetDefaultSensitivity(0.1);

// Analoginen
Accelerometer.SetDefaultAnalogSensitivity(AccelerometerSensitivity.Low);
// Tai
Accelerometer.SetDefaultAnalogSensitivity(0.3);

5.2 Eleet

Kiihtyvyysanturilla voi myös kuunnella puhelimella tehtäviä eleitä. Sillä voi tunnistaa puhelimen tärähdyksen/näpäytyksen tai puhelimen ravistuksen. Eleitä kuunnellaan seuraavasti:

// Oletusherkkyydellä
Accelerometer.Listen(AccelerometerDirection.Shake, Ravistettu, "");
Accelerometer.Listen(AccelerometerDirection.Tap, Täräytetty, "");

// Jos haluaa antaa parametrinä herkkyyden
Accelerometer.Listen(AccelerometerDirection.Shake, 0.4, Ravistettu, "");
Accelerometer.Listen(AccelerometerDirection.Tap, 0.5, Täräytetty, "");

Eleiden välillä on minimiaika millisekunteina jonka pitää kulua ennenkuin uusi ele tunnistetaan. Oletusarvot ovat:

  • TimeBetweenTaps = 300; TimeBetweenShakes = 500;

Aikaa voi muuttaa seuraavasti:

Accelerometer.TimeBetweenTaps = 200;
Accelerometer.TimeBetweenShakes = 700;

5.3 Kalibrointi

Erilaisissa peleissä puhelinta pidetään erilailla kädessä. Tämän takia kiihtyvyysanturin nollakohtaa (eli se kohta kun puhelinta ei ole kallistettu mihinkään päin) voi joutua muuttamaan. Tämä onnistuu seuraavasti:

// Nollakohta = puhelin makaa tasaisella, näyttö ylöspäin
Accelerometer.Calibration = AccelerometerCalibration.ZeroAngle;

// Nollakohta = puhelin on 90'-kulmassa 
Accelerometer.Calibration = AccelerometerCalibration.RightAngle;

// Nollakohta = puhelin on 45'-kulmassa
Accelerometer.Calibration = AccelerometerCalibration.HalfRightAngle;

Kiihtyvyysanturin lukeman saa selville seuraavasti:

Vector suunta = Accelerometer.Reading;

Kiihtyvyysanturin kaikkien akselien (x, y, z) lukemat saa seuraavalla kutsulla (lukemat ja suunnat eivät tässä vektorissa riipu näytön orientaatiosta eikä kalibroinnista, joten sen käyttöä ei suositella):

Vector3 tilaVektori = Accelerometer.State;

5.4 Muuta

Kiihtyvyysanturin voi pysäyttää hetkeksi seuraavasti (parametri tarkoittaa montako sekuntia kiihtyvyysanturi on pois päältä):

Accelerometer.PauseForDuration(1);

Eleet saa pois päältä ja päälle seuraavasti (oletuksena päällä):

Accelerometer.GesturesEnabled = false;
Accelerometer.GesturesEnabled = true;

6. Puhelimen takaisin-näppäin

Oletuksena puhelimen takaisin-näppäimelle ei ole kuuntelijaa. Usein halutaan käyttää näppäintä esimerkiksi palaamaan päävalikkoon tai yksinkertaisesti lopettamaan peli. Jälkimmäisessä tapauksessa riittää rivi

PhoneBackButton.Listen(Exit, "Lopeta peli");

Jos halutaan, että nappulasta tapahtuu jotain muuta, voidaan Exit-aliohjelmakutsu korvata oman aliohjelman kutsulla. Aliohjelmalle ei tule parametreja.

public void AsetaOhjaimet()
{
   // muita ohjainasetuksia...
   PhoneBackButton.Listen(MeneValikkoon, "Palaa päävalikkoon");
}

void MeneValikkoon()
{
   // valikkokoodi tähän
}

7. Puhelimen kosketusnäyttö

Puhelimen kosketusnäyttöä voidaan kuunnella aliohjelmalla TouchPanel.Listen. Parametrit ovat muuten samat kuin muillakin kuuntelijoilla, mutta koska kosketuksen voi tehdä vain yhdellä tavalla, kuuntelija ei tarvitse parametria, joka määrittäisi mitä näppäintä halutaan kuunnella.

Esimerkki pelaajan liikuttamisesta kosketusnäytöllä:

TouchPanel.Listen(ButtonState.Down, LiikutaPelaajaa, "Liikuttaa pelaajaa", pelaaja);

Tapahtumankäsittelijä ottaa annettujen parametrien lisäksi Touch-tyyppisen parametrin, joka kertoo tarkemmat tiedot kosketuksesta. Näitä tietoja ovat

  • PositionOnScreen - kosketuksen paikka näyttökoordinaateissa (mittareille ym. widgeteille) PositionOnWorld - kosketuksen paikka maailmankoordinaateissa (tavallisille peliolioille) MovementOnScreen - kosketuksen paikan muutos näyttökoordinaateissa MovementOnWorld - kosketuksen paikan muutos maailmankoordinaateissa
void LiikutaPelaajaa(Touch kosketus, PhysicsObject pelaaja)
{
    pelaaja.Velocity = kosketus.MovementOnWorld;
}

Huomaa, että Touch-tilaparametri tulee aina ensimmäisenä!

Windows Phone 7:n kosketusnäyttö pystyy seuraamaan maksimissaan viittä kosketusta ruudulla samaan aikaan. Kosketukset voidaan erottaa toisistaan vertailemalla tilaparametrin viitteitä.

Touch aktiivinenKosketus = null;

public override void Begin()
{
    TouchPanel.Listen(ButtonState.Down, LiikutaPelaajaa, "Liikuttaa pelaajaa", pelaaja);
    TouchPanel.Listen(ButtonState.Released, Irroita, null);
}

void LiikutaPelaajaa(Touch kosketus, PhysicsObject pelaaja)
{
    if (aktiivinenKosketus == null)
    {
        // Ei edellistä kosketusta, tehdään tästä nykyinen
        aktiivinenKosketus = kosketus;
    }
    else if (kosketus != aktiivinenKosketus)
    {
        // Kosketus eri sormella
        MessageDisplay.Add("Yksi kerrallaan, kiitos!");
        return;
    }

    pelaaja.Velocity = kosketus.MovementOnWorld;
}

void Irroita(Touch kosketus)
{
    if (kosketus == aktiivinenKosketus)
    aktiivinenKosketus = null;
}

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