Basic laser physics

master
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_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", {
@ -25,7 +26,8 @@ minetest.register_node("lzr_laser:mirror_on", {
"lzr_laser_mirror_on_block.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", {
@ -39,7 +41,8 @@ minetest.register_node("lzr_laser:emitter", {
"lzr_laser_emitter.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", {
@ -53,7 +56,8 @@ minetest.register_node("lzr_laser:emitter_on", {
"lzr_laser_emitter_on.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", {
@ -67,7 +71,8 @@ minetest.register_node("lzr_laser:detector", {
"lzr_laser_detector.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", {
@ -81,6 +86,7 @@ minetest.register_node("lzr_laser:detector_on", {
"lzr_laser_detector_on.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").."/laser.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",
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

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
'active' (1) or 'inactive' (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"
]]
--[[ 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
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
-- * num: Number
-- * minLength: Minimum number of characters the string must have, will
@ -69,3 +92,18 @@ function lzr_laser.dec2bin(num, minLength)
return bin
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