minetest_modding_book/_de/map/environment.md
2022-12-18 11:20:09 +01:00

9.4 KiB

title layout root idx description redirect_from
Grundlegende Kartenoperationen default ../.. 3.1 Grundlegende Operationen wie set_node und get_node /de/chapters/environment.html

Einleitung

In diesem Kapitel erfahren Sie, wie Sie grundlegende Aktionen auf der Karte durchführen können.

Karten-Struktur

Die Minetest-Karte ist in Map-Blöcke(nicht zu verwechseln mit Nodes im Deutschen) aufgeteilt, wobei jeder Map-Block ein Würfel der Kantenlänge 16 ist. Während die Spieler auf der Karte unterwegs sind, werden Map-Blöcke erstellt, geladen, aktiv und entladen. Bereiche der Karte, die noch nicht geladen sind, sind voll von ignore-Nodes, einem unpassierbaren, nicht auswählbaren Platzhalternode. Leerer Raum ist voll von Luft-Blöcken, einem unsichtbaren Node, durch den man hindurchgehen kann.

Ein aktiver Map-Block ist ein Node, der geladen ist und für den Aktualisierungen durchgeführt werden.

Geladene Map-Blöcke werden oft als aktive Nodes bezeichnet. Aktive Nodes können von Mods oder Spielern gelesen oder beschrieben werden und haben aktive Entities. Die Engine führt auch Operationen auf der Karte durch, wie z. B. die Ausführung der Flüssigkeitsphysik.

Map-Blöcke können entweder aus der Weltdatenbank geladen oder generiert werden. Map-Blöcke werden bis zum Limit der Kartengenerierung (mapgen_limit) generiert, das standardmäßig auf den Maximalwert von 31000 gesetzt ist. Vorhandene Map-Blöcke können jedoch außerhalb des Generierungslimits aus der Weltdatenbank geladen werden.

Lesen

Nodes lesen

Sobald Sie eine Position haben, können Sie diese auf der Karte ablesen:

local node = minetest.get_node({ x = 1, y = 3, z = 4 }) --Warnung: Im Englischen ist mit Node der Map-Block gemeint. Daher emphielt sich für die Variabelnamen node(Node) zu verwenden
print(dump(node)) --> { name=.., param1=.., param2=.. }

Handelt es sich bei der Position um eine Dezimalzahl, so wird sie auf den enthaltenen Node gerundet. Die Funktion gibt immer eine Tabelle mit den Nodeinformationen zurück:

  • name - Der Nodename, der beim Entladen des Bereichs ignoriert wird.
  • param1 - Siehe Node-Definition. Dieser ist in der Regel light.
  • param2 - Siehe Node-Definition.

Es ist erwähnenswert, dass die Funktion den enthaltenen Node nicht lädt, wenn der Node inaktiv ist, sondern stattdessen eine Tabelle zurückgibt, in der name ignore ist.

Sie können stattdessen minetest.get_node_or_nil verwenden, was nil zurückgibt und nicht eine Tabelle mit dem Namen ignore. Allerdings wird der Node dann immer noch nicht geladen. Dies kann immer noch ignore zurückgeben, wenn ein Node tatsächlich ignore enthält. Dies wird in der Nähe des Randes der Karte passieren, wie es durch die Kartengenerierung definiert ist Grenze (mapgen_limit) definiert ist.

Nodes finden

Minetest bietet eine Reihe von Hilfsfunktionen, um gängige Map-Aktionen zu beschleunigen. Die am häufigsten verwendeten Funktionen dienen dem Auffinden von Nodesn.

Angenommen, wir wollen eine bestimmte Pflanzenart herstellen, die besser in der Nähe von Mese wächst; müssten Sie nach allen Mese-Blöcke in der Nähe suchen, und die Wachstumsrate entsprechend anpassen.

minetest.find_node_near liefert den ersten gefundenen Node in einem bestimmten Radius der mit den angegebenen Nodenamen oder Gruppen übereinstimmt. Im folgenden Beispiel, suchen wir nach einem Mese-Node innerhalb von 5 Node von der Position:

local wachstums_geschwindigkeit = 1
local node_pos   = minetest.find_node_near(pos, 5, { "default:mese" })
if node_pos then
    minetest.chat_send_all("Bei " .. dump(node_pos) .. " Node gefunden")
    wachstums_geschwindigkeit = 2
end

Nehmen wir zum Beispiel an, dass die Wachstumsrate steigt, je mehr Mese in der Nähe ist. Dann sollten Sie eine Funktion verwenden, die mehrere Nodes in dem Gebiet finden kann:

local pos1       = vector.subtract(pos, { x = 5, y = 5, z = 5 })
local pos2       = vector.add(pos, { x = 5, y = 5, z = 5 })
local pos_list   =
        minetest.find_nodes_in_area(pos1, pos2, { "default:mese" })
local wachstums_geschwindigkeit = 1 + #pos_list

Der obige Code ermittelt die Anzahl der Node in einem kubischen Volumen. Dies ist anders zu find_node_near, das den Abstand zur Position (d.h. einer Kugel) verwendet. Um dies zu beheben, müssen wir den Bereich manuell selbst überprüfen:

local pos1       = vector.subtract(pos, { x = 5, y = 5, z = 5 })
local pos2       = vector.add(pos, { x = 5, y = 5, z = 5 })
local pos_list   =
        minetest.find_nodes_in_area(pos1, pos2, { "default:mese" })
