›_ ebskola.lv
← 1.5

1.6 Noslēguma projekts: Pong

Stundas uzdevums: Apvienot tēmas prasmes - Godot Scene Tree, C++ klases - pilnvērtīgā Pong arkādes spēlē.

SR 2.4.1. Problēmas dekompozīcija SR 2.4.7. UI SR 2.4.15. Modulāras programmas SR 2.4.3. Prototipu izstrāde un testēšana

Pirms sāc: izmanto iepriekš apgūto un šīs lapas teorijas/koda piemērus. Ja vajadzīga jauna komanda vai rīks, vispirms atrodi tās paraugu teorijas sadaļā.

Teorija: Spēles apraksts un arhitektūra

Pong ir klasiska 1972. gada arkādes spēle. Divi spēlētāji vada vertikālas paddles un atsit bumbu pretiniekam. Pirmais ar 5 punktiem uzvar.

Šis projekts ir labs 1. tēmas noslēgumam, jo tajā ir maz objektu, bet tie pārbauda gandrīz visu pamatu: Scene Tree, atkārtoti lietojamas scēnas, Input Map, C++ klases, sadursmes, UI atjaunināšanu un spēles stāvokli. Pong nav izvēlēts tāpēc, ka tas ir vizuāli sarežģīts; tas ir izvēlēts tāpēc, ka kļūdas tajā ir viegli pamanāmas.

Spēles loģika tiek rakstīta C++. Godot editorā drīkst salikt scēnas un iestatīt resursus, bet paddle kustība, bumbas atlēkšana, punktu pieskaitīšana un uzvaras pārbaude jārealizē GDExtension klasēs.

C++ klases:

class Game : public Node {
    GDCLASS(Game, Node)
private:
    int score_left = 0;
    int score_right = 0;
    Ball *ball = nullptr;
public:
    void _ready() override;
    void on_score(bool left_player);
    void reset_ball();
    void update_score_labels();
};

Praktiskie uzdevumi

1. uzdevums - Iesildies ar gatavu piemēru

Šis ir īss iesildīšanās uzdevums. Nokopē sagatavi, ielīmē to pareizajā koda vietā un palaid. Šeit pietiek droši izmēģināt tēmu 1.6 Noslēguma projekts: Pong; detalizētu izpratni veidosi nākamajos uzdevumos.

Kopējamais piemērs vai sagatave: izmanto šo bloku kā starta punktu, nevis kā gala risinājumu.

class Game : public Node {
    GDCLASS(Game, Node)
private:
    int score_left = 0;
    int score_right = 0;
    Ball *ball = nullptr;
public:
    void _ready() override;
    void on_score(bool left_player);
    void reset_ball();
    void update_score_labels();
};
  1. Atver darba failu vai rīku. C++ fragmentu ievieto atbilstošajā .cpp vai .hpp failā pie šīs stundas klases.
  2. Nokopē visu piemēra bloku no šī uzdevuma un ielīmē to norādītajā vietā.
  3. Palaid kodu tieši tādu, kāds tas ir, un pārliecinies, ka parādās rezultāts, izvade vai vismaz nav kļūdas paziņojuma.
  4. Atrodi vienu drošu vietu, ko drīkst mainīt: tekstu, skaitli, krāsu, mainīgā vērtību vai testa ierakstu.
  5. Maini tikai šo vienu vērtību un palaid kodu vēlreiz.
  6. Salīdzini rezultātu pirms un pēc izmaiņas. Ja parādās kļūda, atcel pēdējo izmaiņu un palaid vēlreiz.
  7. Turpini pie 2. uzdevuma tikai tad, kad šis mazais piemērs darbojas.

2. uzdevums - Ievieto algoritmu spēles projektā

