-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathpath.lua
197 lines (174 loc) · 4.14 KB
/
path.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
--[[
Copyright (c) 2016-2019 - Auke Kok <[email protected]>
* entity_ai is licensed as follows:
- All code is: LGPL-2.1
- All artwork is: CC-BY-SA-4.0
--]]
--
-- Path class - manage and execute an entity path
--
-- Class definition
Path = {}
Path.__index = Path
setmetatable(Path, {
__call = function(c, ...)
return c.new(...)
end,
})
-- constructor
function Path.new(obj)
local self = setmetatable({}, Path)
self.object = obj.object
self.driver = obj.object:get_luaentity().driver
self.origin = self.object:getpos()
self.config = {
distance = 30,
jump = 1.0,
fall = 3.0,
algorithm = "Dijkstra",
}
self.path = {}
return self
end
-- to help serialization
function Path:save()
return {
target = self.target,
config = self.config
}
end
function Path:find(finder)
-- select a finder
if not finder then
local finders = self.object:get_luaentity().script[self.driver.name].finders
if not finders then
print("No finder for driver: " .. self.driver.name)
return false
end
for _, v in ipairs(finders) do
-- use the finder
self.target = entity_ai.registered_finders[v](self.object:get_luaentity())
if self.target then
break
end
end
else
self.target = entity_ai.registered_finders[finder](self.object:get_luaentity())
end
if not self.target then
return false
end
-- pathing will fail if we're on a ledge. We can fix this by
-- pathing from the node below instead
local pos = vector.round(self.origin)
local onpos = {x = pos.x, y = pos.y - 1, z = pos.z}
local on = minetest.get_node(onpos)
if not minetest.registered_nodes[on.name].walkable then
pos.y = onpos.y
end
local config = self.config
self.path = minetest.find_path(pos, vector.round(self.target), config.distance, config.jump,
config.fall, config.algorithm)
--[[
if self.path ~= nil then
for k, v in pairs(self.path) do
minetest.add_particle({
pos = v,
velocity = vector.new(),
acceleration = vector.new(),
expirationtime = 3,
size = 3,
collisiondetection = false,
vertical = false,
texture = "wool_white.png",
playername = nil
})
end
end
--]]
return self.path ~= nil
end
function Path:step(dtime)
local curspd = self.object:getvelocity()
local pos = self.object:getpos()
-- if jumping, let jump finish before making more adjustments
if curspd.y >= 0 and curspd.y <= 2 then
local i, v = next(self.path, nil)
if not i then
return false
end
if vector.distance(pos, v) < 0.3 then
-- remove one
--FIXME shouldn't return here
local _, v2 = next(self.path, i)
if not v2 then
return false
end
end
-- prune path more?
local ii, vv = next(self.path, i)
local _, vvv = next(self.path, ii)
if vv and vvv and vvv.y == v.y and vector.distance(vv,v) < 2 then
-- prune one
self.path[ii] = nil
end
-- done pruning
--[[
minetest.add_particle({
pos = {x = v.x, y = v.y + 0.2, z = v.z},
velocity = vector.new(),
acceleration = vector.new(),
expirationtime = 1,
size = 2,
collisiondetection = false,
vertical = false,
texture = "wool_yellow.png",
playername = nil
})
--]]
local vo = {x = v.x, y = v.y - 0.5, z = v.z}
local vec = vector.subtract(vo, pos)
local len = vector.length(vec)
local vdif = vec.y
vec.y = 0
local dir = vector.normalize(vec)
local spd = vector.multiply(dir, self.driver:get_property("speed"))
-- don't jump from too far away
if vdif > 0.1 and len < 1.5 then
-- jump
spd = {x = spd.x/4, y = 5, z = spd.z/4}
self.object:setvelocity(spd)
elseif vdif < 0 and len <= 1.1 then
-- drop one path node just to be sure
self.path[i] = nil
-- falling down, just let if fall
else
spd.y = self.object:getvelocity().y
-- don't change yaw when jumping
self.object:setyaw(minetest.dir_to_yaw(spd))
self.object:setvelocity(spd)
end
end
return true
end
function Path:distance()
if not self.path then
return 0
end
if not self.target then
return 0
end
return vector.distance(self.object:getpos(), self.target)
end
function Path:length()
if not self.path then
return 0
end
return #self.path
end
function Path:get_config()
return self.config
end
function Path:set_config(conf)
self.config = conf
end