Hyppää sisältöön

Törmäysten käsittely

Kun kaksi fysiikkaoliota törmää toisiinsa, syntyy törmäystapahtuma. Näitä tapahtumia voidaan tarkkailla tapahtumankäsittelijöillä, joiden avulla reagoidaan törmäykseen esimerkiksi tuhoamalla toinen olioista tai kasvattamalla pistelaskurin arvoa.

Katso myös, kuinka törmäyksiä voidaan estää täältä.

Törmäyksenkäsittely yhdelle tunnetulle oliolle

Aluksi tapahtumankäsittelijä täytyy asettaa seuraamaan tietyn olion törmäyksiä. Esimerkiksi jos pelissä on olio nimeltä pelaaja, jonka törmäyksistä toisiin olioihin ollaan kiinnostuneita, voidaan pelaaja-olion luomisen jälkeen asettaa tapahtumankäsittelijä:

AddCollisionHandler(pelaaja, PelaajaTormasi);

Aina kun pelaaja törmää johonkin, mihin tahansa, fysiikkaolioon pelikentällä, kutsutaan aliohjelmaa PelaajaTormasi.

Ennen kuin törmäyksenkäsittely toimii, tarvitaan aliohjelma, joka käsittelee törmäyksen. Törmäyksen käsittelevälle aliohjelmalle tulee parametreina törmänneet kaksi oliota.

void PelaajaTormasi(PhysicsObject tormaaja, PhysicsObject kohde)
{
   MessageDisplay.Add("Pelaaja törmäsi!");
}

Näin joka kerta, kun pelaaja törmää johonkin, suoritetaan aliohjelma PelaajaTormasi. Parametreista tormaaja viittaa tässä tapauksessa pelaajaan ja kohde olioon, johon pelaaja törmäsi.

Törmäys kahden tunnetun olion välillä

Jos halutaan reagoida törmäykseen kahden tietyn olion välillä, voidaan tapahtumankäsittelijälle antaa kaksi oliota:

AddCollisionHandler(pelaaja1, pelaaja2, PelaajatTormaavat);

Törmäävät oliot ovat tässä tapauksessa pelaaja1 ja pelaaja2. Tapahtumankäsittelijä PelaajatTormaavat voidaan tehdä samaan tapaan kuin yhden tunnetun olion kanssa.

void PelaajatTormaavat(PhysicsObject tormaaja, PhysicsObject kohde)
{
   MessageDisplay.Add("Bump!");
}

Törmäys yhden tunnetun ja useamman samantyyppisen olion välillä

Usein pelissä on yksi pelaaja ja useampia erityyppisiä olioita: vihollisia, aarteita, piikkiesteitä jne. Törmäyskäsittelyyn ei enää riitäkään tieto siitä, että pelaaja törmää johonkin olioon tai pelaaja törmää tiettyyn yhteen olioon. Samantyyppisille olioille voidaan antaa yhteinen tagi, jolla olioryhmät voidaan erottaa toisistaan. Tagi on järkevintä asettaa samalla, kun olio luodaan.

void LuoVihollinen(Vector paikka, double leveys, double korkeus)
{
   PhysicsObject vihollinen = new PhysicsObject(leveys, korkeus);
   vihollinen.Position = paikka;
   vihollinen.Tag = "pahis";
   Add(vihollinen);
}

void LuoHealthPotion(Vector paikka, double leveys, double korkeus)
{
   PhysicsObject pottu = new PhysicsObject(leveys, korkeus);
   pottu.Position = paikka;
   pottu.Tag = "health";
   Add(pottu);
}

Törmäyskäsittelijät voidaan luoda seuraavalla tavalla esim. pelaajan luomisen yhteydessä:

AddCollisionHandler(pelaaja, "pahis", PelaajaOsuu);
AddCollisionHandler(pelaaja, "health", PelaajaParantuu);

Olion ja tagin väliset tapahtumankäsittelijät voidaan tehdä seuraavaan tapaan:

void PelaajaOsuu(PhysicsObject pelaaja, PhysicsObject kohde)
{
   pelaajanTerveys--;

   if (pelaajanTerveys <= 0)
      pelaaja.Destroy();
}

void PelaajaParantuu(PhysicsObject pelaaja, PhysicsObject kohde)
{
   pelaajanTerveys++;
}

Tässä esimerkissä on oletettu, että kokonaislukumuuttuja pelaajanTerveys löytyy pelin attribuuteista.

