Pong-peli, vaihe 3
Tämä on Pong-pelin tutoriaalin osa 3/7. Tämän vaiheen aikana
- Jaetaan ohjelma pienempiin palasiin (aliohjelmiin)
- Lisätään peliin maila (jota ei voi vielä liikuttaa)
Vaihe on melko pitkä, mutta sitäkin tärkeämpi, joten jaksathan lukea ohjeet huolellisesti loppuun saakka.
1. Aliohjelman tekeminen
Lisäämme pian pelikenttään lisää olioita, tällä kertaa mailan. Jotta koodi pysyisi hallittavan kokoisissa palasissa, teemme kentän luomisesta oman aliohjelman nimeltä LuoKentta
.
Aliohjelma on pienempi osa koodia, jota voidaan kutsua jostain muusta kohtaa koodia. Aliohjelman tarkemman luonteen mukaan käytetään myös nimityksiä funktio (jos aliohjelma palauttaa arvon) tai metodi (jos aliohjelma tarvitsee luokan olio-viitettä this
).
Tässä luvussa aliohjelma on yleisnimi kaikille eri tyyppisille aliohjelmille. Tämän luvun eri tyyppisiä aliohjelmia ovat:
- metodi = aliohjelma jolla on käytössä itse olioon (tässä luvussa itse peliin) liittyvä viite nimeltä
this
. Oletkin jo nähnytBegin
-metodin. Metodin esittelyssä ei olestatic
-sanaa. - funktio = aliohjelma joka palauttaa jonkin arvon. Ihannetilanteessa funktio ei tarvitse muuta tietoa kuin parametrinsa ja silloin se voidaan sanoa
static
-avainsanalla staattiseksi. Koska se on olemassa ennen olioiden luomista, sillä ei voi olla käytössäänthis
-viitettä ellei sitä viedä parametrina.
Kirjoita metodi LuoKentta
. Aliohjelman koodi on seuraavassa merkattu vihreällä värillä. Muu koodi pitäisi olla jo koodissasi, joten sitä ei pidä kirjoittaa.
Kiinnitä erityisesti huomiota siihen, miten aaltosulut tulevat. Rivin void LuoKentta()
jälkeen tulee yksi aaltosulku auki {
ja toinen kiinni }
. Niiden väliin kirjoitetaan LuoKentta
-aliohjelmaan kuuluvat koodirivit.
public class Pong : PhysicsGame
{
public override void Begin()
{
PhysicsObject pallo = new PhysicsObject(40.0, 40.0, Shape.Circle);
pallo.X = -200.0;
pallo.Y = 0.0;
pallo.Restitution = 1.0;
this.Add(pallo);
this.Level.CreateBorders(1.0, false);
this.Level.Background.Color = Color.Black;
this.Camera.ZoomToLevel();
Vector impulssi = new Vector(500.0, 0.0);
pallo.Hit(impulssi * pallo.Mass);
Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
}
Aliohjelman esittelyrivin alussa, ennen sen nimeä, kerrotaan
- kuinka julkinen aliohjelma on
- onko aliohjelmassa käytössä olioviite
this
(jos ei lue mitään, on, jos lukeestatic
ei ole). - minkä tyyppistä tietoa aliohjelma palauttaa.
Jos metodi ei ole tarkoitettu muiden käytettäväksi, sen näkyvyys kannattaa olla private
. Eihän muissa peleissä luoda samanlaista kenttää.
this-viite: Edellä olevaan koodiin on lisätty this
-viitteitä niihin kohti joissa sen oikeasti pitäisi olla. Eli olemme nimenomaan lisäämässä palloa meidän peliimme. Ja siksi se sanotaan this.Add(pallo)
. Taso on meidän pelimme taso, samoin kuin kamera. C#-koodissa this
-viitettä ei ole pakko kirjoittaa ja siksi se yleensä jätetään koodista pois. Tämä voi sitten vähän hämätä koska sama rivi voi olla toimimatta paikassa missä this
-viitettä ei ole (static-aliohjelmat).
Kentän luomisessa haluamme viitata pelin Level
ja Camera
-olihion, joten tarvitsemme siellä this
-viitettä. Siksi static
-sana jätetään pois. Toinen mahdollisuus olisi tuoda peli parametrina, kuten myöhemmin tehdään PiirraPallo
tapauksessa.
Koska metodi LuoKentta
ei palauta mitään arvoa, tyypin kohdalle tulee vain sana void
. Aliohjelman nimen jälkeen tulee sulut, joiden väliin tulee mahdolliset parametrit (joita tässä ei ole vielä yhtään).
Nyt meillä on tyhjä aliohjelma, jonne haluaisimme siirtää kaikki kentän luomiseen liittyvät koodirivit.
2. Aliohjelman kutsuminen
Aliohjelma ei itsessään tee mitään ennen kuin sitä kutsutaan jostakin.
Aliohjelman kutsuminen tarkoittaa, että tietokonetta käsketään suorittamaan aliohjelmaan kuuluvat koodirivit.
Mistä voisimme kutsua tuota aliohjelmaa? Tietysti Begin
-metodista, jota olemme edellisissä vaiheissa tehneet. Tuo metodihan suoritetaan ensimmäisenä kun peli käynnistetään.
Siirrä kentän luontiin liittyvät rivit Begin
:ista metodiin LuoKentta
alla olevan kuvan osoittamalla tavalla. Eli leikkaa punainen koodi pois ja liitä se vihreäksi merkittyyn kohtaan LuoKentta
-metodin aaltosulkujen väliin.
Muista että Ctrl+X leikkaa valitun tekstin ja Ctrl+V liitää sen kursorin kohdalle.
Huomaa, että omassa koodissasi rivit saattavat olla hieman eri järjestyksessä kuin kuvassa.
Pallon luominen ja pallon liikuttamiseen liittyvät kaksi riviä (vektorin luominen ja pallon töytäisy) ja lopetusnapin tekevä rivi jäävät Begin
-metodiin ja kaikki muut rivit siirretään uuteen LuoKentta
-metodiin.
Kirjoitetaan sitten aliohjelmakutsu. Aliohjelman kutsu on käsky tietokoneelle käydä suorittamassa aliohjelmalle kuuluvat koodirivit.
Kutsu tapahtuu yksinkertaisesti kirjoittamalla aliohjelman nimi, jonka jälkeen tulee sulut ja sulkujen sisään mahdolliset parametrit (joita aliohjelmallamme ei ole yhtään) ja lopuksi puolipiste ;
.
Kirjoita siirrettyjen rivien tilalle aliohjelman (metodin) LuoKentta
kutsu kuten seuraavassa:
Koska kirjoitimme aliohjelmakutsun ennen rivejä, joilla luodaan vektori nimeltä impulssi
ja sysätään pallo liikkeelle, LuoKentta
-aliohjelman rivit suoritetaan ennen impulssin
luomista ja pallon liikuttamista. Pelimme toiminta ei siis muutu oikeastaan millään tavalla. Jäsentelemme vain koodia pienempiin osiin.
Pallon luomiseen voi kannattaa vielä lisätä rivit, joilla pallon käytöstä voi hieman "rauhoittaa". Lisää vaikka ennen Add
-kutsua:
Tätä lausetta kannattaisi hieman parantaa esim.: Pallon luomiseen kannattaa vielä lisätä rivit, joilla pallon käytöstä voi hieman "rauhoittaa".
VL: Kiitos, muutettu,
—3. Pallo aliohjelmaksi
Pallon luomisesta haluamme tehdä sellaisen aliohjelman, jota voisivat muutkin halutessaan käyttää. Siksi sanomme että se on julkinen, public
. Jos joku haluaa omaan peliinsä pallon, on meidän kerrottava mihin peliin se tulee. Ja sen jälkeen emme tarvitsekkaan aliohjelmassa this
-viitettä, koska peli
korvaa sen. Eli aliohjelma tulee pärjäämään omilla parametreillaan, siksi kirjoitetaan että se on aina olemassa, eli staattinen, static
.
Kun pallo on luotu, voidaan sitä tarvita luomisen jälkeen. Siksi aliohjelmasta tehdäänkin funktio, joka palauttaa viitteen luomaansa palloon. Siksi annamme paluutyypiksi PhysicsObject
. Aliohjelman parametreiksi viedään pallon keskipisteen haluttu x- ja y-koordinaatti.
Eli tee kuten edellä. Lisää vihreät rivit ja siirrä punaisella maalatut rivit LuoPallo
-funktion sisälle. huomaa vaihtaa this
tilalle peli
.
public static PhysicsObject LuoPallo(PhysicsGame peli, double x, double y)
{
PhysicsObject pallo = new PhysicsObject(40.0, 40.0, Shape.Circle);
pallo.X = x;
pallo.Y = y;
pallo.Restitution = 1.0;
pallo.KineticFriction = 0.0;
pallo.MomentOfInertia = double.PositiveInfinity;
peli.Add(pallo);
return pallo;
}
Huomaat että nyt aliohjelma (siis funktio) loppuu riviin, jossa palautetaan se tieto mitä kutsuva ohjelman osa siltä haluaisi. Eli
Kääntäjä valittaa nyt kuitenkin rivistä pallo.hit
. Koska meillä ei nyt ole pallo
-viitemuuttujaa. Siksi meidän pitää ottaa vastaan LuoPallo
-funktion palauttama pallon viite, eli vaihda rivi muotoon:
Nyt meillä on jälleen palloviite käytössä.
Seuraavassa kuvassa on havannollistettu parametrin välistystä LuoPallo
-funktioon ja miten se palauttaa luomansa pallon viitteen Begin
-metodille.
4. Mailan lisääminen kenttään
Lisätään kenttään maila. Haluaisimme, että maila on paikallaan pysyvä eli staattinen vaikka pallo törmäilee siihen. Vaikka maila on "paikallaan pysyvä", voidaan sitä silti itse toki liikuttaa. Mutta törmäyksistä se ei liiku.
Staattisen fysiikkaolion luominen tapahtuu aliohjelmakutsulla
Lisää vihreällä merkityt rivit LuoKentta
-aliohjelmaan:
Pong-pelissä on maila sekä ruudun vasemmassa että oikeassa reunassa. Lisätään oikeanpuoleinen maila myöhemmin.
Y-koordinaatin asetamme nollaksi, jotta maila menee pystysuunnassa ruudun keskelle.
X-koordinaattia varten kysymme pelikentältä sen vasemman reunan x-koordinaatin (Level.Left
) ja lisäämme siihen 20.0
, jotta maila pysyy kentän rajojen sisällä.
Olisimmeko voineet sijoittaa x-koordinaattiin yksinkertaisesti jonkun arvon, esimerkiksi -300.0
? Olisimme toki. Äsken käyttämämme tapa on kuitenkin siitä parempi, että maila tulee aina kentän vasempaan reunaan vaikka päättäisimme myöhemmin muuttaa kentän kokoa. Näin peli on helpommin muokattavissa.
Laitamme myös mailalle Restitution
-ominaisuuden arvoon 1.0
, koska törmäykseen vaikuttaa kummankin törmäävän kappaleen ominaisuudet.
Kun nyt käynnistät pelin, siinä näkyy pallo sekä yksi maila.
5. Pelin aloittaminen
Kentän luomisen lisäksi pelissä on monia muita toimenpiteitä, jotka voisimme tehdä omina aliohjelminaan. Kun pelitilanne on muuten alustettu, voidaan aloittaa peli, joka tämän pelin tapauksessa tarkoittaa pallon laittamista liikkeelle. Tehdään aliohjelma, joka aloittaa pelin.
Aliohjelmien keskinäisellä järjestyksellä ei sinänsä ole merkitystä, kunhan ne ovat toistensa ulkopuolella (eli muiden aliohjelmien aaltosulkujen ulkopuolella) mutta luokan (eli äärimmäisten aaltosulkujen) sisäpuolella.
Lisää koodiisi uusi aliohjelma AloitaPeli
koko ohjelman viimisen sulun yläpuolelle.
Tässä aloita pelille tuodaan parametrina mikä pallo pistetään liikkeelle. Ja koska mitään muuta tietoa ei tarvitakkaan, voidaan aliohjelma sanoa staattiseksi.
Siirretään koodirivejä aliohjelmasta toiseen samoin kuin kentän luomisen yhteydessä.
Siirrä pelin aloitukseen liittyvät rivit (Vector impulssi
ja pallo.Hit
) Begin
-metodista AloitaPeliin
:
Lisää Begin
-aliohjelmaan siirrettyjen rivien tilalle AloitaPeli
-aliohjelmakutsu:
Huomaa, että koodin voi jakaa aliohjelmiin monin eri tavoin, tämä on vain yksi tapa.
6. Lopputulos
Näiden muutosten jälkeen luokka Pong
eli Pong-pelimme on tämän näköinen.
Huomaa että pallo saattaa kimmota seinästä oudolla kulmalla tai hidastua osuessaan mailaan. Et ole tehnyt mitään väärin, vaan vika on Jypelin käyttämässä fysiikkamoottorissa jota ei ole tarkoitettu tämän tyylisille peleille.
using Jypeli;
namespace Pong;
/// @author vesal
/// @version 20.09.2024
/// <summary>
/// Peli jossa kaksi palaajaa yrittää saada pallon toisen päätyyn.
/// </summary>
public class Pong : PhysicsGame
{
public override void Begin()
{
PhysicsObject pallo = LuoPallo(this, -200, 0);
LuoKentta();
AloitaPeli(pallo);
Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
}
private void LuoKentta()
{
PhysicsObject maila = PhysicsObject.CreateStaticObject(20.0, 100.0, Shape.Rectangle);
maila.X = Level.Left + 20.0;
maila.Y = 0.0;
maila.Restitution = 1.0;
Add(maila);
Level.CreateBorders(1.0, false);
Level.Background.Color = Color.Black;
Camera.ZoomToLevel();
}
public static PhysicsObject LuoPallo(PhysicsGame peli, double x, double y)
{
PhysicsObject pallo = new PhysicsObject(40.0, 40.0, Shape.Circle);
pallo.X = x;
pallo.Y = y;
pallo.Restitution = 1.0;
pallo.KineticFriction = 0.0;
pallo.MomentOfInertia = double.PositiveInfinity;
peli.Add(pallo);
return pallo;
}
private static void AloitaPeli(PhysicsObject pallo)
{
Vector impulssi = new Vector(500.0, 0.0);
pallo.Hit(impulssi * pallo.Mass);
}
}
Huomaa että on hyvä tapa kirjoittaa pari tyhjää riviä aliohjelmien välille.
Koodissa on neljä aliohjelmaa. Ne on merkitty seuraavassa keltaisella värillä. Tämän lisäksi attribuutti pallo
on merkattu sinisellä värillä.
Begin
= metodi joka tarvitseethis
-viitteen, Jypelin aloituskohtaLuoKentta
= metodi joka tarvitsee this, viitteen, ei mielekästä jakaa muille, siksi privateLuoPallo
= funktioaliohjelma joka palauttaa pallo-viitteen, ei tarvitsethis
-viitettä koska tuodaanpeli
parametrina, siksistatic
. Voisi olla hyödyllinen muidenkin peleissä, joten julkinen,public
.AloitaPeli
= staattinen aliohjelma koska ei tarvitse this-viitettä,private
koska ei oikeastaan hyödyllinen muille.
These are the current permissions for this document; please modify if needed. You can always modify these permissions from the manage page.