diff --git a/en/chapters/hud.md b/en/chapters/hud.md index d48c4e0..98882ca 100644 --- a/en/chapters/hud.md +++ b/en/chapters/hud.md @@ -10,106 +10,283 @@ Heads Up Display (HUD) elements allow you to show text, images, and other graphi The HUD doesn't accept user input. For that, you should use a [Formspec](formspecs.html). -* [Basic Interface](#basic-interface) * [Positioning](#positioning) + * [Position and Offset](#position-and-offset) + * [Alignment](#alignment) + * [Scoreboard](#scoreboard) * [Text Elements](#text-elements) + * [Parameters](#parameters) + * [Our Example](#our-example) * [Image Elements](#image-elements) + * [Parameters](#parameters-1) + * [Scale](#scale) +* [Changing an Element](#changing-an-element) +* [Storing IDs](#storing-ids) * [Other Elements](#other-elements) -## Basic Interface - -HUD elements are created using a player object. -You can get the player object from a username: - -{% highlight lua %} -local player = minetest.get_player_by_name("username") -{% endhighlight %} - -Once you have the player object, you can create a HUD element: - -{% highlight lua %} -local idx = player:hud_add({ - hud_elem_type = "text", - position = {x = 1, y = 0}, - offset = {x=-100, y = 20}, - scale = {x = 100, y = 100}, - text = "My Text" -}) -{% endhighlight %} - -The attributes in the HUD element table and what they do vary depending on -the `hud_elem_type`.\\ -The `hud_add` function returns a number which is needed to identify the HUD element -if you wanted to change or delete it. - -You can change an attribute after creating a HUD element. For example, you can change -the text: - -{% highlight lua %} -player:hud_change(idx, "text", "New Text") -{% endhighlight %} - -You can also delete the element: - -{% highlight lua %} -player:hud_remove(idx) -{% endhighlight %} - ## Positioning -Screens come in different sizes, and HUD elements need to work well on all screens. -You locate an element using a combination of a position and an offset. +### Position and Offset -The position is a co-ordinate between (0, 0) and (1, 1) which determines where, -relative to the screen width and height, the element is located. -For example, an element with a position of (0.5, 0.5) will be in the center of the screen. +
+ Diagram showing a centered text element +
-The offset applies a pixel offset to the position.\\ -For example, an element with a position of (0, 0) and an offset of (10, 10) will be at the screen -co-ordinates (0 * width + 10, 0 * height + 10). +Screens come in a variety of different physical sizes and resolutions, and +the HUD needs to work well on all screen types. -Please note that offset scales to DPI and a user defined factor. +Minetest's solution to this is to specify the location of an element using both +a percentage position and an offset. +The percentage position is relative to the screen size, so to place an element +in the center of the screen you would need to provide a percentage position of half +the screen, eg (50%, 50%), and an offset of (0, 0). + +The offset is then used to move an element relative to the percentage position. + +
+ +### Alignment + +Alignment is where the result of position and offset is on the element - +for example, `{x = -1.0, y = 0.0}` will make the result of position and offset point +to the left of the element's bounds. This is particularly useful when you want to +make a text element left, center, or right justified. + +
+ Diagram showing alignment +
+ +The above diagram shows 3 windows (blue), each with a single HUD element (yellow) +with a different alignment each time. The arrow is the result of the position +and offset calculation. + +### Scoreboard + +For the purposes of this chapter, you will learn how to position and update a +score panel like so: + +
+ screenshot of the HUD we're aiming for +
+ +In the above screenshot all of the elements have the same percentage position - +(100%, 50%) - but different offsets. This allows the whole thing to be anchored +to the right of the window, but to resize without breaking. ## Text Elements -A text element is the simplest type of HUD element.\\ -Here is the earlier example, but with comments to explain each part: +You can create a hud element once you have a copy of the player object: {% highlight lua %} +local player = minetest.get_player_by_name("username") local idx = player:hud_add({ - hud_elem_type = "text", -- This is a text element - position = {x = 1, y = 0}, - offset = {x=-100, y = 20}, - scale = {x = 100, y = 100}, -- Maximum size of text, text outside these bounds is cropped - text = "My Text" -- The actual text shown + hud_elem_type = "text", + position = {x = 0.5, y = 0.5}, + offset = {x = 0, y = 0}, + text = "Hello world!", + alignment = {x = 0, y = 0}, -- center aligned + scale = {x = 100, y = 100}, -- covered later }) {% endhighlight %} -### Colors +The `hud_add` function returns an element ID - this can be used later to modify +or remove a HUD element. -Use the `number` attribute to apply colors to the text. -Colors are in [Hexadecimal form](http://www.colorpicker.com/). -For example: +### Parameters + +The element's type is given using the `hud_elem_type` property in the definition +table. The meaning of other properties varies based on this type. + +`scale` is the maximum bounds of text, text outside these bounds is cropped, eg: `{x=100, y=100}`. + +The text's color in [Hexadecimal form](http://www.colorpicker.com/), eg: `0xFF0000`, +and stored in + + +### Our Example + +Let's go ahead, and place all of the text in our score panel: {% highlight lua %} -local idx = player:hud_add({ +player:hud_add({ hud_elem_type = "text", - position = {x = 1, y = 0}, - offset = {x=-100, y = 20}, - scale = {x = 100, y = 100}, - text = "My Text", - number = 0xFF0000 -- Red + position = {x = 1, y = 0.5}, + offset = {x = -120, y = -25}, + text = "Stats", + alignment = 0, + scale = { x = 100, y = 30}, + number = 0xFFFFFF, +}) + +-- Get the dig and place count from storage, or default to 0 +local digs = tonumber(player:get_attribute("scoreboard:digs") or 0) +local digs_text = "Digs: " .. digs +local places = tonumber(player:get_attribute("scoreboard:digs") or 0) +local places_text = "Places: " .. places + +player:hud_add({ + hud_elem_type = "text", + position = {x = 1, y = 0.5}, + offset = {x = -180, y = 0}, + text = digs_text, + alignment = -1, + scale = { x = 50, y = 10}, + number = 0xFFFFFF, +}) + +player:hud_add({ + hud_elem_type = "text", + position = {x = 1, y = 0.5}, + offset = {x = -70, y = 0}, + text = places_text, + alignment = -1, + scale = { x = 50, y = 10}, + number = 0xFFFFFF, }) {% endhighlight %} +This results in the following: + +
+ screenshot of the HUD we're aiming for +
+ + ## Image Elements -Image elements display an image on the HUD. +Image elements are created in a very similar way to text elements: -The X co-ordinate of the `scale` attribute is the scale of the image, with 1 being the original texture size. -Negative values represent the percentage of the screen the image should use. For example, x=-100 means 100% (width). +{% highlight lua %} +player:hud_add({ + hud_elem_type = "image", + position = {x = 1, y = 0.5}, + offset = {x = -220, y = 0}, + text = "scoreboard_background.png", + scale = { x = 1, y = 1}, + alignment = { x = 1, y = 0 }, +}) +{% endhighlight %} + +You will now have this: + +
+ screenshot of the HUD so far +
+ +### Parameters + +The `text` field is used to provide the image name. + +If a co-ordinate is positive, then it is a scale factor with 1 being the +original image size, and 2 being double the size, and so on. +However, if a co-ordinate is negative it is a percentage of the screensize. +For example, `x=-100` is 100% of the width. + +### Scale + +Let's make the progress bar for our score panel as an example of scale: + +{% highlight lua %} +local percent = tonumber(player:get_attribute("scoreboard:score") or 0.2) + +player:hud_add({ + hud_elem_type = "image", + position = {x = 1, y = 0.5}, + offset = {x = -215, y = 23}, + text = "scoreboard_bar_empty.png", + scale = { x = 1, y = 1}, + alignment = { x = 1, y = 0 }, +}) + +player:hud_add({ + hud_elem_type = "image", + position = {x = 1, y = 0.5}, + offset = {x = -215, y = 23}, + text = "scoreboard_bar_full.png", + scale = { x = percent, y = 1}, + alignment = { x = 1, y = 0 }, +}) +{% endhighlight %} + +We now have a HUD that looks like the one in the first post! There is one problem however, it won't update when the stats change + +## Changing an Element + +You can use the ID returned by the hud_add method to update or remove it later. + +{% highlight lua %} +local idx = player:hud_add({ + hud_elem_type = "text", + text = "Hello world!", + -- parameters removed for brevity +}) + +player:hud_change(idx, "text", "New Text") +player:hud_remove(idx) +{% endhighlight %} + +The `hud_change` method takes the element ID, the property to change, and the new +value. The above call changes the `text` property from "Hello World" to "Test". + +This means that doing the `hud_change` immediately after the `hud_add` is +functionally equivalent to the following, in a rather inefficient way: + +{% highlight lua %} +local idx = player:hud_add({ + hud_elem_type = "text", + text = "New Text", +}) +{% endhighlight %} + +## Storing IDs + +{% highlight lua %} +scoreboard = {} +local saved_huds = {} + +function scoreboard.update_hud(player) + local player_name = player:get_player_name() + + local digs = tonumber(player:get_attribute("scoreboard:digs") or 0) + local digs_text = "Digs: " .. digs + local places = tonumber(player:get_attribute("scoreboard:digs") or 0) + local places_text = "Places: " .. places + + local percent = tonumber(player:get_attribute("scoreboard:score") or 0.2) + + local ids = saved_huds[player_name] + if ids then + player:hud_change(ids["places"], "text", places_text) + player:hud_change(ids["digs"], "text", digs_text) + player:hud_change(ids["bar_foreground"], + "scale", { x = percent, y = 1 }) + else + ids = {} + saved_huds[player_name] = ids + + -- create HUD elements and set ids into `ids` + end +end + +minetest.register_on_joinplayer(scoreboard.update_hud) + +minetest.register_on_leaveplayer(function(player) + saved_huds[player:get_player_name()] = nil +end) +{% endhighlight %} -Use `text` to specify the name of the texture. ## Other Elements diff --git a/static/hud_background_img.png b/static/hud_background_img.png new file mode 100644 index 0000000..d07a685 Binary files /dev/null and b/static/hud_background_img.png differ diff --git a/static/hud_diagram_alignment.svg b/static/hud_diagram_alignment.svg new file mode 100644 index 0000000..953f5bd --- /dev/null +++ b/static/hud_diagram_alignment.svg @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + -1, 0 + 0, 0 + 1, 0 + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/hud_diagram_center.svg b/static/hud_diagram_center.svg new file mode 100644 index 0000000..3b84bcf --- /dev/null +++ b/static/hud_diagram_center.svg @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + Hello world! + + (50%, 50%) + + + + + + + + + + diff --git a/static/hud_final.png b/static/hud_final.png new file mode 100644 index 0000000..92a6c3b Binary files /dev/null and b/static/hud_final.png differ diff --git a/static/hud_text.png b/static/hud_text.png new file mode 100644 index 0000000..2340a3d Binary files /dev/null and b/static/hud_text.png differ