public class OmaPeli : Game
{
   int pelaajanTerveys = 5;

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

Törmäykset muuntyyppisiin olioihin kuin PhysicsObject

Pelissä voi olla muunkintyyppisiä olioita kuin PhysicsObject, esimerkiksi PlatformCharacter. Olion täytyy kuitenkin periytyä PhysicsObject-luokasta, jotta sen törmäyksiä voidaan käsitellä.

Jos esimerkiksi PlatformCharacter-tyyppistä oliota käsitellään PhysicsObject:ina, esimerkiksi sen Walk-metodia ei voi käyttää, sillä PhysicsObject:illa ei ole sellaista!

Walk-metodin käyttämiseen on olemassa kaksi ratkaisua.

Ensimmäinen keino on muuttaa olion tyyppi halutuksi:

void Tormays(PhysicsObject tormaaja, PhysicsObject kohde)
{
   PlatformCharacter hahmo = tormaaja as PlatformCharacter;
   hahmo.Walk(Direction.Right);
}

Toinen tapa on käyttää AddCollisionHandler-aliohjelman tyyppiparametrillista versiota:

AddCollisionHandler<PlatformCharacter, PhysicsObject>(pelaaja, HahmonTormays);

Tämä kertoo, että törmäyksenkäsittelijäaliohjelman HahmonTormays parametrit ovat tyyppiä PlatformCharacter (törmääjä) ja PhysicsObject (kohde). Nyt voidaan kirjoittaa törmäyksenkäsittelijä suoraan muotoon

void HahmonTormays(PlatformCharacter tormaaja, PhysicsObject kohde)
{
   tormaaja.Walk(Direction.Right);
}

Huomaa, että jos yrität käyttää yo. aliohjelmaa tavalliselle, tyyppiparametrittomalle AddCollisionHandler-metodille, kääntäjä antaa siitä virheen.

Valmiit törmäystapahtumat

CollisionHandler-luokka sisältää valmiita käsittelijöitä yleisimmille törmäystapahtumille.

Olioiden tuhoaminen

DestroyObject tuhoaa törmäävän olion.

AddCollisionHandler(pelaaja, vihollinen, CollisionHandler.DestroyObject);

DestroyTarget tuhoaa olion, johon törmätään.

ase.ProjectileCollision = CollisionHandler.DestroyTarget;

DestroyBoth tuhoaa molemmat.

ase.ProjectileCollision = CollisionHandler.DestroyBoth;

Räjähdykset

ExplodeObject räjäyttää törmäävän olion. Se ottaa parametriksi räjähdyksen säteen (int) ja totuusarvon (true/false) siitä, tuhotaanko olio samalla.

AddCollisionHandler(pelaaja, vihollinen, CollisionHandler.ExplodeObject(100, true));

ExplodeTarget toimii kuten ExplodeObject, mutta se räjäyttää olion, johon törmätään.

AddCollisionHandler(salama, CollisionHandler.ExplodeTarget(150, false));

ExplodeBoth tekee räjähdyksen olioiden törmäyskohtaan ja valinnaisesti tuhoaa kummatkin oliot samalla.

AddCollisionHandler(salama, CollisionHandler.ExplodeBoth(200, true));

Jos pelissä on käytössä ExplosionSystem (ks. Efektit), voidaan käyttää AddEffectOnTarget-käsittelijää, joka tekee efektin törmäyksen kohteen paikalle (AddEffectOnObject tekee sen törmääjän paikalle). Käsittelijä ottaa parametrikseen räjähdysjärjestelmän ja käytettävien partikkelien määrän. Se ei tuhoa olioita automaattisesti, mutta sekin onnistuu lisäämällä erillisen DestroyObject-käsittelijän:

AddCollisionHandler(pelaaja, vihollinen, CollisionHandler.AddEffectOnTarget(paukkupatteri, 40));
AddCollisionHandler(pelaaja, vihollinen, CollisionHandler.DestroyObject);

Efektit ilman olion tuhoamista:

AddCollisionHandler(salama, CollisionHandler.AddEffectOnTarget(paukkupatteri, 80));

Laskurin arvon muuttaminen

Laskurin arvoa voidaan kasvattaa/vähentää käyttämällä AddMeterValue-törmäyksenkäsittelijää. Näin voidaan esimerkiksi antaa pelaajalle pisteitä kerättävistä esineistä tai vähentää terveyttä/elämiä viholliseen osumisesta.

AddCollisionHandler(pelaaja, "bonus", CollisionHandler.AddMeterValue(pisteet, 10));
AddCollisionHandler(pelaaja, "piikki", CollisionHandler.AddMeterValue(health, -1));

Tätä tapaa ei voida käyttää, mikäli pisteiden laskemisella on joitakin muita ehtoja kuin pelkkä törmääminen. Tällöin pistelaskuri pitää käsitellä normaalissa törmäystapahtumassa ja kirjoittaa sinne ehto, jonka avulla laskurin arvoa muutetaan (ks. laskurin arvon muuttaminen).

Ääniefektin soittaminen

Ääniefektin soittaminen törmäyksen yhteydessä onnistuu tapahtumankäsittelijällä PlaySound, jolle annetaan parametriksi ääniefektin nimi. Nimi on yleensä sama kuin tiedoston nimi, mutta ilman tiedostopäätettä.

AddCollisionHandler(pelaaja, "tuli", CollisionHandler.PlaySound("tuskan_parahdus"));

Impulssi

HitObject lyö törmäävää oliota ja HitTarget oliota, johon törmätään. Molemmat ottavat parametrikseen vektorin, joka kertoo lyönnin suunnan ja voiman.

Vector ylos = new Vector(0, 200);
AddCollisionHandler(pelaaja, "trampoliini", CollisionHandler.HitObject(ylos));

Olion koon muuttaminen

Olion kokoa on mahdollista muuttaa törmäyksessä IncreaseObjectSize ja IncreaseTargetSize -käsittelijöillä. Ensimmäinen muuttaa törmääjän kokoa ja jälkimmäinen sen olion, johon törmätään. Molemmat ottavat parametrikseen leveyden ja korkeuden muutoksen (tässä järjestyksessä). Olioita voi myös pienentää käyttämällä negatiivisia arvoja.

AddCollisionHandler(pelaaja, "nakki", CollisionHandler.IncreaseObjectSize(10, 10));
AddCollisionHandler(kirves, CollisionHandler.IncreaseTargetSize(-5, 0));

Katso myös