ebSkola

3.5 Statistikas sistēma un struct

Stundas uzdevums: Izmantot struct datu grupēšanai un kompozīciju (composition) klašu organizēšanai.

SR 2.4.16. Saliktas datu struktūras SR 2.4.18. OOP

80 min plāns: Teorija un paraugs (~10 min) · 1. uzdevums (~20 min) - izveido struct statistikai · 2. uzdevums (~25 min) - ieliec struct klasē un pievieno metodes · 3. uzdevums (~20 min) - pievieno pagaidu bonusus sarakstā · Iesniegšana (~5 min).

Pirms sāc: atver savu dalībnieku klasi. Šodien sakārtosi tās laukus: tā vietā, lai klasē būtu desmit atsevišķi skaitļi, tie visi dzīvos vienā struct.

Teorija: struct un kompozīcija

struct ir vienkāršāka klase - visi lauki ir public pēc noklusējuma. Lietojama datu grupēšanai.

using System;

public struct Stats
{
    public int Energy;
    public int MaxEnergy;
    public int Focus;
    public int Calm;
    public int Speed;

    public Stats(int energy = 100, int focus = 10, int calm = 5, int speed = 5)
    {
        Energy = energy;
        MaxEnergy = energy;
        Focus = focus;
        Calm = calm;
        Speed = speed;
    }

    public void Heal(int amount)
    {
        Energy = Math.Min(MaxEnergy, Energy + amount);
    }
}

public class Participant
{
    private Stats stats = new Stats();        // kompozīcija!
    private string name;

    public Participant(string name)
    {
        this.name = name;
    }

    public ref Stats GetStats() => ref stats;  // atgriež references
}

Kompozīcija (klase satur citu klasi) bieži ir labāka par mantošanu - fleksiblāka un mazāk saistīta.

Kā šo izmantot projektā

Atceries: ar redzamu efektu editorā nepietiek. Paskaidro, kura C# klase glabā stāvokli, kura metode to maina un kā Godot node struktūra izmanto šo kodu.

Pārbaudi: katrai būtiskai turnīra lomai ir C# klase vienā .cs failā, ar konstruktoriem, metodēm, signāliem vai mantošanu.

public class OopCheckpoint
{
    public string Lesson = "3.5 Statistikas sistēma un struct";
    public bool UsesCSharp = true;
    public bool HasScriptFile = true;
    public bool HasSingleResponsibility = true;
    public bool UsesGodotInspector = true;
}

Praktiskie uzdevumi

1. uzdevums -

Izveido struct statistikai

