Pong-peli, vaihe 5
Tämä on Pong-pelin tutoriaalin osa 5/7. Tämän vaiheen aikana
- Lisäämme peliin näppäimet
- Laitetaan mailat liikkumaan pelaajien ohjaamina
Näin ohjelmaamme voi jo kutsua peliksi :).
1. Taustatietoa näppäimistönkuuntelusta
Jos ymmärrät jo, kuinka näppäimistönkuuntelu toimii, voit hypätä kohtaan 2.
Pelissämme on ollut alusta saakka nappi, josta pelin saa lopetettua. Lopetusnappi on asetettu Begin
-aliohjelmassa.
Pelin lopettamisen nappi on siis tehty siten, että näppäimistöltä kuunnellaan Esc-nappia, ja kun sitä painetaan, kutsutaan aliohjelmaa ConfirmExit
:
(Tätä ei tarvitse kirjoittaa uudestaan.)
Muita näppäimiä saa asetettua vastaavalla tavalla. Omien näppäinten asettamista varten tutkitaan hieman tarkemmin, miten lopetusnappi on tehty.
Aliohjelmaa Keyboard.Listen
kutsumalla saadaan peli kuuntelemaan näppäimistön painalluksia. Listen
-aliohjelmalle annetaan seuraavat parametrit:
Ensimmäinen parametri kertoo mitä näppäintä kuunnellaan. Lopetusnapissa se on Key.Escape
eli Esc-näppäin.
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 vapautettuButtonState.Pressed
: Näppäin on juuri painettu alasButtonState.Up
: Näppäin on ylhäällä (vapautettuna)ButtonState.Down
: Näppäin on alaspainettuna
Kolmas parametri on sen aliohjelman nimi, jota kutsutaan kun näppäin on siinä tilassa, mitä kuunnellaan. ConfirmExit
on valmis aliohjelma, jota kutsumalla peli kysyy halutaanko se lopettaa. Kolmas parametri voi olla myös itse kirjoitettu aliohjelma.
Neljäs parametri on ohjeteksti, joka voidaan näyttää pelaajalle tarvittaessa. Tässä tarvitsee vain kertoa mitä tapahtuu kun näppäintä painetaan. Ohjetekstin tyyppi on string
eli merkkijono eli tekstiä. Teksti kirjoitetaan lainausmerkeissä "
. Tämän parametrin arvo voi olla myös null
eli tyhjä.
Lopuksi Listen
-aliohjelmalle voi antaa lisääkin parametreja sen mukaan mitä pelissä tarvitaan. Nämä ylimääräiset parametrit välitetään näppäintä kuuntelevalle aliohjelmalle.
2. Ohjainten asettaminen
Koska näppäinten asettaminen on uusi selkeä kokonaisuus, tehdään siitä oma metodi.
Lisää ohjelmakoodiin vaikkapa ennen sen viimeistä aaltosulkua uusi metodi nimeltä AsetaOhjaimet
ja siirrä lopetusnapin tekevä rivi sinne:
Lisää AsetaOhjaimet
-aliohjelman kutsu Begin
iin.
Ohjaimet on loogista asettaa ennen kuin peli aloitetaan, joten kirjoita AsetaOhjaimet
-aliohjelman kutsu LuoKentta
ja AloitaPeli
-aliohjelmien kutsujen väliin.
Begin
näyttää muutosten jälkeen tältä:
Pong-pelissä mailan ohjaamisen ideana on, että mailaa liikkuu ylös, kun jokin näppäin on pohjassa. Kun näppäin päästetään pohjasta, maila pysähtyy.
Vaikka emme vielä tarkalleen tiedä miten saamme mailat liikkumaan, tehdään näppäimen kuuntelut toisen mailan liikuttamiseksi ylöspäin. Toivomme että toinen maila liikkuisi ylöspäin näppäimellä A
.
Kirjoita kaksi Listen
-aliohjelman kutsua lisää AsetaOhjaimet
-aliohjelmaan mailan liikuttamista varten:
Kuunnellaan näppäintä Key.A
eli A-näppäintä.
Ensimmäisessä kutsussa kerrotaan aliohjelma (AsetaNopeus
), johon tullaan kun näppäin on pohjassa (ButtonState.Down
). Aliohjelmalle viedään lisäparametreina tieto mille mailalle nopeus asetaaan ja kuinka suuri nopeus.
Toisessa kutsussa kerrotaan mitä tehdään (AsetaNopeus
), kun näppäin vapautetaan (ButtonState.Released
). Tälle ei laiteta ohjeteksitä (null
). Kerrotaan kuitenkin mille mailalle annetaan nollanopeus (Vector.Zero
).
Emme ole vielä toteuttaneet tällaisia aliohjelmia, mutta mietitään sitä vasta seuraavaksi.
3. Aliohjelma mailan liikuttamiseksi
Koska maila on fysiikkaolio, sen yhtenä ominaisuutena on nopeus (engl. velocity). Jos vain asetamme mailalle jonkin nopeuden, fysiikkapeli hoitaa mailan paikan muuttamisen.
Nopeus esitetään vektorina. Vektorin x-arvo kertoo mailan nopeuden vaakasuunnassa ja y-arvo pystysuunnassa. Millaisia vektoreita siis tarvitsemme mailan liikuttamiseen ylös ja alas? Entä miten voisimme ilmaista mailan pysäyttämisen?
Tarvitsemme kolme eri nopeusvektoria:
- Ylöspäin: nopeuden x-arvo nolla ja y-arvo positiivinen
- Alaspäin: nopeuden x-arvo nolla ja y-arvo negatiivinen
- Pysähtyminen: nopeuden x- ja y-arvot molemmat nolla eli nollavektori
Koska lisäksi mailoja on kaksi, voisimme toteuttaa mailojen liikuttamisen kuudella eri aliohjelmalla: LiikutaMaila1Ylos
, LiikutaMaila2Ylos
, LiikutaMaila1Alas
, LiikutaMaila2Alas
, PysaytaMaila1
ja PysaytaMaila2
.
Eli asettaisimme kuuntelijoita tyyliin (älä vielä kirjoita):
Keyboard.Listen(Key.A, ButtonState.Down, LiikutaMaila1Ylos, "Pelaaja 1: Liikuta mailaa ylös");
Keyboard.Listen(Key.A, ButtonState.Released, PysaytaMaila1, null);
Keyboard.Listen(Key.Z, ButtonState.Down, LiikutaMaila1Alas, "Pelaaja 1: Liikuta mailaa alas");
Keyboard.Listen(Key.Z, ButtonState.Released, PysaytaMaila1, null);
Keyboard.Listen(Key.Up, ButtonState.Down, LiikutaMaila2Ylos, "Pelaaja 2: Liikuta mailaa ylös");
Keyboard.Listen(Key.Up, ButtonState.Released, PysaytaMaila2, null);
Keyboard.Listen(Key.Down, ButtonState.Down, LiikutaMaila2Alas, "Pelaaja 2: Liikuta mailaa alas");
Keyboard.Listen(Key.Down, ButtonState.Released, PysaytaMaila2, null);
Tarkemmin ajateltuna kaikki aliohjelmat tekevät kuitenkin samaa asiaa: asettavat mailalle nopeuden. Erilaista on vain maila jolle nopeus asetetaan ja nopeuden suunta.
Viemällä liikutettavan mailan parametrina selviämme mailojen liikuttamisesta vain kolmella aliohjelmalla: LiikutaMailaaYlos
, LiikutaMailaaAlas
ja PysaytaMaila
.
Älä kirjoita alla olevia aliohjelmia itse.
Kun jälleen tarkastellaan kolmea aliohjelmaamme, huomataan että jokaisessa edelleen toistuu vektorin luominen ja sen asettaminen mailalle nopeudeksi. Erilaista on vain millainen vektori nopeudeksi asetetaan.
Jos myös nopeus vietäisiin parametrina, selviäisimme mailojen liikuttamisesta yhdellä ainoalla aliohjelmalla!
Mailojen liikuttamisen voimme siis hoitaa kuuden aliohjelman sijaan yhdellä aliohjelmalla AsetaNopeus
, jolle annetaan parametrina maila jota liikutetaan, ja mailan nopeuden vektori.
Kirjoita siis aliohjelma AsetaNopeus
ja sille alla oleva koodi:
Nopeusvektorit pelin vakioiksi
Listen
-aliohjelmalle voi antaa mitä tahansa omia parametrejä pakollisten parametrien jälkeen. Nämä parametrit toimitetaan näppäintä kuuntelevalle aliohjelmalle.
Tehdään vektoreille vakiot, jotka voimme antaa parametreina mailan liikuttamisesta vastaavalle aliohjelmalle.
Esittele luokan alussa uudet vakiovektorit nopeusYlos
ja nopeusAlas
:
Mailojen luominen
Mailojen kanssa tulee nyt se ongelma, että niitä tarvittaisiin AsetaOhjeimet
-metodissa, mutta ne on luotu LuoKentta
-metodissa. Koska AsetaOhjeimet
kutsutaan Begin
-metodista, voisi sittenkin olla järkeä siirtää mailojen luominen Begin
-metodiin ja sitten kertoa AsetaOhjaimet
-metodille että mihin mailoihin ohjaimet liitetään.
LuoMaila
-funktion tekemät mailat saadaan otettua talteen muuttujiin sen takia, että LuoMaila
palauttaa tehdyn mailan. Ilman palauttamista maila kyllä tehtäisiin, mutta emme luomisen jälkeen pystyisi enää viittaamaan siihen millään tavalla.
Nyt meillä on olemassa mailat maila1
ja maila2
, jotka voidaan viedä parametrina AsetaOhjeimet
-metodille.
3.3. Maila liikkumaan ylöspäin
Lisätään AsetaOhjaimet
-metodiin parametrit mailoja varten ja muutetaan AsetaOhjaimet
-aliohjelman Listen
-kutsuja niin, että suoritetaan AsetaNopeus
-aliohjelmaa ja viedään sille parametrina se maila, johon halutaan vaikuttaa, ja se vektori, joka halutaan mailalle asettaa nopeudeksi:
Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
}
(Ellei pelisi toimi, yritä selvittää mistä vika johtuu, tai pyydä ohjaajaa auttamaan.)
4. Molempien mailojen liikuttaminen
Molempien mailojen liikuttaminen voidaan nyt tehdä helposti vain lisäämällä Keyboard.Listen
-kutsuja.
Täydennä AsetaOhjaimet
-aliohjelmaasi vielä seuraavat vihreällä merkityt Listen
-kutsut:
Keyboard.Listen(Key.Z, ButtonState.Down, AsetaNopeus, "Pelaaja 1: Liikuta mailaa alas", maila1, nopeusAlas);
Keyboard.Listen(Key.Z, ButtonState.Released, AsetaNopeus, null, maila1, Vector.Zero);
Keyboard.Listen(Key.Up, ButtonState.Down, AsetaNopeus, "Pelaaja 2: Liikuta mailaa ylös", maila2, nopeusYlos);
Keyboard.Listen(Key.Up, ButtonState.Released, AsetaNopeus, null, maila2, Vector.Zero);
Keyboard.Listen(Key.Down, ButtonState.Down, AsetaNopeus, "Pelaaja 2: Liikuta mailaa alas", maila2, nopeusAlas);
Keyboard.Listen(Key.Down, ButtonState.Released, AsetaNopeus, null, maila2, Vector.Zero);
Keyboard.Listen(Key.F1, ButtonState.Pressed, ShowControlHelp, "Näytä ohjeet");
Kuten nyt nähdään, mailan ja nopeuden vieminen parametrina Keyboard.Listen
-aliohjelmalle oli todella hyödyllistä, sillä voimme nyt helposti lisätä ohjauksen useammalle kuin yhdelle mailalle emmekä tarvitse ohjaamiseen kuin yhden aliohjelman.
Vielä on lisätty yksi kuunteli, joka F1
-painikkeesta tulostaa ohjainten avustuksen.
Kokeile miten pelisi toimii!
5. Lopputulos
Kun mailojen ohjaaminen on mukana, näyttää koodi seuraavalta:
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
{
private readonly Vector nopeusYlos = new Vector(0, 200);
private readonly Vector nopeusAlas = new Vector(0, -200);
public override void Begin()
{
PhysicsObject pallo = LuoPallo(this, -200, 0);
PhysicsObject maila1 = LuoMaila(this,Level.Left + 20.0, 0.0);
PhysicsObject maila2 = LuoMaila(this,Level.Right - 20.0, 0.0);
LuoKentta();
AsetaOhjaimet(maila1, maila2);
AloitaPeli(pallo);
}
private void LuoKentta()
{
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;
}
public static PhysicsObject LuoMaila(PhysicsGame peli, double x, double y)
{
PhysicsObject maila = PhysicsObject.CreateStaticObject(20.0, 100.0, Shape.Rectangle);
maila.X = x;
maila.Y = y;
maila.Restitution = 1.0;
peli.Add(maila);
return maila;
}
private static void AloitaPeli(PhysicsObject pallo)
{
Vector impulssi = new Vector(500.0, 0.0);
pallo.Hit(impulssi * pallo.Mass);
}
private void AsetaOhjaimet(PhysicsObject maila1, PhysicsObject maila2)
{
Keyboard.Listen(Key.A, ButtonState.Down, AsetaNopeus, "Pelaaja 1: Liikuta mailaa ylös", maila1, nopeusYlos);
Keyboard.Listen(Key.A, ButtonState.Released, AsetaNopeus, null, maila1, Vector.Zero);
Keyboard.Listen(Key.Z, ButtonState.Down, AsetaNopeus, "Pelaaja 1: Liikuta mailaa alas", maila1, nopeusAlas);
Keyboard.Listen(Key.Z, ButtonState.Released, AsetaNopeus, null, maila1, Vector.Zero);
Keyboard.Listen(Key.Up, ButtonState.Down, AsetaNopeus, "Pelaaja 2: Liikuta mailaa ylös", maila2, nopeusYlos);
Keyboard.Listen(Key.Up, ButtonState.Released, AsetaNopeus, null, maila2, Vector.Zero);
Keyboard.Listen(Key.Down, ButtonState.Down, AsetaNopeus, "Pelaaja 2: Liikuta mailaa alas", maila2, nopeusAlas);
Keyboard.Listen(Key.Down, ButtonState.Released, AsetaNopeus, null, maila2, Vector.Zero);
Keyboard.Listen(Key.F1, ButtonState.Pressed, ShowControlHelp, "Näytä ohjeet");
Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
}
public static void AsetaNopeus(PhysicsObject maila, Vector nopeus)
{
maila.Velocity = nopeus;
}
}
These are the current permissions for this document; please modify if needed. You can always modify these permissions from the manage page.