Datu pastāvība //
un algoritmi
Saglabā un ielādē spēles stāvokli ar FileAccess un Json. Ģenerē labirintus ar Random Walk algoritmu. Izproti Big-O.
6 stundas - save/load, procedurālā ģenerēšana un Big-O
Failu I/O Godot vidē
FileAccess.Open(), StoreString(), GetAsText(), user:// direktorija.
JSON serializācija un Resource sistēma
Json.Stringify(), Json.Parse(), Godot Resource saglabāšana, .tres faili.
Save/Load arhitektūra
Viena atbildīgā SaveManager klase, GameState serializācija, ielāde spēles uzsākšanā.
Procedural generation ar Random Walk
Binary Space Partitioning - rekursīva telpu dalīšana, istabu izveide, koridoru savienošana.
Algoritmu efektivitāte
Big-O notācija, O(1)/O(log n)/O(n)/O(n²) salīdzinājums, Godot Profiler izmantošana.
Noslēguma projekts: Procedurālais labirints
Procedurāli ģenerēts labirints ar save/load, meta-progresu un savācamiem materiāliem.
5. tēmas špikeris - dati, saglabāšana un algoritmi
Failu darbs, JSON, saglabāšanas sistēma, procedurālā ģenerēšana un efektivitāte. Katrs bloks atbilst vienai stundai.
5.1 Failu lasīšana un rakstīšana
using Godot;
// res:// - projekta faili, TIKAI lasīšanai gatavā spēlē
// user:// - spēlētāja dati, te saglabā (Project -> Open User Data Folder)
using FileAccess file = FileAccess.Open("user://save.txt", FileAccess.ModeFlags.Write);
if (file != null) // VIENMĒR pārbaudi
{
file.StoreString("Sveiks!");
file.Store32(150);
}
// Nolasīšana ar trūkstoša faila apstrādi (= Python FileNotFoundError)
int LoadScore()
{
if (!FileAccess.FileExists("user://save.txt")) return 0;
using FileAccess readFile = FileAccess.Open("user://save.txt", FileAccess.ModeFlags.Read);
return readFile != null ? (int)readFile.Get32() : 0;
}
Nolasīšanas secībai jābūt TIEŠI tādai pašai kā rakstīšanas secībai, citādi dati sajūk.
5.2 JSON - salasāms saglabāšanas fails
using Godot;
using Godot.Collections;
// Dictionary -> teksts
Dictionary save = new();
save["player_name"] = "Anna";
save["level"] = 5;
string txt = Json.Stringify(save, " "); // " " = atkāpes, salasāmi
// Teksts -> Dictionary AR kļūdas pārbaudi
Json json = new Json();
Error err = json.Parse(txt);
if (err != Error.Ok)
{
GD.PrintErr("Bojāts save fails, sāku no jauna");
return DefaultData(); // nevis avarē
}
Dictionary data = json.Data.AsGodotDictionary();
Salasāms fails ir ērts atkļūdošanai, bet spēlētājs to var arī izlabot - tāpēc nekad neuzticies tā saturam akli.
5.3 Save sistēma ar slotiem un versiju
using Godot.Collections;
using System.Collections.Generic;
public interface ISaveable // interfeiss: ko prot katrs objekts
{
Dictionary SaveState();
void LoadState(Dictionary data);
}
public class SaveManager
{
private readonly List<ISaveable> objects = new();
public string SlotPath(int slot) => $"user://slot{slot}.json";
public Dictionary Collect()
{
Dictionary all = new();
all["version"] = 1; // versija: vecs fails nesabojā spēli
for (int i = 0; i < objects.Count; i++)
all[i] = objects[i].SaveState();
return all;
}
}
// Ielādējot:
if (data["version"].AsInt32() != 1) { /* brīdini un lieto noklusējumus */ }
SaveManager nezina, kas ir spēlētāja iekšienē - katrs objekts saglabā sevi pats.
5.4 Procedurālā ģenerēšana ar Random Walk
using System;
// 1 = siena, 0 = eja
int[,] grid = new int[15, 15];
for (int yy = 0; yy < 15; yy++)
for (int xx = 0; xx < 15; xx++)
grid[yy, xx] = 1;
int x = 7, y = 7; // sāc no centra
grid[y, x] = 0;
Random rng = new Random();
for (int i = 0; i < 200; i++)
{
int dir = rng.Next(0, 4);
if (dir == 0 && x > 1) x--; // robežu pārbaude OBLIGĀTA
else if (dir == 1 && x < 13) x++;
else if (dir == 2 && y > 1) y--;
else if (dir == 3 && y < 13) y++;
grid[y, x] = 0;
}
// OBLIGĀTI: pārbaudi, vai izeja ir sasniedzama, un ģenerē atkārtoti, ja nav.
// Režģis -> ekrāns:
// wall.Position = new Vector2(x * 64, y * 64);
Bez izejamības pārbaudes spēlētājs var sākt līmenī, kuru nav iespējams izspēlēt.
5.5 Efektivitāte: mēri, nevis min
using Godot;
ulong t0 = Time.GetTicksUsec();
Darbiba();
ulong t1 = Time.GetTicksUsec();
GD.Print("Aizņēma ", t1 - t0, " mikrosekundes");
// Big O - kā laiks aug, palielinoties datiem 10x:
// O(1) nemainās saraksts[0]
// O(log n) +daži soļi binārā meklēšana, Dictionary
// O(n) 10x viens cikls
// O(n log n) ~13x Sort()
// O(n^2) 100x divi ligzdoti cikli
// Godot: Debugger -> Profiler -> Start -> spēlē 30 s -> kārto pēc laika
Neoptimizē kodu, kas izpildās reti. Vispirms ar profileri atrodi, kur laiks tiešām aiziet.