›_ ebskola.lv
sākt stundu →
Prog II · 3. tēma · 6 stundas - C# OOP · mantošana · signāli

Objektorientētā // programmēšana

Apgūsti C# klases, mantošanu un polimorfismu Godot .NET vidē. Tēma noslēdzas ar RPG klases simulatora izveidi.

6 stundas class · mantošana virtual · override projekts RPG
C# OOP mantošana · virtual [Export] īpašības
# 02 špikeris

3. tēmas špikeris - klases C# valodā

No pirmās klases līdz signāliem un Inspector īpašībām. Ja klases redzi pirmoreiz, sāc ar pirmo bloku.

3.1 No Python vārdnīcas uz C# klasi

// Python, ko jau zini:
//   dalibnieks = {"vards": "Anna", "energija": 100}
//   dalibnieks["energija"] -= 20

public class Participant
{
    private int energy;          // pieejams TIKAI klases iekšienē
    private int maxEnergy;

    public string Name;          // pieejams no ārpuses
    public int Level = 1;

    public Participant(string name, int energy)  // konstruktors
    {
        Name = name;
        this.energy = energy;
        maxEnergy = energy;
    }

    public void ApplyPenalty(int amount)         // metode = funkcija klasē
    {
        energy -= amount;
        if (energy < 0) energy = 0;
    }

    public bool IsActive() => energy > 0;
    public int GetEnergy() => energy;            // privāto lasa caur metodi
}

Participant p = new Participant("Anna", 100);
p.ApplyPenalty(30);
// p.energy = 9999;   <- KOMPILATORA KĻŪDA: energy ir private

C# klases beigās semikolu nevajag, bet katras komandas rindas beigās parasti vajag ;.

3.2 Mantošana: viena bāze, vairākas lomas

using System;
using System.Collections.Generic;

public class Participant
{
    private string name;
    private int energy;

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

    public virtual void ApplyPenalty(int amount)        // virtual = drīkst pārrakstīt
    {
        energy = Math.Max(0, energy - amount);
    }
}

public class Captain : Participant
{
    private int stability = 10;

    public Captain(string name) : base(name, 150) { }   // izsauc VECĀKA konstruktoru

    public override void ApplyPenalty(int amount)       // override = pārraksta
    {
        amount = Math.Max(1, amount - stability);
        base.ApplyPenalty(amount);                      // izsauc vecāka versiju
    }
}

public class Presenter : Participant
{
    public Presenter(string name) : base(name, 100) { }
}

// Polimorfisms: viens cikls apkalpo visas lomas
List<Participant> party = new()
{
    new Captain("Anna"),
    new Presenter("Jānis")
};

foreach (Participant p in party)
{
    p.ApplyPenalty(20);        // katrai lomai savs rezultāts
}

Bez : base(name, 150) vecāka konstruktors netiek izsaukts. Bez virtual pārrakstīšana nenostrādā.

3.3 Signāli - objekti sarunājas, viens otru nezinot

// RAIDĪTĀJS
[Signal] public delegate void FinishedEventHandler(string name);

public void ApplyPenalty(int amount)
{
    energy -= amount;
    if (energy <= 0) EmitSignal(SignalName.Finished, participantName);
}

// KLAUSĪTĀJS
public override void _Ready()
{
    participant.Finished += OnFinished;
}

private void OnFinished(string name)
{
    GD.Print(name, " izstājās");
}

Dalībnieks nezina, ka menedžeris eksistē. Tāpēc dalībnieku var lietot arī citā spēlē.

3.4 GlobalClass un Inspector īpašības

using Godot;
using System;

[GlobalClass]
public partial class Obstacle : CharacterBody2D
{
    private int energy = 50;
    private float speed = 100.0f;

    [Export]
    public string ObstacleName { get; set; } = "PrinterQueue";

    [Export(PropertyHint.Range, "0,500")]
    public int Energy
    {
        get => energy;
        set => energy = Math.Max(0, value);
    }

    [Export(PropertyHint.Range, "0,500,0.1")]
    public float Speed
    {
        get => speed;
        set => speed = Math.Max(0.0f, value);
    }
}

Tagad vienu klasi var lietot daudziem mezgliem, katram Inspector panelī iestatot citu vērtību.

3.5 struct un kompozīcija

using System;
using System.Collections.Generic;

public struct Buff
{
    public string Name;
    public int FocusBonus;
    public int TurnsLeft;
}

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

    public void Heal(int amount)
    {
        Energy = Math.Min(MaxEnergy, Energy + amount);   // nepārsniedz max
    }

    public int GetTotalFocus()      // RĒĶINA, nevis glabā atsevišķi
    {
        int total = Focus;
        foreach (Buff buff in Buffs) total += buff.FocusBonus;
        return total;
    }
}

public class Participant
{
    private Stats stats = new();    // kompozīcija: klasei PIEDER stats objekts
    public Stats GetStats() => stats;
}

p.GetStats().Heal(30);

Kopējo vērtību rēķini no saraksta. Ja to glabā atsevišķā laukā, tas ātri kļūst nepareizs.

public class Player : Entity { /* mantošana */ } // C# OOP - klašu hierarhija Godot .NET vidē