Add clearance check for spawning, Improved obstacle avoidance

This commit is contained in:
ElCeejo 2022-08-03 02:03:05 -07:00
parent da15c361cf
commit b41924d4cb
4 changed files with 53 additions and 36 deletions

View file

@ -135,7 +135,8 @@ function creatura.get_node_def(node) -- Node can be name or pos
return def return def
end end
function creatura.get_ground_level(pos2, max_diff) function creatura.get_ground_level(pos, max_diff)
local pos2 = pos -- Prevent modifying table that shouldn't be changed
pos2.y = math.floor(pos2.y - 0.49) pos2.y = math.floor(pos2.y - 0.49)
local node = minetest.get_node(pos2) local node = minetest.get_node(pos2)
local node_under = minetest.get_node({ local node_under = minetest.get_node({

View file

@ -38,7 +38,7 @@ local dir2yaw = minetest.dir_to_yaw
texture = tex or "creatura_particle_red.png", texture = tex or "creatura_particle_red.png",
expirationtime = time or 3, expirationtime = time or 3,
glow = 6, glow = 6,
size = 12 size = 1
}) })
end]] end]]
@ -59,20 +59,17 @@ local function raycast(pos1, pos2, liquid)
end end
local function get_collision(self, yaw) local function get_collision(self, yaw)
local width = self.width + 0.5 local width = self.width
local height = self.height + 0.5 local height = self.height
local total_height = height + self.stepheight local total_height = height + self.stepheight
local pos = self.object:get_pos() local pos = self.object:get_pos()
if not pos then return end if not pos then return end
local ground = creatura.get_ground_level(pos, (self.stepheight or 2)) pos.y = pos.y + 0.1
if ground.y > pos.y then local speed = abs(vec_len(self.object:get_velocity()))
pos = ground local pos2 = vec_add(pos, vec_multi(yaw2dir(yaw), (width + 0.5) * ((speed > 1 and speed) or 1)))
end -- Localize for performance
local pos2 = vec_add(pos, vec_multi(yaw2dir(yaw), width + 3)) local pos_x, pos_z = pos.x, pos.z
ground = creatura.get_ground_level(pos2, (self.stepheight or 2)) local pos2_x, pos2_z = pos2.x, pos2.z
if ground.y > pos2.y then
pos2 = ground
end
for x = -width, width, width / ceil(width) do for x = -width, width, width / ceil(width) do
local step_flag = false local step_flag = false
for y = 0, total_height, total_height / ceil(total_height) do for y = 0, total_height, total_height / ceil(total_height) do
@ -81,14 +78,14 @@ local function get_collision(self, yaw)
break break
end end
local vec1 = { local vec1 = {
x = cos(yaw) * ((pos.x + x) - pos.x) + pos.x, x = cos(yaw) * ((pos_x + x) - pos_x) + pos_x,
y = pos.y + y, y = pos.y + y,
z = sin(yaw) * ((pos.x + x) - pos.x) + pos.z z = sin(yaw) * ((pos_x + x) - pos_x) + pos_z
} }
local vec2 = { local vec2 = {
x = cos(yaw) * ((pos2.x + x) - pos2.x) + pos2.x, x = cos(yaw) * ((pos2_x + x) - pos2_x) + pos2_x,
y = vec1.y, y = vec1.y,
z = sin(yaw) * ((pos2.x + x) - pos2.x) + pos2.z z = sin(yaw) * ((pos2_x + x) - pos2_x) + pos2_z
} }
local ray = raycast(vec1, vec2, true) local ray = raycast(vec1, vec2, true)
if ray then if ray then
@ -101,6 +98,14 @@ local function get_collision(self, yaw)
end end
end end
end end
--[[if width > 0.5
and height > 0.5 then
else
local ray = raycast(pos, pos2, true)
if ray then
return true, ray.intersection_point
end
end]]
return false return false
end end
@ -112,7 +117,9 @@ local function get_avoidance_dir(self)
local vel = self.object:get_velocity() local vel = self.object:get_velocity()
local ahead = vec_add(pos, vec_normal(self.object:get_velocity())) local ahead = vec_add(pos, vec_normal(self.object:get_velocity()))
local avoidance_force = vector.subtract(ahead, col_pos) local avoidance_force = vector.subtract(ahead, col_pos)
avoidance_force = vec_multi(vec_normal(avoidance_force), vec_len(vel)) avoidance_force.y = 0
local vel_len = vec_len(vel)
avoidance_force = vec_multi(vec_normal(avoidance_force), (vel_len > 1 and vel_len) or 1)
return vec_dir(pos, vec_add(ahead, avoidance_force)) return vec_dir(pos, vec_add(ahead, avoidance_force))
end end
end end
@ -201,6 +208,7 @@ local function trim_path(pos, path)
local trim = false local trim = false
local closest local closest
for i = #path, 1, -1 do for i = #path, 1, -1 do
if not path[i] then break end
if (closest if (closest
and vec_dist(pos, path[i]) > vec_dist(pos, path[closest])) and vec_dist(pos, path[i]) > vec_dist(pos, path[closest]))
or trim then or trim then
@ -327,6 +335,8 @@ end)
creatura.register_movement_method("creatura:obstacle_avoidance", function(self) creatura.register_movement_method("creatura:obstacle_avoidance", function(self)
local box = clamp(self.width, 0.5, 1.5) local box = clamp(self.width, 0.5, 1.5)
self:set_gravity(-9.8) self:set_gravity(-9.8)
local steer_to
local steer_timer = 0.25
local function func(_self, goal, speed_factor) local function func(_self, goal, speed_factor)
local pos = _self.object:get_pos() local pos = _self.object:get_pos()
if not pos then return end if not pos then return end
@ -337,7 +347,10 @@ creatura.register_movement_method("creatura:obstacle_avoidance", function(self)
_self:halt() _self:halt()
return true return true
end end
local steer_to = get_avoidance_dir(_self, goal) steer_timer = steer_timer - self.dtime
if steer_timer <= 0 then
steer_to = get_avoidance_dir(_self)
end
-- Get movement direction -- Get movement direction
local goal_dir = vec_dir(pos, goal) local goal_dir = vec_dir(pos, goal)
if steer_to then if steer_to then
@ -355,9 +368,7 @@ creatura.register_movement_method("creatura:obstacle_avoidance", function(self)
else else
_self:set_forward_velocity(speed * 0.33) _self:set_forward_velocity(speed * 0.33)
end end
if yaw_diff > 0.1 then
_self:turn_to(goal_yaw, turn_rate) _self:turn_to(goal_yaw, turn_rate)
end end
end
return func return func
end) end)

View file

@ -67,25 +67,23 @@ minetest.register_globalstep(function(dtime)
step_tick = step_tick - dtime step_tick = step_tick - dtime
end) end)
-- A metatable is used to avoid issues
-- With mobs performing functions outside
-- their own scope
local mob = { local mob = {
-- Stats
max_health = 20, max_health = 20,
armor_groups = {fleshy = 100}, armor_groups = {fleshy = 100},
damage = 2, damage = 2,
speed = 4, speed = 4,
tracking_range = 16, tracking_range = 16,
despawn_after = nil, despawn_after = nil,
-- Physics
max_fall = 3, max_fall = 3,
stepheight = 1.1, stepheight = 1.1,
hitbox = { hitbox = {
width = 0.5, width = 0.5,
height = 1 height = 1
}, },
follow = {},
fancy_collide = false,
bouyancy_multiplier = 1,
hydrodynamics_multiplier = 1
} }
local mob_meta = {__index = mob} local mob_meta = {__index = mob}
@ -159,7 +157,7 @@ end
-- Turn to specified yaw -- Turn to specified yaw
local function lerp_rad(a, b, w) local function interp_rad(a, b, w)
local cs = (1 - w) * cos(a) + w * cos(b) local cs = (1 - w) * cos(a) + w * cos(b)
local sn = (1 - w) * sin(a) + w * sin(b) local sn = (1 - w) * sin(a) + w * sin(b)
return atan2(sn, cs) return atan2(sn, cs)
@ -170,7 +168,7 @@ function mob:turn_to(tyaw, rate)
rate = rate or 5 rate = rate or 5
local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
local step = math.min(self.dtime * rate, abs(diff(yaw, tyaw)) % (pi2)) local step = math.min(self.dtime * rate, abs(diff(yaw, tyaw)) % (pi2))
self.object:set_yaw(lerp_rad(yaw, tyaw, step)) self.object:set_yaw(interp_rad(yaw, tyaw, step))
end end
-- Set Gravity (default of -9.8) -- Set Gravity (default of -9.8)
@ -1093,7 +1091,6 @@ function mob:_execute_utilities()
} }
self:clear_action() self:clear_action()
end end
--local us_time = minetest.get_us_time()
local action = self._action local action = self._action
if action if action
and type(action) ~= "table" then and type(action) ~= "table" then
@ -1101,7 +1098,6 @@ function mob:_execute_utilities()
self:clear_action() self:clear_action()
end end
end end
--minetest.chat_send_all(minetest.get_us_time() - us_time)
end end
end end

