minetest_modding_book/_de/map/objects.md

358 lines
14 KiB
Markdown
Raw Normal View History

2022-08-22 18:14:18 +03:00
---
title: Objekte, Spieler, und Entities
layout: default
root: ../..
idx: 3.4
description: Nutzung eines ObjectRef
degrad:
level: warning
title: Grad and Radiant
message: Die Drehung von Anbauteilen wird in Grad angegeben, während die Drehung von Objekten in Radiant
angegeben wird. Stellen Sie sicher, dass Sie das richtige Winkelmaß verwenden.
---
## Einleitung <!-- omit in toc -->
In diesem Kapitel lernen Sie, wie man Objekte manipuliert und eigene Objekte
definiert.
- [Was sind Objekte, Spieler, und Entities?](#was-sind-objekte-spieler-und-entities)
- [Position und Geschwindigkeit](#position-und-geschwindigkeit)
- [Objekt-Eigenschaften](#objekt-eigenschaften)
- [Entities](#entities)
- [Leben und Schaden](#leben-und-schaden)
2022-08-24 12:32:15 +03:00
- [Anhänge](#anhänge)
- [Sie sind dran](#sie-sind-dran)
2022-08-22 18:14:18 +03:00
## Was sind Objekte, Spieler, und Entities?
Spieler und Entities sind beide Arten von Objekten. Ein Objekt ist etwas, das sich unabhängig
vom Block-Raster bewegen kann und Eigenschaften wie Geschwindigkeit und Skalierung besitzt.
Objekte sind keine Gegenstände, und sie haben ihr eigenes Registrierungssystem.
Es gibt ein paar Unterschiede zwischen Spielern und Entities.
Der größte ist, dass Spieler von Spielern gesteuert werden, während Entities von Mods gesteuert werden.
Das bedeutet, dass die Geschwindigkeit eines Spielers nicht von Mods eingestellt werden kann -
Spieler sind client-seitig, und Entities sind serverseitig.
Ein weiterer Unterschied ist, dass Spieler das Laden von Kartenblöcken verursachen, während Entities
nur gespeichert werden und inaktiv werden.
Diese Unterscheidung wird durch die Tatsache erschwert, dass Entities über eine Tabelle
gesteuert werden, die als Lua entity bezeichnet wird, wie später erläutert wird.
## Position und Geschwindigkeit
`get_pos` und `set_pos` existieren, um die Position eines Entitys zu ermitteln und zu setzen.
```lua
local objekt = minetest.get_player_by_name("bob")
local pos = objekt:get_pos()
objekt:set_pos({ x = pos.x, y = pos.y + 1, z = pos.z })
```
`set_pos` setzt die Position sofort und ohne Animation. Wenn Sie ein Objekt
sanft an die neue Position animieren möchten, sollte man `move_to` verwenden.
Dies funktioniert leider nur für Entities.
```lua
objekt:move_to({ x = pos.x, y = pos.y + 1, z = pos.z })
```
Ein wichtiger Punkt beim Umgang mit Entities ist die Latenzzeit im Netz.
In einer idealen Welt würden Nachrichten über Entitybewegungen sofort ankommen,
in der richtigen Reihenfolge und in einem ähnlichen Intervall ankommen, wie Sie sie gesendet haben.
Solange man sich jedoch nicht im Einzelspielermodus befindet, ist dies keine ideale Welt.
Nachrichten brauchen eine Weile, bis sie ankommen. Positionsnachrichten können in der falschen Reihenfolge ankommen,
was dazu führt, dass einige `set_pos`-Aufrufe übersprungen werden, da es keinen Sinn macht, zu einer
Position zu gehen, die älter ist als die aktuell bekannte Position.
Bewegungen können nicht in ähnlichen Abständen erfolgen, was es schwierig macht, sie für Animationen zu verwenden.
All dies führt dazu, dass der Client andere Dinge sieht als der Server, und das ist etwas
das Sie beachten müssen.
## Objekt-Eigenschaften
Objekt-Eigenschaften werden verwendet, um dem Client mitzuteilen, wie ein Objekt zu rendern und zu behandeln ist.
Es ist nicht möglich, benutzerdefinierte Eigenschaften zu definieren, denn die Eigenschaften sind
per Definition von der Engine zu verwenden.
Im Gegensatz zu Blöcken haben Objekte ein dynamisches und kein festes Aussehen.
Sie können unter anderem das Aussehen eines Objekts jederzeit ändern, indem Sie
seine Eigenschaften ändern.
```lua
object:set_properties({
visual = "mesh",
mesh = "character.b3d",
textures = {"character_texture.png"},
visual_size = {x=1, y=1},
})
```
Die aktualisierten Eigenschaften werden an alle Spieler in Reichweite gesendet.
Dies ist sehr nützlich, um eine große Menge an Vielfalt sehr billig zu bekommen, wie zum Beispiel
verschiedene Skins pro Spieler.
Wie im nächsten Abschnitt gezeigt wird, können Entities Erst-Eigenschaften haben
die in ihrer Definition angegeben werden.
Die Standardeigenschaften des Spielers sind jedoch in der Engine definiert, so dass man
`on_joinplayer` die Funktion `set_properties()` verwenden kann, um die Eigenschaften für neue
Spieler zu setzen.
## Entities
Ein Entity hat eine Definitionstabelle, die einer Objektdefinitionstabelle ähnelt.
Diese Tabelle kann Callback-Methoden, anfängliche Objekteigenschaften und benutzerdefinierte
Mitglieder enthalten.
```lua
local MeinEntity = {
initial_properties = {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
visual = "wielditem",
visual_size = {x = 0.4, y = 0.4},
textures = {""},
spritediv = {x = 1, y = 1},
initial_sprite_basepos = {x = 0, y = 0},
},
message = "Default message",
}
function MeinEntity:set_message(msg)
self.message = msg
end
```
Entity-Definitionen unterscheiden sich in einem sehr wichtigen Punkt von Item-Definitionen.
Wenn ein Entity auftaucht (d.h.: geladen oder erstellt wird), wird eine neue Tabelle für
diese Entity erstellt, die von der Definitionstabelle *erbt*.
<!--
Diese Vererbung wird mit Hilfe von Metatabellen durchgeführt.
Metatabellen sind eine wichtige Lua-Funktion, die Sie kennen müssen, da sie
ist ein wesentlicher Bestandteil der Lua-Sprache. Laienhaft ausgedrückt, erlaubt eine Metatabelle
zu steuern, wie sich die Tabelle bei der Verwendung bestimmter Lua-Syntaxen verhält. Die häufigste
Verwendung von Metatabellen ist die Möglichkeit, eine andere Tabelle als Prototyp zu verwenden,
Eigenschaften und Methoden der anderen Tabelle zu verwenden,
wenn sie in der aktuellen Tabelle nicht vorhanden sind.
Angenommen, Sie wollen auf `a.x` zugreifen. Wenn die Tabelle `a` dieses Element hat, dann wird es
normal zurückgegeben. Wenn die Tabelle jedoch nicht über dieses Element verfügt und die
metatable eine Tabelle `b` als Prototyp aufführt, wird die Tabelle `b` daraufhin überprüft
um zu sehen, ob sie dieses Mitglied hat.
-->
Sowohl ein ObjectRef als auch eine Entity-Tabelle bieten Möglichkeiten, das Gegenstück zu erhalten:
```lua
local entity = object:get_luaentity()
local objekt = entity.objekt
print("Entity ist bei " .. minetest.pos_to_string(objekt:get_pos()))
```
Es gibt eine Reihe von Callbacks für die Verwendung mit Entities.
Eine vollständige Liste findet sich in [lua_api.txt](https://minetest.gitlab.io/minetest/minetest-namespace-reference/#registered-definition-tables).
```lua
function MeinEntity:on_step(dtime)
local pos = self.object:get_pos()
local pos_drunter = vector.subtract(pos, vector.new(0, 1, 0))
local delta
if minetest.get_node(pos_drunter).name == "air" then
delta = vector.new(0, -1, 0)
elseif minetest.get_node(pos).name == "air" then
delta = vector.new(0, 0, 1)
else
delta = vector.new(0, 1, 0)
end
delta = vector.multiply(delta, dtime)
self.object:move_to(vector.add(pos, delta))
end
function MeinEntity:on_punch(hitter)
minetest.chat_send_player(hitter:get_player_name(), self.message)
end
```
Wenn Sie nun diese Entity spawnen und verwenden würden, würden Sie feststellen, dass die Nachricht
vergessen wird, wenn die Entity inaktiv und dann wieder aktiv wird.
Das liegt daran, dass die Nachricht nicht gespeichert wird.
Anstatt alles in der Entity-Tabelle zu speichern, gibt Minetest Ihnen die Kontrolle darüber
wie die Dinge gespeichert werden sollen.
Staticdata ist ein String, der alle benutzerdefinierten Informationen enthält, die
gespeichert werden müssen.
```lua
function MeinEntity:get_staticdata()
return minetest.write_json({
message = self.message,
})
end
function MeinEntity:on_activate(staticdata, dtime_s)
if staticdata ~= "" and staticdata ~= nil then
local data = minetest.parse_json(staticdata) or {}
self:set_message(data.message)
end
end
```
Minetest kann `get_staticdata()` so oft wie gewünscht und zu jeder Zeit aufrufen.
Der Grund dafür ist, dass Minetest nicht darauf wartet, dass ein MapBlock inaktiv wird,
um ihn zu speichern, da dies zu Datenverlusten führen würde. MapBlocks werden ungefähr alle 18
Sekunden gespeichert, also sollten Sie ein ähnliches Intervall für den Aufruf von `get_staticdata()` feststellen.
`on_activate()` wird dagegen nur aufgerufen, wenn eine Entity
aktiv wird, entweder wenn der MapBlock aktiv wird oder wenn die Entity spawnen wird.
Dies bedeutet, dass staticdata leer sein könnte.
Schließlich müssen Sie die Typentabelle mit der treffenden Bezeichnung `register_entity` registrieren.
```lua
minetest.register_entity("meinemod:entity", MeinEntity)
```
Die Entity kann von einem Mod wie folgt erzeugt werden:
```lua
local pos = { x = 1, y = 2, z = 3 }
local obj = minetest.add_entity(pos, "meinemod:entity", nil)
```
Der dritte Parameter sind die anfänglichen statischen Daten.
Um die Nachricht einzustellen, können Sie die Methode der Entity-Tabelle verwenden:
```lua
obj:get_luaentity():set_message("hello!")
```
Spieler mit den *give* [privilege](../players/privileges.html) können
einen [chat command](../players/chat.html) zum spawnen von entities benutzen:
/spawnentity mymod:entity
## Leben und Schaden
### Lebenspunkte (HP)
Jedes Objekt hat eine Anzahl von Lebenspunkten (HP), die die aktuelle Gesundheit darstellt.
Spieler haben eine maximale Lebenspunktzahl, die mit der Objekteigenschaft `hp_max` festgelegt wird.
Ein Objekt stirbt, wenn seine HP 0 erreichen.
```lua
local hp = object:get_hp()
object:set_hp(hp + 3)
```
### Schlagen, Damage Groups, und Armor Groups
2022-08-22 18:14:18 +03:00
Schaden ist die Verringerung der HP eines Objekts. Ein Objekt kann ein anderes Objekt *schlagen*, um
Schaden zuzufügen. Ein Schlag muss nicht unbedingt ein echter Schlag sein - es kann auch eine
Explosion, ein Schwerthieb oder etwas anderes sein.
2022-08-22 18:14:18 +03:00
Der Gesamtschaden wird durch Multiplikation der Schadensgruppen des Schlags mit den
Verwundbarkeiten des Ziels berechnet. Dies wird dann begrenzt, je nachdem, wie lange der letzte
Schlag her war. Wir werden gleich ein Beispiel für diese Berechnung erläutern.
2022-08-22 18:14:18 +03:00
Genau wie [Node Grabungsgruppen](../items/nodes_items_crafting.html#tools-capabilities-and-dig-types),
können diese Gruppen jeden Namen annehmen und müssen nicht registriert werden. Es ist jedoch
üblich, dieselben Gruppennamen wie bei Node digging zu verwenden.
2022-08-22 18:14:18 +03:00
Wie anfällig ein Objekt für bestimmte Arten von Schaden ist, hängt von seiner
`armor_groups` [Objekteigenschaft](#object-properties). Trotz seines irreführenden
Namen gibt `armor_groups` den prozentualen Schaden von bestimmten
Schadensgruppen an,und nicht den Widerstand. Wenn eine Schadensgruppe nicht in den Armor Groups eines Objekts aufgeführt ist,
ist das Objekt völlig unverwundbar.
2022-08-22 18:14:18 +03:00
```lua
target:set_properties({
armor_groups = { fleshy = 90, crumbly = 50 },
})
```
Im obigen Beispiel erleidet das Objekt 90 % `fleshy` Schadens und 50 % des
`crumbly`-Schaden.
2022-08-22 18:14:18 +03:00
Wenn ein Spieler ein Objekt schlägt, stammen die Schadensgruppen von dem Gegenstand, das er
gerade trägt. In anderen Fällen entscheiden die Mods, welche Schadensgruppen verwendet werden.
2022-08-22 18:14:18 +03:00
2022-08-24 12:32:15 +03:00
### Beispiel für die Schadensberechnung
2022-08-22 18:14:18 +03:00
2022-08-24 12:32:15 +03:00
Schlagen wir das Objekt `target`:
2022-08-22 18:14:18 +03:00
```lua
2022-08-24 12:32:15 +03:00
local werkzeug_faehigkeiten = {
2022-08-22 18:14:18 +03:00
full_punch_interval = 0.8,
damage_groups = { fleshy = 5, choppy = 10 },
2022-08-24 12:32:15 +03:00
-- Dies wird nur für das abbauen von Nodes verwendet, ist aber dennoch erforderlich
2022-08-22 18:14:18 +03:00
max_drop_level=1,
groupcaps={
fleshy={times={[1]=2.5, [2]=1.20, [3]=0.35}, uses=30, maxlevel=2},
},
}
2022-08-24 12:32:15 +03:00
local zeit_seit_letzten_schlag = werkzeug_faehigkeiten.full_punch_interval
target:punch(object, zeit_seit_letzten_schlag, werkzeug_faehigkeiten)
2022-08-22 18:14:18 +03:00
```
2022-08-24 12:32:15 +03:00
Berechnen wir nun, wie hoch der Schaden sein wird. Die Schadensgruppen des Schlags sind
`fleshy=5` und `choppy=10`, und die Zielperson erleidet 90% Schaden durch fleshy und 0%
von choppy.
2022-08-22 18:14:18 +03:00
2022-08-24 12:32:15 +03:00
Zuerst multiplizieren wir die Schadensgruppen mit der Verwundbarkeit und addieren das Ergebnis.
Dann multiplizieren wir mit einer Zahl zwischen 0 oder 1, abhängig von der `zeit_seit_letzten_schlag`.
2022-08-22 18:14:18 +03:00
```lua
2022-08-24 12:32:15 +03:00
= (5*90/100 + 10*0/100) * limit(zeit_seit_letzten_schlag / full_punch_interval, 0, 1)
2022-08-22 18:14:18 +03:00
= (5*90/100 + 10*0/100) * 1
= 4.5
```
2022-08-24 12:32:15 +03:00
Da die HP eine ganze Zahl sind, wird der Schaden auf 5 Lebenspunkte gerundet.
2022-08-22 18:14:18 +03:00
2022-08-24 12:32:15 +03:00
## Anhänge
2022-08-22 18:14:18 +03:00
2022-08-24 12:32:15 +03:00
Angehängte Objekte bewegen sich, wenn das übergeordnete Objekt - also das Objekt, an das sie angehängt sind -
bewegt wird. Ein angefügtes Objekt ist ein Kind des übergeordneten Objekts.
Ein Objekt kann eine unbegrenzte Anzahl von Kindern haben, aber höchstens ein Elternteil.
2022-08-22 18:14:18 +03:00
```lua
2022-08-24 12:32:15 +03:00
kind:set_attach(elternteil, knochen, position, drehung)
2022-08-22 18:14:18 +03:00
```
2022-08-24 12:32:15 +03:00
Die Funktion `get_pos()` eines Objekts gibt immer die globale Position des Objekts zurück,
unabhängig davon, ob es angehängt ist oder nicht.
`set_attach` nimmt eine relative Position, aber nicht so, wie man es erwarten würde.
Die Anhängeposition ist relativ zum Ursprung des Elternobjekts und wird um das 10-fache vergrößert.
Also wäre "0,5,0" ein halber Node über dem Ursprung des Elternobjekts.
2022-08-22 18:14:18 +03:00
{% include notice.html notice=page.degrad %}
2022-08-24 12:32:15 +03:00
Bei 3D-Modellen mit Animationen wird das Argument knochen verwendet, um das Entity
an einen Knochen zu binden.
3D-Animationen basieren auf Skeletten - einem Netzwerk von Knochen im Modell, bei dem
jedem Knochen eine Position und Drehung zugewiesen werden kann, um das Modell zu verändern, z. B,
um den Arm zu bewegen.
Das Anhängen an einen Knochen ist nützlich, wenn Sie eine Figur etwas halten lassen wollen:
2022-08-22 18:14:18 +03:00
```lua
2022-08-24 12:32:15 +03:00
obj:set_attach(spieler,
"Arm_Right", -- normaler Knochen
{x=0.2, y=6.5, z=3}, -- normale Position
{x=-100, y=225, z=90}) -- normale Drehung
2022-08-22 18:14:18 +03:00
```
2022-08-24 12:32:15 +03:00
## Sie sind dran
2022-08-22 18:14:18 +03:00
2022-08-24 12:32:15 +03:00
* Erstelle eine Windmühle, indem du Nodes und eine Entity kombinierst.
* Erstelle einen Mob deiner Wahl (nur mit der Entity-API und ohne andere Mods zu verwenden).