Improve parachute spawn space checks

This commit is contained in:
Wuzzy 2022-08-06 23:57:20 +02:00
parent b6f3ef6b97
commit 71b26f060c

View File

@ -22,6 +22,55 @@ local function air_physics(v)
return ((m * g + 0.5 * cw * rho * A * v * v) / m)
end
-- Checks if pos is suitable for a parachute to spawn in
-- for player
local check_parachute_spawnable = function(pos, player)
-- We do 5 raycasts, which are all vertical.
-- 4 raycasts for the 4 vertical edges of the
-- (soon-to-exist) parachute collisionbox and
-- 1 raycast for the center.
-- The position is only treated as OK
-- when all raycasts find nothing except the player.
-- Tiny number added to the coordinates to make
-- the checked area slightly bigger than the expected
-- collision box to make sure the collisionbox
-- definitely won't overlap with nodes or objects when
-- spawned.
local tiny = 0.01
local side = CBOX_SIDE + tiny
local offsets = {
-- for testing the middle
{ 0, 0 },
-- for testing the 4 edges of the collisionbox
{ -side, -side },
{ -side, side },
{ side, -side },
{ side, side },
}
local y_extend = 1 -- Check a little bit below the potential collisionbox as well
-- so the parachute isn't spawned when standing on the ground
-- Finally check the rays
for i=1, #offsets do
local off_start = vector.new(offsets[i][1], CBOX_BOTTOM - y_extend - tiny, offsets[i][2])
local off_end = vector.new(offsets[i][1], CBOX_TOP + tiny, offsets[i][2])
local ray_start = vector.add(pos, off_start)
local ray_end = vector.add(pos, off_end)
local ray = minetest.raycast(ray_start, ray_end, true, true)
while true do
local thing = ray:next()
if not thing then
break
end
-- Any collision counts, EXCEPT with the parachuting player
if not (thing.type == "object" and thing.ref == player) then
return false
end
end
end
return true
end
-- Tries to spawn a parachute entity and attaches it to player.
-- Will fail if player is already attached to something
-- or if player is too close to the ground.
@ -40,13 +89,18 @@ local function open_parachute_for_player(player, play_sound, load_area)
local pos = player:get_pos()
local on = minetest.get_node({x = pos.x, y = pos.y - 1, z = pos.z})
if rp_player.player_attached[name] then
return false, "already_attached"
end
if on.name == "air" or on.name == "ignore" then
local spawnable = check_parachute_spawnable(pos, player)
local in_node = minetest.get_node(pos)
if in_node.name == "ignore" then
return false, "on_ground"
end
if spawnable then
-- Spawn parachute
local ppos = vector.new(pos.x, pos.y + CBOX_BOTTOM, pos.z)
@ -62,16 +116,12 @@ local function open_parachute_for_player(player, play_sound, load_area)
minetest.sound_play({name="parachute_open", pos=ppos}, {gain=0.5}, true)
end
if on.name ~= "ignore" then
obj:set_velocity(
{
x = 0,
y = math.min(0, player:get_velocity().y),
z = 0
})
else
obj:set_velocity(vector.zero())
end
player:set_attach(obj, "", {x = 0, y = -8, z = 0}, {x = 0, y = 0, z = 0}, true)
@ -80,9 +130,6 @@ local function open_parachute_for_player(player, play_sound, load_area)
local lua = obj:get_luaentity()
lua.attached = name
local in_node = minetest.get_node(pos)
lua.ignore_mode = in_node.name == "ignore"
rp_player.player_attached[name] = true
local meta = player:get_meta()