Update carts from boost_cart

Better pathfinder algorithm, allows tuning the lag spike compensation.
Smoother movement (when it's laggy).
Set the player animation to stand on attach.
Remove driver when they leave.
Only update velocity when it's necessary.
This commit is contained in:
SmallJoker 2018-07-07 03:08:36 +02:00 committed by Paramat
parent 59dbeebc2f
commit ecea5364f1
3 changed files with 74 additions and 30 deletions

View File

@ -27,6 +27,10 @@ function cart_entity:on_rightclick(clicker)
elseif not self.driver then elseif not self.driver then
self.driver = player_name self.driver = player_name
carts:manage_attachment(clicker, self.object) carts:manage_attachment(clicker, self.object)
-- player_api does not update the animation
-- when the player is attached, reset to default animation
player_api.set_animation(clicker, "stand")
end end
end end
@ -36,7 +40,7 @@ function cart_entity:on_activate(staticdata, dtime_s)
return return
end end
local data = minetest.deserialize(staticdata) local data = minetest.deserialize(staticdata)
if not data or type(data) ~= "table" then if type(data) ~= "table" then
return return
end end
self.railtype = data.railtype self.railtype = data.railtype
@ -52,6 +56,13 @@ function cart_entity:get_staticdata()
}) })
end end
-- 0.5.x and later: When the driver leaves
function cart_entity:on_detach_child(child)
if child and child:get_player_name() == self.driver then
self.driver = nil
end
end
function cart_entity:on_punch(puncher, time_from_last_punch, tool_capabilities, direction) function cart_entity:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
local pos = self.object:get_pos() local pos = self.object:get_pos()
local vel = self.object:get_velocity() local vel = self.object:get_velocity()
@ -82,7 +93,7 @@ function cart_entity:on_punch(puncher, time_from_last_punch, tool_capabilities,
local player = minetest.get_player_by_name(self.driver) local player = minetest.get_player_by_name(self.driver)
carts:manage_attachment(player, nil) carts:manage_attachment(player, nil)
end end
for _,obj_ in ipairs(self.attached_items) do for _, obj_ in ipairs(self.attached_items) do
if obj_ then if obj_ then
obj_:set_detach() obj_:set_detach()
end end
@ -165,6 +176,7 @@ local function get_railparams(pos)
return carts.railparams[node.name] or {} return carts.railparams[node.name] or {}
end end
local v3_len = vector.length
local function rail_on_step(self, dtime) local function rail_on_step(self, dtime)
local vel = self.object:get_velocity() local vel = self.object:get_velocity()
if self.punched then if self.punched then
@ -201,17 +213,23 @@ local function rail_on_step(self, dtime)
local stop_wiggle = false local stop_wiggle = false
if self.old_pos and same_dir then if self.old_pos and same_dir then
-- Detection for "skipping" nodes -- Detection for "skipping" nodes (perhaps use average dtime?)
local found_path = carts:pathfinder( -- It's sophisticated enough to take the acceleration in account
pos, self.old_pos, self.old_dir, ctrl, self.old_switch, self.railtype local acc = self.object:get_acceleration()
local distance = dtime * (v3_len(vel) + 0.5 * dtime * v3_len(acc))
local new_pos, new_dir = carts:pathfinder(
pos, self.old_pos, self.old_dir, distance, ctrl,
self.old_switch, self.railtype
) )
if not found_path then if new_pos then
-- No rail found: reset back to the expected position -- No rail found: set to the expected position
pos = vector.new(self.old_pos) pos = new_pos
update.pos = true update.pos = true
cart_dir = new_dir
end end
elseif self.old_pos and cart_dir.y ~= -1 and not self.punched then elseif self.old_pos and self.old_dir.y ~= 1 and not self.punched then
-- Stop wiggle -- Stop wiggle
stop_wiggle = true stop_wiggle = true
end end
@ -223,12 +241,14 @@ local function rail_on_step(self, dtime)
local dir, switch_keys = carts:get_rail_direction( local dir, switch_keys = carts:get_rail_direction(
pos, cart_dir, ctrl, self.old_switch, self.railtype pos, cart_dir, ctrl, self.old_switch, self.railtype
) )
local dir_changed = not vector.equals(dir, self.old_dir)
local new_acc = {x=0, y=0, z=0} local new_acc = {x=0, y=0, z=0}
if stop_wiggle or vector.equals(dir, {x=0, y=0, z=0}) then if stop_wiggle or vector.equals(dir, {x=0, y=0, z=0}) then
vel = {x = 0, y = 0, z = 0} vel = {x = 0, y = 0, z = 0}
local pos_r = vector.round(pos) local pos_r = vector.round(pos)
if not carts:is_rail(pos_r, self.railtype) then if not carts:is_rail(pos_r, self.railtype)
and self.old_pos then
pos = self.old_pos pos = self.old_pos
elseif not stop_wiggle then elseif not stop_wiggle then
pos = pos_r pos = pos_r
@ -239,7 +259,7 @@ local function rail_on_step(self, dtime)
update.vel = true update.vel = true
else else
-- Direction change detected -- Direction change detected
if not vector.equals(dir, self.old_dir) then if dir_changed then
vel = vector.multiply(dir, math.abs(vel.x + vel.z)) vel = vector.multiply(dir, math.abs(vel.x + vel.z))
update.vel = true update.vel = true
if dir.y ~= self.old_dir.y then if dir.y ~= self.old_dir.y then
@ -291,7 +311,7 @@ local function rail_on_step(self, dtime)
end end
self.object:set_acceleration(new_acc) self.object:set_acceleration(new_acc)
self.old_pos = vector.new(pos) self.old_pos = vector.round(pos)
if not vector.equals(dir, {x=0, y=0, z=0}) and not stop_wiggle then if not vector.equals(dir, {x=0, y=0, z=0}) and not stop_wiggle then
self.old_dir = vector.new(dir) self.old_dir = vector.new(dir)
end end
@ -338,9 +358,15 @@ local function rail_on_step(self, dtime)
end end
self.object:set_animation(anim, 1, 0) self.object:set_animation(anim, 1, 0)
self.object:set_velocity(vel) if update.vel then
self.object:set_velocity(vel)
end
if update.pos then if update.pos then
self.object:set_pos(pos) if dir_changed then
self.object:set_pos(pos)
else
self.object:move_to(pos)
end
end end
-- call event handler -- call event handler

View File

@ -99,6 +99,16 @@ function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
right.z = -dir.x right.z = -dir.x
end end
local straight_priority = ctrl and dir.y ~= 0
-- Normal, to disallow rail switching up- & downhill
if straight_priority then
cur = self:check_front_up_down(pos, dir, true, railtype)
if cur then
return cur
end
end
if ctrl then if ctrl then
if old_switch == 1 then if old_switch == 1 then
left_check = false left_check = false
@ -106,14 +116,14 @@ function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
right_check = false right_check = false
end end
if ctrl.left and left_check then if ctrl.left and left_check then
cur = carts:check_front_up_down(pos, left, false, railtype) cur = self:check_front_up_down(pos, left, false, railtype)
if cur then if cur then
return cur, 1 return cur, 1
end end
left_check = false left_check = false
end end
if ctrl.right and right_check then if ctrl.right and right_check then
cur = carts:check_front_up_down(pos, right, false, railtype) cur = self:check_front_up_down(pos, right, false, railtype)
if cur then if cur then
return cur, 2 return cur, 2
end end
@ -122,9 +132,11 @@ function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
end end
-- Normal -- Normal
cur = carts:check_front_up_down(pos, dir, true, railtype) if not straight_priority then
if cur then cur = self:check_front_up_down(pos, dir, true, railtype)
return cur if cur then
return cur
end
end end
-- Left, if not already checked -- Left, if not already checked
@ -158,33 +170,37 @@ function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
return {x=0, y=0, z=0} return {x=0, y=0, z=0}
end end
function carts:pathfinder(pos_, old_pos, old_dir, ctrl, pf_switch, railtype) function carts:pathfinder(pos_, old_pos, old_dir, distance, ctrl,
if vector.equals(old_pos, pos_) then pf_switch, railtype)
return true
end
local pos = vector.round(pos_) local pos = vector.round(pos_)
if vector.equals(old_pos, pos) then
return
end
local pf_pos = vector.round(old_pos) local pf_pos = vector.round(old_pos)
local pf_dir = vector.new(old_dir) local pf_dir = vector.new(old_dir)
distance = math.min(carts.path_distance_max,
math.floor(distance + 1))
for i = 1, 3 do for i = 1, distance do
pf_dir, pf_switch = carts:get_rail_direction( pf_dir, pf_switch = self:get_rail_direction(
pf_pos, pf_dir, ctrl, pf_switch, railtype) pf_pos, pf_dir, ctrl, pf_switch or 0, railtype)
if vector.equals(pf_dir, {x=0, y=0, z=0}) then if vector.equals(pf_dir, {x=0, y=0, z=0}) then
-- No way forwards -- No way forwards
return false return pf_pos, pf_dir
end end
pf_pos = vector.add(pf_pos, pf_dir) pf_pos = vector.add(pf_pos, pf_dir)
if vector.equals(pf_pos, pos) then if vector.equals(pf_pos, pos) then
-- Success! Cart moved on correctly -- Success! Cart moved on correctly
return true return
end end
end end
-- Cart not found -- Not found. Put cart to predicted position
return false return pf_pos, pf_dir
end end
function carts:register_rail(name, def_overwrite, railparams) function carts:register_rail(name, def_overwrite, railparams)

View File

@ -7,6 +7,8 @@ carts.railparams = {}
carts.speed_max = 7 carts.speed_max = 7
-- Set to -1 to disable punching the cart from inside (min = -1) -- Set to -1 to disable punching the cart from inside (min = -1)
carts.punch_speed_max = 5 carts.punch_speed_max = 5
-- Maximal distance for the path correction (for dtime peaks)
carts.path_distance_max = 3
dofile(carts.modpath.."/functions.lua") dofile(carts.modpath.."/functions.lua")