Pievieno šīs stundas paņēmienu kā nelielu, strādājošu spēles mehānikas daļu.

  1. Izvēlies vienu projekta vietu: spēlētāju, pretinieku, kameru, UI, datu glabāšanu, sadursmi vai līmeņa ģenerēšanu.
  2. Nosauc klases, metodes un mainīgos pēc to lomas, piemēram, PlayerState, velocity, score vai update_ui().
  3. Uzraksti metodi, kas nolasa stāvokli, veic vienu skaidru darbību un atgriež vai parāda rezultātu.
  4. Izsauc šo metodi no piemērotas vietas: _ready(), _process(), _physics_process(), signāla apstrādātāja vai projekta palīgklases.
  5. Pievieno vienu īsu komentāru pie sarežģītākās loģikas vietas.
  6. Pārkompilē projektu un pārbaudi, ka editorā nav kļūdu.
  7. Salabo pirmo atrasto kļūdu pirms pievieno nākamo mehānikas daļu.
  8. Veic Git commit ar īsu tehnisku ziņu par pievienoto C++ funkcionalitāti.

3. uzdevums - Testē mehāniku un izdari secinājumu

Pārbaudi, vai C++ algoritms darbojas paredzami spēles vidē.

  1. Izveido trīs testa scenārijus: parastu darbību, robežgadījumu un kļūdainu vai neērtu spēlētāja darbību.
  2. Palaid parasto scenāriju un pārbaudi rezultātu spēles logā vai Godot konsolē.
  3. Palaid robežgadījumu ar mazāko, lielāko, tukšo vai nulles vērtību, ko mehānika pieļauj.
  4. Palaid kļūdaino scenāriju un pārbaudi, vai projekts neavarē.
  5. Izlabo vienu konkrētu problēmu C++ kodā, node sasaistē vai datu inicializācijā.
  6. Pārkompilē un pārbaudi labojumu vēlreiz ar visiem trim scenārijiem.
  7. Beigās pieraksti vienu secinājumu: kura metode, klase vai algoritma solis vislabāk palīdzēja saprast tēmu 1.6 Noslēguma projekts: Pong.

Papildu uzdevums - Pievieno mazu mehāniku

Ja pamatdarbs ir pabeigts, paplašini spēli ar vienu nelielu C++ uzlabojumu.

  1. Izvēlies vienu mazu papildinājumu, kas izmanto to pašu šīs stundas paņēmienu.
  2. Pievieno vienu jaunu atribūtu, metodi, signāla apstrādi, datu elementu vai UI atjauninājumu.
  3. Savieno papildinājumu ar esošo scēnu vai klasi, nevis atstāj to atsevišķā demonstrācijā.
  4. Pārkompilē un pārliecinies, ka pamatmehānika joprojām darbojas.
  5. Saglabā izmaiņas ar Git commit tikai pēc veiksmīgas pārbaudes.

Papildu izaicinājumi

Pievieno vienu uzlabojumu, kas neizjauc pamata spēli.

Biežākās kļūdas

Godot ekrānuzņēmumi

Pong spēle darbojas pilnekrāna režīmā ar punktiem 3:2, bumba ceļā uz labo paddle, AI pretinieks otrā pusē.
Pong spēle darbojas pilnekrāna režīmā ar punktiem 3:2, bumba ceļā uz labo paddle, AI pretinieks otrā pusē.
Project Settings → Input Map ar konfigurētiem darbībām p1_up, p1_down, p2_up, p2_down un to taustiņu piesaistēm.
Project Settings → Input Map ar konfigurētiem darbībām p1_up, p1_down, p2_up, p2_down un to taustiņu piesaistēm.

Koda piemērs (paplašināts)

void Ball::reset_ball() {
    set_position(Vector2(640, 360));
    double y_speed = UtilityFunctions::randf_range(-180.0, 180.0);
    velocity = Vector2(base_speed, y_speed);
}

void Ball::_physics_process(double delta) {
    auto collision = move_and_collide(velocity * delta);
    if (collision.is_valid()) {
        velocity = velocity.bounce(collision->get_normal());
        velocity *= 1.05f;
    }
}

void Game::on_score(bool left_player) {
    if (left_player) score_left++;
    else score_right++;
    update_score_labels();
    ball->reset_ball();
}

void Game::update_score_labels() {
    score_left_label->set_text(String::num_int64(score_left));
    score_right_label->set_text(String::num_int64(score_right));
}
Pilnvērtīgi spēlējams Pong ar punktu uzskaiti, paātrinošu bumbu un uzvarētāja paziņojumu.
⬅ Iepriekšējā stunda Tēmas apkopojums ➡