Beigās visi dalībnieka skaitļi būs vienuviet.

  1. Uzraksti failā Stats.cs public struct Stats {.
  2. Pievieno laukus public int Energy; un public int MaxEnergy;.
  3. Pievieno arī public int Focus;, public int Calm; un public int Speed;.
  4. Ievēro, ka C# struct laukiem jāraksta public, ja tos vajag lietot ārpus struktūras.
  5. Izveido objektu Stats s = new Stats(); un izdrukā visus laukus.
  6. Nomaini vienu lauku un izdrukā vēlreiz.
  7. Pieraksti, ar ko struct atšķiras no class.

Gatavs, kad: izdrukā redzamas visas noklusējuma vērtības, un tu vari nosaukt atšķirību no class.

2. uzdevums -

Ieliec struct klasē un pievieno metodes

Beigās klase glabās statistiku vienā laukā, nevis piecos.

  1. Pievieno Participant klasei privātu lauku private Stats stats = new Stats();.
  2. Izdzēs vecos atsevišķos skaitļu laukus.
  3. Pievieno Stats struktūrai metodi public void Heal(int amount).
  4. Ieraksti tajā Energy = Math.Min(MaxEnergy, Energy + amount);.
  5. Pievieno klasei publisku metodi public ref Stats GetStats() => ref stats;.
  6. Izsauc p.GetStats().Heal(30); un izdrukā enerģiju.
  7. Pārbaudi, ka enerģija nepārsniedz maksimumu.

Gatavs, kad: pēc lielas dziedināšanas enerģija apstājas tieši uz max_energy, nevis to pārsniedz.

3. uzdevums -

Pievieno pagaidu bonusus sarakstā

Beigās dalībniekam varēs uzlikt bonusus, kas summējas.

  1. Izveido public struct Buff { public string Name; public int FocusBonus; }.
  2. Pievieno Stats klasei lauku public List<Buff> Buffs = new();.
  3. Uzraksti metodi public int GetTotalFocus().
  4. Saskaiti tajā ciklā pamata Focus plus visu bonusu summu.
  5. Pievieno divus bonusus un izdrukā kopējo fokusu.
  6. Izdzēs vienu bonusu un izdrukā vēlreiz.
  7. Pieraksti, kāpēc kopējo vērtību labāk rēķināt, nevis glabāt atsevišķā laukā.

Gatavs, kad: kopējais fokuss mainās, pievienojot un noņemot bonusus, un vienmēr sakrīt ar summu.

Papildu uzdevums - Pievieno bonusiem ilgumu

Ja pamatdarbs ir gatavs, liec bonusiem beigties pēc dažām kārtām.

  1. Pievieno Buff struktūrai lauku public int TurnsLeft;.
  2. Uzraksti metodi, kas samazina visiem bonusiem TurnsLeft par vienu.
  3. Izdzēs no saraksta tos, kuriem tas sasniedzis nulli.
  4. Izsauc šo metodi trīs reizes pēc kārtas.
  5. Izdrukā pēc katras reizes kopējo fokusu.

Gatavs, kad: bonusi pazūd paši pēc norādītā kārtu skaita, un fokuss atgriežas sākuma vērtībā.

Ko sagatavo

Stundas mērķis: Tu proti izveidot struct datu grupēšanai, ielikt to klasē kā lauku (kompozīcija) un rēķināt kopējo vērtību no saraksta, nevis glabāt to atsevišķi.

GitHub krātuvē jābūt:

  1. Faili Stats.cs un atjauninātais Participant.cs.
  2. Ekrānuzņēmums ar Output paneli, kurā redzams kopējais fokuss pirms un pēc bonusa noņemšanas.
  3. README.md: ar ko struct atšķiras no class un kāpēc kopējo fokusu labāk rēķināt.

Kā iesniedz: Veic commit un push. Skolotāja norādītajā vietā ievieto tikai GitHub krātuves saiti; visiem prasītajiem failiem, README.md pierakstiem un pierādījumiem jābūt pašā krātuvē.

Biežākās kļūdas

  • Stats noklusējuma vērtības neuzstādās: C# struct bez konstruktora dod 0 vērtības. Inicializē ar konstruktoru.
  • List iteration kļūda: nemaini List<Buff> tajā pašā foreach; lieto for vai RemoveAll.
  • Slow buff lookup: lielam bonusu skaitam lieto Dictionary<string, Buff> vai atsevišķu indeksu.

Godot ekrānuzņēmumi

Spēles HUD ar varoņa Stats panelu: ENERGY 80/100, FOCUS 15 (+5 buff), CALM 5, SPD 5, aktīvi buffs sarakstā.
Spēles HUD ar varoņa Stats panelu: ENERGY 80/100, FOCUS 15 (+5 buff), CALM 5, SPD 5, aktīvi buffs sarakstā.

Koda piemērs (paplašināts)

using System;
using System.Collections.Generic;

public struct Buff
{
    public string Target;
    public int Amount;
    public float Duration;
}

public class Stats
{
    public int Energy = 100;
    public int MaxEnergy = 100;
    public int Focus = 10;
    public int Calm = 5;
    public int Speed = 5;
    public List<Buff> Buffs = new();

    public int GetTotalFocus()
    {
        int total = Focus;
        foreach (Buff buff in Buffs)
        {
            if (buff.Target == "focus") total += buff.Amount;
        }
        return total;
    }

    public void ApplyPenalty(int amount)
    {
        int actual = Math.Max(1, amount - Calm);
        Energy = Math.Max(0, Energy - actual);
    }

    public void Update(float delta)
    {
        for (int i = 0; i < Buffs.Count; i++)
        {
            Buff buff = Buffs[i];
            buff.Duration -= delta;
            Buffs[i] = buff;
        }
        Buffs.RemoveAll(buff => buff.Duration <= 0);
    }
}
Participant get_total_focus atgriež 15 (10 base + 5 buff), pēc 30 sec - atkal 10.