ebSkola

4.1 List un Array

Stundas uzdevums: Saprast atšķirību starp C# List<T> un Godot Array, izvēlēties piemēroto datu struktūru.

SR 2.4.16. Saliktas datu struktūras SR 2.4.13. Datu tipi

80 min plāns: Teorija un paraugs (~10 min) · 1. uzdevums (~20 min) - izveido ienaidnieku sarakstu ar List<T> · 2. uzdevums (~25 min) - pievieno un izņem elementus droši · 3. uzdevums (~20 min) - salīdzini List<T> ar Godot Array · Iesniegšana (~5 min).

Pirms sāc: atceries no Programmēšanas I sarakstus: materiali.append("x") un materiali.pop(0). C# tas pats parasti ir List<T>, ar Add() un RemoveAt().

Teorija: Sarakstu datu struktūras

Godot C# kontekstā ir divas saraksta opcijas:

TipsLietojumsPiemērs
List<T>Iekšējais C# kods, tipa-drošsList<Enemy> enemies = new();
Godot.Collections.ArrayKomunikācijai ar GodotArray bullets = new();
Godot.Collections.Array<T>Tipa-droša Godot ArrayGodot.Collections.Array<Bullet> bullets = new();
using Godot;
using Godot.Collections;
using System.Collections.Generic;

List<Enemy> enemies = new();

enemies.Add(new Enemy());
foreach (Enemy enemy in enemies) enemy.UpdateEnemy();
enemies.RemoveAt(2);  // dzēš 3.

// Godot Array
Array bullets = new();
bullets.Add(newBullet);
bullets.Count;
bullets.RemoveAt(bullets.Count - 1);

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: C# kodā pamatoti izvēlēti List, Dictionary vai HashSet, AI stāvokļi ir skaidri, un sarežģītākas sistēmas var profilēt vai atkļūdot.

public class AiDataCheckpoint
{
    public string Lesson = "4.1 List un Array";
    public bool UsesCSharp = true;
    public bool ChoosesContainer = true;
    public bool SeparatesAiState = true;
    public bool HandlesRemovalSafely = true;
}

Praktiskie uzdevumi

1. uzdevums -

Izveido ienaidnieku sarakstu ar List

Beigās viens mainīgais glabās visus ienaidniekus.

  1. Pievieno faila sākumā using System.Collections.Generic;.
  2. Pievieno klasei lauku private List<Enemy> enemies = new();.
  3. Pievieno trīs ienaidniekus ar enemies.Add(enemy);.
  4. Izdrukā to skaitu ar enemies.Count.
  5. Uzraksti ciklu foreach (Enemy enemy in enemies) { ... }, kas izdrukā katra nosaukumu.
  6. Pievieno ceturto ienaidnieku un palaid vēlreiz.
  7. Pārbaudi, vai cikls bija jāmaina.

Gatavs, kad: cikls izdrukā visus ienaidniekus, un pievienojot ceturto, kods nav jāmaina.

2. uzdevums -

Pievieno un izņem elementus droši

Beigās tu zināsi, kāpēc sarakstu nedrīkst mainīt cikla laikā.

  1. Izņem otro elementu ar enemies.RemoveAt(1);.
  2. Izdrukā saraksta izmēru pirms un pēc izņemšanas.
  3. Mēģini piekļūt elementam enemies[10] un pieraksti, kas notiek.
  4. Nomaini to uz if (index >= 0 && index < enemies.Count) pārbaudi un salīdzini rezultātu.
  5. Uzraksti ciklu, kas cikla iekšpusē mēģina izdzēst elementu, un palaid to.
  6. Pārraksti to tā, lai dzēšamos vispirms savāktu otrā sarakstā.
  7. Pieraksti, kāpēc pirmais variants ir bīstams.

Gatavs, kad: saraksta izmērs pēc dzēšanas ir par vienu mazāks, un droši dzēst izdodas tikai pēc cikla.

3. uzdevums -

Salīdzini List ar Godot Array

Beigās tu zināsi, kuru sarakstu kurā vietā lietot.

  1. Izveido Godot.Collections.Array bullets = new(); un pievieno tam dažas vērtības.
  2. Izdrukā tā izmēru ar bullets.Count.
  3. Mēģini ielikt Array sarakstā gan skaitli, gan tekstu.
  4. Mēģini to pašu ar List<int> un izlasi kompilatora kļūdu.
  5. Pieraksti, kurš saraksts pieļauj dažādus tipus.
  6. Pieraksti, kurš saraksts ir vajadzīgs, lai datus nodotu Godot editoram.
  7. Izvēlies savam ienaidnieku sarakstam pareizo variantu un pamato izvēli.

Gatavs, kad: tu vari pateikt, ka List<T> ir tipa-drošs un ērts iekšējam C# kodam, bet Array vajadzīgs saziņai ar Godot datiem.

Papildu uzdevums - Atrodi tuvāko ienaidnieku

Ja pamatdarbs ir gatavs, izmanto sarakstu reālam aprēķinam.

  1. Uzraksti metodi, kas saņem spēlētāja pozīciju.
  2. Izej ciklā cauri visiem ienaidniekiem.
  3. Izrēķini katram attālumu ar Position.DistanceTo(...).
  4. Saglabā mainīgajā to, kuram attālums ir mazākais.
  5. Izdrukā tuvākā ienaidnieka nosaukumu un attālumu.

Gatavs, kad: metode atgriež tieši to ienaidnieku, kurš ekrānā ir vistuvāk spēlētājam.

Ko sagatavo

Stundas mērķis: Tu proti C# izveidot List<T> sarakstu, droši pievienot un izņemt elementus un izskaidrot, ar ko tas atšķiras no Godot Array.

GitHub krātuvē jābūt:

  1. C# fails ar ienaidnieku sarakstu un ciklu.
  2. Ekrānuzņēmums ar Output paneli, kurā redzams saraksta izmērs pirms un pēc dzēšanas.
  3. README.md: kāpēc sarakstu nedrīkst mainīt cikla laikā un kad lieto Array, nevis List<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

  • ArgumentOutOfRangeException: sarakstā nav elementa ar tādu indeksu - pārbaudi index < enemies.Count.
  • NullReferenceException: sarakstā ielikta tukša reference vai mezgls nav atrasts.
  • Collection was modified: pievienojot vai dzēšot no List<T> foreach laikā, cikls apstājas ar kļūdu.

Godot ekrānuzņēmumi

Spēles aina: 5 ienaidnieki dažādās vietās ekrānā, viens ar 0 HP, kas tūlīt pazudīs.
Spēles aina: 5 ienaidnieki dažādās vietās ekrānā, viens ar 0 HP, kas tūlīt pazudīs.

Koda piemērs (paplašināts)

using Godot;
using System.Collections.Generic;

public partial class Game : Node2D
{
    [Export] public PackedScene EnemyScene;
    private readonly List<Enemy> enemies = new();
    private double spawnTimer = 0.0;

    private void SpawnEnemy()
    {
        Enemy enemy = EnemyScene.Instantiate<Enemy>();
        AddChild(enemy);
        enemy.Position = new Vector2((float)GD.RandRange(0.0, 1280.0), 0);
        enemies.Add(enemy);
    }

    public override void _PhysicsProcess(double delta)
    {
        spawnTimer += delta;
        if (spawnTimer >= 2.0)
        {
            SpawnEnemy();
            spawnTimer = 0.0;
        }

        // Noņem mirušos
        enemies.RemoveAll(enemy => !enemy.IsAlive());
    }
}
Spēle spawno 1 ienaidnieku ik pa 2 sec, mirstīgi tiek noņemti no vektora un scēnas.