Lua und "Objekte"

» Siedler Map Source Forum » Siedler DEdK Script Forum » Lua und "Objekte"

Seiten: 1

BalistiK
#1
05.11.2019 09:48
Beiträge: 70

Lua und "Objekte"

Hallo Zusammen,

ich stoße seit letzter Zeit auf ein paar (verständins) Probleme mit Lua. Selbst bin ich behaftet mit der Idee der Objektorientierten Programmierung, welche sich in Lua ansatzweise durch Tables umsetzen lässt.
Vorab eine Frage: Ist es sinnvoll einen "objektorientieren" Lösungsansatz in Lua anzugehen oder sollte man darauf lieber verzichten, sprich sparsam damit umgehen?
Ich stoße da auf folgendes Problem: Ich habe ein Table mit Werten und Funktionen (Klasse). Diesen Table kopiere ich mit samt den Funktionen und !ohne vorgesetzten Werten (Objekt Erzeugung). Hier ein Code-Ausschnitt:

Template = {numbers = {}};

function Template.create(...)
	local copy = copyTable(Template);
	for _, v in pairs({unpack(arg)}) do
		copy:addPlayer(v);
	end
	return copy;
end

function copyTable(origTable)
	local copy = {};

	if type(origTable) == 'table' then
		for origTableK, origTableV in pairs(origTable) do
			copy[origTableK] = origTableV;
		end
	end
	
	return copy;
end



Jetzt stoße ich allerding auf folgendes Problem: Der Table wird anscheinend nicht korrekt kopiert und ich weiß nicht warum...
Folgende Aufrufe ergeben die unerwarteten Ergebnisse:

local test1 = Template.create(1, 2); -- "Neues Objekt"
for _, v in pairs(test1) do
	Message(tostring(v));	-- Gibt aus: 1, 2
end

local test2 = Template.create(3, 4); -- "Neues Objekt"
for _, v in pairs(test2) do
	Message(tostring(v));	-- Gibt aus: 1, 2, 3, 4
end

for _, v in pairs(test1) do
	Message(tostring(v));	-- Gibt jetzt aus: 1, 2, 3, 4
end



So weit wie ich es überprüfen kann ist test1 ungleich test2, also nicht der selbe Table. Ebenso ist weder test1 noch test2 gleich Template. Wo liegt jetzt genau der Fehler? Ich schätze ich kopiere den Table falsch, aber wie würde ich es richtig machen?

Danke schonmal im Vorraus.

mcb
#2
05.11.2019 13:11
Beiträge: 1472

Ok, also zur Frage ob OOP in Lua sinnvoll ist: Kommt darauf an, wie viel Script du hast und ob du überhaupt mehrere objekte davon anlegen kannst. Also z.B. für eine eigene KI definitiv ja, Quests und Briefings für ein Mapscript eher nicht und kleinere Funktionen wie CopyTable definitiv nicht.
Und jetzt zur Umsetzung in Lua: Klassischerweise benutzt man dafür metatables, was aber in Siedler nicht ganz so gut funktioniert. Kopieren funktioniert aber genausogut.
Das Problem liegt vermtulich an deinem CopyTable, das keine deep copy macht (ich würde die hier nehmen: https://github.com/mcb5637/s5C...er/comfort/table/CopyTable.lua) und deiner implementierung von Template:addPlayer . Ich vermute du verwendest irgendwo Template anstatt self oder speicherst die Daten in einem table das aus Template referenziert wird.

Edit: Falls du ein beispiel haben willst, wie andere sowas machen sieh dir mal meine Vector imlementierung an: https://github.com/mcb5637/s5C...master/comfort/math/Vector.lua (wobei ich da nicht wirklich Vererbung mache) oder das Script zu twas mapwizard (da ist glaub ich Vererbung bei).

totalwarANGEL
#3
06.11.2019 15:45
Beiträge: 2123

Versuche es mal mit dieser Funktion zum kopieren (leicht abgeändert):

function CopyTableRecursive(_Source, _Dest)
    _Dest = _Dest or {};
    assert(type(_Source) == "table")
    assert(type(_Dest) == "table")

    for k, v in pairs(_Source) do
        if type(v) == "table" then
            _Dest[k] = _Dest[k] or {};
            for kk, vv in pairs(CopyTableRecursive(v)) do
                _Dest[k][kk] = _Dest[k][kk] or vv;
            end
        else
            _Dest[k] = _Dest[k] or v;
        end
    end
    return _Dest;
end


So verwende ich das selbst erfolgreich in Siedler 5 und 6.

Für Objekte empfiehlt es sich außerdem, wenn man keine Metatables nutzt, eine :New Methode anzulegen. Dazu mein bleibtes Katzen-Beispiel (momentan nur bei mir beliebt):

Cat = {}

function Cat:New()
    local NewCat = CopyTableRecursive(self);
    NewCat.m_Name   = "0815 Katze";
    NewCat.m_Gender = 0;
    NewCat.m_Color  = "black";
    return NewCat;
end

function Cat:Name(_Name)
    if _Name then
        self.m_Name = _Name;
    end
    return self.m_Name;
end

function Cat:Gender(_Gender)
    if _Gender then
        self.m_Gender = _Gender;
    end
    return self.m_Gender;
end

function Cat:Color(_Color)
    if _Color then
        self.m_Color = _Color;
    end
    return self.m_Color;
end

-- -------------------------------------------------------------------------- --

Happy = Cat:New();
Happy:Name("Happy");
Happy:Gender(0);
Happy:Color("blue");

Carla = Cat:New();
Carla:Name("Carla");
Carla:Gender(1);
Carla:Color("white");

Lilly = Cat:New();
Lilly:Name("Lilly");
Lilly:Gender(0);
Lilly:Color("black");


In der Art sollte das alles wunderbar klappen.
(Außer ich habe irgend wo einen Tippfehler.)

____________________
Die Welt ist arschlochförmig und wir leben in der Mitte.

Seiten: 1

SiteEngine v1.5.0 by nevermind, ©2005-2007
Design by SpiderFive (www.siedler-games.de) - English translation by juja

Impressum