Basic laser physics

This commit is contained in:
Wuzzy 2021-12-21 17:45:26 +01:00
parent e651c2757b
commit d254ae1d49
5 changed files with 126 additions and 8 deletions

View File

@ -11,7 +11,8 @@ minetest.register_node("lzr_laser:mirror", {
"lzr_laser_mirror_block.png", "lzr_laser_mirror_block.png",
"lzr_laser_mirror_hole.png", "lzr_laser_mirror_hole.png",
}, },
groups = { mirror = 1, dig_immediate = 2 }, groups = { mirror = 1, laser_block = 1, dig_immediate = 2 },
_lzr_active = "lzr_laser:mirror_on",
}) })
minetest.register_node("lzr_laser:mirror_on", { minetest.register_node("lzr_laser:mirror_on", {
@ -25,7 +26,8 @@ minetest.register_node("lzr_laser:mirror_on", {
"lzr_laser_mirror_on_block.png", "lzr_laser_mirror_on_block.png",
"lzr_laser_mirror_on_hole.png", "lzr_laser_mirror_on_hole.png",
}, },
groups = { mirror = 2, laser = 2, dig_immediate = 2, not_in_creative_inventory = 1 }, groups = { mirror = 2, laser_block = 1, dig_immediate = 2, not_in_creative_inventory = 1 },
_lzr_inactive = "lzr_laser:mirror",
}) })
minetest.register_node("lzr_laser:emitter", { minetest.register_node("lzr_laser:emitter", {
@ -39,7 +41,8 @@ minetest.register_node("lzr_laser:emitter", {
"lzr_laser_emitter.png", "lzr_laser_emitter.png",
"lzr_laser_emitter_front.png", "lzr_laser_emitter_front.png",
}, },
groups = { emitter = 1, dig_immediate = 2 }, groups = { emitter = 1, laser_block = 1, dig_immediate = 2 },
_lzr_active = "lzr_laser:emitter_on",
}) })
minetest.register_node("lzr_laser:emitter_on", { minetest.register_node("lzr_laser:emitter_on", {
@ -53,7 +56,8 @@ minetest.register_node("lzr_laser:emitter_on", {
"lzr_laser_emitter_on.png", "lzr_laser_emitter_on.png",
"lzr_laser_emitter_on_front.png", "lzr_laser_emitter_on_front.png",
}, },
groups = { emitter = 2, dig_immediate = 2, not_in_creative_inventory = 1 }, groups = { emitter = 2, laser_block = 1, dig_immediate = 2, not_in_creative_inventory = 1 },
_lzr_inactive = "lzr_laser:emitter",
}) })
minetest.register_node("lzr_laser:detector", { minetest.register_node("lzr_laser:detector", {
@ -67,7 +71,8 @@ minetest.register_node("lzr_laser:detector", {
"lzr_laser_detector.png", "lzr_laser_detector.png",
"lzr_laser_detector_front.png", "lzr_laser_detector_front.png",
}, },
groups = { detector = 1, dig_immediate = 2 }, groups = { detector = 1, laser_block = 1, dig_immediate = 2 },
_lzr_active = "lzr_laser:detector_on",
}) })
minetest.register_node("lzr_laser:detector_on", { minetest.register_node("lzr_laser:detector_on", {
@ -81,6 +86,7 @@ minetest.register_node("lzr_laser:detector_on", {
"lzr_laser_detector_on.png", "lzr_laser_detector_on.png",
"lzr_laser_detector_on_front.png", "lzr_laser_detector_on_front.png",
}, },
groups = { detector = 2, dig_immediate = 2, not_in_creative_inventory = 1 }, groups = { detector = 2, laser_block = 1, dig_immediate = 2, not_in_creative_inventory = 1 },
_lzr_inactive = "lzr_laser:detector",
}) })

View File

@ -3,3 +3,4 @@ lzr_laser = {}
dofile(minetest.get_modpath("lzr_laser").."/util.lua") dofile(minetest.get_modpath("lzr_laser").."/util.lua")
dofile(minetest.get_modpath("lzr_laser").."/laser.lua") dofile(minetest.get_modpath("lzr_laser").."/laser.lua")
dofile(minetest.get_modpath("lzr_laser").."/blocks.lua") dofile(minetest.get_modpath("lzr_laser").."/blocks.lua")
dofile(minetest.get_modpath("lzr_laser").."/physics.lua")

View File

@ -65,6 +65,6 @@ for i=1, 64 do
type = "fixed", type = "fixed",
fixed = dirs_to_nodebox(dirs), fixed = dirs_to_nodebox(dirs),
}, },
groups = { laser = 1, dig_immediate = 3, not_in_creative_inventory = 1 }, groups = { laser = i, dig_immediate = 3, not_in_creative_inventory = 1 },
}) })
end end

View File

