Merge pull request 'Change arrow hit detection for accruate shooting' (#2289) from Raytraced_arrows into master

Reviewed-on: https://git.minetest.land/MineClone2/MineClone2/pulls/2289
Reviewed-by: cora <cora@noreply.git.minetest.land>
This commit is contained in:
cora 2022-06-11 02:29:26 +00:00
commit e4f514bb10

View file

@ -188,7 +188,8 @@ function ARROW_ENTITY.on_step(self, dtime)
-- The radius of 3 is fairly liberal, but anything lower than than will cause -- The radius of 3 is fairly liberal, but anything lower than than will cause
-- arrow to hilariously go through mobs often. -- arrow to hilariously go through mobs often.
-- TODO: Implement an ACTUAL collision detection (engine support needed). -- TODO: Implement an ACTUAL collision detection (engine support needed).
local objs = minetest.get_objects_inside_radius(pos, 1.5)
local closest_object local closest_object
local closest_distance local closest_distance
@ -196,32 +197,33 @@ function ARROW_ENTITY.on_step(self, dtime)
self._deflection_cooloff = self._deflection_cooloff - dtime self._deflection_cooloff = self._deflection_cooloff - dtime
end end
-- Iterate through all objects and remember the closest attackable object local arrow_dir = self.object:get_velocity()
for k, obj in pairs(objs) do --create a raycast from the arrow based on the velocity of the arrow to deal with lag
local ok = false local raycast = minetest.raycast(pos, vector.add(pos, vector.multiply(arrow_dir, 0.1)), true, false)
-- Arrows can only damage players and mobs for hitpoint in raycast do
if obj:is_player() then if hitpoint.type == "object" then
ok = true -- find the closest object that is in the way of the arrow
elseif obj:get_luaentity() then local ok = false
if (obj:get_luaentity().is_mob or obj:get_luaentity()._hittable_by_projectile) then if hitpoint.ref:is_player() then
ok = true ok = true
elseif hitpoint.ref:get_luaentity() then
if (hitpoint.ref:get_luaentity().is_mob or hitpoint.ref:get_luaentity()._hittable_by_projectile) then
ok = true
end
end end
end if ok then
local dist = vector.distance(hitpoint.ref:get_pos(), pos)
if ok then if not closest_object or not closest_distance then
local dist = vector.distance(pos, obj:get_pos()) closest_object = hitpoint.ref
if not closest_object or not closest_distance then closest_distance = dist
closest_object = obj elseif dist < closest_distance then
closest_distance = dist closest_object = hitpoint.ref
elseif dist < closest_distance then closest_distance = dist
closest_object = obj end
closest_distance = dist
end end
end end
end end
-- If an attackable object was found, we will damage the closest one only
if closest_object then if closest_object then
local obj = closest_object local obj = closest_object
local is_player = obj:is_player() local is_player = obj:is_player()
@ -249,7 +251,7 @@ function ARROW_ENTITY.on_step(self, dtime)
-- Punch target object but avoid hurting enderman. -- Punch target object but avoid hurting enderman.
if not lua or lua.name ~= "mobs_mc:enderman" then if not lua or lua.name ~= "mobs_mc:enderman" then
if not self._in_player then if not self._in_player then
damage_particles(self.object:get_pos(), self._is_critical) damage_particles(vector.add(pos, vector.multiply(self.object:get_velocity(), 0.1)), self._is_critical)
end end
if mcl_burning.is_burning(self.object) then if mcl_burning.is_burning(self.object) then
mcl_burning.set_on_fire(obj, 5) mcl_burning.set_on_fire(obj, 5)
@ -304,6 +306,8 @@ function ARROW_ENTITY.on_step(self, dtime)
minetest.after(150, function() minetest.after(150, function()
self.object:remove() self.object:remove()
end) end)
else
self.object:remove()
end end
end end
end end