forked from whosit/waypoint_compass
267 lines
8.1 KiB
Lua
267 lines
8.1 KiB
Lua
local WAYPOINT_PRECISION = 1 -- set to 1 to show whole number or 10 for 1 decimal
|
|
local UPDATE_INTERVAL = 0.47
|
|
|
|
|
|
-- get actual eye_pos of the player (including eye_offset)
|
|
local function player_get_eye_pos(player)
|
|
local p_pos = player:get_pos()
|
|
local p_eye_height = player:get_properties().eye_height
|
|
p_pos.y = p_pos.y + p_eye_height
|
|
local p_eye_pos = p_pos
|
|
local p_eye_offset = vector.multiply(player:get_eye_offset(), 0.1)
|
|
local yaw = player:get_look_horizontal()
|
|
p_eye_pos = vector.add(p_eye_pos, vector.rotate_around_axis(p_eye_offset, {x=0,y=1,z=0}, yaw))
|
|
return p_eye_pos
|
|
end
|
|
|
|
|
|
-- return first thing player is pointing at
|
|
local function raycast_crosshair(player, range, point_to_objects, point_to_liquids)
|
|
local p_eye_pos = player_get_eye_pos(player)
|
|
local to = vector.add(p_eye_pos, vector.multiply(player:get_look_dir(), range))
|
|
local ray = minetest.raycast(p_eye_pos, to, point_to_objects, point_to_liquids)
|
|
local pointed_thing = ray:next()
|
|
while pointed_thing do
|
|
if pointed_thing.type == "object" and pointed_thing.ref == player then
|
|
-- exclude the player themselves from the raycast
|
|
pointed_thing = ray:next()
|
|
else
|
|
return pointed_thing
|
|
end
|
|
end
|
|
-- FIXME return "nothing" pointed thing?
|
|
return nil
|
|
end
|
|
|
|
|
|
-- get position and thing that player is pointing at or nil
|
|
local function get_pointed_position(player, range, point_to_objects, point_to_liquids)
|
|
local pointed_thing = raycast_crosshair(player, range, point_to_objects, point_to_liquids)
|
|
local pointed_pos = nil
|
|
if pointed_thing then
|
|
if pointed_thing.type == "node" then
|
|
-- middle between "above" and "under"
|
|
pointed_pos = vector.multiply(vector.add(pointed_thing.above, pointed_thing.under), 0.5)
|
|
elseif pointed_thing.type == "object" then
|
|
-- TODO point at the middle of collision box? (or not, ground may be better)
|
|
pointed_pos = pointed_thing.ref:get_pos()
|
|
end
|
|
end
|
|
return pointed_pos, pointed_thing
|
|
end
|
|
|
|
|
|
local function round(x)
|
|
local f = math.floor(x)
|
|
if (x == f) or (x % 2.0 == 0.5) then
|
|
return f
|
|
else
|
|
return math.floor(x + 0.5)
|
|
end
|
|
end
|
|
|
|
|
|
local function get_texture_rotation_for_direction(dir, quad_steps)
|
|
-- angle relative to player position
|
|
local angle = math.atan2(dir.x, dir.z)
|
|
local pi = math.pi
|
|
-- snap/round to increments and convert to degrees
|
|
local bias = 1/quad_steps/2 -- add bias to floor into correct quardant
|
|
local angle_quad = math.floor(angle/(2*pi) * 4 + bias) * (360 / 4) % 360
|
|
local angle_quad_map = {[0] = "I", [90] = "R270", [180] = "R180", [270] = "R90"}
|
|
local step_size = 90/quad_steps
|
|
local angle_quad_step = (round((math.deg(angle) - angle_quad)/step_size) * step_size) % 90
|
|
return angle_quad_step, angle_quad_map[angle_quad]
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- [[ Waypoint HUD element with distance, label an icon above it ]] --
|
|
local IconWaypointHUD = {}
|
|
function IconWaypointHUD:new(point_pos, label, label_color, icon, icon_scale, icon_color)
|
|
local w = {
|
|
hud_id_distance = nil,
|
|
hud_id_label = nil,
|
|
hud_id_icon = nil,
|
|
}
|
|
self.__index = self
|
|
setmetatable(w, self)
|
|
|
|
w.huddef_distance = {
|
|
hud_elem_type = "waypoint",
|
|
text = "m", -- distance suffix
|
|
precision = WAYPOINT_PRECISION, -- TODO make this configurable?
|
|
number = label_color,
|
|
world_pos = point_pos,
|
|
offset = {x=0,y=0},
|
|
alignment = {x=0, y=0.5}, -- move down
|
|
}
|
|
|
|
w.huddef_label = {
|
|
hud_elem_type = "waypoint",
|
|
name = label,
|
|
precision = 0, -- value of 0 disables the distance display
|
|
number = label_color,
|
|
world_pos = point_pos,
|
|
offset = {x=0,y=0},
|
|
alignment = {x=0, y=4}, -- move futher down
|
|
}
|
|
|
|
w.huddef_icon = {
|
|
hud_elem_type = "image_waypoint",
|
|
scale = icon_scale,
|
|
text = icon .. "^[multiply:" .. icon_color,
|
|
alignment = {x=0,y=-1},
|
|
world_pos = point_pos,
|
|
offset = {x=0,y=0},
|
|
--name = name,
|
|
--precision = WAYPOINT_PRECISION,
|
|
--number = waypoint_color,
|
|
}
|
|
|
|
return w
|
|
end
|
|
|
|
|
|
function IconWaypointHUD:show(player)
|
|
--self.player_name = player:get_player_name()
|
|
self.hud_id_distance = player:hud_add(self.huddef_distance)
|
|
self.hud_id_label = player:hud_add(self.huddef_label)
|
|
self.hud_id_icon = player:hud_add(self.huddef_icon)
|
|
end
|
|
|
|
|
|
function IconWaypointHUD:hide(player)
|
|
player:hud_remove(self.hud_id_distance)
|
|
player:hud_remove(self.hud_id_label)
|
|
player:hud_remove(self.hud_id_icon)
|
|
end
|
|
|
|
|
|
function IconWaypointHUD:update(player)
|
|
error("No reason to call IconWaypointHUD:update(), fix your code")
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- [[ Just an arrow HUD element. Can be turned any direction with update() ]] --
|
|
local CompassHUD = {}
|
|
function CompassHUD:new(size, alignment, direction, icon_format, icon_color, quad_steps)
|
|
local c = {
|
|
icon_format = icon_format,
|
|
icon_color = icon_color,
|
|
quad_steps = quad_steps,
|
|
-- TODO have a callback to auto-update the direction?
|
|
}
|
|
self.__index = self
|
|
setmetatable(c, self)
|
|
|
|
local texture = c:get_texture(direction)
|
|
|
|
c.huddef_compass = {
|
|
hud_elem_type = "compass",
|
|
size = size,
|
|
text = texture,
|
|
alignment = alignment,
|
|
dir = 1,
|
|
}
|
|
|
|
return c
|
|
end
|
|
|
|
|
|
function CompassHUD:get_texture(direction)
|
|
local angle_quad_step, rotation_t = get_texture_rotation_for_direction(direction, self.quad_steps)
|
|
|
|
local texture = self.icon_format:format(angle_quad_step) .. "^[transform" .. rotation_t .. "^[multiply:" .. self.icon_color
|
|
return texture
|
|
end
|
|
|
|
|
|
function CompassHUD:show(player)
|
|
--self.player_name = player:get_player_name()
|
|
self.hud_id_compass = player:hud_add(self.huddef_compass)
|
|
end
|
|
|
|
|
|
function CompassHUD:hide(player)
|
|
player:hud_remove(self.hud_id_compass)
|
|
end
|
|
|
|
|
|
function CompassHUD:update(player, direction)
|
|
player:hud_change(self.hud_id_compass, "text", self:get_texture(direction))
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
local WaypointHUD = {}
|
|
function WaypointHUD:new(player, point_pos,
|
|
label, label_color,
|
|
point_icon, point_icon_scale, point_color,
|
|
size, alignment, arrow_icon_format, arrow_icon_color, quad_steps,
|
|
do_auto_update)
|
|
point_pos = point_pos or {x=0, y=0, z=0}
|
|
local w = {
|
|
point_pos = point_pos,
|
|
do_auto_update = do_auto_update,
|
|
auto_update_job = nil,
|
|
}
|
|
self.__index = self
|
|
setmetatable(w, self)
|
|
|
|
w.waypoint_hud = IconWaypointHUD:new(point_pos, label, label_color, point_icon, point_icon_scale, point_color)
|
|
|
|
local d = vector.subtract(point_pos, player:get_pos())
|
|
w.compass_hud = CompassHUD:new(size, alignment, d, arrow_icon_format, arrow_icon_color, quad_steps)
|
|
|
|
return w
|
|
end
|
|
|
|
|
|
function WaypointHUD:show(player)
|
|
self.waypoint_hud:show(player)
|
|
self.compass_hud:show(player)
|
|
self:update(player) -- FIXME? needed to start auto update
|
|
end
|
|
|
|
|
|
function WaypointHUD:hide(player)
|
|
self.waypoint_hud:hide(player)
|
|
self.compass_hud:hide(player)
|
|
if self.auto_update_job then
|
|
self.auto_update_job.cancel()
|
|
self.auto_update_job = nil
|
|
end
|
|
end
|
|
|
|
|
|
function WaypointHUD:update(player)
|
|
local direction = vector.subtract(self.point_pos, player:get_pos())
|
|
self.compass_hud:update(player, direction)
|
|
if self.do_auto_update then
|
|
local player_name = player:get_player_name()
|
|
local job = minetest.after(UPDATE_INTERVAL,
|
|
function()
|
|
local player = minetest.get_player_by_name(player_name)
|
|
if player then
|
|
self:update(player)
|
|
end
|
|
end
|
|
)
|
|
self.auto_update_job = job
|
|
end
|
|
end
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
waypoint_lib = {
|
|
raycast_crosshair = raycast_crosshair,
|
|
get_pointed_position = get_pointed_position,
|
|
IconWaypointHUD = IconWaypointHUD,
|
|
CompassHUD = CompassHUD,
|
|
WaypointHUD = WaypointHUD,
|
|
}
|
|
|
|
return waypoint_lib
|