From 19db0a99ce12422b4d2d8fe47f143f5a3ed0018b Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Wed, 12 Sep 2018 15:29:15 +0100 Subject: [PATCH] Objects: Add chapter --- _en/map/objects.md | 221 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 _en/map/objects.md diff --git a/_en/map/objects.md b/_en/map/objects.md new file mode 100644 index 0000000..883a643 --- /dev/null +++ b/_en/map/objects.md @@ -0,0 +1,221 @@ +--- +title: Objects, Players, and Entities +layout: default +root: ../.. +idx: 3.35 +description: Using an ObjectRef +--- + +## Introduction + +In this chapter, you will learn how to manipulate objects and how to define your +own. + +* [What are Objects, Players, and Entities?](#objects_players_and_entities) +* [Position and Velocity](#position_and_velocity) +* [Object Properties](#object_properties) +* [Entities](#entities) +* [Attachments](#attachments) +* [Your Turn](#your_turn) + +## What are Objects, Players, and Entities? + +Players and Entities are both types of Objects. An Object is something that can move +independently of the node grid and has properties such as velocity and scale. +An Object is not an item, and they have their own separate registration system. + +There are a few differences between Players and Entities. +The biggest one is that Players are player-controlled, whereas Entities are mod-controlled. +This means that the velocity of a player cannot be set by mods - players are client-side, +and entities are server-side. +Another difference is that Players will cause map blocks to be loaded, whereas Entities +will just be saved and become inactive. + +Entities are sometimes known as Lua Entities. +Don't be fooled though, all entities are Lua entities. + +## Position and Velocity + +`get_pos` and `set_pos` exist to allow you to get and set an entity's position. + +{% highlight lua %} +local object = minetest.get_player_by_name("bob") +local pos = object:get_pos() +object:set_pos({ x = pos.x, y = pos.y + 1, z = pos.z }) +{% endhighlight %} + +`set_pos` immediately sets the position, with no animation. If you'd like to +smoothly animate an object to the new position, you should use `move_to`. +This, unfortunately, only works for entities. + +{% highlight lua %} +object:move_to({ x = pos.x, y = pos.y + 1, z = pos.z }) +{% endhighlight %} + +An important thing to think about when dealing with entities is network latency. +In an ideal world, messages about entity movements would arrive immediately, +in the correct order, and with a similar interval as to how you sent them. +However, unless you're in singleplayer, this isn't an ideal world. +Messages will take a while to arrive. Position messages may arrive out of order, +resulting in some `set_pos` calls being skipped as there's no point going to +a position older than the current known position. +Moves may not be similarly spaced, which makes it difficult to use them for animation. +All this results in the client seeing different things to the server, which is something +you need to be aware of. + +## Object Properties + +Unlike nodes, objects have a dynamic rather than set appearance. +You can change how an object looks, among other things, at any time by updating +its properties. + +{% highlight lua %} +object:set_properties({ + visual = "mesh", + mesh = "character.b3d", + textures = {"character_texture.png"}, + visual_size = {x=1, y=1}, +}) +{% endhighlight %} + +The updated properties will be sent to all players in range. +This is very useful to get a large amount of variety very cheaply, such as having +different skins per-player. + +As shown in the next section, entities can have a default set of properties defined +in their definition. +The default Player properties are defined in the engine, however, so you'll +need to use `set_properties()` in `on_joinplayer` to set the properties for newly +joined players. + +## Entities + +An Entity has a type table much like an item does. +This table can contain callback methods, default object properties, and custom elements. + +{% highlight lua %} +local MyEntity = { + 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 MyEntity:set_message(msg) + self.message = msg +end +{% endhighlight %} + +When an entity is emerged, a table is created for it by copying everything from +its type table. +This table can be used to store variables for that particular entity. + +Both an ObjectRef and an entity table provide ways to get the counterpart: + +{% highlight lua %} +local entity = object:get_luaentity() +local object = entity.object +print("entity is at " .. minetest.pos_to_string(object:get_pos())) +{% endhighlight %} + +There are a number of available callbacks for use with entities. +A complete list can be found in [lua_api.txt]({{ page.root }}/lua_api.html#registered-entities) + +{% highlight lua %} +function MyEntity:on_step(dtime) + local pos = self.object:get_pos() + + local delta + if minetest.get_node(vector.subtract(pos, vector.new(0, 1, 0))).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 MyEntity:on_punch(hitter) + minetest.chat_send_player(hitter:get_player_name(), self.message) +end +{% endhighlight %} + +Now, if you were to spawn and use this entity, you'd notice that the message +would be forgotten when the entity becomes inactive then active again. +This is because the message isn't saved. +Rather than saving everything in the entity table, Minetest gives you control over +how to save things. +Staticdata is a string which contains all of the custom information that +needs to stored. + +{% highlight lua %} +function MyEntity:get_staticdata() + return minetest.write_json({ + message = self.message, + }) +end + +function MyEntity: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 +{% endhighlight %} + +Minetest may call `get_staticdata()` as many times as it once and at any time. +This is because Minetest doesn't wait for a MapBlock to become inactive to save +it, as this would result in data loss. MapBlocks are saved roughly every 18 +seconds, so you should notice a similar interval for `get_staticdata()` being called. + +`on_activate()`, on the other hand, will only be called when an entity becomes +active either from the MapBlock becoming active or from the entity spawning. +This means that staticdata could be empty. + +Finally, you need to register the type table using the aptly named `register_entity`. + +{% highlight lua %} +minetest.register_entity("9_entities:myentity", MyEntity) +{% endhighlight %} + + +## Attachments + +Attached objects will move when the parent - the object they are attached to - +is moved. An attached object is said to be a child of the parent. +An object can have an unlimited number of children, but at most one parent. + +{% highlight lua %} +child:set_attach(parent, bone, position, rotation) +{% endhighlight %} + +An Object's `get_pos()` will always return the global position of the object, no +matter whether it is attached or not. +`set_attach` takes a relative position, but not as you'd expect. +The attachment position is relative to the parent's origin as scaled up by 10 times. +So `0,5,0` would be half a node above the parent's origin. + +For 3D models with animations, the bone argument is used to attach the entity +to a bone. +3D animations are based on skeletons - a network of bones in the model where +each bone can be given a position and rotation to change the model, for example +to move the arm. +Attaching to a bone is useful if you want to make a character hold something. + +## Your Turn + +* Make a windmill by combining nodes and an entity. +* Make a mob of your choice (without using any other mods).