@ -0,0 +1,73 @@
-- Max. number of steps in the laser travel algorithm
local MAX_LASER_ITERATIONS = 50
-- Add a laser node to pos with the direction `dir`.
-- Dir is a direction vector, and only one direction must be set
function lzr_laser.add_laser(pos, dir)
local node = minetest.get_node(pos)
-- Laser through air
if node.name == "air" then
local dirs = lzr_laser.vector_to_dirs(dir)
local dirstring = lzr_laser.dirs_to_dirstring(dirs)
minetest.set_node(pos, {name="lzr_laser:laser_"..dirstring})
return true
-- Laser through laser (laser intersection)
elseif minetest.get_item_group(node.name, "laser") > 0 then
local dirnum = minetest.get_item_group(node.name, "laser")
local dirstring_old = lzr_laser.dec2bin(dirnum, 6)
local dirs_new = lzr_laser.vector_to_dirs(dir)
local dirstring_new = lzr_laser.dirs_to_dirstring(dirs_new)
local place_dirstring = lzr_laser.bitwise_or(dirstring_old, dirstring_new)
minetest.set_node(pos, {name="lzr_laser:laser_"..place_dirstring})
return true
-- Anything else: fail
else
return false
end
end
function lzr_laser.emit_laser(pos)
local node = minetest.get_node(pos)
if not minetest.get_item_group(node.name, "emitter") > 0 then
minetest.log("error", "[lzr_lazer] lzr_laser.emit_laser was called at invalid pos!")
return false
end
local dir = minetest.facedir_to_dir(node.param2)
local i_pos = vector.add(pos, dir)
end
function lzr_laser.travel_laser(pos, dir)
local i_pos = vector.add(pos, dir)
local cond = true
local i = 0
while cond do
i = i + 1
-- Halt execution for very long loops to prevent freezing the game
if i > MAX_LASER_ITERATIONS then
minetest.log("error", "[lzr_laser] lzr_laser.travel_laser aborted (too many iterations!)")
break
end
local i_node = minetest.get_node(i_pos)
cond = lzr_laser.add_laser(i_pos, dir)
i_pos = vector.add(i_pos, dir)
end
end
-- Remove all lasers in area and disable all laser blocks
function lzr_laser.clear_lasers_in_area(pos1, pos2)
local lasers = minetest.find_nodes_in_area(pos1, pos2, {"group:laser"})
minetest.bulk_set_node(lasers, {name="air"})
local laser_blocks = minetest.find_nodes_in_area(pos1, pos2, {"group:laser_block"})
for b=1, #laser_blocks do
local block = minetest.get_node(laser_blocks[b])
local def = minetest.registered_nodes[block.name]
if def then
local inactive = def._lzr_inactive
if inactive then
minetest.set_node(block, {name="inactive", param2=block.param2})
end
end
end
end

View File

@ -5,7 +5,7 @@ local LASER_RADIUS = -1/16
--[[ dirstring: A representation of 6 cardinal directions which are either --[[ dirstring: A representation of 6 cardinal directions which are either
'active' (1) or 'inactive' (0) 'active' (1) or 'inactive' (0)
Each direction has the character "1" or "0". Each direction has the character "1" or "0".
The characters stand for these directions, in order: -X, +X, -Y, +Y, -Z, +Z The characters stand for these directions, in order: -X, -Y, -Z, +X, +Y, +Z
Example: "101010" Example: "101010"
]] ]]
--[[ dirs table: Like dirstring, but in table format. It's a table --[[ dirs table: Like dirstring, but in table format. It's a table
@ -44,6 +44,29 @@ function lzr_laser.dirs_to_dirstring(dirs)
return dirstring return dirstring
end end
function lzr_laser.vector_to_dirs(dir_vector)
local dirs = {0,0,0,0,0,0}
if dir_vector.x > 0 then
dirs[4] = 1
end
if dir_vector.x < 0 then
dirs[1] = 1
end
if dir_vector.y > 0 then
dirs[5] = 1
end
if dir_vector.y < 0 then
dirs[2] = 1
end
if dir_vector.z > 0 then
dirs[6] = 1
end
if dir_vector.z < 0 then
dirs[3] = 1
end
return dirs
end
-- Convert number to string in binary form -- Convert number to string in binary form
-- * num: Number -- * num: Number
-- * minLength: Minimum number of characters the string must have, will -- * minLength: Minimum number of characters the string must have, will
@ -69,3 +92,18 @@ function lzr_laser.dec2bin(num, minLength)
return bin return bin
end end
-- Takes 2 binary numbers (as strings!)
-- and returns the 'bitwise or' of them (also as string).
-- Both strings MUST be of equal length.
function lzr_laser.bitwise_or(bin1, bin2)
local len = string.len(bin1)
local out = ""
for i=1, len do
if string.sub(bin1, i, i) == "1" or string.sub(bin2, i, i) == "1" then
out = out .. "1"
else
out = out .. "0"
end
end
return out
end