View file

@ -57,7 +57,7 @@ function creatura.register_spawn_egg(name, col1, col2, inventory_image) -- depre
local mobdef = minetest.registered_entities[name] local mobdef = minetest.registered_entities[name]
local spawn_offset = abs(mobdef.collisionbox[2]) local spawn_offset = abs(mobdef.collisionbox[2])
local pos = minetest.get_pointed_thing_position(pointed_thing, true) local pos = minetest.get_pointed_thing_position(pointed_thing, true)
pos.y = (pos.y - 0.49) + spawn_offset pos.y = (pos.y - 0.4) + spawn_offset
local object = minetest.add_entity(pos, name) local object = minetest.add_entity(pos, name)
if object then if object then
object:set_yaw(random(1, 6)) object:set_yaw(random(1, 6))
@ -245,6 +245,14 @@ local function execute_spawns(player)
return return
end end
local mob_def = minetest.registered_entities[mob]
local mob_width = mob_def.collisionbox[4]
local mob_height = math.max(0, mob_def.collisionbox[5] - mob_def.collisionbox[2])
if not creatura.is_pos_moveable(spawn_pos, mob_width, mob_height) then
return
end
local group_size = random(spawn.min_group or 1, spawn.max_group or 1) local group_size = random(spawn.min_group or 1, spawn.max_group or 1)
if spawn.spawn_cluster then if spawn.spawn_cluster then
@ -290,7 +298,8 @@ end)
minetest.register_node("creatura:spawn_node", { minetest.register_node("creatura:spawn_node", {
drawtype = "airlike", drawtype = "airlike",
groups = {not_in_creative_inventory = 1} groups = {not_in_creative_inventory = 1},
walkable = false
}) })
local spawn_interval = tonumber(minetest.settings:get("creatura_spawn_interval")) or 10 local spawn_interval = tonumber(minetest.settings:get("creatura_spawn_interval")) or 10