local grow_speed = 1
for i=1, #pos_list do
    local delta = vector.subtract(pos_list[i], pos)
    if delta.x*delta.x + delta.y*delta.y + delta.z*delta.z <= 5*5 then
        wachstums_geschwindigkeit = wachstums_geschwindigkeit + 1
    end
end

Jetzt erhöht der Code korrekt die wachstums_geschwindigkeit basierend auf der Anzahl der Node in Reichweite.

Beachten Sie, dass wir den quadrierten Abstand von der Position verglichen haben, anstatt ihn zu quadrierenum die tatsächliche Entfernung zu erhalten. Dies liegt daran, dass Quadratwurzeln für den Computer sehr rechenintensiv sind und daher möglichst vermieden werden sollten.

Es gibt weitere Variationen der beiden oben genannten Funktionen, wie z.B. find_nodes_with_meta und find_nodes_in_area_under_air, die ähnlich funktionieren und unter anderen Umständen nützlich sind.

Schreiben

Nodes schreiben

Sie können set_node verwenden, um in die Karte zu schreiben. Jeder Aufruf von set_node wird dazu führen, dass die Beleuchtung neu berechnet und Node-Callbacks ausgeführt werden, was bedeutet, dass set_node bei einer großen Anzahl von Nodesn ziemlich langsam ist.

minetest.set_node({ x = 1, y = 3, z = 4 }, { name = "default:mese" })

local node = minetest.get_node({ x = 1, y = 3, z = 4 })
print(node.name) --> default:mese

set_node entfernt alle zugehörigen Metadaten oder Bestände von dieser Position. Dies ist nicht unter allen Umständen wünschenswert, insbesondere wenn Sie mehrere Node-Definitionen verwenden, um einen konzeptionellen Nodes zu repräsentieren. Ein Beispiel hierfür ist der Ofennode - während man ihn konzeptionell als einen Node betrachtet, sind es eigentlich zwei.

Sie können einen Node setzen, ohne die Metadaten oder das Inventar zu löschen, wie folgt:

minetest.swap_node({ x = 1, y = 3, z = 4 }, { name = "default:mese" })

Nodes löschen

Ein Node muss immer vorhanden sein. Um einen Node zu entfernen, setzen Sie die Position auf "Luft".

Die folgenden beiden Zeilen entfernen beide einen Node und sind identisch:

minetest.remove_node(pos)
minetest.set_node(pos, { name = "air" })

Tatsächlich ist remove_node nur eine Hilfsfunktion, die set_node mit "air" aufruft.

Mapblöcke laden

Sie können minetest.emerge_area verwenden, um Map-Blöcke zu laden. Emerge area ist asynchron, das heißt, die Mapblöcke werden nicht sofort geladen. Stattdessen werden sie in der Zukunft geladen und der Callback wird jedes Mal aufgerufen.

-- Lädt einen 20x20x20-Bereich
local halbegroesse = { x = 10, y = 10, z = 10 } --ss = ß
local pos1 = vector.subtract(pos, halbegroesse)
local pos2 = vector.add     (pos, halbegroesse)

local kontext = {} -- Daten zwischen Callback-Aufrufen aufrechterhalten
minetest.emerge_area(pos1, pos2, emerge_callback, kontext)

Minetest ruft emerge_callback immer dann auf, wenn er einen Map-Block, mit einigen Fortschrittsinformationen, lädt.

local function emerge_callback(pos, aktion,
        verbleibende_calls, kontext)
    -- Beim ersten Aufruf, Anzahl der Mapblöcke erfassen
    if not kontext.bloecke_insgesamt then
        kontext.bloecke_insgesamt  = verbleibende_calls + 1
        kontext.geladene_bloecke = 0
    end

    -- Erhöhung der Anzahl der geladenen Nodes
    kontext.bloecke_insgesamt = kontext.geladene_bloecke + 1

    -- Fortschrittsmeldung senden
    if kontext.bloecke_insgesamt == kontext.geladene_bloecke then
        minetest.chat_send_all("Blöcke laden abgeschlossen!")
    end
        local perc = 100 * kontext.geladene_bloecke / kontext.bloecke_insgesamt
        local msg  = string.format("Geladene Nodes %d/%d (%.2f%%)",
                kontext.geladene_bloecke, kontext.bloecke_insgesamt, perc)
        minetest.chat_send_all(msg)
    end
end

Dies ist nicht die einzige Möglichkeit, Mapblöcke zu laden; die Verwendung eines Lua Voxel Manipulator (LVM) bewirkt ebenfalls, dass die umschlossenen Mapblöcke synchron geladen werden.

Nodes löschen

Sie können delete_blocks verwenden, um einen Bereich von Map-Blöcken zu löschen:

-- Löscht einen 20x20x20-Bereich
local halbegroesse = { x = 10, y = 10, z = 10 }
local pos1 = vector.subtract(pos, halbegroesse)
local pos2 = vector.add     (pos, halbegroesse)

minetest.delete_area(pos1, pos2)

Dadurch werden alle Map-Blöcke in diesem Bereich inklusive gelöscht. Das bedeutet, dass einige Blöcke außerhalb des Bereichs gelöscht werden, da sie sich auf einem Map-Block befinden, der sich mit den die Bereichsgrenzen überlappen.