Menu
Coddy logo textTech

Stosowanie wielu mixinów

Część sekcji Programowanie obiektowe ścieżki Lua w Coddy. Lekcja 52 z 70.

Pojedyncza domieszka dodaje klasie jeden zestaw zachowań. Jednak rzeczywiste obiekty często potrzebują możliwości z wielu źródeł. Obiekt w grze może potrzebować możliwości poruszania się i bycia widocznym na ekranie: to dwie odrębne kwestie, które nie powinny znaleźć się w tej samej domieszce.

Rozwiązanie jest proste: zastosuj wiele domieszek do tej samej klasy. Każda domieszka wnosi własne metody, a klasa otrzymuje je wszystkie:

local Movable = {}
function Movable:move(dx, dy)
    self.x = self.x + dx
    self.y = self.y + dy
end

local Visible = {}
function Visible:show()
    print("Showing at " .. self.x .. ", " .. self.y)
end
function Visible:hide()
    print("Hidden")
end

Zastosuj oba miksy do swojej klasy, używając tej samej funkcji pomocniczej co wcześniej:

local function applyMixin(class, mixin)
    for key, value in pairs(mixin) do
        class[key] = value
    end
end

local GameObject = {}
GameObject.__index = GameObject

applyMixin(GameObject, Movable)
applyMixin(GameObject, Visible)

Teraz instancje GameObject mogą się poruszać i wyświetlać:

local obj = setmetatable({x = 0, y = 0}, GameObject)
obj:move(5, 3)
obj:show()  -- Wyświetlanie w 5, 3

Jedna uwaga: jeśli dwie domieszki definiują metodę o tej samej nazwie, druga zastosowana nadpisze pierwszą. Dbaj o to, by metody w domieszkach miały różne nazwy, aby uniknąć nieoczekiwanego zachowania.

challenge icon

Wyzwanie

Łatwy

Zbudujmy klasę Character do gry, która łączy wiele możliwości za pomocą mikserów! Twoja postać będzie mogła zarówno atakować wrogów, jak i leczyć samą siebie: to dwa odrębne zachowania pochodzące z osobnych mikserów.

Rozmieścisz swój kod w czterech plikach:

  • Attacker.lua: Utwórz mikser z metodą :attack(targetName), która wypisuje {self.name} attacks {targetName} for {self.damage} damage! (zakłada, że obiekt ma pola name i damage)
  • Healer.lua: Utwórz mikser z metodą :heal(amount), która dodaje podaną wartość do self.health i wypisuje {self.name} heals for {amount}. Health: {newHealth}
  • Character.lua: Utwórz klasę Character z konstruktorem :new(name, health, damage), który zapisuje wszystkie trzy atrybuty. Zastosuj miksery Attacker i Healer, aby każda postać mogła atakować i leczyć się. Dodaj metodę :status(), która wypisuje {name} - Health: {health}, Damage: {damage}
  • main.lua: Napisz tutaj funkcję pomocniczą applyMixin. Wczytaj imię postaci, jej zdrowie i obrażenia, cel ataku oraz wartość leczenia. Utwórz postać Character, wyświetl jej status, każ jej zaatakować cel, uleczyć się, a następnie ponownie wyświetl jej status.

Otrzymasz pięć danych wejściowych:

  1. Imię postaci (ciąg znaków)
  2. Początkowy poziom zdrowia (liczba)
  3. Wartość obrażeń (liczba)
  4. Imię celu ataku (ciąg znaków)
  5. Wartość leczenia (liczba)

Wynik powinien pokazywać, jak postać korzysta z obu umiejętności mikserów:

{name} - Health: {health}, Damage: {damage}
{name} attacks {target} for {damage} damage!
{name} heals for {healAmount}. Health: {newHealth}
{name} - Health: {newHealth}, Damage: {damage}

Na przykład, jeśli danymi wejściowymi są Warrior, 100, 25, Goblin i 30, wynikiem powinno być:

Warrior - Health: 100, Damage: 25
Warrior attacks Goblin for 25 damage!
Warrior heals for 30. Health: 130
Warrior - Health: 130, Damage: 25

Każdy mikser wnosi własną metodę do klasy Character. Postać nie dziedziczy po żadnym z mikserów. Po prostu zyskuje ich możliwości za pomocą funkcji applyMixin. Na tym polega siła łączenia wielu mikserów!

Spróbuj swoich sił

-- Plik główny

-- TODO: Napisz funkcję pomocniczą applyMixin
-- Ta funkcja powinna skopiować wszystkie metody z tabeli mixin do tabeli docelowej
local function applyMixin(target, mixin)
    -- TODO: Zaimplementuj zastosowanie mixin
end

-- Udostępnij applyMixin globalnie, aby Character.lua mógł z niej korzystać
_G.applyMixin = applyMixin

local Character = require('Character')

-- Odczytaj dane wejściowe
local name = io.read()
local health = tonumber(io.read())
local damage = tonumber(io.read())
local targetName = io.read()
local healAmount = tonumber(io.read())

-- TODO: Utwórz obiekt Character o podanych wartościach name, health i damage

-- TODO: Wyświetl stan postaci

-- TODO: Spraw, by postać zaatakowała cel

-- TODO: Spraw, by postać się uleczyła

-- TODO: Ponownie wyświetl stan postaci
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Lua online