233 lines
9.4 KiB
Markdown
233 lines
9.4 KiB
Markdown
---
|
|
title: Grundlegende Kartenoperationen
|
|
layout: default
|
|
root: ../..
|
|
idx: 3.1
|
|
description: Grundlegende Operationen wie set_node und get_node
|
|
redirect_from: /de/chapters/environment.html
|
|
---
|
|
|
|
## Einleitung <!-- omit in toc -->
|
|
|
|
In diesem Kapitel erfahren Sie, wie Sie grundlegende Aktionen auf der Karte durchführen können.
|
|
|
|
- [Karten-Struktur](#karten-struktur)
|
|
- [Lesen](#lesen)
|
|
- [Blöcke lesen](#blöcke-lesen)
|
|
- [Blöcke finden](#blöcke-finden)
|
|
- [Schreiben](#schreiben)
|
|
- [Blöcke schreiben](#blöcke-schreiben)
|
|
- [Blöcke löschen](#blöcke-löschen)
|
|
- [Mapblöcke laden](#mapblöcke-laden)
|
|
- [Blöcke löschen](#blöcke-löschen)
|
|
|
|
## Karten-Struktur
|
|
|
|
Die Minetest-Karte ist in Map-Blöcke(nicht zu verwechseln mit Blöcken in 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*-Blöcken, einem unpassierbaren, nicht auswählbaren Platzhalterblock. Leerer Raum ist
|
|
voll von *Luft*-Blöcken, einem unsichtbaren Block, durch den man hindurchgehen kann.
|
|
|
|
Ein aktiver Map-Block ist ein Block, der geladen ist und für den Aktualisierungen durchgeführt werden.
|
|
|
|
Geladene Map-Blöcke werden oft als *aktive Blöcke* bezeichnet. Aktive Blöcke 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
|
|
|
|
### Blöcke lesen
|
|
|
|
Sobald Sie eine Position haben, können Sie diese auf der Karte ablesen:
|
|
|
|
```lua
|
|
local node = minetest.get_node({ x = 1, y = 3, z = 4 }) --Warnung: Im Englischen ist mit block der Map-Block gemeint. Daher emphielt sich für die Variabelnamen node(Knoten) anstatt block zu nehmen
|
|
print(dump(node)) --> { name=.., param1=.., param2=.. }
|
|
```
|
|
|
|
Handelt es sich bei der Position um eine Dezimalzahl, so wird sie auf den enthaltenen Knoten gerundet.
|
|
Die Funktion gibt immer eine Tabelle mit den Blockinformationen zurück:
|
|
|
|
* `name` - Der Knotenname, der beim Entladen des Bereichs *ignoriert* wird.
|
|
* `param1` - Siehe Block-Definition. Dieser ist in der Regel light.
|
|
* `param2` - Siehe Block-Definition.
|
|
|
|
Es ist erwähnenswert, dass die Funktion den enthaltenen Block nicht lädt, wenn der Block
|
|
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 Block dann immer noch nicht geladen.
|
|
Dies kann immer noch `ignore` zurückgeben, wenn ein Block 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.
|
|
|
|
### Blöcke finden
|
|
|
|
Minetest bietet eine Reihe von Hilfsfunktionen, um gängige Map-Aktionen zu beschleunigen.
|
|
Die am häufigsten verwendeten Funktionen dienen dem Auffinden von Blöcken.
|
|
|
|
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 Block in einem bestimmten Radius
|
|
der mit den angegebenen Knotennamen oder Gruppen übereinstimmt. Im folgenden Beispiel,
|
|
suchen wir nach einem Mese-Block innerhalb von 5 Knoten von der Position:
|
|
```lua
|
|
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) .. " Block 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 Blöcke in dem Gebiet finden kann:
|
|
|
|
```lua
|
|
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 Knoten 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:
|
|
|
|
```lua
|
|
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 Knoten 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
|
|
|
|
### Blöcke 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 Block-Callbacks ausgeführt werden, was bedeutet, dass set_node
|
|
bei einer großen Anzahl von Blöcken ziemlich langsam ist.
|
|
|
|
```lua
|
|
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
|
|
Block-Definitionen verwenden, um einen konzeptionellen Blöcke zu repräsentieren. Ein Beispiel hierfür ist der
|
|
Ofenblock - während man ihn konzeptionell als einen Block betrachtet, sind es eigentlich
|
|
zwei.
|
|
|
|
Sie können einen Knoten setzen, ohne die Metadaten oder das Inventar zu löschen, wie folgt:
|
|
|
|
```lua
|
|
minetest.swap_node({ x = 1, y = 3, z = 4 }, { name = "default:mese" })
|
|
```
|
|
|
|
### Blöcke löschen
|
|
|
|
Ein Block muss immer vorhanden sein. Um einen Block zu entfernen, setzen Sie die Position auf "Luft".
|
|
|
|
Die folgenden beiden Zeilen entfernen beide einen Block und sind identisch:
|
|
|
|
```lua
|
|
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.
|
|
|
|
```lua
|
|
-- 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 Mapblock, mit einigen
|
|
Fortschrittsinformationen, lädt.
|
|
|
|
```lua
|
|
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 Blöcke
|
|
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 Blöcke %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)](../advmap/lvm.html) bewirkt ebenfalls, dass die
|
|
umschlossenen Mapblöcke synchron geladen werden.
|
|
|
|
## Blöcke löschen
|
|
|
|
Sie können delete_blocks verwenden, um einen Bereich von Map-Blöcken zu löschen:
|
|
|
|
```lua
|
|
-- 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.
|