airutils/physics_lib.lua

180 lines
4.3 KiB
Lua
Executable File

airutils.gravity = -9.8
local abs = math.abs
local pi = math.pi
local floor = math.floor
local ceil = math.ceil
local random = math.random
local sqrt = math.sqrt
local max = math.max
local min = math.min
local tan = math.tan
local pow = math.pow
local sign = function(x)
return (x<0) and -1 or 1
end
function airutils.rot_to_dir(rot) -- keep rot within <-pi/2,pi/2>
local dir = minetest.yaw_to_dir(rot.y)
dir.y = dir.y+tan(rot.x)*vector.length(dir)
return vector.normalize(dir)
end
function airutils.dir_to_rot(v,rot)
rot = rot or {x=0,y=0,z=0}
return {x = (v.x==0 and v.y==0 and v.z==0) and rot.x or math.atan2(v.y,vector.length({x=v.x,y=0,z=v.z})),
y = (v.x==0 and v.z==0) and rot.y or minetest.dir_to_yaw(v),
z=rot.z}
end
function airutils.pos_shift(pos,vec) -- vec components can be omitted e.g. vec={y=1}
vec.x=vec.x or 0
vec.y=vec.y or 0
vec.z=vec.z or 0
return {x=pos.x+vec.x,
y=pos.y+vec.y,
z=pos.z+vec.z}
end
function airutils.get_stand_pos(thing) -- thing can be luaentity or objectref.
local pos = {}
local colbox = {}
if type(thing) == 'table' then
pos = thing.object:get_pos()
colbox = thing.object:get_properties().collisionbox
elseif type(thing) == 'userdata' then
pos = thing:get_pos()
colbox = thing:get_properties().collisionbox
else
return false
end
return airutils.pos_shift(pos,{y=colbox[2]+0.01}), pos
end
function airutils.get_node_pos(pos)
return {
x=floor(pos.x+0.5),
y=floor(pos.y+0.5),
z=floor(pos.z+0.5),
}
end
function airutils.nodeatpos(pos)
local node = minetest.get_node_or_nil(pos)
if node then return minetest.registered_nodes[node.name] end
end
function airutils.minmax(v,m)
return min(abs(v),m)*sign(v)
end
function airutils.set_acceleration(thing,vec,limit)
limit = limit or 100
if type(thing) == 'table' then thing=thing.object end
vec.x=airutils.minmax(vec.x,limit)
vec.y=airutils.minmax(vec.y,limit)
vec.z=airutils.minmax(vec.z,limit)
thing:set_acceleration(vec)
end
function airutils.actfunc(self, staticdata, dtime_s)
self.logic = self.logic or self.brainfunc
self.physics = self.physics or airutils.physics
self.lqueue = {}
self.hqueue = {}
self.nearby_objects = {}
self.nearby_players = {}
self.pos_history = {}
self.path_dir = 1
self.time_total = 0
self.water_drag = self.water_drag or 1
local sdata = minetest.deserialize(staticdata)
if sdata then
for k,v in pairs(sdata) do
self[k] = v
end
end
if self.textures==nil then
local prop_tex = self.object:get_properties().textures
if prop_tex then self.textures=prop_tex end
end
if not self.memory then -- this is the initial activation
self.memory = {}
-- texture variation
if #self.textures > 1 then self.texture_no = random(#self.textures) end
end
if self.timeout and ((self.timeout>0 and dtime_s > self.timeout and next(self.memory)==nil) or
(self.timeout<0 and dtime_s > abs(self.timeout))) then
self.object:remove()
end
-- apply texture
if self.textures and self.texture_no then
local props = {}
props.textures = {self.textures[self.texture_no]}
self.object:set_properties(props)
end
--hp
self.max_hp = self.max_hp or 10
self.hp = self.hp or self.max_hp
--armor
if type(self.armor_groups) ~= 'table' then
self.armor_groups={}
end
self.armor_groups.immortal = 1
self.object:set_armor_groups(self.armor_groups)
self.buoyancy = self.buoyancy or 0
self.oxygen = self.oxygen or self.lung_capacity
self.lastvelocity = {x=0,y=0,z=0}
end
function airutils.get_box_height(self)
if type(self) == 'table' then self = self.object end
local colbox = self:get_properties().collisionbox
local height = 0.1
if colbox then height = colbox[5]-colbox[2] end
return height > 0 and height or 0.1
end
function airutils.stepfunc(self,dtime,colinfo)
self.dtime = min(dtime,0.2)
self.colinfo = colinfo
self.height = airutils.get_box_height(self)
-- physics comes first
local vel = self.object:get_velocity()
if colinfo then
self.isonground = colinfo.touching_ground
else
if self.lastvelocity.y==0 and vel.y==0 then
self.isonground = true
else
self.isonground = false
end
end
self:physics()
if self.logic then
if self.view_range then self:sensefunc() end
self:logic()
execute_queues(self)
end
self.lastvelocity = self.object:get_velocity()
self.time_total=self.time_total+self.dtime
end